diff --git a/.editorconfig b/.editorconfig index 22371b92..9d8da2b8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,15 +15,6 @@ insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 -# Python files -[*.py] -indent_size = 4 -# isort plugin configuration -known_first_party = invenio_vocabularies -multi_line_output = 2 -default_section = THIRDPARTY -skip = .eggs - # RST files (used by sphinx) [*.rst] indent_size = 4 diff --git a/docs/conf.py b/docs/conf.py index 6b2174fc..0149acb8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ master_doc = "index" # General information about the project. -project = u"Invenio-Vocabularies" -copyright = u"2020, CERN" -author = u"CERN" +project = "Invenio-Vocabularies" +copyright = "2020, CERN" +author = "CERN" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -248,8 +248,8 @@ ( master_doc, "invenio-vocabularies.tex", - u"invenio-vocabularies Documentation", - u"CERN", + "invenio-vocabularies Documentation", + "CERN", "manual", ), ] @@ -283,7 +283,7 @@ ( master_doc, "invenio-vocabularies", - u"invenio-vocabularies Documentation", + "invenio-vocabularies Documentation", [author], 1, ) @@ -302,7 +302,7 @@ ( master_doc, "invenio-vocabularies", - u"Invenio-Vocabularies Documentation", + "Invenio-Vocabularies Documentation", author, "invenio-vocabularies", "Invenio module for managing vocabularies.", diff --git a/invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py b/invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py index efb80053..f1d8d903 100644 --- a/invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py +++ b/invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py @@ -13,8 +13,8 @@ from sqlalchemy.dialects import mysql, postgresql # revision identifiers, used by Alembic. -revision = '17c703ce1eb7' -down_revision = '4a9a4fd235f8' +revision = "17c703ce1eb7" +down_revision = "4a9a4fd235f8" branch_labels = () depends_on = None @@ -22,37 +22,33 @@ def upgrade(): """Upgrade database.""" op.create_table( - 'name_metadata', + "name_metadata", sa.Column( - 'created', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "created", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), sa.Column( - 'updated', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "updated", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( - 'id', - sqlalchemy_utils.types.uuid.UUIDType(), - nullable=False - ), - sa.Column( - 'json', + "json", sa.JSON() - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'mysql') + .with_variant(sqlalchemy_utils.types.json.JSONType(), "mysql") .with_variant( - postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), - 'postgresql') - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'sqlite'), - nullable=True + postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), "postgresql" + ) + .with_variant(sqlalchemy_utils.types.json.JSONType(), "sqlite"), + nullable=True, ), - sa.Column('version_id', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_name_metadata')) + sa.Column("version_id", sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_name_metadata")), ) def downgrade(): """Downgrade database.""" - op.drop_table('name_metadata') + op.drop_table("name_metadata") diff --git a/invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py b/invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py index 6d6d983f..822f3cdb 100644 --- a/invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py +++ b/invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py @@ -10,8 +10,8 @@ from alembic import op # revision identifiers, used by Alembic. -revision = '4a9a4fd235f8' -down_revision = '6312f33645c1' +revision = "4a9a4fd235f8" +down_revision = "6312f33645c1" branch_labels = () depends_on = None @@ -19,19 +19,19 @@ def upgrade(): """Upgrade database.""" op.create_table( - 'vocabularies_schemes', - sa.Column('id', sa.String(), nullable=False), - sa.Column('parent_id', sa.String(), nullable=False), - sa.Column('name', sa.String(), nullable=True), - sa.Column('uri', sa.String(), nullable=True), + "vocabularies_schemes", + sa.Column("id", sa.String(), nullable=False), + sa.Column("parent_id", sa.String(), nullable=False), + sa.Column("name", sa.String(), nullable=True), + sa.Column("uri", sa.String(), nullable=True), sa.PrimaryKeyConstraint( - 'id', 'parent_id', name=op.f('pk_vocabularies_schemes') - ) + "id", "parent_id", name=op.f("pk_vocabularies_schemes") + ), ) def downgrade(): """Downgrade database.""" # ### commands auto generated by Alembic - please adjust! ### - op.drop_table('vocabularies_schemes') + op.drop_table("vocabularies_schemes") # ### end Alembic commands ### diff --git a/invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py b/invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py index f4df2600..a936f5ed 100644 --- a/invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py +++ b/invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py @@ -34,9 +34,7 @@ def upgrade(): sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), nullable=False, ), - sa.Column( - "id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False - ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( "json", sa.JSON() @@ -63,9 +61,7 @@ def upgrade(): sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), nullable=False, ), - sa.Column( - "id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False - ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( "json", sa.JSON() @@ -85,9 +81,7 @@ def upgrade(): sa.Column("id", sa.String(), nullable=False), sa.Column("pid_type", sa.String(), nullable=True), sa.PrimaryKeyConstraint("id", name=op.f("pk_vocabularies_types")), - sa.UniqueConstraint( - "pid_type", name=op.f("uq_vocabularies_types_pid_type") - ), + sa.UniqueConstraint("pid_type", name=op.f("uq_vocabularies_types_pid_type")), ) diff --git a/invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py b/invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py index 62aac911..30c40002 100644 --- a/invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py +++ b/invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py @@ -13,8 +13,8 @@ from sqlalchemy.dialects import mysql, postgresql # revision identifiers, used by Alembic. -revision = '6312f33645c1' -down_revision = '4f365fced43f' +revision = "6312f33645c1" +down_revision = "4f365fced43f" branch_labels = () depends_on = None @@ -22,37 +22,33 @@ def upgrade(): """Upgrade database.""" op.create_table( - 'affiliation_metadata', + "affiliation_metadata", sa.Column( - 'created', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "created", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), sa.Column( - 'updated', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "updated", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( - 'id', - sqlalchemy_utils.types.uuid.UUIDType(), - nullable=False - ), - sa.Column( - 'json', + "json", sa.JSON() - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'mysql') + .with_variant(sqlalchemy_utils.types.json.JSONType(), "mysql") .with_variant( - postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), - 'postgresql') - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'sqlite'), - nullable=True + postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), "postgresql" + ) + .with_variant(sqlalchemy_utils.types.json.JSONType(), "sqlite"), + nullable=True, ), - sa.Column('version_id', sa.Integer(), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_affiliation_metadata')) + sa.Column("version_id", sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint("id", name=op.f("pk_affiliation_metadata")), ) def downgrade(): """Downgrade database.""" - op.drop_table('affiliation_metadata') + op.drop_table("affiliation_metadata") diff --git a/invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py b/invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py index 74057814..9617d840 100644 --- a/invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py +++ b/invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py @@ -13,8 +13,8 @@ from sqlalchemy.dialects import mysql, postgresql # revision identifiers, used by Alembic. -revision = '676dd587542d' -down_revision = '17c703ce1eb7' +revision = "676dd587542d" +down_revision = "17c703ce1eb7" branch_labels = () depends_on = None @@ -22,41 +22,37 @@ def upgrade(): """Upgrade database.""" op.create_table( - 'funder_metadata', + "funder_metadata", sa.Column( - 'created', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "created", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), sa.Column( - 'updated', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "updated", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( - 'id', - sqlalchemy_utils.types.uuid.UUIDType(), - nullable=False - ), - sa.Column( - 'json', + "json", sa.JSON() - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'mysql') + .with_variant(sqlalchemy_utils.types.json.JSONType(), "mysql") .with_variant( - postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), - 'postgresql' - ).with_variant(sqlalchemy_utils.types.json.JSONType(), 'sqlite'), - nullable=True + postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), "postgresql" + ) + .with_variant(sqlalchemy_utils.types.json.JSONType(), "sqlite"), + nullable=True, ), - sa.Column('version_id', sa.Integer(), nullable=False), - sa.Column('pid', sa.String(), nullable=True), - sa.PrimaryKeyConstraint('id', name=op.f('pk_funder_metadata')), - sa.UniqueConstraint('pid', name=op.f('uq_funder_metadata_pid')) + sa.Column("version_id", sa.Integer(), nullable=False), + sa.Column("pid", sa.String(), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_funder_metadata")), + sa.UniqueConstraint("pid", name=op.f("uq_funder_metadata_pid")), ) # ### end Alembic commands ### def downgrade(): """Downgrade database.""" - op.drop_table('funder_metadata') + op.drop_table("funder_metadata") # ### end Alembic commands ### diff --git a/invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py b/invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py index 1bbff5ad..cd12fa31 100644 --- a/invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py +++ b/invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py @@ -13,8 +13,8 @@ from sqlalchemy.dialects import mysql, postgresql # revision identifiers, used by Alembic. -revision = 'e1146238edd3' -down_revision = '676dd587542d' +revision = "e1146238edd3" +down_revision = "676dd587542d" branch_labels = () depends_on = None @@ -22,39 +22,35 @@ def upgrade(): """Downgrade database.""" op.create_table( - 'award_metadata', + "award_metadata", sa.Column( - 'created', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "created", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), sa.Column( - 'updated', - sa.DateTime().with_variant(mysql.DATETIME(fsp=6), 'mysql'), - nullable=False + "updated", + sa.DateTime().with_variant(mysql.DATETIME(fsp=6), "mysql"), + nullable=False, ), + sa.Column("id", sqlalchemy_utils.types.uuid.UUIDType(), nullable=False), sa.Column( - 'id', - sqlalchemy_utils.types.uuid.UUIDType(), - nullable=False - ), - sa.Column( - 'json', + "json", sa.JSON() - .with_variant(sqlalchemy_utils.types.json.JSONType(), 'mysql') + .with_variant(sqlalchemy_utils.types.json.JSONType(), "mysql") .with_variant( - postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), - 'postgresql' - ).with_variant(sqlalchemy_utils.types.json.JSONType(), 'sqlite'), - nullable=True + postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), "postgresql" + ) + .with_variant(sqlalchemy_utils.types.json.JSONType(), "sqlite"), + nullable=True, ), - sa.Column('version_id', sa.Integer(), nullable=False), - sa.Column('pid', sa.String(), nullable=True), - sa.PrimaryKeyConstraint('id', name=op.f('pk_award_metadata')), - sa.UniqueConstraint('pid', name=op.f('uq_award_metadata_pid')) + sa.Column("version_id", sa.Integer(), nullable=False), + sa.Column("pid", sa.String(), nullable=True), + sa.PrimaryKeyConstraint("id", name=op.f("pk_award_metadata")), + sa.UniqueConstraint("pid", name=op.f("uq_award_metadata_pid")), ) def downgrade(): """Upgrade database.""" - op.drop_table('award_metadata') + op.drop_table("award_metadata") diff --git a/invenio_vocabularies/cli.py b/invenio_vocabularies/cli.py index 80ccb3eb..2f9e9cf5 100644 --- a/invenio_vocabularies/cli.py +++ b/invenio_vocabularies/cli.py @@ -107,7 +107,7 @@ def _output_process(vocabulary, op, success, errored, filtered): f"{success} items succeeded\n" f"{errored} contained errors\n" f"{filtered} were filtered.", - fg=color + fg=color, ) @@ -157,22 +157,17 @@ def update(vocabulary, filepath=None, origin=None): @click.option("-t", "--target", type=click.STRING) @click.option("-n", "--num-samples", type=click.INT) @with_appcontext -def convert( - vocabulary, filepath=None, origin=None, target=None, num_samples=None -): +def convert(vocabulary, filepath=None, origin=None, target=None, num_samples=None): """Convert a vocabulary to a new format.""" if not filepath and (not origin or not target): click.secho( - "One of --filepath or --origin and --target must be present.", - fg="red" + "One of --filepath or --origin and --target must be present.", fg="red" ) exit(1) config = get_config_for_ds(vocabulary, filepath, origin) if not filepath: - config["writers"] = [ - {"type": "yaml", "args": {"filepath": target}} - ] + config["writers"] = [{"type": "yaml", "args": {"filepath": target}}] success, errored, filtered = _process_vocab(config, num_samples) _output_process(vocabulary, "converted", success, errored, filtered) @@ -184,31 +179,20 @@ def convert( "-i", "--identifier", type=click.STRING, - help="Identifier of the vocabulary item to delete." -) -@click.option( - "--all", - is_flag=True, - default=False, - help="Not supported yet." + help="Identifier of the vocabulary item to delete.", ) +@click.option("--all", is_flag=True, default=False, help="Not supported yet.") @with_appcontext def delete(vocabulary, identifier, all): """Delete all items or a specific one of the vocabulary.""" if not id and not all: - click.secho( - "An identifier or the --all flag must be present.", - fg="red" - ) + click.secho("An identifier or the --all flag must be present.", fg="red") exit(1) service = get_service_for_vocabulary(vocabulary) if identifier: try: if service.delete(identifier, system_identity): - click.secho( - f"{identifier} deleted from {vocabulary}.", - fg="green" - ) + click.secho(f"{identifier} deleted from {vocabulary}.", fg="green") except (PIDDeletedError, PIDDoesNotExistError): click.secho(f"PID {identifier} not found.") diff --git a/invenio_vocabularies/config.py b/invenio_vocabularies/config.py index a004c767..3b7f50c4 100644 --- a/invenio_vocabularies/config.py +++ b/invenio_vocabularies/config.py @@ -12,8 +12,16 @@ import idutils from flask_babelex import lazy_gettext as _ -from .datastreams.readers import CSVReader, GzipReader, JsonLinesReader, \ - JsonReader, TarReader, XMLReader, YamlReader, ZipReader +from .datastreams.readers import ( + CSVReader, + GzipReader, + JsonLinesReader, + JsonReader, + TarReader, + XMLReader, + YamlReader, + ZipReader, +) from .datastreams.transformers import XMLTransformer from .datastreams.writers import ServiceWriter, YamlWriter from .resources.resource import VocabulariesResourceConfig @@ -26,22 +34,10 @@ """Configure the service.""" VOCABULARIES_IDENTIFIER_SCHEMES = { - "grid": { - "label": _("GRID"), - "validator": lambda x: True - }, - "gnd": { - "label": _("GND"), - "validator": idutils.is_gnd - }, - "isni": { - "label": _("ISNI"), - "validator": idutils.is_isni - }, - "ror": { - "label": _("ROR"), - "validator": idutils.is_ror - }, + "grid": {"label": _("GRID"), "validator": lambda x: True}, + "gnd": {"label": _("GND"), "validator": idutils.is_gnd}, + "isni": {"label": _("ISNI"), "validator": idutils.is_isni}, + "ror": {"label": _("ROR"), "validator": idutils.is_ror}, } """"Generic identifier schemes, usable by other vocabularies.""" @@ -52,10 +48,7 @@ VOCABULARIES_FUNDER_SCHEMES = { **VOCABULARIES_IDENTIFIER_SCHEMES, - "doi": { - "label": _("DOI"), - "validator": idutils.is_doi - }, + "doi": {"label": _("DOI"), "validator": idutils.is_doi}, } """Funders allowed identifier schemes.""" @@ -63,41 +56,35 @@ """DOI prefix for the identifier formed with the FundRef id.""" VOCABULARIES_AWARD_SCHEMES = { - "url": { - "label": _("URL"), - "validator": idutils.is_url - }, - "doi": { - "label": _("DOI"), - "validator": idutils.is_doi - }, + "url": {"label": _("URL"), "validator": idutils.is_url}, + "doi": {"label": _("DOI"), "validator": idutils.is_doi}, } """Awards allowed identifier schemes.""" VOCABULARIES_AWARDS_OPENAIRE_FUNDERS = { - 'anr_________': '00rbzpz17', - 'aka_________': '05k73zm37', - 'arc_________': '05mmh0f86', - 'cihr________': '01gavpb45', - 'corda_______': '00k4n6c32', - 'corda__h2020': '00k4n6c32', - 'euenvagency_': '02k4b9v70', - 'fct_________': '00snfqn58', - 'fwf_________': '013tf3c58', - 'irb_hr______': '03n51vw80', - 'mestd_______': '01znas443', - 'nhmrc_______': '011kf5r70', - 'nih_________': '01cwqze88', - 'nserc_______': '01h531d29', - 'nsf_________': '021nxhr62', - 'nwo_________': '04jsz6e67', - 'rcuk________': '10.13039/501100000690', - 'ukri________': '001aqnf71', - 'sfi_________': '0271asj38', - 'snsf________': '00yjd3n13', - 'sshrc_______': '006cvnv84', - 'tubitakf____': '04w9kkr77', - 'wt__________': '029chgv08', + "anr_________": "00rbzpz17", + "aka_________": "05k73zm37", + "arc_________": "05mmh0f86", + "cihr________": "01gavpb45", + "corda_______": "00k4n6c32", + "corda__h2020": "00k4n6c32", + "euenvagency_": "02k4b9v70", + "fct_________": "00snfqn58", + "fwf_________": "013tf3c58", + "irb_hr______": "03n51vw80", + "mestd_______": "01znas443", + "nhmrc_______": "011kf5r70", + "nih_________": "01cwqze88", + "nserc_______": "01h531d29", + "nsf_________": "021nxhr62", + "nwo_________": "04jsz6e67", + "rcuk________": "10.13039/501100000690", + "ukri________": "001aqnf71", + "sfi_________": "0271asj38", + "snsf________": "00yjd3n13", + "sshrc_______": "006cvnv84", + "tubitakf____": "04w9kkr77", + "wt__________": "029chgv08", } """Mapping of OpenAIRE and ROR funder codes.""" @@ -105,21 +92,9 @@ """ROR ID for EC funder.""" VOCABULARIES_NAMES_SCHEMES = { - "orcid": { - "label": _("ORCID"), - "validator": idutils.is_orcid, - "datacite": "ORCID" - }, - "isni": { - "label": _("ISNI"), - "validator": idutils.is_isni, - "datacite": "ISNI" - }, - "gnd": { - "label": _("GND"), - "validator": idutils.is_gnd, - "datacite": "GND" - } + "orcid": {"label": _("ORCID"), "validator": idutils.is_orcid, "datacite": "ORCID"}, + "isni": {"label": _("ISNI"), "validator": idutils.is_isni, "datacite": "ISNI"}, + "gnd": {"label": _("GND"), "validator": idutils.is_gnd, "datacite": "GND"}, } """Names allowed identifier schemes.""" diff --git a/invenio_vocabularies/contrib/affiliations/affiliations.py b/invenio_vocabularies/contrib/affiliations/affiliations.py index 751304de..48fdee75 100644 --- a/invenio_vocabularies/contrib/affiliations/affiliations.py +++ b/invenio_vocabularies/contrib/affiliations/affiliations.py @@ -23,7 +23,7 @@ # Data layer pid_field_kwargs={ "create": False, - "provider": PIDProviderFactory.create(pid_type='aff'), + "provider": PIDProviderFactory.create(pid_type="aff"), "context_cls": BaseVocabularyPIDFieldContext, }, schema_version="1.0.0", @@ -40,5 +40,5 @@ service_components=service_components, permission_policy_cls=PermissionPolicy, # Resource layer - endpoint_route='/affiliations', + endpoint_route="/affiliations", ) diff --git a/invenio_vocabularies/contrib/affiliations/config.py b/invenio_vocabularies/contrib/affiliations/config.py index 97687aa6..b6225310 100644 --- a/invenio_vocabularies/contrib/affiliations/config.py +++ b/invenio_vocabularies/contrib/affiliations/config.py @@ -12,14 +12,13 @@ from flask_babelex import lazy_gettext as _ from invenio_records_resources.services import SearchOptions from invenio_records_resources.services.records.components import DataComponent -from invenio_records_resources.services.records.params import \ - SuggestQueryParser +from invenio_records_resources.services.records.params import SuggestQueryParser from werkzeug.local import LocalProxy from ...services.components import PIDComponent affiliation_schemes = LocalProxy( - lambda: current_app.config["VOCABULARIES_AFFILIATION_SCHEMES"] + lambda: current_app.config["VOCABULARIES_AFFILIATION_SCHEMES"] ) @@ -28,34 +27,34 @@ class AffiliationsSearchOptions(SearchOptions): suggest_parser_cls = SuggestQueryParser.factory( fields=[ - 'name^100', - 'acronym^20', - 'title.*^5', - 'title.*._2gram', - 'title.*._3gram', + "name^100", + "acronym^20", + "title.*^5", + "title.*._2gram", + "title.*._3gram", ], ) - sort_default = 'bestmatch' + sort_default = "bestmatch" - sort_default_no_query = 'name' + sort_default_no_query = "name" sort_options = { "bestmatch": dict( - title=_('Best match'), - fields=['_score'], # ES defaults to desc on `_score` field + title=_("Best match"), + fields=["_score"], # ES defaults to desc on `_score` field ), "name": dict( - title=_('Name'), - fields=['name_sort'], + title=_("Name"), + fields=["name_sort"], ), "newest": dict( - title=_('Newest'), - fields=['-created'], + title=_("Newest"), + fields=["-created"], ), "oldest": dict( - title=_('Oldest'), - fields=['created'], + title=_("Oldest"), + fields=["created"], ), } diff --git a/invenio_vocabularies/contrib/affiliations/schema.py b/invenio_vocabularies/contrib/affiliations/schema.py index 964a264f..7a60023f 100644 --- a/invenio_vocabularies/contrib/affiliations/schema.py +++ b/invenio_vocabularies/contrib/affiliations/schema.py @@ -23,13 +23,15 @@ class AffiliationSchema(BaseVocabularySchema): """Service schema for affiliations.""" acronym = SanitizedUnicode() - identifiers = IdentifierSet(fields.Nested( - partial( - IdentifierSchema, - allowed_schemes=affiliation_schemes, - identifier_required=False + identifiers = IdentifierSet( + fields.Nested( + partial( + IdentifierSchema, + allowed_schemes=affiliation_schemes, + identifier_required=False, + ) ) - )) + ) name = SanitizedUnicode(required=True) @@ -51,6 +53,5 @@ def validate_affiliation(self, data, **kwargs): if not id_ and not name: raise ValidationError( - _("An existing id or a free text name must be present."), - "affiliations" + _("An existing id or a free text name must be present."), "affiliations" ) diff --git a/invenio_vocabularies/contrib/awards/awards.py b/invenio_vocabularies/contrib/awards/awards.py index 61fbb35c..ea20df05 100644 --- a/invenio_vocabularies/contrib/awards/awards.py +++ b/invenio_vocabularies/contrib/awards/awards.py @@ -14,8 +14,7 @@ from invenio_records.dumpers.relations import RelationDumperExt from invenio_records.systemfields import RelationsField from invenio_records_resources.factories.factory import RecordTypeFactory -from invenio_records_resources.records.systemfields import ModelPIDField, \ - PIDRelation +from invenio_records_resources.records.systemfields import ModelPIDField, PIDRelation from ...services.permissions import PermissionPolicy from ..funders.api import Funder @@ -24,10 +23,10 @@ award_relations = RelationsField( funders=PIDRelation( - 'funder', - keys=['name'], + "funder", + keys=["name"], pid_field=Funder.pid, - cache_key='funder', + cache_key="funder", ) ) @@ -44,11 +43,11 @@ "pid": db.Column(db.String, unique=True), }, record_dumper=ElasticsearchDumper( - model_fields={'pid': ('id', str)}, + model_fields={"pid": ("id", str)}, extensions=[ - RelationDumperExt('relations'), + RelationDumperExt("relations"), IndexedAtDumperExt(), - ] + ], ), schema_version="1.0.0", schema_path="local://awards/award-v1.0.0.json", @@ -60,5 +59,5 @@ service_components=service_components, permission_policy_cls=PermissionPolicy, # Resource layer - endpoint_route='/awards', + endpoint_route="/awards", ) diff --git a/invenio_vocabularies/contrib/awards/config.py b/invenio_vocabularies/contrib/awards/config.py index 379e8591..2807924a 100644 --- a/invenio_vocabularies/contrib/awards/config.py +++ b/invenio_vocabularies/contrib/awards/config.py @@ -11,19 +11,18 @@ from flask import current_app from flask_babelex import lazy_gettext as _ from invenio_records_resources.services import SearchOptions -from invenio_records_resources.services.records.components import \ - DataComponent, RelationsComponent +from invenio_records_resources.services.records.components import ( + DataComponent, + RelationsComponent, +) from invenio_records_resources.services.records.facets import TermsFacet -from invenio_records_resources.services.records.params import \ - SuggestQueryParser +from invenio_records_resources.services.records.params import SuggestQueryParser from werkzeug.local import LocalProxy from ...services.components import ModelPIDComponent from ..funders.facets import FundersLabels -award_schemes = LocalProxy( - lambda: current_app.config["VOCABULARIES_AWARD_SCHEMES"] -) +award_schemes = LocalProxy(lambda: current_app.config["VOCABULARIES_AWARD_SCHEMES"]) awards_openaire_funders_mapping = LocalProxy( lambda: current_app.config["VOCABULARIES_AWARDS_OPENAIRE_FUNDERS"] @@ -39,19 +38,17 @@ class AwardsSearchOptions(SearchOptions): suggest_parser_cls = SuggestQueryParser.factory( fields=[ - 'acronym^100', - 'title.*^50', - 'title.*._2gram', - 'title.*._3gram', - 'number^10' + "acronym^100", + "title.*^50", + "title.*._2gram", + "title.*._3gram", + "number^10", ], ) facets = { - 'funders': TermsFacet( - field='funder.id', - label=_('Funders'), - value_labels=FundersLabels('funders') + "funders": TermsFacet( + field="funder.id", label=_("Funders"), value_labels=FundersLabels("funders") ) } diff --git a/invenio_vocabularies/contrib/awards/datastreams.py b/invenio_vocabularies/contrib/awards/datastreams.py index 62dfe26f..8ad404b4 100644 --- a/invenio_vocabularies/contrib/awards/datastreams.py +++ b/invenio_vocabularies/contrib/awards/datastreams.py @@ -34,26 +34,31 @@ def apply(self, stream_entry, **kwargs): award = {} code = record["code"] - openaire_funder_prefix = record['id'].split("::")[0].split("|")[1] + openaire_funder_prefix = record["id"].split("::")[0].split("|")[1] funder_id = awards_openaire_funders_mapping.get(openaire_funder_prefix) if funder_id is None: raise TransformerError( - _("Unknown OpenAIRE funder prefix {openaire_funder_prefix}" - .format(openaire_funder_prefix=openaire_funder_prefix))) + _( + "Unknown OpenAIRE funder prefix {openaire_funder_prefix}".format( + openaire_funder_prefix=openaire_funder_prefix + ) + ) + ) award["id"] = f"{funder_id}::{code}" identifiers = [] if funder_id == awards_ec_ror_id: - identifiers.append({ - "identifier": f"https://cordis.europa.eu/projects/{code}", - "scheme": "url" - }) + identifiers.append( + { + "identifier": f"https://cordis.europa.eu/projects/{code}", + "scheme": "url", + } + ) elif record.get("websiteurl"): - identifiers.append({ - "identifier": record.get("websiteurl"), - "scheme": "url" - }) + identifiers.append( + {"identifier": record.get("websiteurl"), "scheme": "url"} + ) if identifiers: award["identifiers"] = identifiers @@ -86,7 +91,7 @@ def apply(self, stream_entry, **kwargs): "args": { "regex": ".json.gz$", "mode": "r", - } + }, }, {"type": "gzip"}, {"type": "jsonl"}, @@ -94,13 +99,15 @@ def apply(self, stream_entry, **kwargs): "transformers": [ {"type": "openaire-award"}, ], - "writers": [{ - "type": "awards-service", - "args": { - "service_or_name": "awards", - "identity": system_identity, + "writers": [ + { + "type": "awards-service", + "args": { + "service_or_name": "awards", + "identity": system_identity, + }, } - }], + ], } """Data Stream configuration. diff --git a/invenio_vocabularies/contrib/awards/schema.py b/invenio_vocabularies/contrib/awards/schema.py index 3d550435..a6e16cb5 100644 --- a/invenio_vocabularies/contrib/awards/schema.py +++ b/invenio_vocabularies/contrib/awards/schema.py @@ -12,8 +12,15 @@ from attr import attr from flask_babelex import lazy_gettext as _ -from marshmallow import Schema, ValidationError, fields, post_load, pre_dump, \ - validate, validates_schema +from marshmallow import ( + Schema, + ValidationError, + fields, + post_load, + pre_dump, + validate, + validates_schema, +) from marshmallow_utils.fields import IdentifierSet, SanitizedUnicode from marshmallow_utils.schemas import IdentifierSchema @@ -25,23 +32,25 @@ class AwardSchema(BaseVocabularySchema): """Award schema.""" - identifiers = IdentifierSet(fields.Nested( - partial( - IdentifierSchema, - allowed_schemes=award_schemes, - identifier_required=False + identifiers = IdentifierSet( + fields.Nested( + partial( + IdentifierSchema, + allowed_schemes=award_schemes, + identifier_required=False, + ) ) - )) + ) number = SanitizedUnicode( required=True, - validate=validate.Length(min=1, error=_('Number cannot be blank.')) + validate=validate.Length(min=1, error=_("Number cannot be blank.")), ) funder = fields.Nested(FunderRelationSchema) acronym = SanitizedUnicode() id = SanitizedUnicode( - validate=validate.Length(min=1, error=_('Pid cannot be blank.')) + validate=validate.Length(min=1, error=_("Pid cannot be blank.")) ) @validates_schema @@ -63,7 +72,7 @@ def move_id(self, data, **kwargs): @pre_dump(pass_many=False) def extract_pid_value(self, data, **kwargs): """Extracts the PID value.""" - data['id'] = data.pid.pid_value + data["id"] = data.pid.pid_value return data @@ -73,13 +82,15 @@ class AwardRelationSchema(Schema): id = SanitizedUnicode() number = SanitizedUnicode() title = i18n_strings - identifiers = IdentifierSet(fields.Nested( - partial( - IdentifierSchema, - allowed_schemes=award_schemes, - identifier_required=False + identifiers = IdentifierSet( + fields.Nested( + partial( + IdentifierSchema, + allowed_schemes=award_schemes, + identifier_required=False, + ) ) - )) + ) @validates_schema def validate_data(self, data, **kwargs): @@ -89,8 +100,7 @@ def validate_data(self, data, **kwargs): title = data.get("title") if not id_ and not (number and title): raise ValidationError( - _("An existing id or number/title must be present."), - "award" + _("An existing id or number/title must be present."), "award" ) @@ -103,8 +113,9 @@ class FundingRelationSchema(Schema): @validates_schema def validate_data(self, data, **kwargs): """Validate either funder or award is present.""" - funder = data.get('funder') - award = data.get('award') + funder = data.get("funder") + award = data.get("award") if not funder and not award: raise ValidationError( - {"funding": _("At least award or funder should be present.")}) + {"funding": _("At least award or funder should be present.")} + ) diff --git a/invenio_vocabularies/contrib/funders/config.py b/invenio_vocabularies/contrib/funders/config.py index d2b67cd8..c1a549e8 100644 --- a/invenio_vocabularies/contrib/funders/config.py +++ b/invenio_vocabularies/contrib/funders/config.py @@ -12,15 +12,12 @@ from flask_babelex import lazy_gettext as _ from invenio_records_resources.services import SearchOptions from invenio_records_resources.services.records.components import DataComponent -from invenio_records_resources.services.records.params import \ - SuggestQueryParser +from invenio_records_resources.services.records.params import SuggestQueryParser from werkzeug.local import LocalProxy from ...services.components import ModelPIDComponent -funder_schemes = LocalProxy( - lambda: current_app.config["VOCABULARIES_FUNDER_SCHEMES"] -) +funder_schemes = LocalProxy(lambda: current_app.config["VOCABULARIES_FUNDER_SCHEMES"]) funder_fundref_doi_prefix = LocalProxy( lambda: current_app.config["VOCABULARIES_FUNDER_DOI_PREFIX"] @@ -32,33 +29,33 @@ class FundersSearchOptions(SearchOptions): suggest_parser_cls = SuggestQueryParser.factory( fields=[ - 'name^100', - 'title.*^5', - 'title.*._2gram', - 'title.*._3gram', + "name^100", + "title.*^5", + "title.*._2gram", + "title.*._3gram", ] ) - sort_default = 'bestmatch' + sort_default = "bestmatch" - sort_default_no_query = 'name' + sort_default_no_query = "name" sort_options = { "bestmatch": dict( - title=_('Best match'), - fields=['_score'], # ES defaults to desc on `_score` field + title=_("Best match"), + fields=["_score"], # ES defaults to desc on `_score` field ), "name": dict( - title=_('Name'), - fields=['name_sort'], + title=_("Name"), + fields=["name_sort"], ), "newest": dict( - title=_('Newest'), - fields=['-created'], + title=_("Newest"), + fields=["-created"], ), "oldest": dict( - title=_('Oldest'), - fields=['created'], + title=_("Oldest"), + fields=["created"], ), } diff --git a/invenio_vocabularies/contrib/funders/datastreams.py b/invenio_vocabularies/contrib/funders/datastreams.py index c2c9b9c2..a3815a61 100644 --- a/invenio_vocabularies/contrib/funders/datastreams.py +++ b/invenio_vocabularies/contrib/funders/datastreams.py @@ -36,8 +36,7 @@ def apply(self, stream_entry, **kwargs): funder["id"] = normalize_ror(record.get("id")) if not funder["id"]: - raise TransformerError( - _(f"Id not found in ROR entry.")) + raise TransformerError(_(f"Id not found in ROR entry.")) funder["name"] = record.get("name") if not funder["name"]: @@ -63,10 +62,12 @@ def apply(self, stream_entry, **kwargs): value = f"{funder_fundref_doi_prefix}/{value}" scheme = "doi" - funder["identifiers"].append({ - "identifier": value, - "scheme": scheme, - }) + funder["identifiers"].append( + { + "identifier": value, + "scheme": scheme, + } + ) stream_entry.entry = funder return stream_entry @@ -90,20 +91,22 @@ def apply(self, stream_entry, **kwargs): "type": "zip", "args": { "regex": ".json$", - } + }, }, - {"type": "json"} + {"type": "json"}, ], "transformers": [ {"type": "ror-funder"}, ], - "writers": [{ - "type": "funders-service", - "args": { - "service_or_name": "funders", - "identity": system_identity, + "writers": [ + { + "type": "funders-service", + "args": { + "service_or_name": "funders", + "identity": system_identity, + }, } - }], + ], } """Data Stream configuration. diff --git a/invenio_vocabularies/contrib/funders/facets.py b/invenio_vocabularies/contrib/funders/facets.py index 60cc5ee1..9c4c80df 100644 --- a/invenio_vocabularies/contrib/funders/facets.py +++ b/invenio_vocabularies/contrib/funders/facets.py @@ -17,7 +17,9 @@ class FundersLabels(VocabularyLabels): def __init__(self, vocabulary, cache=False, service_name=None): """Initialize the labels.""" super().__init__( - vocabulary, cache, service_name="funders", + vocabulary, + cache, + service_name="funders", ) self.fields = ["id", "title", "country"] # not configurable diff --git a/invenio_vocabularies/contrib/funders/funders.py b/invenio_vocabularies/contrib/funders/funders.py index 4097ebf4..0a3de7d5 100644 --- a/invenio_vocabularies/contrib/funders/funders.py +++ b/invenio_vocabularies/contrib/funders/funders.py @@ -31,10 +31,10 @@ "pid": db.Column(db.String, unique=True), }, record_dumper=ElasticsearchDumper( - model_fields={'pid': ('id', str)}, + model_fields={"pid": ("id", str)}, extensions=[ IndexedAtDumperExt(), - ] + ], ), schema_version="1.0.0", schema_path="local://funders/funder-v1.0.0.json", @@ -45,5 +45,5 @@ service_components=service_components, permission_policy_cls=PermissionPolicy, # Resource layer - endpoint_route='/funders', + endpoint_route="/funders", ) diff --git a/invenio_vocabularies/contrib/funders/schema.py b/invenio_vocabularies/contrib/funders/schema.py index 99582c13..cfc1832d 100644 --- a/invenio_vocabularies/contrib/funders/schema.py +++ b/invenio_vocabularies/contrib/funders/schema.py @@ -11,8 +11,15 @@ from functools import partial from flask_babelex import lazy_gettext as _ -from marshmallow import Schema, ValidationError, fields, post_load, pre_dump, \ - validate, validates_schema +from marshmallow import ( + Schema, + ValidationError, + fields, + post_load, + pre_dump, + validate, + validates_schema, +) from marshmallow_utils.fields import IdentifierSet, SanitizedUnicode from marshmallow_utils.schemas import IdentifierSchema @@ -24,7 +31,7 @@ class FunderRelationSchema(Schema): """Funder schema.""" name = SanitizedUnicode( - validate=validate.Length(min=1, error=_('Name cannot be blank.')) + validate=validate.Length(min=1, error=_("Name cannot be blank.")) ) id = SanitizedUnicode() @@ -40,8 +47,7 @@ def validate_funder(self, data, **kwargs): if not id_ and not name: raise ValidationError( - _("An existing id or a free text name must be present."), - "funder" + _("An existing id or a free text name must be present."), "funder" ) @@ -49,20 +55,21 @@ class FunderSchema(BaseVocabularySchema): """Service schema for funders.""" name = SanitizedUnicode( - required=True, - validate=validate.Length(min=1, error=_('Name cannot be blank.')) + required=True, validate=validate.Length(min=1, error=_("Name cannot be blank.")) ) country = SanitizedUnicode() - identifiers = IdentifierSet(fields.Nested( - partial( - IdentifierSchema, - allowed_schemes=funder_schemes, - identifier_required=False + identifiers = IdentifierSet( + fields.Nested( + partial( + IdentifierSchema, + allowed_schemes=funder_schemes, + identifier_required=False, + ) ) - )) + ) id = SanitizedUnicode( - validate=validate.Length(min=1, error=_('Pid cannot be blank.')) + validate=validate.Length(min=1, error=_("Pid cannot be blank.")) ) @validates_schema @@ -84,5 +91,5 @@ def move_id(self, data, **kwargs): @pre_dump(pass_many=False) def extract_pid_value(self, data, **kwargs): """Extracts the PID value.""" - data['id'] = data.pid.pid_value + data["id"] = data.pid.pid_value return data diff --git a/invenio_vocabularies/contrib/names/__init__.py b/invenio_vocabularies/contrib/names/__init__.py index 5b309853..9ea0e8de 100644 --- a/invenio_vocabularies/contrib/names/__init__.py +++ b/invenio_vocabularies/contrib/names/__init__.py @@ -13,7 +13,6 @@ __all__ = ( "NamesResource", - "NamesResourceConfig" - "NamesService", + "NamesResourceConfig" "NamesService", "NamesServiceConfig", ) diff --git a/invenio_vocabularies/contrib/names/config.py b/invenio_vocabularies/contrib/names/config.py index c2a7cdba..ad31ec56 100644 --- a/invenio_vocabularies/contrib/names/config.py +++ b/invenio_vocabularies/contrib/names/config.py @@ -11,17 +11,16 @@ from flask import current_app from flask_babelex import lazy_gettext as _ from invenio_records_resources.services import SearchOptions -from invenio_records_resources.services.records.components import \ - DataComponent, RelationsComponent -from invenio_records_resources.services.records.params import \ - SuggestQueryParser +from invenio_records_resources.services.records.components import ( + DataComponent, + RelationsComponent, +) +from invenio_records_resources.services.records.params import SuggestQueryParser from werkzeug.local import LocalProxy from ...services.components import PIDComponent -names_schemes = LocalProxy( - lambda: current_app.config["VOCABULARIES_NAMES_SCHEMES"] -) +names_schemes = LocalProxy(lambda: current_app.config["VOCABULARIES_NAMES_SCHEMES"]) class NamesSearchOptions(SearchOptions): @@ -29,34 +28,34 @@ class NamesSearchOptions(SearchOptions): suggest_parser_cls = SuggestQueryParser.factory( fields=[ - 'name^100', - 'family_name^100', - 'given_name^100', - 'identifiers.identifier^20', - 'affiliations.name^10', + "name^100", + "family_name^100", + "given_name^100", + "identifiers.identifier^20", + "affiliations.name^10", ], ) - sort_default = 'bestmatch' + sort_default = "bestmatch" - sort_default_no_query = 'name' + sort_default_no_query = "name" sort_options = { "bestmatch": dict( - title=_('Best match'), - fields=['_score'], # ES defaults to desc on `_score` field + title=_("Best match"), + fields=["_score"], # ES defaults to desc on `_score` field ), "name": dict( - title=_('Name'), - fields=['name_sort'], + title=_("Name"), + fields=["name_sort"], ), "newest": dict( - title=_('Newest'), - fields=['-created'], + title=_("Newest"), + fields=["-created"], ), "oldest": dict( - title=_('Oldest'), - fields=['created'], + title=_("Oldest"), + fields=["created"], ), } diff --git a/invenio_vocabularies/contrib/names/datastreams.py b/invenio_vocabularies/contrib/names/datastreams.py index 3151a68b..1c61c2c0 100644 --- a/invenio_vocabularies/contrib/names/datastreams.py +++ b/invenio_vocabularies/contrib/names/datastreams.py @@ -92,9 +92,7 @@ def _entry_id(self, entry): def _resolve(self, id_): """Resolve an entry given an id.""" - return self._service.resolve( - self._identity, id_=id_, id_type=self._scheme_id - ) + return self._service.resolve(self._identity, id_=id_, id_type=self._scheme_id) def write(self, stream_entry, *args, **kwargs): """Writes the input entry using a given service.""" @@ -105,9 +103,7 @@ def write(self, stream_entry, *args, **kwargs): # the pid is recidv2 not e.g. the orcid current = self._resolve(vocab_id) if not self._update: - raise WriterError( - [f"Vocabulary entry already exists: {entry}"] - ) + raise WriterError([f"Vocabulary entry already exists: {entry}"]) updated = dict(current.to_dict(), **entry) return StreamEntry( self._service.update(self._identity, current.id, updated) @@ -142,20 +138,20 @@ def write(self, stream_entry, *args, **kwargs): "type": "tar", "args": { "regex": ".xml$", - } + }, }, {"type": "xml"}, ], - "transformers": [ - {"type": "orcid"} - ], - "writers": [{ - "type": "names-service", - "args": { - "service_or_name": "names", - "identity": system_identity, + "transformers": [{"type": "orcid"}], + "writers": [ + { + "type": "names-service", + "args": { + "service_or_name": "names", + "identity": system_identity, + }, } - }], + ], } """ORCiD Data Stream configuration. diff --git a/invenio_vocabularies/contrib/names/names.py b/invenio_vocabularies/contrib/names/names.py index e4c21699..cab7a9fb 100644 --- a/invenio_vocabularies/contrib/names/names.py +++ b/invenio_vocabularies/contrib/names/names.py @@ -25,10 +25,10 @@ name_relations = RelationsField( affiliations=PIDListRelation( - 'affiliations', - keys=['name'], + "affiliations", + keys=["name"], pid_field=Affiliation.pid, - cache_key='affiliations', + cache_key="affiliations", ) ) @@ -38,7 +38,7 @@ pid_field_kwargs={ "create": False, "provider": PIDProviderFactory.create( - pid_type='names', base_cls=RecordIdProviderV2 + pid_type="names", base_cls=RecordIdProviderV2 ), "context_cls": BaseVocabularyPIDFieldContext, }, @@ -47,7 +47,7 @@ record_relations=name_relations, record_dumper=ElasticsearchDumper( extensions=[ - RelationDumperExt('relations'), + RelationDumperExt("relations"), IndexedAtDumperExt(), ] ), @@ -58,5 +58,5 @@ service_components=service_components, permission_policy_cls=PermissionPolicy, # Resource layer - endpoint_route='/names', + endpoint_route="/names", ) diff --git a/invenio_vocabularies/contrib/names/resources.py b/invenio_vocabularies/contrib/names/resources.py index 2b062e35..78e94eba 100644 --- a/invenio_vocabularies/contrib/names/resources.py +++ b/invenio_vocabularies/contrib/names/resources.py @@ -11,8 +11,7 @@ from flask import g from flask_resources import resource_requestctx, response_handler, route -from invenio_records_resources.resources.records.resource import \ - request_view_args +from invenio_records_resources.resources.records.resource import request_view_args from marshmallow import fields from .names import record_type @@ -37,11 +36,7 @@ def create_url_rules(self): routes = self.config.routes url_rules = super(NamesResource, self).create_url_rules() url_rules += [ - route( - "GET", - routes["item-names-resolve"], - self.name_resolve_by_id - ), + route("GET", routes["item-names-resolve"], self.name_resolve_by_id), ] return url_rules diff --git a/invenio_vocabularies/contrib/names/schema.py b/invenio_vocabularies/contrib/names/schema.py index 831fa9ef..e205b445 100644 --- a/invenio_vocabularies/contrib/names/schema.py +++ b/invenio_vocabularies/contrib/names/schema.py @@ -31,28 +31,26 @@ class NameSchema(BaseRecordSchema): given_name = SanitizedUnicode() family_name = SanitizedUnicode() identifiers = IdentifierSet( - fields.Nested(partial( - IdentifierSchema, - # It is intended to allow org schemes to be sent as personal - # and viceversa. This is a trade off learnt from running - # Zenodo in production. - allowed_schemes=names_schemes - )) + fields.Nested( + partial( + IdentifierSchema, + # It is intended to allow org schemes to be sent as personal + # and viceversa. This is a trade off learnt from running + # Zenodo in production. + allowed_schemes=names_schemes, + ) + ) ) affiliations = fields.List(fields.Nested(AffiliationRelationSchema)) @validates_schema def validate_names(self, data, **kwargs): """Validate names.""" - can_compose = data.get('family_name') and data.get("given_name") + can_compose = data.get("family_name") and data.get("given_name") name = data.get("name") if not can_compose and not name: - messages = [ - _("name or family_name and given_name must be present.") - ] - raise ValidationError({ - "family_name": messages - }) + messages = [_("name or family_name and given_name must be present.")] + raise ValidationError({"family_name": messages}) @post_load def calculate_name(self, data, **kwargs): diff --git a/invenio_vocabularies/contrib/names/services.py b/invenio_vocabularies/contrib/names/services.py index 6ec2982d..c6b309ec 100644 --- a/invenio_vocabularies/contrib/names/services.py +++ b/invenio_vocabularies/contrib/names/services.py @@ -27,12 +27,12 @@ def resolve(self, identity, id_, id_type): (i.e. only one name record can have a pair of identifier:scheme). """ es_query = Q( - 'bool', + "bool", minimum_should_match=1, must=[ - Q('term', identifiers__identifier=id_), - Q('term', identifiers__scheme=id_type), - ] + Q("term", identifiers__identifier=id_), + Q("term", identifiers__scheme=id_type), + ], ) # max_records = 1, we assume there cannot be duplicates diff --git a/invenio_vocabularies/contrib/subjects/config.py b/invenio_vocabularies/contrib/subjects/config.py index 06e66f9e..43f7f633 100644 --- a/invenio_vocabularies/contrib/subjects/config.py +++ b/invenio_vocabularies/contrib/subjects/config.py @@ -21,34 +21,34 @@ class SubjectsSearchOptions(SearchOptions): """Search options.""" suggest_parser_cls = FilteredSuggestQueryParser.factory( - filter_field='scheme', + filter_field="scheme", fields=[ # suggest fields - 'subject^100', - 'subject._2gram', - 'subject._3gram', + "subject^100", + "subject._2gram", + "subject._3gram", ], ) - sort_default = 'bestmatch' + sort_default = "bestmatch" - sort_default_no_query = 'subject' + sort_default_no_query = "subject" sort_options = { "bestmatch": dict( - title=_('Best match'), - fields=['_score'], # ES defaults to desc on `_score` field + title=_("Best match"), + fields=["_score"], # ES defaults to desc on `_score` field ), "subject": dict( - title=_('Name'), - fields=['subject_sort'], + title=_("Name"), + fields=["subject_sort"], ), "newest": dict( - title=_('Newest'), - fields=['-created'], + title=_("Newest"), + fields=["-created"], ), "oldest": dict( - title=_('Oldest'), - fields=['created'], + title=_("Oldest"), + fields=["created"], ), } diff --git a/invenio_vocabularies/contrib/subjects/schema.py b/invenio_vocabularies/contrib/subjects/schema.py index de78c619..bb6f904b 100644 --- a/invenio_vocabularies/contrib/subjects/schema.py +++ b/invenio_vocabularies/contrib/subjects/schema.py @@ -45,6 +45,5 @@ def validate_subject(self, data, **kwargs): if not id_ and not subject: raise ValidationError( - _("An existing id or a free text subject must be present."), - "subjects" + _("An existing id or a free text subject must be present."), "subjects" ) diff --git a/invenio_vocabularies/contrib/subjects/services.py b/invenio_vocabularies/contrib/subjects/services.py index d52589b8..ff011ecf 100644 --- a/invenio_vocabularies/contrib/subjects/services.py +++ b/invenio_vocabularies/contrib/subjects/services.py @@ -24,6 +24,7 @@ def create_scheme(self, identity, id_, name="", uri=""): """Create a row for the subject scheme metadata.""" self.require_permission(identity, "manage") scheme = VocabularyScheme.create( - id=id_, parent_id="subjects", name=name, uri=uri) + id=id_, parent_id="subjects", name=name, uri=uri + ) db.session.commit() return scheme diff --git a/invenio_vocabularies/contrib/subjects/subjects.py b/invenio_vocabularies/contrib/subjects/subjects.py index 3de0c9bd..b03ad234 100644 --- a/invenio_vocabularies/contrib/subjects/subjects.py +++ b/invenio_vocabularies/contrib/subjects/subjects.py @@ -24,7 +24,7 @@ # Data layer pid_field_kwargs={ "create": False, - "provider": PIDProviderFactory.create(pid_type='sub'), + "provider": PIDProviderFactory.create(pid_type="sub"), "context_cls": BaseVocabularyPIDFieldContext, }, schema_version="1.0.0", @@ -41,5 +41,5 @@ service_components=service_components, permission_policy_cls=PermissionPolicy, # Resource layer - endpoint_route='/subjects', + endpoint_route="/subjects", ) diff --git a/invenio_vocabularies/datastreams/datastreams.py b/invenio_vocabularies/datastreams/datastreams.py index 70650946..3fc2d1e4 100644 --- a/invenio_vocabularies/datastreams/datastreams.py +++ b/invenio_vocabularies/datastreams/datastreams.py @@ -62,6 +62,7 @@ def process(self, *args, **kwargs): def read(self): """Recursively read the entries.""" + def pipe_gen(gen_funcs, piped_item=None): _gen_funcs = list(gen_funcs) # copy to avoid modifying ref list # use and remove the current generator @@ -77,10 +78,9 @@ def pipe_gen(gen_funcs, piped_item=None): except ReaderError as err: yield StreamEntry( entry=item, - errors=[ - f"{current_gen_func.__qualname__}: {str(err)}" - ] + errors=[f"{current_gen_func.__qualname__}: {str(err)}"], ) + read_gens = [r.read for r in self._readers] yield from pipe_gen(read_gens) @@ -103,9 +103,7 @@ def write(self, stream_entry, *args, **kwargs): try: writer.write(stream_entry) except WriterError as err: - stream_entry.errors.append( - f"{writer.__class__.__name__}: {str(err)}" - ) + stream_entry.errors.append(f"{writer.__class__.__name__}: {str(err)}") return stream_entry diff --git a/invenio_vocabularies/datastreams/factories.py b/invenio_vocabularies/datastreams/factories.py index c927cdd5..fd526087 100644 --- a/invenio_vocabularies/datastreams/factories.py +++ b/invenio_vocabularies/datastreams/factories.py @@ -67,9 +67,7 @@ class DataStreamFactory: """Data streams factory.""" @classmethod - def create( - cls, readers_config, writers_config, transformers_config=None, **kwargs - ): + def create(cls, readers_config, writers_config, transformers_config=None, **kwargs): """Creates a data stream based on the config.""" readers = [] for r_conf in readers_config: @@ -84,6 +82,4 @@ def create( for t_conf in transformers_config: transformers.append(TransformerFactory.create(t_conf)) - return DataStream( - readers=readers, writers=writers, transformers=transformers - ) + return DataStream(readers=readers, writers=writers, transformers=transformers) diff --git a/invenio_vocabularies/datastreams/readers.py b/invenio_vocabularies/datastreams/readers.py index 79f8549b..0b02128b 100644 --- a/invenio_vocabularies/datastreams/readers.py +++ b/invenio_vocabularies/datastreams/readers.py @@ -28,7 +28,7 @@ class BaseReader(ABC): """Base reader.""" - def __init__(self, origin=None, mode='r', *args, **kwargs): + def __init__(self, origin=None, mode="r", *args, **kwargs): """Constructor. :param origin: Data source (e.g. filepath). @@ -88,9 +88,7 @@ def read(self, item=None, *args, **kwargs): class SimpleHTTPReader(BaseReader): """Simple HTTP Reader.""" - def __init__( - self, origin, id=None, ids=None, content_type=None, *args, **kwargs - ): + def __init__(self, origin, id=None, ids=None, content_type=None, *args, **kwargs): """Constructor.""" assert id or ids self._ids = ids if ids else [id] @@ -156,9 +154,7 @@ def _iter(self, fp, *args, **kwargs): else: yield entries # just one entry except JSONDecodeError as err: - raise ReaderError( - f"Cannot decode JSON file {fp.name}: {str(err)}" - ) + raise ReaderError(f"Cannot decode JSON file {fp.name}: {str(err)}") class JsonLinesReader(BaseReader): @@ -190,9 +186,7 @@ def _iter(self, fp, *args, **kwargs): class CSVReader(BaseReader): """Reads a CSV file and returns a dictionary per element.""" - def __init__( - self, *args, csv_options=None, as_dict=True, **kwargs - ): + def __init__(self, *args, csv_options=None, as_dict=True, **kwargs): """Constructor.""" self.csv_options = csv_options or {} self.as_dict = as_dict @@ -221,16 +215,14 @@ def _etree_to_dict(cls, tree): for dc in map(cls._etree_to_dict, children): for k, v in dc.items(): dd[k].append(v) - d = {tree.tag: {k: v[0] if len(v) == 1 else v - for k, v in dd.items()}} + d = {tree.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}} if tree.attrib: - d[tree.tag].update(('@' + k, v) - for k, v in tree.attrib.items()) + d[tree.tag].update(("@" + k, v) for k, v in tree.attrib.items()) if tree.text: text = tree.text.strip() if children or tree.attrib: if text: - d[tree.tag]['#text'] = text + d[tree.tag]["#text"] = text else: d[tree.tag] = text return d diff --git a/invenio_vocabularies/datastreams/transformers.py b/invenio_vocabularies/datastreams/transformers.py index fae232b0..09e74663 100644 --- a/invenio_vocabularies/datastreams/transformers.py +++ b/invenio_vocabularies/datastreams/transformers.py @@ -46,16 +46,14 @@ def _etree_to_dict(cls, tree): for dc in map(cls._etree_to_dict, children): for k, v in dc.items(): dd[k].append(v) - d = {tree.tag: {k: v[0] if len(v) == 1 else v - for k, v in dd.items()}} + d = {tree.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}} if tree.attrib: - d[tree.tag].update(('@' + k, v) - for k, v in tree.attrib.items()) + d[tree.tag].update(("@" + k, v) for k, v in tree.attrib.items()) if tree.text: text = tree.text.strip() if children or tree.attrib: if text: - d[tree.tag]['#text'] = text + d[tree.tag]["#text"] = text else: d[tree.tag] = text return d diff --git a/invenio_vocabularies/datastreams/writers.py b/invenio_vocabularies/datastreams/writers.py index 83cc5091..4a768f5b 100644 --- a/invenio_vocabularies/datastreams/writers.py +++ b/invenio_vocabularies/datastreams/writers.py @@ -39,9 +39,7 @@ def write(self, stream_entry, *args, **kwargs): class ServiceWriter(BaseWriter): """Writes the entries to an RDM instance using a Service object.""" - def __init__( - self, service_or_name, identity, *args, update=False, **kwargs - ): + def __init__(self, service_or_name, identity, *args, update=False, **kwargs): """Constructor. :param service_or_name: a service instance or a key of the @@ -70,14 +68,10 @@ def write(self, stream_entry, *args, **kwargs): entry = stream_entry.entry try: try: - return StreamEntry( - self._service.create(self._identity, entry) - ) + return StreamEntry(self._service.create(self._identity, entry)) except PIDAlreadyExists: if not self._update: - raise WriterError( - [f"Vocabulary entry already exists: {entry}"] - ) + raise WriterError([f"Vocabulary entry already exists: {entry}"]) vocab_id = self._entry_id(entry) current = self._resolve(vocab_id) updated = dict(current.to_dict(), **entry) @@ -106,7 +100,7 @@ def __init__(self, filepath, *args, **kwargs): def write(self, stream_entry, *args, **kwargs): """Writes the input stream entry using a given service.""" - with open(self._filepath, 'a') as file: + with open(self._filepath, "a") as file: # made into array for safer append # will always read array (good for reader) yaml.safe_dump([stream_entry.entry], file) diff --git a/invenio_vocabularies/ext.py b/invenio_vocabularies/ext.py index 22235e02..4c34513c 100644 --- a/invenio_vocabularies/ext.py +++ b/invenio_vocabularies/ext.py @@ -9,17 +9,36 @@ """Invenio module for managing vocabularies.""" from . import config -from .contrib.affiliations import AffiliationsResource, \ - AffiliationsResourceConfig, AffiliationsService, \ - AffiliationsServiceConfig -from .contrib.awards import AwardsResource, AwardsResourceConfig, \ - AwardsService, AwardsServiceConfig -from .contrib.funders import FundersResource, FundersResourceConfig, \ - FundersService, FundersServiceConfig -from .contrib.names import NamesResource, NamesResourceConfig, NamesService, \ - NamesServiceConfig -from .contrib.subjects import SubjectsResource, SubjectsResourceConfig, \ - SubjectsService, SubjectsServiceConfig +from .contrib.affiliations import ( + AffiliationsResource, + AffiliationsResourceConfig, + AffiliationsService, + AffiliationsServiceConfig, +) +from .contrib.awards import ( + AwardsResource, + AwardsResourceConfig, + AwardsService, + AwardsServiceConfig, +) +from .contrib.funders import ( + FundersResource, + FundersResourceConfig, + FundersService, + FundersServiceConfig, +) +from .contrib.names import ( + NamesResource, + NamesResourceConfig, + NamesService, + NamesServiceConfig, +) +from .contrib.subjects import ( + SubjectsResource, + SubjectsResourceConfig, + SubjectsService, + SubjectsServiceConfig, +) from .resources.resource import VocabulariesResource from .services.service import VocabulariesService @@ -70,15 +89,9 @@ def init_services(self, app): self.awards_service = AwardsService( config=service_configs.awards, ) - self.funders_service = FundersService( - config=service_configs.funders - ) - self.names_service = NamesService( - config=service_configs.names - ) - self.subjects_service = SubjectsService( - config=service_configs.subjects - ) + self.funders_service = FundersService(config=service_configs.funders) + self.names_service = NamesService(config=service_configs.names) + self.subjects_service = SubjectsService(config=service_configs.subjects) self.service = VocabulariesService( config=app.config["VOCABULARIES_SERVICE_CONFIG"], ) diff --git a/invenio_vocabularies/proxies.py b/invenio_vocabularies/proxies.py index 435b84dc..f6b9704a 100644 --- a/invenio_vocabularies/proxies.py +++ b/invenio_vocabularies/proxies.py @@ -15,12 +15,13 @@ def _ext_proxy(attr): return LocalProxy( - lambda: getattr(current_app.extensions['invenio-vocabularies'], attr)) + lambda: getattr(current_app.extensions["invenio-vocabularies"], attr) + ) -current_service = _ext_proxy('service') +current_service = _ext_proxy("service") """Proxy to the instantiated vocabulary service.""" -current_resource = _ext_proxy('resource') +current_resource = _ext_proxy("resource") """Proxy to the instantiated vocabulary resource.""" diff --git a/invenio_vocabularies/records/api.py b/invenio_vocabularies/records/api.py index bfb54fb0..1b662c07 100644 --- a/invenio_vocabularies/records/api.py +++ b/invenio_vocabularies/records/api.py @@ -32,9 +32,7 @@ class Vocabulary(Record): "local://vocabularies/vocabulary-v1.0.0.json", ) - index = IndexField( - "vocabularies-vocabulary-v1.0.0", search_alias="vocabularies" - ) + index = IndexField("vocabularies-vocabulary-v1.0.0", search_alias="vocabularies") #: Disable the metadata system field. metadata = None @@ -42,7 +40,7 @@ class Vocabulary(Record): type = RelatedModelField(VocabularyType, required=True) pid = PIDField( - 'id', + "id", provider=VocabularyIdProvider, context_cls=VocabularyPIDFieldContext, create=False, diff --git a/invenio_vocabularies/records/models.py b/invenio_vocabularies/records/models.py index 2b92f6f8..20a83a22 100644 --- a/invenio_vocabularies/records/models.py +++ b/invenio_vocabularies/records/models.py @@ -32,8 +32,8 @@ def create(cls, **data): def dump_obj(cls, field, record, obj): """Serializer the object into a record.""" record[field.attr_name] = { - 'id': obj.id, - 'pid_type': obj.pid_type, + "id": obj.id, + "pid_type": obj.pid_type, } @classmethod @@ -42,8 +42,8 @@ def load_obj(cls, field, record): data = record.get(field.attr_name) if data: obj = cls( - id=data.get('id'), - pid_type=data.get('pid_type'), + id=data.get("id"), + pid_type=data.get("pid_type"), ) return obj return None @@ -79,7 +79,9 @@ def create(cls, **data): """Create a new vocabulary subtype.""" banned = [",", ":"] for b in banned: - assert b not in data["id"], f"No '{b}' allowed in VocabularyScheme.id" # noqa + assert ( + b not in data["id"] + ), f"No '{b}' allowed in VocabularyScheme.id" # noqa with db.session.begin_nested(): obj = cls(**data) diff --git a/invenio_vocabularies/records/pidprovider.py b/invenio_vocabularies/records/pidprovider.py index c188c950..a2ec51b9 100644 --- a/invenio_vocabularies/records/pidprovider.py +++ b/invenio_vocabularies/records/pidprovider.py @@ -40,13 +40,14 @@ def create(cls, object_type=None, object_uuid=None, record=None, **kwargs): :returns: A :class:`VocabularyIdProvider` instance. """ assert record is not None, "Missing or invalid 'record'." - assert 'id' in record and \ - isinstance(record['id'], str), "Missing 'id' key in record." + assert "id" in record and isinstance( + record["id"], str + ), "Missing 'id' key in record." # Retrieve pid type from type. pid_type = record.type.pid_type # Retrieve pid value form record. - pid_value = record['id'] + pid_value = record["id"] # You must assign immediately. assert object_uuid @@ -57,7 +58,7 @@ def create(cls, object_type=None, object_uuid=None, record=None, **kwargs): pid_value=pid_value, object_type=object_type, object_uuid=object_uuid, - status=PIDStatus.REGISTERED + status=PIDStatus.REGISTERED, ) @@ -83,11 +84,12 @@ def create(cls, object_type=None, object_uuid=None, record=None, **kwargs): :returns: A :class:`AffiliationProvider` instance. """ assert record is not None, "Missing or invalid 'record'." - assert 'id' in record and \ - isinstance(record['id'], str), "Missing 'id' key in record." + assert "id" in record and isinstance( + record["id"], str + ), "Missing 'id' key in record." # Retrieve pid value form record. - pid_value = record['id'] + pid_value = record["id"] # You must assign immediately. assert object_uuid @@ -98,11 +100,11 @@ def create(cls, object_type=None, object_uuid=None, record=None, **kwargs): pid_value=pid_value, object_type=object_type, object_uuid=object_uuid, - status=PIDStatus.REGISTERED + status=PIDStatus.REGISTERED, ) -class PIDProviderFactory(): +class PIDProviderFactory: """Vocabulary PID provider factory.""" @staticmethod @@ -113,7 +115,5 @@ def create(pid_type, base_cls=CustomVocabularyPIDProvider): } return type( - "CustomVocabularyPIDProvider", - (base_cls,), - provider_class_attributes + "CustomVocabularyPIDProvider", (base_cls,), provider_class_attributes ) diff --git a/invenio_vocabularies/records/systemfields/__init__.py b/invenio_vocabularies/records/systemfields/__init__.py index d02601ed..1a5d2523 100644 --- a/invenio_vocabularies/records/systemfields/__init__.py +++ b/invenio_vocabularies/records/systemfields/__init__.py @@ -11,6 +11,6 @@ from .pid import BaseVocabularyPIDFieldContext, VocabularyPIDFieldContext __all__ = ( - 'BaseVocabularyPIDFieldContext', - 'VocabularyPIDFieldContext', + "BaseVocabularyPIDFieldContext", + "VocabularyPIDFieldContext", ) diff --git a/invenio_vocabularies/records/systemfields/pid.py b/invenio_vocabularies/records/systemfields/pid.py index 6d4fde13..cf958514 100644 --- a/invenio_vocabularies/records/systemfields/pid.py +++ b/invenio_vocabularies/records/systemfields/pid.py @@ -86,7 +86,7 @@ def resolve(self, pid_value): resolver = self.field._resolver_cls( pid_type=pid_type, object_type=self.field._object_type, - getter=self.record_cls.get_record + getter=self.record_cls.get_record, ) # Resolve @@ -110,9 +110,9 @@ def pid_type(self): """Get the current defined type.""" # This ensures that when we use Vocabulary.pid.with_type_ctx('...') # we cache the pid type to avoid querying the database every time. - type_id = getattr(self, '_type_id', None) + type_id = getattr(self, "_type_id", None) if type_id: - pid_type = getattr(self, '_pid_type', None) + pid_type = getattr(self, "_pid_type", None) if pid_type is None: pid_type = self.get_pid_type(type_id) self._pid_type = pid_type diff --git a/invenio_vocabularies/resources/resource.py b/invenio_vocabularies/resources/resource.py index 430273e1..34eec9b4 100644 --- a/invenio_vocabularies/resources/resource.py +++ b/invenio_vocabularies/resources/resource.py @@ -12,14 +12,26 @@ import marshmallow as ma from flask import g -from flask_resources import JSONSerializer, MarshmallowJSONSerializer, \ - ResponseHandler, resource_requestctx, response_handler -from invenio_records_resources.resources import RecordResource, \ - RecordResourceConfig, SearchRequestArgsSchema +from flask_resources import ( + JSONSerializer, + MarshmallowJSONSerializer, + ResponseHandler, + resource_requestctx, + response_handler, +) +from invenio_records_resources.resources import ( + RecordResource, + RecordResourceConfig, + SearchRequestArgsSchema, +) from invenio_records_resources.resources.records.headers import etag_headers -from invenio_records_resources.resources.records.resource import \ - request_data, request_headers, request_search_args, request_view_args, \ - route +from invenio_records_resources.resources.records.resource import ( + request_data, + request_headers, + request_search_args, + request_view_args, + route, +) from invenio_records_resources.resources.records.utils import es_preference from marshmallow import fields @@ -43,11 +55,7 @@ class VocabulariesResourceConfig(RecordResourceConfig): blueprint_name = "vocabularies" url_prefix = "/vocabularies" - routes = { - "list": "/", - "item": "//", - "tasks": "/tasks" - } + routes = {"list": "/", "item": "//", "tasks": "/tasks"} request_view_args = { "pid_value": ma.fields.Str(), @@ -57,10 +65,7 @@ class VocabulariesResourceConfig(RecordResourceConfig): request_search_args = VocabularySearchRequestArgsSchema response_handlers = { - "application/json": ResponseHandler( - JSONSerializer(), - headers=etag_headers - ), + "application/json": ResponseHandler(JSONSerializer(), headers=etag_headers), "application/vnd.inveniordm.v1+json": ResponseHandler( MarshmallowJSONSerializer( schema_cls=VocabularyL10NItemSchema, @@ -116,7 +121,7 @@ def read(self): """Read an item.""" pid_value = ( resource_requestctx.view_args["type"], - resource_requestctx.view_args["pid_value"] + resource_requestctx.view_args["pid_value"], ) item = self.service.read(g.identity, pid_value) return item.to_dict(), 200 @@ -129,7 +134,7 @@ def update(self): """Update an item.""" pid_value = ( resource_requestctx.view_args["type"], - resource_requestctx.view_args["pid_value"] + resource_requestctx.view_args["pid_value"], ) item = self.service.update( g.identity, @@ -145,7 +150,7 @@ def delete(self): """Delete an item.""" pid_value = ( resource_requestctx.view_args["type"], - resource_requestctx.view_args["pid_value"] + resource_requestctx.view_args["pid_value"], ) self.service.delete( g.identity, diff --git a/invenio_vocabularies/resources/serializer.py b/invenio_vocabularies/resources/serializer.py index b027f7f5..14c8eee7 100644 --- a/invenio_vocabularies/resources/serializer.py +++ b/invenio_vocabularies/resources/serializer.py @@ -19,9 +19,9 @@ def current_default_locale(): """Get the Flask app's default locale.""" if current_app: - return current_app.config.get('BABEL_DEFAULT_LOCALE', 'en') + return current_app.config.get("BABEL_DEFAULT_LOCALE", "en") # Use english by default if not specified - return 'en' + return "en" L10NString = partial(BabelGettextDictField, get_locale, current_default_locale) @@ -31,8 +31,8 @@ class VocabularyL10NItemSchema(Schema): """Vocabulary serializer schema.""" id = fields.String(dump_only=True) - title = L10NString(data_key='title_l10n') - description = L10NString(data_key='description_l10n') + title = L10NString(data_key="title_l10n") + description = L10NString(data_key="description_l10n") props = fields.Dict(dump_only=True) icon = fields.String(dump_only=True) tags = fields.List(fields.Str(), dump_only=True) @@ -41,12 +41,10 @@ class VocabularyL10NItemSchema(Schema): class VocabularyL10NListSchema(Schema): """Vocabulary serializer schema.""" - hits = fields.Method('get_hits') + hits = fields.Method("get_hits") def get_hits(self, obj_list): """Apply hits transformation.""" - schema = self.context['schema_cls']() - obj_list['hits']['hits'] = [ - schema.dump(h) for h in obj_list['hits']['hits'] - ] - return obj_list['hits'] + schema = self.context["schema_cls"]() + obj_list["hits"]["hits"] = [schema.dump(h) for h in obj_list["hits"]["hits"]] + return obj_list["hits"] diff --git a/invenio_vocabularies/services/components.py b/invenio_vocabularies/services/components.py index fcebb0af..73219689 100644 --- a/invenio_vocabularies/services/components.py +++ b/invenio_vocabularies/services/components.py @@ -9,8 +9,7 @@ """Vocabulary components.""" from flask_babelex import lazy_gettext as _ -from invenio_records_resources.services.records.components import \ - ServiceComponent +from invenio_records_resources.services.records.components import ServiceComponent from marshmallow import ValidationError from sqlalchemy.orm.exc import NoResultFound @@ -21,15 +20,14 @@ class VocabularyTypeComponent(ServiceComponent): """Set the record's vocabulary type.""" def _set_type(self, data, record): - type_id = data.pop('type', None) + type_id = data.pop("type", None) if type_id: try: - record.type = VocabularyType.query.filter_by( - id=type_id['id']).one() + record.type = VocabularyType.query.filter_by(id=type_id["id"]).one() except NoResultFound: raise ValidationError( - _('The vocabulary type does not exists.'), - field_name='type', + _("The vocabulary type does not exists."), + field_name="type", ) def create(self, identity, data=None, record=None, **kwargs): diff --git a/invenio_vocabularies/services/facets.py b/invenio_vocabularies/services/facets.py index 1129e02f..85e8d4fe 100644 --- a/invenio_vocabularies/services/facets.py +++ b/invenio_vocabularies/services/facets.py @@ -19,21 +19,15 @@ def lazy_get_label(vocab_item): """Lazy evaluation of a localized vocabulary label.""" - params = { - "locale": current_i18n.locale, - "default_locale": "en" - } + params = {"locale": current_i18n.locale, "default_locale": "en"} - return make_lazy_string( - gettext_from_dict, vocab_item, **params) + return make_lazy_string(gettext_from_dict, vocab_item, **params) class VocabularyLabels: """Fetching of vocabulary labels for facets.""" - def __init__( - self, vocabulary, cache=False, service_name=None, id_field="id" - ): + def __init__(self, vocabulary, cache=False, service_name=None, id_field="id"): """Initialize the labels.""" self.vocabulary = vocabulary self.cache = cache @@ -61,10 +55,12 @@ def __call__(self, ids): identity = AnonymousIdentity() if not self.cache: vocabs = self.service.read_many( - identity, type=self.vocabulary, ids=ids, fields=self.fields) + identity, type=self.vocabulary, ids=ids, fields=self.fields + ) else: vocabs = self.service.read_all( - identity, type=self.vocabulary, fields=self.fields) + identity, type=self.vocabulary, fields=self.fields + ) labels = {} vocab_list = list(vocabs.hits) # the service returns a generator diff --git a/invenio_vocabularies/services/querystr.py b/invenio_vocabularies/services/querystr.py index c36c0644..2b98c5c6 100644 --- a/invenio_vocabularies/services/querystr.py +++ b/invenio_vocabularies/services/querystr.py @@ -11,8 +11,7 @@ from functools import partial from elasticsearch_dsl import Q -from invenio_records_resources.services.records.params import \ - SuggestQueryParser +from invenio_records_resources.services.records.params import SuggestQueryParser class FilteredSuggestQueryParser(SuggestQueryParser): @@ -21,9 +20,7 @@ class FilteredSuggestQueryParser(SuggestQueryParser): @classmethod def factory(cls, filter_field=None, **extra_params): """Create a prepared instance of the query parser.""" - return partial( - cls, filter_field=filter_field, extra_params=extra_params - ) + return partial(cls, filter_field=filter_field, extra_params=extra_params) def __init__(self, identity=None, filter_field=None, extra_params=None): """Constructor.""" @@ -35,7 +32,7 @@ def parse(self, query_str): subtype_s, query_str = self.extract_subtype_s(query_str) query = super().parse(query_str) if subtype_s: - query = query & Q('terms', **{self.filter_field: subtype_s}) + query = query & Q("terms", **{self.filter_field: subtype_s}) return query def extract_subtype_s(self, query_str): diff --git a/invenio_vocabularies/services/schema.py b/invenio_vocabularies/services/schema.py index 55954638..da513f82 100644 --- a/invenio_vocabularies/services/schema.py +++ b/invenio_vocabularies/services/schema.py @@ -31,11 +31,9 @@ class BaseVocabularySchema(BaseRecordSchema): class VocabularySchema(BaseVocabularySchema): """Service schema for vocabulary records.""" - props = fields.Dict( - allow_none=False, keys=fields.Str(), values=fields.Str() - ) + props = fields.Dict(allow_none=False, keys=fields.Str(), values=fields.Str()) tags = fields.List(SanitizedUnicode()) - type = fields.Str(attribute='type.id', required=True) + type = fields.Str(attribute="type.id", required=True) class DatastreamObject(Schema): diff --git a/invenio_vocabularies/services/service.py b/invenio_vocabularies/services/service.py index ad9c317e..aba893f2 100644 --- a/invenio_vocabularies/services/service.py +++ b/invenio_vocabularies/services/service.py @@ -14,13 +14,20 @@ from flask_babelex import lazy_gettext as _ from invenio_cache import current_cache from invenio_db import db -from invenio_records_resources.services import Link, LinksTemplate, \ - RecordService, RecordServiceConfig, SearchOptions, pagination_links +from invenio_records_resources.services import ( + Link, + LinksTemplate, + RecordService, + RecordServiceConfig, + SearchOptions, + pagination_links, +) from invenio_records_resources.services.records.components import DataComponent -from invenio_records_resources.services.records.params import FilterParam, \ - SuggestQueryParser -from invenio_records_resources.services.records.schema import \ - ServiceSchemaWrapper +from invenio_records_resources.services.records.params import ( + FilterParam, + SuggestQueryParser, +) +from invenio_records_resources.services.records.schema import ServiceSchemaWrapper from invenio_records_resources.services.uow import unit_of_work from ..records.api import Vocabulary @@ -35,40 +42,40 @@ class VocabularySearchOptions(SearchOptions): """Search options.""" params_interpreters_cls = [ - FilterParam.factory(param='tags', field='tags'), + FilterParam.factory(param="tags", field="tags"), ] + SearchOptions.params_interpreters_cls suggest_parser_cls = SuggestQueryParser.factory( fields=[ - 'id.text^100', - 'id.text._2gram', - 'id.text._3gram', - 'title.en^5', - 'title.en._2gram', - 'title.en._3gram', + "id.text^100", + "id.text._2gram", + "id.text._3gram", + "title.en^5", + "title.en._2gram", + "title.en._3gram", ], ) - sort_default = 'bestmatch' + sort_default = "bestmatch" - sort_default_no_query = 'title' + sort_default_no_query = "title" sort_options = { "bestmatch": dict( - title=_('Best match'), - fields=['_score'], # ES defaults to desc on `_score` field + title=_("Best match"), + fields=["_score"], # ES defaults to desc on `_score` field ), "title": dict( - title=_('Title'), - fields=['title_sort'], + title=_("Title"), + fields=["title_sort"], ), "newest": dict( - title=_('Newest'), - fields=['-created'], + title=_("Newest"), + fields=["-created"], ), "oldest": dict( - title=_('Oldest'), - fields=['created'], + title=_("Oldest"), + fields=["created"], ), } @@ -94,10 +101,12 @@ class VocabulariesServiceConfig(RecordServiceConfig): links_item = { "self": Link( "{+api}/vocabularies/{type}/{id}", - vars=lambda record, vars: vars.update({ - "id": record.pid.pid_value, - "type": record.type.id, - }) + vars=lambda record, vars: vars.update( + { + "id": record.pid.pid_value, + "type": record.type.id, + } + ), ), } @@ -119,10 +128,9 @@ def create_type(self, identity, id, pid_type, uow=None): type_ = VocabularyType.create(id=id, pid_type=pid_type) return type_ - def search(self, identity, params=None, es_preference=None, type=None, - **kwargs): + def search(self, identity, params=None, es_preference=None, type=None, **kwargs): """Search for vocabulary entries.""" - self.require_permission(identity, 'search') + self.require_permission(identity, "search") # If not found, NoResultFound is raised (caught by the resource). vocabulary_type = VocabularyType.query.filter_by(id=type).one() @@ -130,11 +138,11 @@ def search(self, identity, params=None, es_preference=None, type=None, # Prepare and execute the search params = params or {} search_result = self._search( - 'search', + "search", identity, params, es_preference, - extra_filter=Q('term', type__id=vocabulary_type.id), + extra_filter=Q("term", type__id=vocabulary_type.id), **kwargs ).execute() @@ -143,22 +151,17 @@ def search(self, identity, params=None, es_preference=None, type=None, identity, search_result, params, - links_tpl=LinksTemplate(self.config.links_search, context={ - "args": params, - "type": vocabulary_type.id, - }), + links_tpl=LinksTemplate( + self.config.links_search, + context={ + "args": params, + "type": vocabulary_type.id, + }, + ), links_item_tpl=self.links_item_tpl, ) - def read_all( - self, - identity, - fields, - type, - cache=True, - extra_filter='', - **kwargs - ): + def read_all(self, identity, fields, type, cache=True, extra_filter="", **kwargs): """Search for records matching the querystring.""" cache_key = type + "_" + str(extra_filter) + "_" + "-".join(fields) results = current_cache.get(cache_key) @@ -167,12 +170,12 @@ def read_all( if not results: # If not found, NoResultFound is raised (caught by the resource). vocabulary_type = VocabularyType.query.filter_by(id=type).one() - vocab_id_filter = Q('term', type__id=vocabulary_type.id) + vocab_id_filter = Q("term", type__id=vocabulary_type.id) if extra_filter: vocab_id_filter = vocab_id_filter & extra_filter results = self._read_many( - identity, es_query, fields, - extra_filter=vocab_id_filter, **kwargs) + identity, es_query, fields, extra_filter=vocab_id_filter, **kwargs + ) if cache: # ES DSL Response is not pickable. # If saved in cache serialization wont work with to_dict() @@ -183,7 +186,7 @@ def read_all( identity=identity, record_cls=self.record_cls, search_opts=self.config.search, - permission_action='search', + permission_action="search", ).query(es_query) results = Response(search, results) @@ -194,16 +197,16 @@ def read_many(self, identity, type, ids, fields=None, **kwargs): """Search for records matching the querystring filtered by ids.""" es_query = Q("match_all") vocabulary_type = VocabularyType.query.filter_by(id=type).one() - vocab_id_filter = Q('term', type__id=vocabulary_type.id) + vocab_id_filter = Q("term", type__id=vocabulary_type.id) filters = [] for id_ in ids: - filters.append(Q('term', **{"id": id_})) - filter = Q('bool', minimum_should_match=1, should=filters) + filters.append(Q("term", **{"id": id_})) + filter = Q("bool", minimum_should_match=1, should=filters) filter = filter & vocab_id_filter results = self._read_many( - identity, es_query, fields, - extra_filter=filter, **kwargs) + identity, es_query, fields, extra_filter=filter, **kwargs + ) return self.result_list(self, identity, results) @@ -218,7 +221,7 @@ def launch(self, identity, data): task_config, _ = self.task_schema.load( data, context={"identity": identity}, # FIXME: is this needed - raise_errors=True + raise_errors=True, ) process_datastream.delay(task_config) diff --git a/invenio_vocabularies/views.py b/invenio_vocabularies/views.py index e1c592b4..be150406 100644 --- a/invenio_vocabularies/views.py +++ b/invenio_vocabularies/views.py @@ -10,7 +10,7 @@ from flask import Blueprint -blueprint = Blueprint('invenio_vocabularies_ext', __name__) +blueprint = Blueprint("invenio_vocabularies_ext", __name__) @blueprint.record_once @@ -19,24 +19,22 @@ def init(state): app = state.app # Register services - cannot be done in extension because # Invenio-Records-Resources might not have been initialized. - sregistry = app.extensions['invenio-records-resources'].registry - ext = app.extensions['invenio-vocabularies'] - sregistry.register(ext.affiliations_service, service_id='affiliations') - sregistry.register(ext.awards_service, service_id='awards') - sregistry.register(ext.funders_service, service_id='funders') - sregistry.register(ext.names_service, service_id='names') - sregistry.register(ext.subjects_service, service_id='subjects') - sregistry.register(ext.service, service_id='vocabularies') + sregistry = app.extensions["invenio-records-resources"].registry + ext = app.extensions["invenio-vocabularies"] + sregistry.register(ext.affiliations_service, service_id="affiliations") + sregistry.register(ext.awards_service, service_id="awards") + sregistry.register(ext.funders_service, service_id="funders") + sregistry.register(ext.names_service, service_id="names") + sregistry.register(ext.subjects_service, service_id="subjects") + sregistry.register(ext.service, service_id="vocabularies") # Register indexers - iregistry = app.extensions['invenio-indexer'].registry - iregistry.register( - ext.affiliations_service.indexer, indexer_id='affiliations' - ) - iregistry.register(ext.awards_service.indexer, indexer_id='awards') - iregistry.register(ext.funders_service.indexer, indexer_id='funders') - iregistry.register(ext.names_service.indexer, indexer_id='names') - iregistry.register(ext.subjects_service.indexer, indexer_id='subjects') - iregistry.register(ext.service.indexer, indexer_id='vocabularies') + iregistry = app.extensions["invenio-indexer"].registry + iregistry.register(ext.affiliations_service.indexer, indexer_id="affiliations") + iregistry.register(ext.awards_service.indexer, indexer_id="awards") + iregistry.register(ext.funders_service.indexer, indexer_id="funders") + iregistry.register(ext.names_service.indexer, indexer_id="names") + iregistry.register(ext.subjects_service.indexer, indexer_id="subjects") + iregistry.register(ext.service.indexer, indexer_id="vocabularies") def create_blueprint_from_app(app): @@ -46,20 +44,17 @@ def create_blueprint_from_app(app): def create_affiliations_blueprint_from_app(app): """Create app blueprint.""" - return app.extensions["invenio-vocabularies"].affiliations_resource \ - .as_blueprint() + return app.extensions["invenio-vocabularies"].affiliations_resource.as_blueprint() def create_awards_blueprint_from_app(app): """Create app blueprint.""" - return app.extensions["invenio-vocabularies"].awards_resource \ - .as_blueprint() + return app.extensions["invenio-vocabularies"].awards_resource.as_blueprint() def create_funders_blueprint_from_app(app): """Create app blueprint.""" - return app.extensions["invenio-vocabularies"].funders_resource \ - .as_blueprint() + return app.extensions["invenio-vocabularies"].funders_resource.as_blueprint() def create_names_blueprint_from_app(app): @@ -69,5 +64,4 @@ def create_names_blueprint_from_app(app): def create_subjects_blueprint_from_app(app): """Create app blueprint.""" - return app.extensions["invenio-vocabularies"].subjects_resource \ - .as_blueprint() + return app.extensions["invenio-vocabularies"].subjects_resource.as_blueprint() diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 8fc6719c..00000000 --- a/pytest.ini +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2020 CERN. -# -# Invenio-Vocabularies is free software; you can redistribute it and/or -# modify it under the terms of the MIT License; see LICENSE file for more -# details. - -[pytest] -addopts = --isort --pydocstyle --pycodestyle --doctest-glob="*.rst" --doctest-modules --cov=invenio_vocabularies --cov-report=term-missing -testpaths = tests invenio_vocabularies diff --git a/setup.cfg b/setup.cfg index fb222a4e..0901a008 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # # Copyright (C) 2020-2022 CERN. -# Copyright (C) 2021 Graz University of Technology. +# Copyright (C) 2022 Graz University of Technology. # # Invenio-Vocabularies is free software; you can redistribute it and/or # modify it under the terms of the MIT License; see LICENSE file for more @@ -33,6 +33,7 @@ install_requires = [options.extras_require] tests = + pytest-black>=0.3.0,<0.3.10 invenio-app>=1.3.3 invenio-db[postgresql,mysql,versioning]>=1.0.14,<2.0.0 pytest-invenio>=1.4.11 @@ -90,7 +91,6 @@ invenio_search.mappings = invenio_i18n.translations = invenio_vocabularies = invenio_vocabularies - [build_sphinx] source-dir = docs/ build-dir = docs/_build @@ -102,9 +102,6 @@ universal = 1 [pydocstyle] add_ignore = D401 -[pycodestyle] -exclude = docs/conf.py - [compile_catalog] directory = invenio_vocabularies/translations/ use-fuzzy = True @@ -122,3 +119,10 @@ output-dir = invenio_vocabularies/translations/ [update_catalog] input-file = invenio_vocabularies/translations/messages.pot output-dir = invenio_vocabularies/translations/ + +[isort] +profile=black + +[tool:pytest] +addopts = --black --isort --pydocstyle --doctest-glob="*.rst" --doctest-modules --cov=invenio_vocabularies --cov-report=term-missing +testpaths = tests invenio_vocabularies diff --git a/tests/conftest.py b/tests/conftest.py index b85408e2..f68eccef 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -21,12 +21,14 @@ try: # Werkzeug <2.1 from werkzeug import security + security.safe_str_cmp except AttributeError: # Werkzeug >=2.1 import hmac from werkzeug import security + security.safe_str_cmp = hmac.compare_digest @@ -44,7 +46,7 @@ from invenio_vocabularies.records.api import Vocabulary from invenio_vocabularies.records.models import VocabularyType -pytest_plugins = ("celery.contrib.pytest", ) +pytest_plugins = ("celery.contrib.pytest",) @pytest.fixture(scope="module") @@ -57,28 +59,30 @@ def h(): def extra_entry_points(): """Extra entry points to load the mock_module features.""" return { - 'invenio_db.models': [ - 'mock_module = mock_module.models', + "invenio_db.models": [ + "mock_module = mock_module.models", ], - 'invenio_jsonschemas.schemas': [ - 'mock_module = mock_module.jsonschemas', + "invenio_jsonschemas.schemas": [ + "mock_module = mock_module.jsonschemas", + ], + "invenio_search.mappings": [ + "records = mock_module.mappings", ], - 'invenio_search.mappings': [ - 'records = mock_module.mappings', - ] } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def app_config(app_config): """Mimic an instance's configuration.""" - app_config["JSONSCHEMAS_HOST"] = 'localhost' - app_config["BABEL_DEFAULT_LOCALE"] = 'en' - app_config["I18N_LANGUAGES"] = [('da', 'Danish')] - app_config['RECORDS_REFRESOLVER_CLS'] = \ - "invenio_records.resolver.InvenioRefResolver" - app_config['RECORDS_REFRESOLVER_STORE'] = \ - "invenio_jsonschemas.proxies.current_refresolver_store" + app_config["JSONSCHEMAS_HOST"] = "localhost" + app_config["BABEL_DEFAULT_LOCALE"] = "en" + app_config["I18N_LANGUAGES"] = [("da", "Danish")] + app_config[ + "RECORDS_REFRESOLVER_CLS" + ] = "invenio_records.resolver.InvenioRefResolver" + app_config[ + "RECORDS_REFRESOLVER_STORE" + ] = "invenio_jsonschemas.proxies.current_refresolver_store" return app_config @@ -97,7 +101,7 @@ def identity_simple(): return i -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def identity(): """Simple identity to interact with the service.""" i = Identity(1) @@ -107,36 +111,33 @@ def identity(): return i -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(app): """Vocabularies service object.""" - return app.extensions['invenio-vocabularies'].service + return app.extensions["invenio-vocabularies"].service @pytest.fixture() def lang_type(db): """Get a language vocabulary type.""" - v = VocabularyType.create(id='languages', pid_type='lng') + v = VocabularyType.create(id="languages", pid_type="lng") db.session.commit() return v -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def lang_data(): """Example data.""" return { - 'id': 'eng', - 'title': {'en': 'English', 'da': 'Engelsk'}, - 'description': { - 'en': 'English description', - 'da': 'Engelsk beskrivelse' - }, - 'icon': 'file-o', - 'props': { - 'akey': 'avalue', + "id": "eng", + "title": {"en": "English", "da": "Engelsk"}, + "description": {"en": "English description", "da": "Engelsk beskrivelse"}, + "icon": "file-o", + "props": { + "akey": "avalue", }, - 'tags': ['recommended'], - 'type': 'languages', + "tags": ["recommended"], + "type": "languages", } @@ -144,7 +145,7 @@ def lang_data(): def lang_data2(lang_data): """Example data for testing invalid cases.""" data = dict(lang_data) - data['id'] = 'new' + data["id"] = "new" return data @@ -159,24 +160,21 @@ def example_record(db, identity, service, example_data): record = service.create( identity=identity, - data=dict( - **example_data, - vocabulary_type_id=vocabulary_type_languages.id - ), + data=dict(**example_data, vocabulary_type_id=vocabulary_type_languages.id), ) Vocabulary.index.refresh() # Refresh the index return record -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def lang_data_many(lang_type, lic_type, lang_data, service, identity): """Create many language vocabulary.""" - lang_ids = ['fr', 'tr', 'gr', 'ger', 'es'] + lang_ids = ["fr", "tr", "gr", "ger", "es"] data = dict(lang_data) for lang_id in lang_ids: - data['id'] = lang_id + data["id"] = lang_id service.create(identity, data) Vocabulary.index.refresh() # Refresh the index return lang_ids @@ -190,7 +188,7 @@ def user(app, db): _user = datastore.create_user( email="info@inveniosoftware.org", password=hash_password("password"), - active=True + active=True, ) db.session.commit() return _user diff --git a/tests/contrib/affiliations/conftest.py b/tests/contrib/affiliations/conftest.py index b17b53d0..b2d51fa0 100644 --- a/tests/contrib/affiliations/conftest.py +++ b/tests/contrib/affiliations/conftest.py @@ -22,18 +22,13 @@ def affiliation_full_data(): return { "acronym": "TEST", "id": "cern", - "identifiers": [ - {"identifier": "03yrm5c26", "scheme": "ror"} - ], + "identifiers": [{"identifier": "03yrm5c26", "scheme": "ror"}], "name": "Test affiliation", - "title": { - "en": "Test affiliation", - "es": "Afiliacion de test" - } + "title": {"en": "Test affiliation", "es": "Afiliacion de test"}, } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(): """Affiliations service object.""" return current_service_registry.get("affiliations") diff --git a/tests/contrib/affiliations/test_affiliations_api.py b/tests/contrib/affiliations/test_affiliations_api.py index 6aa9784e..118e5770 100644 --- a/tests/contrib/affiliations/test_affiliations_api.py +++ b/tests/contrib/affiliations/test_affiliations_api.py @@ -21,9 +21,7 @@ @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Affiliation.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Affiliation.index._name, doc_type="_doc") @pytest.fixture() @@ -66,16 +64,14 @@ def test_affiliation_schema_validation(app, db, example_affiliation): # name must be a string {"id": "cern", "name": 123}, # acronym must be a string - {"id": "cern", "name": "cern", "acronym": 123} + {"id": "cern", "name": "cern", "acronym": 123}, ] for ex in examples: pytest.raises(SchemaValidationError, Affiliation.create, ex) -def test_affiliation_indexing( - app, db, es, example_affiliation, indexer, search_get -): +def test_affiliation_indexing(app, db, es, example_affiliation, indexer, search_get): """Test indexing of an affiliation.""" # Index document in ES assert indexer.index(example_affiliation)["result"] == "created" diff --git a/tests/contrib/affiliations/test_affiliations_jsonschema.py b/tests/contrib/affiliations/test_affiliations_jsonschema.py index 65d98027..2248173c 100644 --- a/tests/contrib/affiliations/test_affiliations_jsonschema.py +++ b/tests/contrib/affiliations/test_affiliations_jsonschema.py @@ -38,20 +38,10 @@ def test_valid_full(appctx, schema): "$schema": schema, "acronym": "TEST", "id": "aff-1", - "identifiers": [ - {"identifier": "03yrm5c26", "scheme": "ror"} - ], + "identifiers": [{"identifier": "03yrm5c26", "scheme": "ror"}], "name": "Test affiliation", - "pid": { - "pk": 1, - "status": "R", - "pid_type": "affid", - "obj_type": "aff" - }, - "title": { - "en": "Test affiliation", - "es": "Afiliacion de test" - } + "pid": {"pk": 1, "status": "R", "pid_type": "affid", "obj_type": "aff"}, + "title": {"en": "Test affiliation", "es": "Afiliacion de test"}, } assert validates(data) @@ -59,9 +49,7 @@ def test_valid_full(appctx, schema): def test_valid_empty(appctx, schema): # check there are no requirements at JSONSchema level - data = { - "$schema": schema - } + data = {"$schema": schema} assert validates(data) @@ -71,18 +59,12 @@ def test_valid_empty(appctx, schema): def test_fails_acronym(appctx, schema): - data = { - "$schema": schema, - "acronym": 1 - } + data = {"$schema": schema, "acronym": 1} assert fails(data) def test_fails_name(appctx, schema): - data = { - "$schema": schema, - "name": 1 - } + data = {"$schema": schema, "name": 1} assert fails(data) diff --git a/tests/contrib/affiliations/test_affiliations_resource.py b/tests/contrib/affiliations/test_affiliations_resource.py index ea2537b4..4ebf2f60 100644 --- a/tests/contrib/affiliations/test_affiliations_resource.py +++ b/tests/contrib/affiliations/test_affiliations_resource.py @@ -24,9 +24,7 @@ def prefix(): @pytest.fixture() -def example_affiliation( - app, db, es_clear, identity, service, affiliation_full_data -): +def example_affiliation(app, db, es_clear, identity, service, affiliation_full_data): """Example affiliation.""" aff = service.create(identity, affiliation_full_data) Affiliation.index.refresh() # Refresh the index @@ -49,11 +47,13 @@ def test_affiliations_forbidden( affiliation_full_data_too = deepcopy(affiliation_full_data) affiliation_full_data_too["id"] = "other" res = client.post( - f"{prefix}", headers=h, data=json.dumps(affiliation_full_data_too)) + f"{prefix}", headers=h, data=json.dumps(affiliation_full_data_too) + ) assert res.status_code == 403 res = client.put( - f"{prefix}/cern", headers=h, data=json.dumps(affiliation_full_data)) + f"{prefix}/cern", headers=h, data=json.dumps(affiliation_full_data) + ) assert res.status_code == 403 res = client.delete(f"{prefix}/cern") @@ -68,9 +68,7 @@ def test_affiliations_get(client, example_affiliation, h, prefix): assert res.status_code == 200 assert res.json["id"] == id_ # Test links - assert res.json["links"] == { - "self": "https://127.0.0.1:5000/api/affiliations/cern" - } + assert res.json["links"] == {"self": "https://127.0.0.1:5000/api/affiliations/cern"} def test_affiliations_search(client, example_affiliation, h, prefix): @@ -91,25 +89,18 @@ def _create_affiliations(service, identity): "name": "CERN", "title": { "en": "European Organization for Nuclear Research", - "fr": "Conseil Européen pour la Recherche Nucléaire" - } - }, - { - "acronym": "OTHER", - "id": "other", - "name": "OTHER", - "title": { - "en": "CERN" - } + "fr": "Conseil Européen pour la Recherche Nucléaire", + }, }, + {"acronym": "OTHER", "id": "other", "name": "OTHER", "title": {"en": "CERN"}}, { "acronym": "CERT", "id": "cert", "name": "CERT", "title": { "en": "Computer Emergency Response Team", - "fr": "Équipe d'Intervention d'Urgence Informatique" - } + "fr": "Équipe d'Intervention d'Urgence Informatique", + }, }, { "acronym": "NU", @@ -117,8 +108,8 @@ def _create_affiliations(service, identity): "name": "Northwestern University", "title": { "en": "Northwestern University", - } - } + }, + }, ] for aff in affiliations: service.create(identity, aff) diff --git a/tests/contrib/affiliations/test_affiliations_schema.py b/tests/contrib/affiliations/test_affiliations_schema.py index 0462b8d4..9d5d44be 100644 --- a/tests/contrib/affiliations/test_affiliations_schema.py +++ b/tests/contrib/affiliations/test_affiliations_schema.py @@ -11,8 +11,10 @@ import pytest from marshmallow import ValidationError -from invenio_vocabularies.contrib.affiliations.schema import \ - AffiliationRelationSchema, AffiliationSchema +from invenio_vocabularies.contrib.affiliations.schema import ( + AffiliationRelationSchema, + AffiliationSchema, +) def test_valid_full(app, affiliation_full_data): @@ -32,13 +34,8 @@ def test_invalid_no_name(app): invalid = { "acronym": "TEST", "id": "aff-1", - "identifiers": [ - {"identifier": "03yrm5c26", "scheme": "ror"} - ], - "title": { - "en": "Test affiliation", - "es": "Afiliacion de test" - } + "identifiers": [{"identifier": "03yrm5c26", "scheme": "ror"}], + "title": {"en": "Test affiliation", "es": "Afiliacion de test"}, } with pytest.raises(ValidationError): data = AffiliationSchema().load(invalid) @@ -55,17 +52,12 @@ def test_valid_id(): def test_valid_name(): - valid_name = { - "name": "Entity One" - } + valid_name = {"name": "Entity One"} assert valid_name == AffiliationRelationSchema().load(valid_name) def test_valid_both_id_name(): - valid_id_name = { - "id": "test", - "name": "Entity One" - } + valid_id_name = {"id": "test", "name": "Entity One"} assert valid_id_name == AffiliationRelationSchema().load(valid_id_name) diff --git a/tests/contrib/affiliations/test_affiliations_service.py b/tests/contrib/affiliations/test_affiliations_service.py index b7563d6b..8580a1b3 100644 --- a/tests/contrib/affiliations/test_affiliations_service.py +++ b/tests/contrib/affiliations/test_affiliations_service.py @@ -27,12 +27,12 @@ def test_simple_flow(app, db, service, identity, affiliation_full_data): item = service.create(identity, affiliation_full_data) id_ = item.id - assert item.id == affiliation_full_data['id'] + assert item.id == affiliation_full_data["id"] for k, v in affiliation_full_data.items(): assert item.data[k] == v # Read it - read_item = service.read(identity, 'cern') + read_item = service.read(identity, "cern") assert item.id == read_item.id assert item.data == read_item.data @@ -40,17 +40,16 @@ def test_simple_flow(app, db, service, identity, affiliation_full_data): Affiliation.index.refresh() # Search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0] == read_item.data # Update it data = read_item.data - data['title']['en'] = 'New title' + data["title"]["en"] = "New title" update_item = service.update(identity, id_, data) assert item.id == update_item.id - assert update_item['title']['en'] == 'New title' + assert update_item["title"]["en"] == "New title" # Delete it assert service.delete(identity, id_) @@ -62,8 +61,7 @@ def test_simple_flow(app, db, service, identity, affiliation_full_data): # - db pytest.raises(PIDDeletedError, service.read, identity, id_) # - search - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 0 @@ -72,33 +70,25 @@ def test_pid_already_registered( ): """Recreating a record with same id should fail.""" service.create(identity, affiliation_full_data) - pytest.raises( - PIDAlreadyExists, service.create, identity, affiliation_full_data) + pytest.raises(PIDAlreadyExists, service.create, identity, affiliation_full_data) def test_extra_fields(app, db, service, identity, affiliation_full_data): """Extra fields in data should fail.""" - affiliation_full_data['invalid'] = 1 - pytest.raises( - ValidationError, service.create, identity, affiliation_full_data) + affiliation_full_data["invalid"] = 1 + pytest.raises(ValidationError, service.create, identity, affiliation_full_data) -def test_indexed_at_query( - app, db, service, identity, affiliation_full_data -): +def test_indexed_at_query(app, db, service, identity, affiliation_full_data): before = arrow.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f") _ = service.create(identity, affiliation_full_data) now = arrow.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f") Affiliation.index.refresh() # there is previous to before - res = service.search( - identity, q=f"indexed_at:[* TO {before}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {before}]", size=25, page=1) assert res.total == 0 # there is previous to now - res = service.search( - identity, q=f"indexed_at:[* TO {now}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {now}]", size=25, page=1) assert res.total == 1 diff --git a/tests/contrib/awards/conftest.py b/tests/contrib/awards/conftest.py index f9908a43..06ca2cb6 100644 --- a/tests/contrib/awards/conftest.py +++ b/tests/contrib/awards/conftest.py @@ -32,9 +32,9 @@ def example_funder(db, identity, funders_service, funder_indexer): "name": "CERN", "title": { "en": "European Organization for Nuclear Research", - "fr": "Organisation européenne pour la recherche nucléaire" + "fr": "Organisation européenne pour la recherche nucléaire", }, - "country": "CH" + "country": "CH", } funder = funders_service.create(identity, funder_data) Funder.index.refresh() # Refresh the index @@ -50,11 +50,8 @@ def example_funder_ec(db, identity, funders_service, funder_indexer): funder_data = { "id": "00k4n6c32", "name": "EC", - "title": { - "en": "European Commission", - "fr": "Commission Européenne" - }, - "country": "BE" + "title": {"en": "European Commission", "fr": "Commission Européenne"}, + "country": "BE", } funder = funders_service.create(identity, funder_data) Funder.index.refresh() # Refresh the index @@ -64,7 +61,7 @@ def example_funder_ec(db, identity, funders_service, funder_indexer): db.session.commit() -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def funders_service(): """Funders service object.""" return current_service_registry.get("funders") @@ -87,7 +84,7 @@ def award_full_data(): "identifiers": [ { "identifier": "https://cordis.europa.eu/project/id/755021", - "scheme": "url" + "scheme": "url", } ], "number": "755021", @@ -95,9 +92,7 @@ def award_full_data(): "en": "Personalised Treatment For Cystic Fibrosis Patients With \ Ultra-rare CFTR Mutations (and beyond)", }, - "funder": { - "id": "00k4n6c32" - }, + "funder": {"id": "00k4n6c32"}, "acronym": "HIT-CF", } @@ -110,7 +105,7 @@ def award_full_data_invalid_id(): "identifiers": [ { "identifier": "https://cordis.europa.eu/project/id/755021", - "scheme": "url" + "scheme": "url", } ], "number": "755021", @@ -118,18 +113,13 @@ def award_full_data_invalid_id(): "en": "Personalised Treatment For Cystic Fibrosis Patients With \ Ultra-rare CFTR Mutations (and beyond)", }, - "funder": { - "id": "010101010" - }, + "funder": {"id": "010101010"}, "acronym": "HIT-CF", - } @pytest.fixture(scope="function") -def example_award( - db, example_funder_ec, award_full_data, identity, indexer, service -): +def example_award(db, example_funder_ec, award_full_data, identity, indexer, service): """Creates and hard deletes an award.""" award = service.create(identity, award_full_data) Award.index.refresh() # Refresh the index @@ -139,7 +129,7 @@ def example_award( db.session.commit() -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(): """Awards service object.""" return current_service_registry.get("awards") diff --git a/tests/contrib/awards/test_awards_api.py b/tests/contrib/awards/test_awards_api.py index 7f47e88f..70a07c51 100644 --- a/tests/contrib/awards/test_awards_api.py +++ b/tests/contrib/awards/test_awards_api.py @@ -22,9 +22,7 @@ @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Award.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Award.index._name, doc_type="_doc") @pytest.fixture() @@ -59,16 +57,14 @@ def test_award_schema_validation(app, example_award): # number must be a string {"number": 123}, # funder must be an object - {"funder": 123} + {"funder": 123}, ] for ex in examples: pytest.raises(SchemaValidationError, Award.create, ex) -def test_award_indexing( - app, example_award, indexer, search_get -): +def test_award_indexing(app, example_award, indexer, search_get): """Test indexing of an award.""" # Index document in ES assert indexer.index(example_award)["result"] == "created" diff --git a/tests/contrib/awards/test_awards_datastreams.py b/tests/contrib/awards/test_awards_datastreams.py index daa62ac3..285b5a6a 100644 --- a/tests/contrib/awards/test_awards_datastreams.py +++ b/tests/contrib/awards/test_awards_datastreams.py @@ -14,72 +14,74 @@ from invenio_access.permissions import system_identity from invenio_vocabularies.contrib.awards.api import Award -from invenio_vocabularies.contrib.awards.datastreams import \ - AwardsServiceWriter, OpenAIREProjectTransformer +from invenio_vocabularies.contrib.awards.datastreams import ( + AwardsServiceWriter, + OpenAIREProjectTransformer, +) from invenio_vocabularies.datastreams import StreamEntry from invenio_vocabularies.datastreams.errors import WriterError @pytest.fixture(scope="function") def dict_award_entry(): - return StreamEntry({ - "acronym": "TA", - "code": "0751743", - "enddate": "2010-09-30", - "funding": [ - { - "funding_stream": { - "description": "Directorate for Geosciences - Division of " - "Ocean Sciences", - "id": "NSF::GEO/OAD::GEO/OCE", - }, - "jurisdiction": "US", - "name": "National Science Foundation", - "shortName": "NSF" - } - ], - "h2020programme": [], - "id": "40|nsf_________::3eb1b4f6d6e251a19f9fdeed2aab88d8", - "openaccessmandatefordataset": False, - "openaccessmandateforpublications": False, - "startdate": "2008-04-01", - "subject": [ - "Oceanography" - ], - "title": "Test title", - "websiteurl": "https://test.com" - }) + return StreamEntry( + { + "acronym": "TA", + "code": "0751743", + "enddate": "2010-09-30", + "funding": [ + { + "funding_stream": { + "description": "Directorate for Geosciences - Division of " + "Ocean Sciences", + "id": "NSF::GEO/OAD::GEO/OCE", + }, + "jurisdiction": "US", + "name": "National Science Foundation", + "shortName": "NSF", + } + ], + "h2020programme": [], + "id": "40|nsf_________::3eb1b4f6d6e251a19f9fdeed2aab88d8", + "openaccessmandatefordataset": False, + "openaccessmandateforpublications": False, + "startdate": "2008-04-01", + "subject": ["Oceanography"], + "title": "Test title", + "websiteurl": "https://test.com", + } + ) @pytest.fixture(scope="function") def dict_award_entry_ec(): """Full award data.""" - return StreamEntry({ - "acronym": "TS", - "code": "129123", - "enddate": "2025-12-31", - "funding": [ - { - "funding_stream": { - "description": "Test stream", - "id": "TST::test::test", - }, - "jurisdiction": "GR", - "name": "Test Name", - "shortName": "TST" - } - ], - "h2020programme": [], - "id": "40|corda__h2020::000000000000000000", - "openaccessmandatefordataset": False, - "openaccessmandateforpublications": False, - "startdate": "2008-04-01", - "subject": [ - "Oceanography" - ], - "title": "Test title", - "websiteurl": "https://test.com" - }) + return StreamEntry( + { + "acronym": "TS", + "code": "129123", + "enddate": "2025-12-31", + "funding": [ + { + "funding_stream": { + "description": "Test stream", + "id": "TST::test::test", + }, + "jurisdiction": "GR", + "name": "Test Name", + "shortName": "TST", + } + ], + "h2020programme": [], + "id": "40|corda__h2020::000000000000000000", + "openaccessmandatefordataset": False, + "openaccessmandateforpublications": False, + "startdate": "2008-04-01", + "subject": ["Oceanography"], + "title": "Test title", + "websiteurl": "https://test.com", + } + ) @pytest.fixture(scope="function") @@ -98,10 +100,9 @@ def expected_from_award_json(): def expected_from_award_json_ec(): return { "id": "00k4n6c32::129123", - "identifiers": [{ - "identifier": "https://cordis.europa.eu/projects/129123", - "scheme": "url" - }], + "identifiers": [ + {"identifier": "https://cordis.europa.eu/projects/129123", "scheme": "url"} + ], "number": "129123", "title": {"en": "Test title"}, "funder": {"id": "00k4n6c32"}, @@ -111,9 +112,7 @@ def expected_from_award_json_ec(): def test_awards_transformer(app, dict_award_entry, expected_from_award_json): transformer = OpenAIREProjectTransformer() - assert ( - expected_from_award_json == transformer.apply(dict_award_entry).entry - ) + assert expected_from_award_json == transformer.apply(dict_award_entry).entry def test_awards_service_writer_create( @@ -131,16 +130,22 @@ def test_awards_service_writer_create( def test_awards_funder_id_not_exist( - app, es_clear, example_funder, example_funder_ec, + app, + es_clear, + example_funder, + example_funder_ec, award_full_data_invalid_id, ): awards_writer = AwardsServiceWriter("awards", system_identity) with pytest.raises(WriterError) as err: awards_writer.write(StreamEntry(award_full_data_invalid_id)) - expected_error = [{ - 'InvalidRelationValue': 'Invalid value {funder_id}.'.format( - funder_id=award_full_data_invalid_id.get('funder').get('id')) - }] + expected_error = [ + { + "InvalidRelationValue": "Invalid value {funder_id}.".format( + funder_id=award_full_data_invalid_id.get("funder").get("id") + ) + } + ] assert expected_error in err.value.args @@ -151,10 +156,13 @@ def test_awards_funder_id_not_exist_no_funders( awards_writer = AwardsServiceWriter("awards", system_identity) with pytest.raises(WriterError) as err: awards_writer.write(StreamEntry(award_full_data_invalid_id)) - expected_error = [{ - 'InvalidRelationValue': 'Invalid value {funder_id}.'.format( - funder_id=award_full_data_invalid_id.get('funder').get('id')) - }] + expected_error = [ + { + "InvalidRelationValue": "Invalid value {funder_id}.".format( + funder_id=award_full_data_invalid_id.get("funder").get("id") + ) + } + ] assert expected_error in err.value.args @@ -168,13 +176,8 @@ def test_awards_transformer_ec_functionality( expected_from_award_json_ec, ): transformer = OpenAIREProjectTransformer() - assert ( - expected_from_award_json == transformer.apply(dict_award_entry).entry - ) - assert ( - expected_from_award_json_ec == - transformer.apply(dict_award_entry_ec).entry - ) + assert expected_from_award_json == transformer.apply(dict_award_entry).entry + assert expected_from_award_json_ec == transformer.apply(dict_award_entry_ec).entry def test_awards_service_writer_duplicate( diff --git a/tests/contrib/awards/test_awards_jsonschema.py b/tests/contrib/awards/test_awards_jsonschema.py index a6139a1e..bbb30fb6 100644 --- a/tests/contrib/awards/test_awards_jsonschema.py +++ b/tests/contrib/awards/test_awards_jsonschema.py @@ -39,7 +39,7 @@ def test_valid_full(appctx, schema): "identifiers": [ { "identifier": "https://cordis.europa.eu/project/id/755021", - "scheme": "url" + "scheme": "url", } ], "title": { @@ -47,10 +47,7 @@ def test_valid_full(appctx, schema): Ultra-rare CFTR Mutations (and beyond)" }, "number": "755021", - "funder": { - "id": "ria", - "name": "Research annd Innovation action" - } + "funder": {"id": "ria", "name": "Research annd Innovation action"}, } assert validates(data) @@ -58,9 +55,7 @@ def test_valid_full(appctx, schema): def test_valid_empty(appctx, schema): # check there are no requirements at JSONSchema level - data = { - "$schema": schema - } + data = {"$schema": schema} assert validates(data) @@ -70,9 +65,6 @@ def test_valid_empty(appctx, schema): def test_fails_number(appctx, schema): - data = { - "$schema": schema, - "number": 123 - } + data = {"$schema": schema, "number": 123} assert fails(data) diff --git a/tests/contrib/awards/test_awards_resource.py b/tests/contrib/awards/test_awards_resource.py index 895c1f12..dc7bdb4a 100644 --- a/tests/contrib/awards/test_awards_resource.py +++ b/tests/contrib/awards/test_awards_resource.py @@ -31,19 +31,15 @@ def test_awards_invalid(client, h, prefix): assert res.status_code == 404 -def test_awards_forbidden( - client, h, prefix, example_award, award_full_data -): +def test_awards_forbidden(client, h, prefix, example_award, award_full_data): """Test invalid type.""" # invalid type award_full_data_too = deepcopy(award_full_data) award_full_data_too["pid"] = "other" - res = client.post( - f"{prefix}", headers=h, data=json.dumps(award_full_data_too)) + res = client.post(f"{prefix}", headers=h, data=json.dumps(award_full_data_too)) assert res.status_code == 403 - res = client.put( - f"{prefix}/755021", headers=h, data=json.dumps(award_full_data)) + res = client.put(f"{prefix}/755021", headers=h, data=json.dumps(award_full_data)) assert res.status_code == 403 res = client.delete(f"{prefix}/755021") @@ -58,9 +54,7 @@ def test_awards_get(client, example_award, h, prefix): assert res.status_code == 200 assert res.json["id"] == id_ # Test links - assert res.json["links"] == { - "self": "https://127.0.0.1:5000/api/awards/755021" - } + assert res.json["links"] == {"self": "https://127.0.0.1:5000/api/awards/755021"} def test_awards_search(client, example_award, h, prefix): @@ -94,26 +88,24 @@ def example_awards(service, identity, indexer, example_funder_ec): }, "id": "847507", "number": "847507", - }, { + }, + { "title": { "en": "Palliative care in Parkinson disease", }, "id": "825785", "number": "825785", - "funder": { - "id": example_funder_ec.id - }, - }, { + "funder": {"id": example_funder_ec.id}, + }, + { "title": { "en": "Palliative Show", }, "acronym": "Palliative", "id": "000001", "number": "000001", - "funder": { - "name": "Another Funder" - }, - } + "funder": {"name": "Another Funder"}, + }, ] awards = [] @@ -152,9 +144,7 @@ def test_awards_suggest_sort(client, h, prefix, example_awards): assert res.json["hits"]["hits"][1]["id"] == "825785" -def test_awards_faceted_suggest( - client, h, prefix, example_funder_ec, example_awards -): +def test_awards_faceted_suggest(client, h, prefix, example_funder_ec, example_awards): """Test a successful suggest with filtering.""" # Should show 1 results because of the funder filtering res = client.get( @@ -173,7 +163,7 @@ def test_awards_delete( identity, service, award_full_data, - example_funder_ec + example_funder_ec, ): """Test a successful delete.""" award = service.create(identity, award_full_data) @@ -198,7 +188,8 @@ def test_awards_update( new_title = "updated" award_full_data["title"]["en"] = new_title res = client_with_credentials.put( - f"{prefix}/755021", headers=h, data=json.dumps(award_full_data)) + f"{prefix}/755021", headers=h, data=json.dumps(award_full_data) + ) assert res.status_code == 200 assert res.json["id"] == id_ # result_items wraps pid into id assert res.json["title"]["en"] == new_title @@ -209,6 +200,7 @@ def test_awards_create( ): """Tests a successful creation.""" res = client_with_credentials.post( - f"{prefix}", headers=h, data=json.dumps(award_full_data)) + f"{prefix}", headers=h, data=json.dumps(award_full_data) + ) assert res.status_code == 201 assert res.json["id"] == award_full_data["id"] diff --git a/tests/contrib/awards/test_awards_schema.py b/tests/contrib/awards/test_awards_schema.py index c222c9ce..f753180c 100644 --- a/tests/contrib/awards/test_awards_schema.py +++ b/tests/contrib/awards/test_awards_schema.py @@ -10,8 +10,11 @@ import pytest from marshmallow import ValidationError -from invenio_vocabularies.contrib.awards.schema import AwardRelationSchema, \ - AwardSchema, FundingRelationSchema +from invenio_vocabularies.contrib.awards.schema import ( + AwardRelationSchema, + AwardSchema, + FundingRelationSchema, +) # @@ -24,10 +27,7 @@ def test_valid_full(app, award_full_data): def test_valid_minimal(): - valid_minimal = { - "id": "755021", - "number": "755021" - } + valid_minimal = {"id": "755021", "number": "755021"} assert { "pid": "755021", "number": "755021", @@ -36,32 +36,21 @@ def test_valid_minimal(): def test_invalid_no_number(app): invalid_no_number = { - "identifiers": [ - { - "identifier": "10.5281/zenodo.9999999", - "scheme": "doi" - } - ] + "identifiers": [{"identifier": "10.5281/zenodo.9999999", "scheme": "doi"}] } with pytest.raises(ValidationError): data = AwardSchema().load(invalid_no_number) def test_invalid_empty_number(app): - invalid_empty_number = { - "id": "755021", - "number": "" - } + invalid_empty_number = {"id": "755021", "number": ""} with pytest.raises(ValidationError): data = AwardSchema().load(invalid_empty_number) def test_invalid_empty_pid(app): - invalid_empty_pid = { - "id": "", - "number": "755021" - } + invalid_empty_pid = {"id": "", "number": "755021"} with pytest.raises(ValidationError): AwardSchema().load(invalid_empty_pid) @@ -73,14 +62,14 @@ def test_award_funder_name(app): "number": "755021", "funder": { "name": "custom funder", - } + }, } assert { "pid": "755021", "number": "755021", "funder": { "name": "custom funder", - } + }, } == AwardSchema().load(with_funder_name) @@ -90,14 +79,14 @@ def test_award_funder_id(app): "number": "755021", "funder": { "id": "01ggx4157", - } + }, } assert { "pid": "755021", "number": "755021", "funder": { "id": "01ggx4157", - } + }, } == AwardSchema().load(with_funder_id) @@ -114,12 +103,7 @@ def test_valid_id(): def test_valid_number_title(): - valid_data = { - "number": "123456", - "title": { - "en": "Test title." - } - } + valid_data = {"number": "123456", "title": {"en": "Test title."}} assert valid_data == AwardRelationSchema().load(valid_data) @@ -130,23 +114,17 @@ def test_invalid_empty(): def test_invalid_number_type(): - invalid_data = { - "number": 123 - } + invalid_data = {"number": 123} with pytest.raises(ValidationError): data = AwardRelationSchema().load(invalid_data) + # # FundingRelationSchema # -AWARD = { - "title": { - "en": "Some award" - }, - "number": "755021" -} +AWARD = {"title": {"en": "Some award"}, "number": "755021"} FUNDER = { "name": "Someone", @@ -154,64 +132,37 @@ def test_invalid_number_type(): def test_valid_award_funding(): - valid_funding = { - "award": AWARD - } + valid_funding = {"award": AWARD} assert valid_funding == FundingRelationSchema().load(valid_funding) # Test a valid award with different representation - valid_funding = { - "award": { - "id": "test-award-id" - } - } + valid_funding = {"award": {"id": "test-award-id"}} assert valid_funding == FundingRelationSchema().load(valid_funding) def test_invalid_award_funding(): - invalid_funding = { - "award": { - "identifiers": [ - AWARD.get('identifiers') - ] - } - } + invalid_funding = {"award": {"identifiers": [AWARD.get("identifiers")]}} with pytest.raises(ValidationError): data = FundingRelationSchema().load(invalid_funding) def test_valid_funder_funding(): - valid_funding = { - "funder": FUNDER - } + valid_funding = {"funder": FUNDER} assert valid_funding == FundingRelationSchema().load(valid_funding) # Test a valid funder with different representation - valid_funding = { - "funder": { - "id": "test-funder-id" - } - } + valid_funding = {"funder": {"id": "test-funder-id"}} assert valid_funding == FundingRelationSchema().load(valid_funding) def test_invalid_funder_funding(): - invalid_funding = { - "funder": { - "identifiers": [ - AWARD.get('identifiers') - ] - } - } + invalid_funding = {"funder": {"identifiers": [AWARD.get("identifiers")]}} with pytest.raises(ValidationError): data = FundingRelationSchema().load(invalid_funding) def test_valid_award_funder_funding(): - valid_funding = { - "funder": FUNDER, - "award": AWARD - } + valid_funding = {"funder": FUNDER, "award": AWARD} assert valid_funding == FundingRelationSchema().load(valid_funding) diff --git a/tests/contrib/awards/test_awards_service.py b/tests/contrib/awards/test_awards_service.py index 7c5ef413..84c4cfdc 100644 --- a/tests/contrib/awards/test_awards_service.py +++ b/tests/contrib/awards/test_awards_service.py @@ -20,9 +20,7 @@ from invenio_vocabularies.contrib.awards.api import Award -def test_simple_flow( - app, service, identity, award_full_data, example_funder_ec -): +def test_simple_flow(app, service, identity, award_full_data, example_funder_ec): """Test a simple vocabulary service flow.""" # Service assert service.id == "awards" @@ -36,12 +34,12 @@ def test_simple_flow( expected_data = deepcopy(award_full_data) expected_data["funder"]["name"] = "EC" - assert id_ == award_full_data['id'] + assert id_ == award_full_data["id"] for k, v in expected_data.items(): assert item.data[k] == v # Read it - read_item = service.read(identity, '755021') + read_item = service.read(identity, "755021") assert item.id == read_item.id assert item.data == read_item.data @@ -49,19 +47,18 @@ def test_simple_flow( Award.index.refresh() # Search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0] == read_item.data # Update it data = read_item.data - data['title']['en'] = 'New title' + data["title"]["en"] = "New title" update_item = service.update(identity, id_, data) # the pid is not save to the json metadata assert not update_item._record.get("pid") assert item.id == update_item.id - assert update_item['title']['en'] == 'New title' + assert update_item["title"]["en"] == "New title" # Delete it assert service.delete(identity, id_) @@ -76,24 +73,18 @@ def test_simple_flow( deleted_rec = service.read(identity, id_).to_dict() assert set(deleted_rec.keys()) == base_keys # - search - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 0 # not-ideal cleanup item._record.delete(force=True) -def test_create_invalid_funder( - app, service, identity, award_full_data, example_funder -): +def test_create_invalid_funder(app, service, identity, award_full_data, example_funder): award_with_invalid_funder = deepcopy(award_full_data) award_with_invalid_funder["funder"]["id"] = "invalid" pytest.raises( - InvalidRelationValue, - service.create, - identity, - award_with_invalid_funder + InvalidRelationValue, service.create, identity, award_with_invalid_funder ) @@ -101,17 +92,13 @@ def test_pid_already_registered( app, db, service, identity, award_full_data, example_award ): # example_funder does the first creation - pytest.raises( - PIDAlreadyExists, service.create, identity, award_full_data) + pytest.raises(PIDAlreadyExists, service.create, identity, award_full_data) -def test_extra_fields( - app, service, identity, award_full_data, example_funder -): +def test_extra_fields(app, service, identity, award_full_data, example_funder): """Extra fields in data should fail.""" - award_full_data['invalid'] = 1 - pytest.raises( - ValidationError, service.create, identity, award_full_data) + award_full_data["invalid"] = 1 + pytest.raises(ValidationError, service.create, identity, award_full_data) def test_award_dereferenced( @@ -134,8 +121,7 @@ def test_award_dereferenced( assert read_item["funder"] == expected_funder # Search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0]["funder"] == expected_funder @@ -149,13 +135,9 @@ def test_indexed_at_query( Award.index.refresh() # there is previous to before - res = service.search( - identity, q=f"indexed_at:[* TO {before}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {before}]", size=25, page=1) assert res.total == 0 # there is previous to now - res = service.search( - identity, q=f"indexed_at:[* TO {now}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {now}]", size=25, page=1) assert res.total == 1 diff --git a/tests/contrib/funders/conftest.py b/tests/contrib/funders/conftest.py index 309e061f..b4ba621e 100644 --- a/tests/contrib/funders/conftest.py +++ b/tests/contrib/funders/conftest.py @@ -32,18 +32,18 @@ def funder_full_data(): { "identifier": "grid.9132.9", "scheme": "grid", - } + }, ], "name": "CERN", "title": { "en": "European Organization for Nuclear Research", - "fr": "Organisation européenne pour la recherche nucléaire" + "fr": "Organisation européenne pour la recherche nucléaire", }, - "country": "CH" + "country": "CH", } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(): """Funders service object.""" return current_service_registry.get("funders") diff --git a/tests/contrib/funders/test_funders_api.py b/tests/contrib/funders/test_funders_api.py index e6906801..a03f7936 100644 --- a/tests/contrib/funders/test_funders_api.py +++ b/tests/contrib/funders/test_funders_api.py @@ -21,9 +21,7 @@ @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Funder.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Funder.index._name, doc_type="_doc") @pytest.fixture() @@ -51,16 +49,14 @@ def test_funder_schema_validation(app, example_funder): # name must be a string {"name": 123}, # country must be a string - {"name": "cern", "country": 123} + {"name": "cern", "country": 123}, ] for ex in examples: pytest.raises(ValidationError, Funder.create, ex) -def test_funder_indexing( - app, example_funder, indexer, search_get -): +def test_funder_indexing(app, example_funder, indexer, search_get): """Test indexing of a funder.""" # Index document in ES assert indexer.index(example_funder)["result"] == "created" diff --git a/tests/contrib/funders/test_funders_datastreams.py b/tests/contrib/funders/test_funders_datastreams.py index 5fe16ec4..727824ca 100644 --- a/tests/contrib/funders/test_funders_datastreams.py +++ b/tests/contrib/funders/test_funders_datastreams.py @@ -14,65 +14,42 @@ from invenio_access.permissions import system_identity from invenio_vocabularies.contrib.funders.api import Funder -from invenio_vocabularies.contrib.funders.datastreams import \ - FundersServiceWriter, RORTransformer +from invenio_vocabularies.contrib.funders.datastreams import ( + FundersServiceWriter, + RORTransformer, +) from invenio_vocabularies.datastreams import StreamEntry from invenio_vocabularies.datastreams.errors import WriterError @pytest.fixture(scope="module") def dict_ror_entry(): - return StreamEntry({ - "id": "https://ror.org/0aaaaaa11", - "name": "Funder", - "types": [ - "Facility" - ], - "links": [ - "http://test.com" - ], - "aliases": [], - "acronyms": [ - "FND" - ], - "status": "active", - "wikipedia_url": "https://en.wikipedia.org/wiki/FUNDER_TEST", - "labels": [ - { - "label": "Funder", - "iso639": "en" - }, - { - "label": "Geldgeber", - "iso639": "de" - } - ], - "email_address": None, - "ip_addresses": [], - "established": 1954, - "country": { - "country_code": "GR", - "country_name": "Greece" - }, - "relationships": [], - - "external_ids": { - "ISNI": { - "preferred": None, - "all": [ - "0000 0001 2156 142X" - ] - }, - "GRID": { - "preferred": "grid.9132.9", - "all": "grid.9132.9" + return StreamEntry( + { + "id": "https://ror.org/0aaaaaa11", + "name": "Funder", + "types": ["Facility"], + "links": ["http://test.com"], + "aliases": [], + "acronyms": ["FND"], + "status": "active", + "wikipedia_url": "https://en.wikipedia.org/wiki/FUNDER_TEST", + "labels": [ + {"label": "Funder", "iso639": "en"}, + {"label": "Geldgeber", "iso639": "de"}, + ], + "email_address": None, + "ip_addresses": [], + "established": 1954, + "country": {"country_code": "GR", "country_name": "Greece"}, + "relationships": [], + "external_ids": { + "ISNI": {"preferred": None, "all": ["0000 0001 2156 142X"]}, + "GRID": {"preferred": "grid.9132.9", "all": "grid.9132.9"}, + "FundRef": {"preferred": "000000000000", "all": []}, }, - "FundRef": { - "preferred": "000000000000", - "all": [] - } } - }) + ) @pytest.fixture(scope="module") @@ -83,16 +60,9 @@ def expected_from_ror_json(): "title": {"en": "Funder", "de": "Geldgeber"}, "country": "GR", "identifiers": [ - { - "scheme": "isni", - "identifier": "0000 0001 2156 142X" - }, { - "scheme": "grid", - "identifier": "grid.9132.9" - }, { - "scheme": "doi", - "identifier": "10.13039/000000000000" - } + {"scheme": "isni", "identifier": "0000 0001 2156 142X"}, + {"scheme": "grid", "identifier": "grid.9132.9"}, + {"scheme": "doi", "identifier": "10.13039/000000000000"}, ], } diff --git a/tests/contrib/funders/test_funders_jsonschema.py b/tests/contrib/funders/test_funders_jsonschema.py index d79682fd..28835d9e 100644 --- a/tests/contrib/funders/test_funders_jsonschema.py +++ b/tests/contrib/funders/test_funders_jsonschema.py @@ -45,10 +45,9 @@ def test_valid_full(appctx, schema): { "identifier": "grid.1234.5", "scheme": "grid", - } + }, ], "country": "CH", - } assert validates(data) @@ -56,9 +55,7 @@ def test_valid_full(appctx, schema): def test_valid_empty(appctx, schema): # check there are no requirements at JSONSchema level - data = { - "$schema": schema - } + data = {"$schema": schema} assert validates(data) @@ -68,18 +65,12 @@ def test_valid_empty(appctx, schema): def test_fails_name(appctx, schema): - data = { - "$schema": schema, - "name": 1 - } + data = {"$schema": schema, "name": 1} assert fails(data) def test_fails_country(appctx, schema): - data = { - "$schema": schema, - "country": 1 - } + data = {"$schema": schema, "country": 1} assert fails(data) diff --git a/tests/contrib/funders/test_funders_resource.py b/tests/contrib/funders/test_funders_resource.py index 8065c1fc..0037a16e 100644 --- a/tests/contrib/funders/test_funders_resource.py +++ b/tests/contrib/funders/test_funders_resource.py @@ -31,19 +31,17 @@ def test_funders_invalid(client, h, prefix): assert res.status_code == 404 -def test_funders_forbidden( - client, h, prefix, example_funder, funder_full_data -): +def test_funders_forbidden(client, h, prefix, example_funder, funder_full_data): """Test invalid type.""" # invalid type funder_full_data_too = deepcopy(funder_full_data) funder_full_data_too["pid"] = "other" - res = client.post( - f"{prefix}", headers=h, data=json.dumps(funder_full_data_too)) + res = client.post(f"{prefix}", headers=h, data=json.dumps(funder_full_data_too)) assert res.status_code == 403 res = client.put( - f"{prefix}/01ggx4157", headers=h, data=json.dumps(funder_full_data)) + f"{prefix}/01ggx4157", headers=h, data=json.dumps(funder_full_data) + ) assert res.status_code == 403 res = client.delete(f"{prefix}/01ggx4157") @@ -58,9 +56,7 @@ def test_funders_get(client, example_funder, h, prefix): assert res.status_code == 200 assert res.json["id"] == id_ # Test links - assert res.json["links"] == { - "self": "https://127.0.0.1:5000/api/funders/01ggx4157" - } + assert res.json["links"] == {"self": "https://127.0.0.1:5000/api/funders/01ggx4157"} def test_funders_search(client, example_funder, h, prefix): @@ -82,25 +78,18 @@ def example_funders(service, identity, indexer): "country": "CH", "title": { "en": "European Organization for Nuclear Research", - "fr": "Conseil Européen pour la Recherche Nucléaire" - } - }, - { - "id": "0aaaaaa11", - "name": "OTHER", - "country": "CH", - "title": { - "en": "CERN" - } + "fr": "Conseil Européen pour la Recherche Nucléaire", + }, }, + {"id": "0aaaaaa11", "name": "OTHER", "country": "CH", "title": {"en": "CERN"}}, { "id": "0aaaaaa22", "name": "CERT", "country": "CH", "title": { "en": "Computer Emergency Response Team", - "fr": "Équipe d'Intervention d'Urgence Informatique" - } + "fr": "Équipe d'Intervention d'Urgence Informatique", + }, }, { "id": "000e0be47", @@ -108,8 +97,8 @@ def example_funders(service, identity, indexer): "country": "US", "title": { "en": "Northwestern University", - } - } + }, + }, ] funders = [] for data in funders_data: @@ -166,7 +155,8 @@ def test_funders_update( new_name = "updated" funder_full_data["name"] = new_name res = client_with_credentials.put( - f"{prefix}/01ggx4157", headers=h, data=json.dumps(funder_full_data)) + f"{prefix}/01ggx4157", headers=h, data=json.dumps(funder_full_data) + ) assert res.status_code == 200 assert res.json["id"] == id_ # result_items wraps pid into id assert res.json["name"] == new_name @@ -175,6 +165,7 @@ def test_funders_update( def test_funders_create(client_with_credentials, funder_full_data, h, prefix): """Tests a successful creation.""" res = client_with_credentials.post( - f"{prefix}", headers=h, data=json.dumps(funder_full_data)) + f"{prefix}", headers=h, data=json.dumps(funder_full_data) + ) assert res.status_code == 201 assert res.json["id"] == funder_full_data["id"] diff --git a/tests/contrib/funders/test_funders_schema.py b/tests/contrib/funders/test_funders_schema.py index e2fcb9cd..b1031c8b 100644 --- a/tests/contrib/funders/test_funders_schema.py +++ b/tests/contrib/funders/test_funders_schema.py @@ -10,8 +10,10 @@ import pytest from marshmallow import ValidationError -from invenio_vocabularies.contrib.funders.schema import FunderRelationSchema, \ - FunderSchema +from invenio_vocabularies.contrib.funders.schema import ( + FunderRelationSchema, + FunderSchema, +) def test_valid_full(app, funder_full_data): @@ -42,13 +44,13 @@ def test_invalid_no_name(): { "identifier": "grid.9132.9", "scheme": "grid", - } + }, ], "title": { "en": "European Organization for Nuclear Research", - "fr": "Organisation européenne pour la recherche nucléaire" + "fr": "Organisation européenne pour la recherche nucléaire", }, - "country": "CH" + "country": "CH", } with pytest.raises(ValidationError): data = FunderSchema().load(invalid_no_name) @@ -77,14 +79,11 @@ def test_invalid_empty_funder(): def test_invalid_country(): - invalid_country = { - "id": "01ggx4157", - "name": "Test funder", - "country": 1 - } + invalid_country = {"id": "01ggx4157", "name": "Test funder", "country": 1} with pytest.raises(ValidationError): data = FunderSchema().load(invalid_country) + # # FunderRelationSchema # @@ -98,17 +97,12 @@ def test_valid_id(): def test_valid_name(): - valid_name = { - "name": "Funder One" - } + valid_name = {"name": "Funder One"} assert valid_name == FunderRelationSchema().load(valid_name) def test_valid_both_id_name(): - valid_id_name = { - "id": "test", - "name": "Funder One" - } + valid_id_name = {"id": "test", "name": "Funder One"} assert valid_id_name == FunderRelationSchema().load(valid_id_name) diff --git a/tests/contrib/funders/test_funders_service.py b/tests/contrib/funders/test_funders_service.py index 0a74d3b2..17d15fb4 100644 --- a/tests/contrib/funders/test_funders_service.py +++ b/tests/contrib/funders/test_funders_service.py @@ -27,12 +27,12 @@ def test_simple_flow(app, service, identity, funder_full_data): item = service.create(identity, funder_full_data) id_ = item.id - assert item.id == funder_full_data['id'] + assert item.id == funder_full_data["id"] for k, v in funder_full_data.items(): assert item.data[k] == v # Read it - read_item = service.read(identity, '01ggx4157') + read_item = service.read(identity, "01ggx4157") assert item.id == read_item.id assert item.data == read_item.data @@ -41,26 +41,25 @@ def test_simple_flow(app, service, identity, funder_full_data): Funder.index.refresh() # Search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0] == read_item.data # Update its country data = read_item.data - data['country'] = 'New country' + data["country"] = "New country" update_item = service.update(identity, id_, data) assert item.id == update_item.id - assert update_item['country'] == 'New country' + assert update_item["country"] == "New country" # Update its title data = read_item.data - data['title']['en'] = 'New title' + data["title"]["en"] = "New title" update_item = service.update(identity, id_, data) # the pid is not save to the json metadata assert not update_item._record.get("pid") assert item.id == update_item.id - assert update_item['title']['en'] == 'New title' + assert update_item["title"]["en"] == "New title" # Delete it assert service.delete(identity, id_) @@ -75,8 +74,7 @@ def test_simple_flow(app, service, identity, funder_full_data): deleted_rec = service.read(identity, id_).to_dict() assert set(deleted_rec.keys()) == base_keys # - search - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 0 # not-ideal cleanup @@ -88,15 +86,13 @@ def test_pid_already_registered( ): """Recreating a record with same id should fail.""" # example_funder does the first creation - pytest.raises( - PIDAlreadyExists, service.create, identity, funder_full_data) + pytest.raises(PIDAlreadyExists, service.create, identity, funder_full_data) def test_extra_fields(app, service, identity, funder_full_data): """Extra fields in data should fail.""" - funder_full_data['invalid'] = 1 - pytest.raises( - ValidationError, service.create, identity, funder_full_data) + funder_full_data["invalid"] = 1 + pytest.raises(ValidationError, service.create, identity, funder_full_data) def test_indexed_at_query(app, db, service, identity, funder_full_data): @@ -106,13 +102,9 @@ def test_indexed_at_query(app, db, service, identity, funder_full_data): Funder.index.refresh() # there is previous to before - res = service.search( - identity, q=f"indexed_at:[* TO {before}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {before}]", size=25, page=1) assert res.total == 0 # there is previous to now - res = service.search( - identity, q=f"indexed_at:[* TO {now}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {now}]", size=25, page=1) assert res.total == 1 diff --git a/tests/contrib/names/conftest.py b/tests/contrib/names/conftest.py index d5091345..bd5e0505 100644 --- a/tests/contrib/names/conftest.py +++ b/tests/contrib/names/conftest.py @@ -18,7 +18,7 @@ from invenio_vocabularies.contrib.affiliations.api import Affiliation -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(): """Names service object.""" return current_service_registry.get("names") @@ -27,10 +27,9 @@ def service(): @pytest.fixture() def example_affiliation(db): """Example affiliation.""" - aff = Affiliation.create({ - "id": "cern", - "name": "European Organization for Nuclear Research" - }) + aff = Affiliation.create( + {"id": "cern", "name": "European Organization for Nuclear Research"} + ) Affiliation.pid.create(aff) aff.commit() db.session.commit() @@ -45,20 +44,8 @@ def name_full_data(): "given_name": "John", "family_name": "Doe", "identifiers": [ - { - "identifier": "0000-0001-8135-3489", - "scheme": "orcid" - }, { - "identifier": "gnd:4079154-3", - "scheme": "gnd" - } + {"identifier": "0000-0001-8135-3489", "scheme": "orcid"}, + {"identifier": "gnd:4079154-3", "scheme": "gnd"}, ], - "affiliations": [ - { - "id": "cern" - }, - { - "name": "CustomORG" - } - ] + "affiliations": [{"id": "cern"}, {"name": "CustomORG"}], } diff --git a/tests/contrib/names/test_names_api.py b/tests/contrib/names/test_names_api.py index 68106df1..63f33337 100644 --- a/tests/contrib/names/test_names_api.py +++ b/tests/contrib/names/test_names_api.py @@ -22,9 +22,7 @@ @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Name.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Name.index._name, doc_type="_doc") @pytest.fixture() diff --git a/tests/contrib/names/test_names_datastreams.py b/tests/contrib/names/test_names_datastreams.py index 9c5db74c..53de7952 100644 --- a/tests/contrib/names/test_names_datastreams.py +++ b/tests/contrib/names/test_names_datastreams.py @@ -16,8 +16,11 @@ from invenio_records_resources.proxies import current_service_registry from invenio_vocabularies.contrib.names.api import Name -from invenio_vocabularies.contrib.names.datastreams import \ - NamesServiceWriter, OrcidHTTPReader, OrcidTransformer +from invenio_vocabularies.contrib.names.datastreams import ( + NamesServiceWriter, + OrcidHTTPReader, + OrcidTransformer, +) from invenio_vocabularies.datastreams import StreamEntry from invenio_vocabularies.datastreams.errors import WriterError @@ -26,65 +29,62 @@ def name_full_data(): """Full name data.""" return { - 'given_name': 'Lars Holm', - 'family_name': 'Nielsen', - 'identifiers': [ + "given_name": "Lars Holm", + "family_name": "Nielsen", + "identifiers": [ { - 'scheme': 'orcid', - 'identifier': '0000-0001-8135-3489' # normalized after create + "scheme": "orcid", + "identifier": "0000-0001-8135-3489", # normalized after create } ], - 'affiliations': [{'name': 'CERN'}] + "affiliations": [{"name": "CERN"}], } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_from_xml(): return { - 'given_name': 'Lars Holm', - 'family_name': 'Nielsen', - 'identifiers': [ - { - 'scheme': 'orcid', - 'identifier': 'https://orcid.org/0000-0001-8135-3489' - } + "given_name": "Lars Holm", + "family_name": "Nielsen", + "identifiers": [ + {"scheme": "orcid", "identifier": "https://orcid.org/0000-0001-8135-3489"} ], - 'affiliations': [{'name': 'CERN'}] + "affiliations": [{"name": "CERN"}], } XML_ENTRY_DATA = bytes( - '\n' - '\n' - ' \n' - ' https://orcid.org/0000-0001-8135-3489\n' # noqa - ' 0000-0001-8135-3489\n' - ' orcid.org\n' - ' \n' - ' \n' - ' \n' # noqa - ' Lars Holm' # noqa - ' Nielsen\n' # noqa - ' \n' - ' \n' # noqa - ' \n' - ' \n' # noqa - ' \n' # noqa - ' \n' - ' \n' - ' \n' - ' CERN\n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - '\n', - encoding="raw_unicode_escape" - ) + '\n' + '\n' + " \n" + " https://orcid.org/0000-0001-8135-3489\n" # noqa + " 0000-0001-8135-3489\n" + " orcid.org\n" + " \n" + ' \n' + ' \n' # noqa + " Lars Holm" # noqa + " Nielsen\n" # noqa + " \n" + ' \n' # noqa + " \n" + ' \n' # noqa + ' \n' # noqa + " \n" + " \n" + " \n" + " CERN\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n", + encoding="raw_unicode_escape", +) -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def bytes_xml_data(): # simplified version of an XML file of the ORCiD dump return XML_ENTRY_DATA @@ -92,37 +92,37 @@ def bytes_xml_data(): @pytest.fixture(scope="module") def dict_xml_entry(): - return StreamEntry({ - 'orcid-identifier': { - 'uri': 'https://orcid.org/0000-0001-8135-3489', - 'path': '0000-0001-8135-3489', - 'host': 'orcid.org' - }, - 'person': { - 'name': { - 'given-names': 'Lars Holm', - 'family-name': 'Nielsen', - '@visibility': 'public', - '@path': '0000-0001-8135-3489' + return StreamEntry( + { + "orcid-identifier": { + "uri": "https://orcid.org/0000-0001-8135-3489", + "path": "0000-0001-8135-3489", + "host": "orcid.org", }, - 'external-identifiers': { - '@path': '/0000-0001-8135-3489/external-identifiers' + "person": { + "name": { + "given-names": "Lars Holm", + "family-name": "Nielsen", + "@visibility": "public", + "@path": "0000-0001-8135-3489", + }, + "external-identifiers": { + "@path": "/0000-0001-8135-3489/external-identifiers" + }, + "@path": "/0000-0001-8135-3489/person", }, - '@path': '/0000-0001-8135-3489/person' - }, - 'activities-summary': { - 'employments': { - 'affiliation-group': { - 'employment-summary': { - 'organization': {'name': 'CERN'} - } + "activities-summary": { + "employments": { + "affiliation-group": { + "employment-summary": {"organization": {"name": "CERN"}} + }, + "@path": "/0000-0001-8135-3489/employments", }, - '@path': '/0000-0001-8135-3489/employments' + "@path": "/0000-0001-8135-3489/activities", }, - '@path': '/0000-0001-8135-3489/activities' - }, - '@path': '/0000-0001-8135-3489' - }) + "@path": "/0000-0001-8135-3489", + } + ) def test_orcid_transformer(dict_xml_entry, expected_from_xml): @@ -130,12 +130,12 @@ def test_orcid_transformer(dict_xml_entry, expected_from_xml): assert expected_from_xml == transformer.apply(dict_xml_entry).entry -class MockResponse(): +class MockResponse: content = XML_ENTRY_DATA status_code = 200 -@patch('requests.get', side_effect=lambda url, headers: MockResponse()) +@patch("requests.get", side_effect=lambda url, headers: MockResponse()) def test_orcid_http_reader(_, bytes_xml_data): reader = OrcidHTTPReader(id="0000-0001-8135-3489") results = [] @@ -185,9 +185,7 @@ def test_names_service_writer_update_existing(app, es_clear, name_full_data): assert dict(record, **updated_name) == record -def test_names_service_writer_update_non_existing( - app, es_clear, name_full_data -): +def test_names_service_writer_update_non_existing(app, es_clear, name_full_data): # vocabulary item not created, call update directly updated_name = deepcopy(name_full_data) updated_name["given_name"] = "Pablo" diff --git a/tests/contrib/names/test_names_jsonschema.py b/tests/contrib/names/test_names_jsonschema.py index 73331861..f9e3437b 100644 --- a/tests/contrib/names/test_names_jsonschema.py +++ b/tests/contrib/names/test_names_jsonschema.py @@ -39,29 +39,15 @@ def test_valid_full(appctx, schema): "name": "Doe, John", "given_name": "John", "family_name": "Doe", - "identifiers": [ - { - "identifier": "0000-0001-8135-3489", - "scheme": "orcid" - } - ], - "affiliations": [ - { - "id": "cern" - }, - { - "name": "CustomORG" - } - ] + "identifiers": [{"identifier": "0000-0001-8135-3489", "scheme": "orcid"}], + "affiliations": [{"id": "cern"}, {"name": "CustomORG"}], } assert validates(data) def test_valid_empty(appctx, schema): # check there are no requirements at JSONSchema level - data = { - "$schema": schema - } + data = {"$schema": schema} assert validates(data) @@ -69,22 +55,17 @@ def test_valid_empty(appctx, schema): # only acronym and name are defined by the affiliation schema # the rest are inherited and should be tested elsewhere + def test_fails_name_identifiers(appctx, schema): # string - data = { - "$schema": schema, - "identifiers": "0000-0001-8135-3489" - } + data = {"$schema": schema, "identifiers": "0000-0001-8135-3489"} assert fails(data) # dict data = { "$schema": schema, - "identifiers": { - "identifier": "0000-0001-8135-3489", - "scheme": "orcid" - } + "identifiers": {"identifier": "0000-0001-8135-3489", "scheme": "orcid"}, } assert fails(data) @@ -92,20 +73,11 @@ def test_fails_name_identifiers(appctx, schema): def test_fails_name_affiliations(appctx, schema): # string, comma separated list - data = { - "$schema": schema, - "affiliations": "cern, CustomORG" - } + data = {"$schema": schema, "affiliations": "cern, CustomORG"} assert fails(data) # dict - data = { - "$schema": schema, - "affiliations": { - "id": "cern", - "name": "CustomORG" - } - } + data = {"$schema": schema, "affiliations": {"id": "cern", "name": "CustomORG"}} assert fails(data) diff --git a/tests/contrib/names/test_names_resource.py b/tests/contrib/names/test_names_resource.py index b3ad48e1..e89c12d8 100644 --- a/tests/contrib/names/test_names_resource.py +++ b/tests/contrib/names/test_names_resource.py @@ -44,14 +44,11 @@ def test_names_invalid(client, h, prefix): def test_names_forbidden(client, h, prefix, example_name, name_full_data): """Test invalid type.""" # invalid type - res = client.post( - f"{prefix}", headers=h, data=json.dumps(name_full_data)) + res = client.post(f"{prefix}", headers=h, data=json.dumps(name_full_data)) assert res.status_code == 403 res = client.put( - f"{prefix}/{example_name.id}", - headers=h, - data=json.dumps(name_full_data) + f"{prefix}/{example_name.id}", headers=h, data=json.dumps(name_full_data) ) assert res.status_code == 403 diff --git a/tests/contrib/names/test_names_schema.py b/tests/contrib/names/test_names_schema.py index 2fe34283..748e2960 100644 --- a/tests/contrib/names/test_names_schema.py +++ b/tests/contrib/names/test_names_schema.py @@ -26,40 +26,29 @@ def test_valid_minimal(app): loaded = NameSchema().load(data) assert data == loaded - data = { - "family_name": "Doe", - "given_name": "John" - } + data = {"family_name": "Doe", "given_name": "John"} loaded = NameSchema().load(data) - data["name"] = 'Doe, John' # it will be calculated and included + data["name"] = "Doe, John" # it will be calculated and included assert data == loaded def test_invalid_no_names(app): # no name invalid = { - "identifiers": [ - { - "identifier": "0000-0001-8135-3489", - "scheme": "orcid" - } - ], - "affiliations": [ - {"id": "cern"}, - {"name": "CustomORG"} - ] + "identifiers": [{"identifier": "0000-0001-8135-3489", "scheme": "orcid"}], + "affiliations": [{"id": "cern"}, {"name": "CustomORG"}], } with pytest.raises(ValidationError): data = NameSchema().load(invalid) # only given name - invalid["given_name"] = "John", + invalid["given_name"] = ("John",) with pytest.raises(ValidationError): data = NameSchema().load(invalid) # only family name - invalid["family_name"] = "Doe", + invalid["family_name"] = ("Doe",) invalid.pop("given_name") with pytest.raises(ValidationError): diff --git a/tests/contrib/names/test_names_service.py b/tests/contrib/names/test_names_service.py index 824c3f35..c977cded 100644 --- a/tests/contrib/names/test_names_service.py +++ b/tests/contrib/names/test_names_service.py @@ -20,9 +20,7 @@ from invenio_vocabularies.contrib.names.api import Name -def test_simple_flow( - app, service, identity, name_full_data, example_affiliation -): +def test_simple_flow(app, service, identity, name_full_data, example_affiliation): """Test a simple vocabulary service flow.""" # Service assert service.id == "names" @@ -34,8 +32,9 @@ def test_simple_flow( # add dereferenced values expected_data = deepcopy(name_full_data) - expected_data["affiliations"][0]["name"] = \ - "European Organization for Nuclear Research" + expected_data["affiliations"][0][ + "name" + ] = "European Organization for Nuclear Research" for k, v in expected_data.items(): assert item.data[k] == v @@ -49,8 +48,7 @@ def test_simple_flow( Name.index.refresh() # Search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0] == read_item.data @@ -59,8 +57,8 @@ def test_simple_flow( data["given_name"] = "Jane" update_item = service.update(identity, id_, data) assert item.id == update_item.id - assert update_item['given_name'] == 'Jane' - assert update_item['name'] == "Doe, Jane" # automatic update + assert update_item["given_name"] == "Jane" + assert update_item["name"] == "Doe, Jane" # automatic update # Delete it assert service.delete(identity, id_) @@ -78,7 +76,7 @@ def test_simple_flow( def test_extra_fields(app, service, identity, name_full_data): """Extra fields in data should fail.""" - name_full_data['invalid'] = 1 + name_full_data["invalid"] = 1 pytest.raises(ValidationError, service.create, identity, name_full_data) @@ -90,20 +88,12 @@ def test_identifier_resolution( id_ = item.id Name.index.refresh() - resolved = service.resolve( - identity, - id_="0000-0001-8135-3489", - id_type="orcid" - ) + resolved = service.resolve(identity, id_="0000-0001-8135-3489", id_type="orcid") assert resolved.id == id_ # non-existent orcid pytest.raises( - PIDDoesNotExistError, - service.resolve, - identity, - "0000-0002-5082-6404", - "orcid" + PIDDoesNotExistError, service.resolve, identity, "0000-0002-5082-6404", "orcid" ) # non-existent scheme @@ -112,23 +102,15 @@ def test_identifier_resolution( service.resolve, identity, "0000-0001-8135-3489", - "invalid" + "invalid", ) -def test_names_dereferenced( - app, es_clear, service, identity, example_affiliation -): +def test_names_dereferenced(app, es_clear, service, identity, example_affiliation): """Extra fields in data should fail.""" - expected_aff = { - "id": "cern", - "name": "European Organization for Nuclear Research" - } + expected_aff = {"id": "cern", "name": "European Organization for Nuclear Research"} - name_data = { - "name": "Doe, John", - "affiliations": [{"id": "cern"}] - } + name_data = {"name": "Doe, John", "affiliations": [{"id": "cern"}]} # data is not dereferenced assert not name_data["affiliations"][0].get("name") @@ -143,8 +125,7 @@ def test_names_dereferenced( assert read_item["affiliations"][0] == expected_aff # search it - res = service.search( - identity, q=f"id:{id_}", size=25, page=1) + res = service.search(identity, q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0]["affiliations"][0] == expected_aff @@ -158,13 +139,9 @@ def test_indexed_at_query( Name.index.refresh() # there is previous to before - res = service.search( - identity, q=f"indexed_at:[* TO {before}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {before}]", size=25, page=1) assert res.total == 0 # there is previous to now - res = service.search( - identity, q=f"indexed_at:[* TO {now}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {now}]", size=25, page=1) assert res.total == 1 diff --git a/tests/contrib/subjects/conftest.py b/tests/contrib/subjects/conftest.py index b566bd5a..979fc682 100644 --- a/tests/contrib/subjects/conftest.py +++ b/tests/contrib/subjects/conftest.py @@ -23,11 +23,11 @@ def subject_full_data(): return { "id": "https://id.nlm.nih.gov/mesh/D000001", "scheme": "MeSH", - "subject": "Calcimycin" + "subject": "Calcimycin", } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def service(): """Subjects service object.""" return current_service_registry.get("subjects") diff --git a/tests/contrib/subjects/test_subjects_api.py b/tests/contrib/subjects/test_subjects_api.py index fa39a492..8b32118e 100644 --- a/tests/contrib/subjects/test_subjects_api.py +++ b/tests/contrib/subjects/test_subjects_api.py @@ -21,9 +21,7 @@ @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Subject.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Subject.index._name, doc_type="_doc") @pytest.fixture() @@ -45,9 +43,7 @@ def example_subject(db, subject_full_data): return subj -def test_subject_indexing( - app, db, es, example_subject, indexer, search_get -): +def test_subject_indexing(app, db, es, example_subject, indexer, search_get): """Test indexing of a subject.""" # Index document in ES assert indexer.index(example_subject)["result"] == "created" diff --git a/tests/contrib/subjects/test_subjects_jsonschema.py b/tests/contrib/subjects/test_subjects_jsonschema.py index 9ac8379c..e8b8d0ba 100644 --- a/tests/contrib/subjects/test_subjects_jsonschema.py +++ b/tests/contrib/subjects/test_subjects_jsonschema.py @@ -37,12 +37,7 @@ def test_valid_full(appctx, schema): data = { "$schema": schema, "id": "https://id.nlm.nih.gov/mesh/D000001", - "pid": { - "pk": 1, - "status": "R", - "pid_type": "subid", - "obj_type": "sub" - }, + "pid": {"pk": 1, "status": "R", "pid_type": "subid", "obj_type": "sub"}, "scheme": "MeSH", "subject": "Calcimycin", } @@ -52,26 +47,18 @@ def test_valid_full(appctx, schema): def test_valid_empty(appctx, schema): # check there are no requirements at JSONSchema level - data = { - "$schema": schema - } + data = {"$schema": schema} assert validates(data) def test_fails_scheme(appctx, schema): - data = { - "$schema": schema, - "scheme": 1 - } + data = {"$schema": schema, "scheme": 1} assert fails(data) def test_fails_name(appctx, schema): - data = { - "$schema": schema, - "subject": 1 - } + data = {"$schema": schema, "subject": 1} assert fails(data) diff --git a/tests/contrib/subjects/test_subjects_resource.py b/tests/contrib/subjects/test_subjects_resource.py index 4c634a77..10e1cf42 100644 --- a/tests/contrib/subjects/test_subjects_resource.py +++ b/tests/contrib/subjects/test_subjects_resource.py @@ -53,9 +53,7 @@ def test_get_invalid(client, h, prefix): assert res.status_code == 404 -def test_forbidden_endpoints( - client, h, prefix, example_subject, subject_full_data -): +def test_forbidden_endpoints(client, h, prefix, example_subject, subject_full_data): # POST subject_full_data_too = deepcopy(subject_full_data) subject_full_data_too["id"] = "other" @@ -85,8 +83,8 @@ def test_search(client, h, prefix, example_subject): def example_subjects(app, db, es_clear, identity, service): subjects = [ { - 'id': 'other-1', - 'scheme': 'Other', + "id": "other-1", + "scheme": "Other", "subject": "Abdomen", }, { @@ -95,19 +93,19 @@ def example_subjects(app, db, es_clear, identity, service): "subject": "Calcimycin", }, { - 'id': 'https://id.nlm.nih.gov/mesh/D000005', - 'scheme': 'MeSH', - 'subject': 'Abdomen', + "id": "https://id.nlm.nih.gov/mesh/D000005", + "scheme": "MeSH", + "subject": "Abdomen", }, { - 'id': 'https://id.nlm.nih.gov/mesh/D000006', - 'scheme': 'MeSH', - 'subject': 'Abdomen, Acute', + "id": "https://id.nlm.nih.gov/mesh/D000006", + "scheme": "MeSH", + "subject": "Abdomen, Acute", }, { - 'id': 'yet-another-954514', - 'scheme': 'Other2', - 'subject': 'Abdomen', + "id": "yet-another-954514", + "scheme": "Other2", + "subject": "Abdomen", }, ] records = [service.create(identity, s) for s in subjects] @@ -118,20 +116,20 @@ def example_subjects(app, db, es_clear, identity, service): def test_suggest(client, h, prefix, example_subjects): """Test FilteredSuggestParam.""" # No filter - res = client.get(f'{prefix}?suggest=abdo', headers=h) + res = client.get(f"{prefix}?suggest=abdo", headers=h) assert res.json["hits"]["total"] == 4 # Single filter - res = client.get(f'{prefix}?suggest=MeSH:abdo', headers=h) + res = client.get(f"{prefix}?suggest=MeSH:abdo", headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 2 # Multiple filters - res = client.get(f'{prefix}?suggest=MeSH,Other:abdo', headers=h) + res = client.get(f"{prefix}?suggest=MeSH,Other:abdo", headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 3 # Ignore non existing filter - res = client.get(f'{prefix}?suggest=MeSH,Foo:abdo', headers=h) + res = client.get(f"{prefix}?suggest=MeSH,Foo:abdo", headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 2 diff --git a/tests/contrib/subjects/test_subjects_schema.py b/tests/contrib/subjects/test_subjects_schema.py index cad1c0ff..51d5d2c1 100644 --- a/tests/contrib/subjects/test_subjects_schema.py +++ b/tests/contrib/subjects/test_subjects_schema.py @@ -13,8 +13,10 @@ import pytest from marshmallow import ValidationError -from invenio_vocabularies.contrib.subjects.schema import \ - SubjectRelationSchema, SubjectSchema +from invenio_vocabularies.contrib.subjects.schema import ( + SubjectRelationSchema, + SubjectSchema, +) def test_valid_full(subject_full_data): @@ -53,9 +55,7 @@ def test_valid_id(): def test_valid_subject(): - valid_subject = { - "subject": "Entity One" - } + valid_subject = {"subject": "Entity One"} assert valid_subject == SubjectRelationSchema().load(valid_subject) diff --git a/tests/contrib/subjects/test_subjects_service.py b/tests/contrib/subjects/test_subjects_service.py index a85dd63a..53a80f80 100644 --- a/tests/contrib/subjects/test_subjects_service.py +++ b/tests/contrib/subjects/test_subjects_service.py @@ -27,12 +27,12 @@ def test_subject_simple_flow(app, db, service, identity, subject_full_data): id_ = item.id data = item.data - assert id_ == subject_full_data['id'] + assert id_ == subject_full_data["id"] for k, v in subject_full_data.items(): assert data[k] == v, data # Read it - read_item = service.read(identity, 'https://id.nlm.nih.gov/mesh/D000001') + read_item = service.read(identity, "https://id.nlm.nih.gov/mesh/D000001") assert item.id == read_item.id assert item.data == read_item.data @@ -48,10 +48,10 @@ def test_subject_simple_flow(app, db, service, identity, subject_full_data): # Update it data = read_item.data - data['subject'] = 'Antibiotics' + data["subject"] = "Antibiotics" update_item = service.update(identity, id_, data) assert item.id == update_item.id - assert update_item['subject'] == 'Antibiotics' + assert update_item["subject"] == "Antibiotics" # Delete it assert service.delete(identity, id_) @@ -74,13 +74,9 @@ def test_indexed_at_query(app, db, service, identity, subject_full_data): Subject.index.refresh() # there is previous to before - res = service.search( - identity, q=f"indexed_at:[* TO {before}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {before}]", size=25, page=1) assert res.total == 0 # there is previous to now - res = service.search( - identity, q=f"indexed_at:[* TO {now}]", size=25, page=1 - ) + res = service.search(identity, q=f"indexed_at:[* TO {now}]", size=25, page=1) assert res.total == 1 diff --git a/tests/datastreams/conftest.py b/tests/datastreams/conftest.py index a139657f..f9c01b98 100644 --- a/tests/datastreams/conftest.py +++ b/tests/datastreams/conftest.py @@ -18,10 +18,8 @@ import pytest -from invenio_vocabularies.datastreams.errors import TransformerError, \ - WriterError -from invenio_vocabularies.datastreams.readers import BaseReader, JsonReader, \ - ZipReader +from invenio_vocabularies.datastreams.errors import TransformerError, WriterError +from invenio_vocabularies.datastreams.readers import BaseReader, JsonReader, ZipReader from invenio_vocabularies.datastreams.transformers import BaseTransformer from invenio_vocabularies.datastreams.writers import BaseWriter @@ -73,7 +71,7 @@ def write(self, stream_entry, *args, **kwargs): raise WriterError(f"{self.fail_on} value found.") -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def app_config(app_config): """Mimic an instance's configuration.""" app_config["VOCABULARIES_DATASTREAM_READERS"] = { @@ -81,9 +79,7 @@ def app_config(app_config): "test": TestReader, "zip": ZipReader, } - app_config["VOCABULARIES_DATASTREAM_TRANSFORMERS"] = { - "test": TestTransformer - } + app_config["VOCABULARIES_DATASTREAM_TRANSFORMERS"] = {"test": TestTransformer} app_config["VOCABULARIES_DATASTREAM_WRITERS"] = { "test": TestWriter, "fail": FailingTestWriter, @@ -92,34 +88,19 @@ def app_config(app_config): return app_config -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def json_list(): """Expected json list.""" - return [ - { - "test": { - "inner": "value" - } - }, - { - "test": { - "inner": "value" - } - } - ] - - -@pytest.fixture(scope='module') + return [{"test": {"inner": "value"}}, {"test": {"inner": "value"}}] + + +@pytest.fixture(scope="module") def json_element(): """Expected json element.""" - return { - "test": { - "inner": "value" - } - } + return {"test": {"inner": "value"}} -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def zip_file(json_list): """Creates a Zip file with three files (two json) inside. @@ -131,7 +112,7 @@ def zip_file(json_list): with zipfile.ZipFile(file=filename, mode="w") as archive: for file_ in files: inner_filename = Path(file_) - with open(inner_filename, 'w') as file: + with open(inner_filename, "w") as file: json.dump(json_list, file) archive.write(inner_filename) inner_filename.unlink() diff --git a/tests/datastreams/test_datastreams.py b/tests/datastreams/test_datastreams.py index efad30cc..61c62b9b 100644 --- a/tests/datastreams/test_datastreams.py +++ b/tests/datastreams/test_datastreams.py @@ -21,20 +21,16 @@ def vocabulary_config(): """Parsed vocabulary configuration.""" return { - "transformers": [ - {"type": "test"} - ], + "transformers": [{"type": "test"}], "readers": [ { "type": "test", "args": { "origin": [1, -1], - } + }, } ], - "writers": [ - {"type": "test"} - ] + "writers": [{"type": "test"}], } @@ -57,10 +53,12 @@ def test_base_datastream(app, vocabulary_config): def test_base_datastream_fail_on_write(app, vocabulary_config): custom_config = dict(vocabulary_config) - custom_config["writers"].append({ - "type": "fail", - "args": {"fail_on": 2} # 2 means 1 as entry cuz transformers sums 1 - }) + custom_config["writers"].append( + { + "type": "fail", + "args": {"fail_on": 2}, # 2 means 1 as entry cuz transformers sums 1 + } + ) datastream = DataStreamFactory.create( readers_config=vocabulary_config["readers"], @@ -79,7 +77,7 @@ def test_base_datastream_fail_on_write(app, vocabulary_config): assert "TestTransformer: Value cannot be negative" in invalid_tr.errors -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def zip_file(json_list): """Creates a Zip file with three files inside. @@ -90,7 +88,7 @@ def zip_file(json_list): def _correct_file(archive, idx): correct_file = Path(f"correct_{idx}.json") - with open(correct_file, 'w') as file: + with open(correct_file, "w") as file: json.dump(json_list, file) archive.write(correct_file) correct_file.unlink() @@ -99,7 +97,7 @@ def _correct_file(archive, idx): with zipfile.ZipFile(file=filename, mode="w") as archive: _correct_file(archive, 1) errored_file = Path("errored.json") - with open(errored_file, 'w') as file: + with open(errored_file, "w") as file: file.write( # to dump incorrect json format # missing comma and closing bracket '[{"test": {"inner": "value"}{"test": {"inner": "value"}}]' @@ -121,13 +119,11 @@ def test_piping_readers(app, zip_file, json_element): "args": { "origin": "reader_test.zip", "regex": ".json$", - } + }, }, - {"type": "json"} + {"type": "json"}, ], - "writers": [ - {"type": "test"} - ] + "writers": [{"type": "test"}], } datastream = DataStreamFactory.create( diff --git a/tests/datastreams/test_readers.py b/tests/datastreams/test_readers.py index 429f85f3..b7848e72 100644 --- a/tests/datastreams/test_readers.py +++ b/tests/datastreams/test_readers.py @@ -14,29 +14,23 @@ import pytest import yaml -from invenio_vocabularies.datastreams.readers import JsonReader, TarReader, \ - YamlReader, ZipReader +from invenio_vocabularies.datastreams.readers import ( + JsonReader, + TarReader, + YamlReader, + ZipReader, +) -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_from_yaml(): - return [ - { - "test": { - "inner": "value" - } - }, { - "test": { - "inner": "value" - } - } - ] - - -@pytest.fixture(scope='function') + return [{"test": {"inner": "value"}}, {"test": {"inner": "value"}}] + + +@pytest.fixture(scope="function") def yaml_file(expected_from_yaml): - filename = Path('reader_test.yaml') - with open(filename, 'w') as file: + filename = Path("reader_test.yaml") + with open(filename, "w") as file: yaml.dump(expected_from_yaml, file) yield filename @@ -51,16 +45,12 @@ def test_yaml_reader(yaml_file, expected_from_yaml): assert data == expected_from_yaml[idx] -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_from_tar(): - return { - "test": { - "inner": "value" - } - } + return {"test": {"inner": "value"}} -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def tar_file(expected_from_tar): """Creates a Tar file with three files (two yaml) inside. @@ -72,7 +62,7 @@ def tar_file(expected_from_tar): with tarfile.open(filename, "w:gz") as tar: for file_ in files: inner_filename = Path(file_) - with open(inner_filename, 'w') as file: + with open(inner_filename, "w") as file: yaml.dump(expected_from_tar, file) tar.add(inner_filename) inner_filename.unlink() @@ -103,11 +93,11 @@ def test_zip_reader(zip_file, json_list): assert total == 2 # ignored the `.other` file -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def json_list_file(json_list): """Creates a JSON file with an array inside.""" filename = Path("reader_test.json") - with open(filename, mode='w') as file: + with open(filename, mode="w") as file: json.dump(json_list, file) yield filename @@ -124,11 +114,11 @@ def test_json_list_reader(json_list_file, json_element): assert count == 2 -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def json_element_file(json_element): """Creates a JSON file with only one element inside.""" filename = Path("reader_test.json") - with open(filename, mode='w') as file: + with open(filename, mode="w") as file: json.dump(json_element, file) yield filename filename.unlink() # delete created file @@ -142,4 +132,5 @@ def test_json_element_reader(json_element_file, json_element): assert count == 1 + # FIXME: add test for csv reader diff --git a/tests/datastreams/test_transformers.py b/tests/datastreams/test_transformers.py index 00578385..aab05aae 100644 --- a/tests/datastreams/test_transformers.py +++ b/tests/datastreams/test_transformers.py @@ -15,44 +15,45 @@ from invenio_vocabularies.datastreams.transformers import XMLTransformer -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_from_xml(): return { - 'field_one': 'value', - 'multi_field': { - 'some': 'value', - 'another': 'value too' - } + "field_one": "value", + "multi_field": {"some": "value", "another": "value too"}, } def test_xml_transformer(expected_from_xml): - bytes_xml_entry = StreamEntry(bytes( - '\n' - '\n' - ' value\n' - ' \n' - ' value\n' - ' value too\n' - ' \n' - '\n', - encoding="raw_unicode_escape" - )) + bytes_xml_entry = StreamEntry( + bytes( + '\n' + "\n" + " value\n" + " \n" + " value\n" + " value too\n" + " \n" + "\n", + encoding="raw_unicode_escape", + ) + ) transformer = XMLTransformer() assert expected_from_xml == transformer.apply(bytes_xml_entry).entry def test_bad_xml_transformer(): - bytes_xml_entry = StreamEntry(bytes( - '\n' - 'value\n' - '\n' - ' value\n' - ' value too\n' - '\n', - encoding="raw_unicode_escape" - )) + bytes_xml_entry = StreamEntry( + bytes( + '\n' + "value\n" + "\n" + " value\n" + " value too\n" + "\n", + encoding="raw_unicode_escape", + ) + ) transformer = XMLTransformer() with pytest.raises(TransformerError): diff --git a/tests/datastreams/test_writers.py b/tests/datastreams/test_writers.py index 576dba4c..58663531 100644 --- a/tests/datastreams/test_writers.py +++ b/tests/datastreams/test_writers.py @@ -38,9 +38,7 @@ def test_service_writer_duplicate(lang_type, lang_data, service, identity): assert expected_error in err.value.args -def test_service_writer_update_existing( - lang_type, lang_data, service, identity -): +def test_service_writer_update_existing(lang_type, lang_data, service, identity): # create vocabulary writer = ServiceWriter(service, identity, update=True) lang = writer.write(stream_entry=StreamEntry(lang_data)) @@ -56,9 +54,7 @@ def test_service_writer_update_existing( assert dict(record, **updated_lang) == record -def test_service_writer_update_non_existing( - lang_type, lang_data, service, identity -): +def test_service_writer_update_non_existing(lang_type, lang_data, service, identity): # vocabulary item not created, call update directly updated_lang = deepcopy(lang_data) updated_lang["description"]["en"] = "Updated english description" @@ -73,11 +69,8 @@ def test_service_writer_update_non_existing( def test_yaml_writer(): - filepath = Path('writer_test.yaml') - test_output = [ - {"key_one": [{"inner_one": 1}]}, - {"key_two": [{"inner_two": "two"}]} - ] + filepath = Path("writer_test.yaml") + test_output = [{"key_one": [{"inner_one": 1}]}, {"key_two": [{"inner_two": "two"}]}] writer = YamlWriter(filepath=filepath) for output in test_output: diff --git a/tests/mock_module/api.py b/tests/mock_module/api.py index dec50f37..1fed25b7 100644 --- a/tests/mock_module/api.py +++ b/tests/mock_module/api.py @@ -15,8 +15,11 @@ from invenio_records.dumpers.relations import RelationDumperExt from invenio_records.systemfields import ConstantField, RelationsField from invenio_records_resources.records.api import Record as RecordBase -from invenio_records_resources.records.systemfields import IndexField, \ - PIDField, PIDListRelation +from invenio_records_resources.records.systemfields import ( + IndexField, + PIDField, + PIDListRelation, +) from invenio_vocabularies.records.api import Vocabulary @@ -27,23 +30,22 @@ class Record(RecordBase): """Example bibliographic record API.""" model_cls = models.RecordMetadata - schema = ConstantField( - '$schema', 'local://records/record-v1.0.0.json') - index = IndexField('records-record-v1.0.0', search_alias='records') - pid = PIDField('id', provider=RecordIdProviderV2) + schema = ConstantField("$schema", "local://records/record-v1.0.0.json") + index = IndexField("records-record-v1.0.0", search_alias="records") + pid = PIDField("id", provider=RecordIdProviderV2) # Definitions of relationships from a bibliographic record to the # generic vocabularies. relations = RelationsField( languages=PIDListRelation( - 'metadata.languages', - keys=['id', 'title'], - pid_field=Vocabulary.pid.with_type_ctx('languages') + "metadata.languages", + keys=["id", "title"], + pid_field=Vocabulary.pid.with_type_ctx("languages"), ), ) dumper = ElasticsearchDumper( extensions=[ - RelationDumperExt('relations'), + RelationDumperExt("relations"), ] ) diff --git a/tests/mock_module/models.py b/tests/mock_module/models.py index 2564718b..615dd6e1 100644 --- a/tests/mock_module/models.py +++ b/tests/mock_module/models.py @@ -16,4 +16,4 @@ class RecordMetadata(db.Model, RecordMetadataBase): """Model for mock module metadata.""" - __tablename__ = 'mock_metadata' + __tablename__ = "mock_metadata" diff --git a/tests/records/conftest.py b/tests/records/conftest.py index 5d8e2218..1689c93b 100644 --- a/tests/records/conftest.py +++ b/tests/records/conftest.py @@ -31,27 +31,25 @@ def indexer(): @pytest.fixture() def search_get(): """Get a document from an index.""" - return partial( - current_search_client.get, Vocabulary.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Vocabulary.index._name, doc_type="_doc") @pytest.fixture() def lic_type(): """Get a language vocabulary type.""" - return VocabularyType.create(id='licenses', pid_type='lic') + return VocabularyType.create(id="licenses", pid_type="lic") @pytest.fixture() def example_data(): """Example data.""" return { - 'id': 'eng', - 'title': {'en': 'English', 'da': 'Engelsk'}, - 'description': {'en': 'Text', 'da': 'Tekst'}, - 'icon': 'file-o', - 'props': { - 'datacite_type': 'Text', + "id": "eng", + "title": {"en": "English", "da": "Engelsk"}, + "description": {"en": "Text", "da": "Tekst"}, + "icon": "file-o", + "props": { + "datacite_type": "Text", }, } diff --git a/tests/records/test_api.py b/tests/records/test_api.py index b920c064..9fbe7936 100644 --- a/tests/records/test_api.py +++ b/tests/records/test_api.py @@ -18,31 +18,32 @@ def test_record_schema_validation(app, db, lang_type): """Record schema validation.""" # Good data - record = Vocabulary.create({ - 'id': 'eng', - 'title': {'en': 'English', 'da': 'Engelsk'}, - 'description': {'en': 'English', 'da': 'Engelsk'}, - 'icon': 'en', - 'props': { - 'akey': 'a value' + record = Vocabulary.create( + { + "id": "eng", + "title": {"en": "English", "da": "Engelsk"}, + "description": {"en": "English", "da": "Engelsk"}, + "icon": "en", + "props": {"akey": "a value"}, + "tags": ["recommended"], }, - 'tags': ['recommended'], - }, type=lang_type) + type=lang_type, + ) assert record.schema # Bad data examples = [ # title/descriptions are objects of key/string. - {'id': 'en', 'title': 'not a string'}, - {'id': 'en', 'title': {'en': 123}}, - {'id': 'en', 'description': 'not a string'}, + {"id": "en", "title": "not a string"}, + {"id": "en", "title": {"en": 123}}, + {"id": "en", "description": "not a string"}, # icon must be strings - {'id': 'en', 'icon': 123}, + {"id": "en", "icon": 123}, # props values must be strings - {'id': 'en', 'props': {'key': 123}}, - {'id': 'en', 'props': {'key': {'test': 'test'}}}, + {"id": "en", "props": {"key": 123}}, + {"id": "en", "props": {"key": {"test": "test"}}}, # Additional properties false - {'id': 'en', 'metadata': {'title': 'test'}}, + {"id": "en", "metadata": {"title": "test"}}, ] for ex in examples: @@ -67,8 +68,8 @@ def test_record_indexing(app, db, es, example_record, indexer, search_get): # Check system fields - i.e reading related type object from assert record == example_record - assert record.type.id == 'languages' - assert record.type.pid_type == 'lng' + assert record.type.id == "languages" + assert record.type.pid_type == "lng" # Check that object was recrated without hitting DB assert inspect(record.type).persistent is False @@ -78,21 +79,20 @@ def test_record_indexing(app, db, es, example_record, indexer, search_get): def test_record_pids(app, db, lang_type, lic_type): """Test record pid creation.""" - record = Vocabulary.create({ - 'id': 'eng', 'title': {'en': 'English', 'da': 'Engelsk'}}, - type=lang_type + record = Vocabulary.create( + {"id": "eng", "title": {"en": "English", "da": "Engelsk"}}, type=lang_type ) Vocabulary.pid.create(record) assert record.type == lang_type - assert record.pid.pid_value == 'eng' - assert record.pid.pid_type == 'lng' - assert Vocabulary.pid.resolve(('languages', 'eng')) + assert record.pid.pid_value == "eng" + assert record.pid.pid_type == "lng" + assert Vocabulary.pid.resolve(("languages", "eng")) - record = Vocabulary.create({ - 'id': 'cc-by', 'title': {'en': 'CC-BY', 'da': 'CC-BY'} - }, type=lic_type) + record = Vocabulary.create( + {"id": "cc-by", "title": {"en": "CC-BY", "da": "CC-BY"}}, type=lic_type + ) Vocabulary.pid.create(record) assert record.type == lic_type - assert record.pid.pid_value == 'cc-by' - assert record.pid.pid_type == 'lic' - assert Vocabulary.pid.resolve(('licenses', 'cc-by')) + assert record.pid.pid_value == "cc-by" + assert record.pid.pid_type == "lic" + assert Vocabulary.pid.resolve(("licenses", "cc-by")) diff --git a/tests/records/test_jsonschema.py b/tests/records/test_jsonschema.py index 8b337f34..c4840366 100644 --- a/tests/records/test_jsonschema.py +++ b/tests/records/test_jsonschema.py @@ -21,28 +21,15 @@ def vocabulary_json(): "$schema": "local://vocabularies/vocabulary-v1.0.0.json", "description": { "en": "Test affiliation description", - "es": "Descripcion de una afiliacion de test" + "es": "Descripcion de una afiliacion de test", }, "icon": "test.png", "id": "voc-1", - "pid": { - "pk": 1, - "status": "R", - "pid_type": "vocid", - "obj_type": "voc" - }, - "props": { - "example": "test" - }, + "pid": {"pk": 1, "status": "R", "pid_type": "vocid", "obj_type": "voc"}, + "props": {"example": "test"}, "tags": ["one_tag", "two_tag"], - "title": { - "en": "Test affiliation", - "es": "Afiliacion de test" - }, - "type": { - "id": "vocabulary", - "pid_type": "vocid" - } + "title": {"en": "Test affiliation", "es": "Afiliacion de test"}, + "type": {"id": "vocabulary", "pid_type": "vocid"}, } @@ -65,23 +52,22 @@ def test_valid_full(appctx, vocabulary_json): def test_valid_empty(appctx): # check there are no requirements at JSONSchema level - data = { - "$schema": "local://vocabularies/vocabulary-v1.0.0.json" - } + data = {"$schema": "local://vocabularies/vocabulary-v1.0.0.json"} assert validates(data) def test_fails_description(appctx, vocabulary_json): vocabulary_json["description"] = [ - "Test affiliation description", "Descripcion de una afiliacion de test" + "Test affiliation description", + "Descripcion de una afiliacion de test", ] assert fails(vocabulary_json) vocabulary_json["description"] = [ {"en": "Test affiliation description"}, - {"es": "Descripcion de una afiliacion de test"} + {"es": "Descripcion de una afiliacion de test"}, ] assert fails(vocabulary_json) @@ -97,9 +83,7 @@ def test_fails_icon(appctx, vocabulary_json): def test_fails_props(appctx, vocabulary_json): - vocabulary_json["props"] = { - "key": 1234 - } + vocabulary_json["props"] = {"key": 1234} assert fails(vocabulary_json) @@ -110,15 +94,13 @@ def test_fails_tags(appctx, vocabulary_json): def test_fails_title(appctx, vocabulary_json): - vocabulary_json["title"] = [ - "Test affiliation", "Afiliacion de test" - ] + vocabulary_json["title"] = ["Test affiliation", "Afiliacion de test"] assert fails(vocabulary_json) vocabulary_json["title"] = [ {"en": "Test affiliation"}, - {"es": "Afiliacion de test"} + {"es": "Afiliacion de test"}, ] assert fails(vocabulary_json) diff --git a/tests/records/test_models.py b/tests/records/test_models.py index 3b154c8f..05ecd93f 100644 --- a/tests/records/test_models.py +++ b/tests/records/test_models.py @@ -20,14 +20,12 @@ def test_well_formed_subtype(database): with pytest.raises(AssertionError): VocabularyScheme.create( - id='foo,bar,baz', parent_id='subjects', name="Foo Bar Baz", uri="" + id="foo,bar,baz", parent_id="subjects", name="Foo Bar Baz", uri="" ) with pytest.raises(AssertionError): VocabularyScheme.create( - id='foo:bar', parent_id='subjects', name="Foo: Bar", uri="" + id="foo:bar", parent_id="subjects", name="Foo: Bar", uri="" ) - assert VocabularyScheme.create( - id='foo', parent_id='subjects', name="Foo", uri="" - ) + assert VocabularyScheme.create(id="foo", parent_id="subjects", name="Foo", uri="") diff --git a/tests/records/test_relationship.py b/tests/records/test_relationship.py index 5b161f77..72fd882b 100644 --- a/tests/records/test_relationship.py +++ b/tests/records/test_relationship.py @@ -22,8 +22,7 @@ @pytest.fixture() def mock_record(app, db, example_record): """An example mock record.""" - return Record.create({}, metadata={ - 'title': 'Test', 'languages': [{'id': 'eng'}]}) + return Record.create({}, metadata={"title": "Test", "languages": [{"id": "eng"}]}) @pytest.fixture() @@ -38,9 +37,7 @@ def mock_indexer(): @pytest.fixture() def mock_search(): """Get a search client.""" - return partial( - current_search_client.get, Record.index._name, doc_type="_doc" - ) + return partial(current_search_client.get, Record.index._name, doc_type="_doc") # @@ -63,19 +60,19 @@ def test_dereferencing(mock_record): """Record dereferencing.""" # Dereference the linked language record mock_record.relations.languages.dereference() - deferenced_lang_record = mock_record.metadata['languages'][0] + deferenced_lang_record = mock_record.metadata["languages"][0] # Test that only part of the language record is denormalised. - assert sorted(deferenced_lang_record.keys()) == ['@v', 'id', 'title'] + assert sorted(deferenced_lang_record.keys()) == ["@v", "id", "title"] def test_dumping(mock_record, example_record): """Record schema validation.""" # Create a record linked to a language record. - lang = mock_record.dumps()['metadata']['languages'][0] + lang = mock_record.dumps()["metadata"]["languages"][0] assert lang == { - 'id': 'eng', - 'title': {'da': 'Engelsk', 'en': 'English'}, - '@v': str(example_record.id) + '::' + str(example_record.revision_id), + "id": "eng", + "title": {"da": "Engelsk", "en": "English"}, + "@v": str(example_record.id) + "::" + str(example_record.revision_id), } @@ -93,5 +90,5 @@ def test_indexing(mock_record, mock_indexer, mock_search, example_record): # Dereferencing also works record.relations.languages.dereference() - deferenced_lang_record = mock_record.metadata['languages'][0] - assert sorted(deferenced_lang_record.keys()) == ['@v', 'id', 'title'] + deferenced_lang_record = mock_record.metadata["languages"][0] + assert sorted(deferenced_lang_record.keys()) == ["@v", "id", "title"] diff --git a/tests/resources/test_resources_get.py b/tests/resources/test_resources_get.py index ea8a9dc6..f3365bb5 100644 --- a/tests/resources/test_resources_get.py +++ b/tests/resources/test_resources_get.py @@ -20,17 +20,19 @@ def example_data(): """Example data for records.""" return [ - {'id': 'cc-by', 'title': {'en': 'Creative Commons Attribution'}, - 'type': 'licenses'}, - {'id': 'cc0', 'title': {'en': 'Creative Commons Zero'}, - 'type': 'licenses'}, + { + "id": "cc-by", + "title": {"en": "Creative Commons Attribution"}, + "type": "licenses", + }, + {"id": "cc0", "title": {"en": "Creative Commons Zero"}, "type": "licenses"}, ] @pytest.fixture() def example_records(db, identity, service, example_data): """Create some example records.""" - service.create_type(identity, 'licenses', 'lic') + service.create_type(identity, "licenses", "lic") records = [] for data in example_data: records.append(service.create(identity, data)) @@ -41,7 +43,7 @@ def example_records(db, identity, service, example_data): @pytest.fixture() def prefix(): """API prefix.""" - return '/vocabularies/licenses/' + return "/vocabularies/licenses/" # @@ -51,12 +53,12 @@ def test_get(client, example_records, h, prefix): """Test the endpoint to retrieve a single item.""" id_ = example_records[0].id - res = client.get(f'{prefix}{id_}', headers=h) + res = client.get(f"{prefix}{id_}", headers=h) assert res.status_code == 200 - assert res.json['id'] == id_ + assert res.json["id"] == id_ # Test links - assert res.json['links'] == { - 'self': 'https://127.0.0.1:5000/api/vocabularies/licenses/cc-by' + assert res.json["links"] == { + "self": "https://127.0.0.1:5000/api/vocabularies/licenses/cc-by" } @@ -64,14 +66,26 @@ def test_not_found(client, example_records, h, prefix): """Test not found.""" id_ = example_records[0].id # invalid id - res = client.get(f'{prefix}invalid-id', headers=h,) + res = client.get( + f"{prefix}invalid-id", + headers=h, + ) assert res.status_code == 404 # invalid type (wrong type for pid) - res = client.get(f'/vocabularies/invalid/{id_}', headers=h,) + res = client.get( + f"/vocabularies/invalid/{id_}", + headers=h, + ) assert res.status_code == 404 # trailing slash on search - res = client.get(f'{prefix}/', headers=h,) + res = client.get( + f"{prefix}/", + headers=h, + ) assert res.status_code == 404 # invalid type (not existing) - res = client.get(f'/vocabularies/invalid', headers=h,) + res = client.get( + f"/vocabularies/invalid", + headers=h, + ) assert res.status_code == 404 diff --git a/tests/resources/test_resources_l10n.py b/tests/resources/test_resources_l10n.py index 4a5f761a..5e468fd0 100644 --- a/tests/resources/test_resources_l10n.py +++ b/tests/resources/test_resources_l10n.py @@ -16,30 +16,29 @@ # # Fixtures # -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_data(): """Example data for records.""" return { - 'id': 'text', - 'title': { - 'en': 'Text', - 'da': 'Tekst', + "id": "text", + "title": { + "en": "Text", + "da": "Tekst", }, - 'description': { - 'en': 'Publications', - 'da': 'Publikationer', + "description": { + "en": "Publications", + "da": "Publikationer", }, - 'icon': 'file-o', - 'props': { - }, - 'type': 'resourcetypes2' + "icon": "file-o", + "props": {}, + "type": "resourcetypes2", } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_record(database, identity, service, example_data): """Create a vocabulary record.""" - service.create_type(identity, 'resourcetypes2', 'rt2') + service.create_type(identity, "resourcetypes2", "rt2") item = service.create(identity, example_data) Vocabulary.index.refresh() return item @@ -48,36 +47,36 @@ def example_record(database, identity, service, example_data): @pytest.fixture() def prefix(): """API prefix.""" - return '/vocabularies/resourcetypes2' + return "/vocabularies/resourcetypes2" @pytest.fixture() def h(): """Header for localised versions.""" - return {'accept': 'application/vnd.inveniordm.v1+json'} + return {"accept": "application/vnd.inveniordm.v1+json"} -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_da(): """Expected serialization when danish chosen.""" return { - 'id': 'text', - 'title_l10n': 'Tekst', - 'description_l10n': 'Publikationer', - 'icon': 'file-o', - 'props': {}, + "id": "text", + "title_l10n": "Tekst", + "description_l10n": "Publikationer", + "icon": "file-o", + "props": {}, } -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def expected_en(): """Expected serialization when english chosen.""" return { - 'id': 'text', - 'title_l10n': 'Text', - 'description_l10n': 'Publications', - 'icon': 'file-o', - 'props': {}, + "id": "text", + "title_l10n": "Text", + "description_l10n": "Publications", + "icon": "file-o", + "props": {}, } @@ -89,43 +88,43 @@ def test_get(client, example_record, h, prefix, expected_da, expected_en): id_ = example_record.id # Default locale - res = client.get(f'{prefix}/{id_}', headers=h) + res = client.get(f"{prefix}/{id_}", headers=h) assert res.json == expected_en # Choose via querystring (?ln=da) - res = client.get(f'{prefix}/{id_}?ln=da', headers=h) + res = client.get(f"{prefix}/{id_}?ln=da", headers=h) assert res.json == expected_da - res = client.get(f'{prefix}/{id_}?ln=en', headers=h) + res = client.get(f"{prefix}/{id_}?ln=en", headers=h) assert res.json == expected_en # Choose via header - h['accept-language'] = 'da' - res = client.get(f'{prefix}/{id_}', headers=h) + h["accept-language"] = "da" + res = client.get(f"{prefix}/{id_}", headers=h) assert res.json == expected_da - h['accept-language'] = 'en' - res = client.get(f'{prefix}/{id_}', headers=h) + h["accept-language"] = "en" + res = client.get(f"{prefix}/{id_}", headers=h) assert res.json == expected_en def test_search(client, example_record, h, prefix, expected_da, expected_en): """Test search result serialization.""" - expected_en = {'hits': {'hits': [expected_en], 'total': 1}} - expected_da = {'hits': {'hits': [expected_da], 'total': 1}} + expected_en = {"hits": {"hits": [expected_en], "total": 1}} + expected_da = {"hits": {"hits": [expected_da], "total": 1}} # Default locale - res = client.get(f'{prefix}', headers=h) + res = client.get(f"{prefix}", headers=h) assert res.json == expected_en # Choose via querystring (?ln=da) - res = client.get(f'{prefix}?ln=da', headers=h) + res = client.get(f"{prefix}?ln=da", headers=h) assert res.json == expected_da - res = client.get(f'{prefix}?ln=en', headers=h) + res = client.get(f"{prefix}?ln=en", headers=h) assert res.json == expected_en # Choose via header - h['accept-language'] = 'da' - res = client.get(f'{prefix}', headers=h) + h["accept-language"] = "da" + res = client.get(f"{prefix}", headers=h) assert res.json == expected_da - h['accept-language'] = 'en' - res = client.get(f'{prefix}', headers=h) + h["accept-language"] = "en" + res = client.get(f"{prefix}", headers=h) assert res.json == expected_en diff --git a/tests/resources/test_resources_search.py b/tests/resources/test_resources_search.py index 5c913215..1df4fa44 100644 --- a/tests/resources/test_resources_search.py +++ b/tests/resources/test_resources_search.py @@ -16,20 +16,24 @@ # # Fixtures # -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_data(): """Example data for records.""" return [ - {'id': 'text', 'title': {'en': 'Text'}, 'type': 'resourcetypes'}, - {'id': 'data', 'title': {'en': 'Data'}, 'type': 'resourcetypes', - 'tags': ['recommended']}, + {"id": "text", "title": {"en": "Text"}, "type": "resourcetypes"}, + { + "id": "data", + "title": {"en": "Data"}, + "type": "resourcetypes", + "tags": ["recommended"], + }, ] -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_records(database, identity, service, example_data): """Create some example records.""" - service.create_type(identity, 'resourcetypes', 'rt') + service.create_type(identity, "resourcetypes", "rt") records = [] for data in example_data: records.append(service.create(identity, data)) @@ -40,7 +44,7 @@ def example_records(database, identity, service, example_data): @pytest.fixture() def prefix(): """API prefix.""" - return '/vocabularies/resourcetypes' + return "/vocabularies/resourcetypes" # @@ -49,27 +53,27 @@ def prefix(): def test_invalid_type(app, client, h): """Test invalid type.""" # invalid type - res = client.get('/vocabularies/invalid', headers=h) + res = client.get("/vocabularies/invalid", headers=h) assert res.status_code == 404 # trailing slash - res = client.get('/vocabularies/invalid/', headers=h) + res = client.get("/vocabularies/invalid/", headers=h) assert res.status_code == 404 def test_type_as_query_arg(app, lang_type, example_records, client, h, prefix): """Test passing an invalid query parameter.""" # Ensure we cannot pass invalid query parameters - res = client.get(f'{prefix}?invalid=test', headers=h) + res = client.get(f"{prefix}?invalid=test", headers=h) assert res.status_code == 200 - assert 'invalid' not in res.json['links']['self'] + assert "invalid" not in res.json["links"]["self"] # It should not be possible to pass 'type' in query args (because it's in # the URL route instead) - res = client.get(f'{prefix}?type={lang_type.id}', headers=h) + res = client.get(f"{prefix}?type={lang_type.id}", headers=h) assert res.status_code == 200 - assert lang_type.id not in res.json['links']['self'] - assert 'type=' not in res.json['links']['self'] - assert 'resourcetypes' in res.json['links']['self'] + assert lang_type.id not in res.json["links"]["self"] + assert "type=" not in res.json["links"]["self"] + assert "resourcetypes" in res.json["links"]["self"] def test_search(client, example_records, h, prefix): @@ -77,33 +81,33 @@ def test_search(client, example_records, h, prefix): res = client.get(prefix, headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 2 - assert res.json['sortBy'] == 'title' + assert res.json["sortBy"] == "title" def test_query_q(client, example_records, h, prefix): """Test a successful search.""" # Test query (q=) - res = client.get(f'{prefix}?q=title.en:text', headers=h) + res = client.get(f"{prefix}?q=title.en:text", headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 1 - assert res.json['sortBy'] == 'bestmatch' + assert res.json["sortBy"] == "bestmatch" # Test sort - res = client.get(f'{prefix}?q=*&sort=bestmatch', headers=h) + res = client.get(f"{prefix}?q=*&sort=bestmatch", headers=h) assert res.status_code == 200 - assert res.json['sortBy'] == 'bestmatch' + assert res.json["sortBy"] == "bestmatch" # Test size - res = client.get(f'{prefix}?size=1&page=1', headers=h) + res = client.get(f"{prefix}?size=1&page=1", headers=h) assert res.status_code == 200 - assert res.json['hits']['total'] == 2 - assert len(res.json['hits']['hits']) == 1 - assert 'next' in res.json['links'] + assert res.json["hits"]["total"] == 2 + assert len(res.json["hits"]["hits"]) == 1 + assert "next" in res.json["links"] def test_tags_filter(client, example_records, h, prefix): """Test filter on tags.""" # Test query (q=) - res = client.get(f'{prefix}?tags=recommended', headers=h) + res = client.get(f"{prefix}?tags=recommended", headers=h) assert res.status_code == 200 assert res.json["hits"]["total"] == 1 diff --git a/tests/resources/test_tasks_resources.py b/tests/resources/test_tasks_resources.py index 113bf826..28d2b1e5 100644 --- a/tests/resources/test_tasks_resources.py +++ b/tests/resources/test_tasks_resources.py @@ -49,18 +49,12 @@ def write(stream_entry, *args, **kwargs): pass -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def app_config(app_config): """Mimic an instance's configuration.""" - app_config["VOCABULARIES_DATASTREAM_READERS"] = { - "test": TestReader - } - app_config["VOCABULARIES_DATASTREAM_TRANSFORMERS"] = { - "test": TestTransformer - } - app_config["VOCABULARIES_DATASTREAM_WRITERS"] = { - "test": TestWriter - } + app_config["VOCABULARIES_DATASTREAM_READERS"] = {"test": TestReader} + app_config["VOCABULARIES_DATASTREAM_TRANSFORMERS"] = {"test": TestTransformer} + app_config["VOCABULARIES_DATASTREAM_WRITERS"] = {"test": TestWriter} return app_config @@ -68,29 +62,20 @@ def app_config(app_config): def test_task_creation(app, client_with_credentials, h): client = client_with_credentials task_config = { - "readers": [{ - "type": "test", - "args": { - "origin": "somewhere" - } - }], + "readers": [{"type": "test", "args": {"origin": "somewhere"}}], "transformers": [{"type": "test"}], - "writers": [{"type": "test"}] + "writers": [{"type": "test"}], } with patch.object( - TestReader, 'read', side_effect=TestReader.read - ) as p_read, \ - patch.object( - TestTransformer, 'apply', side_effect=TestTransformer.apply - ) as p_apply, \ - patch.object( - TestWriter, 'write', side_effect=TestWriter.write + TestReader, "read", side_effect=TestReader.read + ) as p_read, patch.object( + TestTransformer, "apply", side_effect=TestTransformer.apply + ) as p_apply, patch.object( + TestWriter, "write", side_effect=TestWriter.write ) as p_write: resp = client.post( - "/vocabularies/tasks", - headers=h, - data=json.dumps(task_config) + "/vocabularies/tasks", headers=h, data=json.dumps(task_config) ) assert resp.status_code == 202 p_read.assert_called() diff --git a/tests/services/test_labels.py b/tests/services/test_labels.py index ea78c65f..15d4ae56 100644 --- a/tests/services/test_labels.py +++ b/tests/services/test_labels.py @@ -15,32 +15,32 @@ from invenio_vocabularies.services.facets import VocabularyLabels -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_data(): """Example data.""" return [ { - 'id': 'eng', - 'title': {'en': 'English', 'da': 'Engelsk'}, - 'type': 'languages', + "id": "eng", + "title": {"en": "English", "da": "Engelsk"}, + "type": "languages", }, { - 'id': 'spa', - 'title': {'en': 'Spanish', 'da': 'Spansk'}, - 'type': 'languages', + "id": "spa", + "title": {"en": "Spanish", "da": "Spansk"}, + "type": "languages", }, { - 'id': 'fra', - 'title': {'en': 'French', 'da': 'Fransk'}, - 'type': 'languages', + "id": "fra", + "title": {"en": "French", "da": "Fransk"}, + "type": "languages", }, ] -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def example_records(database, identity, service, example_data): """Create some example records.""" - service.create_type(identity, 'languages', 'lng') + service.create_type(identity, "languages", "lng") records = [] for data in example_data: records.append(service.create(identity, data)) diff --git a/tests/services/test_permissions.py b/tests/services/test_permissions.py index c444cbd1..3025e73a 100644 --- a/tests/services/test_permissions.py +++ b/tests/services/test_permissions.py @@ -43,28 +43,28 @@ def test_permissions_readonly(anyuser_idty, lang_type, lang_data, service): id_ = item.id # Read - both allowed - item = service.read(anyuser_idty, ('languages', id_)) - item = service.read(system_identity, ('languages', id_)) + item = service.read(anyuser_idty, ("languages", id_)) + item = service.read(system_identity, ("languages", id_)) # Refresh index to make changes live. Vocabulary.index.refresh() # Search - both allowed - res = service.search( - anyuser_idty, type='languages', q=f"id:{id_}", size=25, page=1) + res = service.search(anyuser_idty, type="languages", q=f"id:{id_}", size=25, page=1) assert res.total == 1 res = service.search( - system_identity, type='languages', q=f"id:{id_}", size=25, page=1) + system_identity, type="languages", q=f"id:{id_}", size=25, page=1 + ) assert res.total == 1 # Update - only system allowed data = item.data - data['title']['en'] = 'New title' + data["title"]["en"] = "New title" with pytest.raises(PermissionDenied): - service.update(anyuser_idty, ('languages', id_), data) - service.update(system_identity, ('languages', id_), data) + service.update(anyuser_idty, ("languages", id_), data) + service.update(system_identity, ("languages", id_), data) # Delete - only system allowed with pytest.raises(PermissionDenied): - service.delete(anyuser_idty, ('languages', id_)) - service.delete(system_identity, ('languages', id_)) + service.delete(anyuser_idty, ("languages", id_)) + service.delete(system_identity, ("languages", id_)) diff --git a/tests/services/test_schema.py b/tests/services/test_schema.py index 868aa551..80882b7c 100644 --- a/tests/services/test_schema.py +++ b/tests/services/test_schema.py @@ -15,76 +15,50 @@ def test_valid_minimal(): - valid_minimal = { - "readers": [{ - "type": "test" - }], - "writers": [{"type": "test"}] - } + valid_minimal = {"readers": [{"type": "test"}], "writers": [{"type": "test"}]} assert valid_minimal == TaskSchema().load(valid_minimal) def test_valid_full(): valid_full = { - "readers": [{ - "type": "test", - "args": { - "one": 1, - "two": "two" - } - }], - "transformers": [{ - "type": "test", - "args": { - "one": 1, - "two": "two" - } - }, { - "type": "testtoo", - "args": { - "one": "1", - "two": 2 - } - }], - "writers": [{ - "type": "test", - "args": { - "one": 1, - "two": "two" - } - }, { - "type": "testtoo", - "args": { - "one": "1", - "two": 2 - } - }], + "readers": [{"type": "test", "args": {"one": 1, "two": "two"}}], + "transformers": [ + {"type": "test", "args": {"one": 1, "two": "two"}}, + {"type": "testtoo", "args": {"one": "1", "two": 2}}, + ], + "writers": [ + {"type": "test", "args": {"one": 1, "two": "two"}}, + {"type": "testtoo", "args": {"one": "1", "two": 2}}, + ], } assert valid_full == TaskSchema().load(valid_full) -@pytest.mark.parametrize("invalid", [ - {}, - { - "readers": {"type": "test"}, # non-list readers - "writers": [{"type": "test"}], - }, - { - "readers": [{"type": "testtoo"}], - "writers": {"type": "test"}, # non-list writers - }, - { - "readers": [{"type": "testtoo"}], - "transformers": {"type": "test"}, # non-list transformers - "writers": [{"type": "test"}], - }, - { - "readers": [{"type": "testtoo"}], # no writers - }, - { - "writers": [{"type": "test"}], # no readers - }, -]) +@pytest.mark.parametrize( + "invalid", + [ + {}, + { + "readers": {"type": "test"}, # non-list readers + "writers": [{"type": "test"}], + }, + { + "readers": [{"type": "testtoo"}], + "writers": {"type": "test"}, # non-list writers + }, + { + "readers": [{"type": "testtoo"}], + "transformers": {"type": "test"}, # non-list transformers + "writers": [{"type": "test"}], + }, + { + "readers": [{"type": "testtoo"}], # no writers + }, + { + "writers": [{"type": "test"}], # no readers + }, + ], +) def test_invalid_empty(invalid): with pytest.raises(ValidationError): data = TaskSchema().load(invalid) diff --git a/tests/services/test_service.py b/tests/services/test_service.py index d64cb96c..b8c7f683 100644 --- a/tests/services/test_service.py +++ b/tests/services/test_service.py @@ -25,7 +25,7 @@ @pytest.fixture() def lic_type(db): """Get a language vocabulary type.""" - return VocabularyType.create(id='licenses', pid_type='lic') + return VocabularyType.create(id="licenses", pid_type="lic") # @@ -37,49 +37,46 @@ def test_simple_flow(lang_type, lic_type, lang_data, service, identity): item = service.create(identity, lang_data) id_ = item.id - assert item.id == lang_data['id'] + assert item.id == lang_data["id"] for k, v in lang_data.items(): assert item.data[k] == v # Read it - read_item = service.read(identity, ('languages', 'eng')) + read_item = service.read(identity, ("languages", "eng")) assert item.id == read_item.id assert item.data == read_item.data - assert read_item.data['type'] == 'languages' + assert read_item.data["type"] == "languages" # Refresh index to make changes live. Vocabulary.index.refresh() # Search it - res = service.search( - identity, type='languages', q=f"id:{id_}", size=25, page=1) + res = service.search(identity, type="languages", q=f"id:{id_}", size=25, page=1) assert res.total == 1 assert list(res.hits)[0] == read_item.data # Search another type - res = service.search( - identity, type='licenses', q=f"id:{id_}", size=25, page=1) + res = service.search(identity, type="licenses", q=f"id:{id_}", size=25, page=1) assert res.total == 0 # Update it data = read_item.data - data['title']['en'] = 'New title' - update_item = service.update(identity, ('languages', id_), data) + data["title"]["en"] = "New title" + update_item = service.update(identity, ("languages", id_), data) assert item.id == update_item.id - assert update_item['title']['en'] == 'New title' + assert update_item["title"]["en"] == "New title" # Delete it - assert service.delete(identity, ('languages', id_)) + assert service.delete(identity, ("languages", id_)) # Refresh to make changes live Vocabulary.index.refresh() # Fail to retrieve it # - db - pytest.raises(PIDDeletedError, service.read, identity, ('languages', id_)) + pytest.raises(PIDDeletedError, service.read, identity, ("languages", id_)) # - search - res = service.search( - identity, type='languages', q=f"id:{id_}", size=25, page=1) + res = service.search(identity, type="languages", q=f"id:{id_}", size=25, page=1) assert res.total == 0 @@ -91,78 +88,76 @@ def test_pid_already_registered(lang_type, lang_data, service, identity): def test_extra_fields(lang_data2, service, identity): """Extra fields in data should fail.""" - lang_data2['invalid'] = 1 + lang_data2["invalid"] = 1 pytest.raises(ValidationError, service.create, identity, lang_data2) def test_missing_or_invalid_type(lang_data2, service, identity): """A missing type should raise validation error.""" # No type specified - del lang_data2['type'] + del lang_data2["type"] pytest.raises(ValidationError, service.create, identity, lang_data2) # Invalid value data types - for val in [1, {'id': 'languages'}, ]: - lang_data2['type'] = val + for val in [ + 1, + {"id": "languages"}, + ]: + lang_data2["type"] = val pytest.raises(ValidationError, service.create, identity, lang_data2) # Non-existing type - lang_data2['type'] = 'invalid' + lang_data2["type"] = "invalid" pytest.raises(ValidationError, service.create, identity, lang_data2) def test_update(lang_type, lang_data2, service, identity): """Removing keys should work.""" - lang_data2['id'] = 'dan' + lang_data2["id"] = "dan" item = service.create(identity, lang_data2) id_ = item.id data = item.data # Unset a subkey - del data['title']['en'] + del data["title"]["en"] # Unset a top-level key - del data['icon'] - update_item = service.update(identity, ('languages', id_), data) + del data["icon"] + update_item = service.update(identity, ("languages", id_), data) # Ensure they really got cleared. - assert 'en' not in update_item.data['title'] - assert 'icon' not in update_item.data + assert "en" not in update_item.data["title"] + assert "icon" not in update_item.data def test_missing_or_invalid_type(lang_data2, service, identity): """Custom props should only accept strings.""" # Invalid data types - for v in [1, {'id': 'test'}]: - lang_data2['props']['newkey'] = v - pytest.raises( - ValidationError, service.create, identity, lang_data2) - - -def test_read_all_no_cache( - lang_type, lang_data_many, service, identity, cache -): - """ read_all method should return all languages created in this scope. """ - items = service.read_all(identity, fields=['id'], - type='languages', cache=False) + for v in [1, {"id": "test"}]: + lang_data2["props"]["newkey"] = v + pytest.raises(ValidationError, service.create, identity, lang_data2) + + +def test_read_all_no_cache(lang_type, lang_data_many, service, identity, cache): + """read_all method should return all languages created in this scope.""" + items = service.read_all(identity, fields=["id"], type="languages", cache=False) assert set(lang_data_many).issubset(set([i["id"] for i in items])) cached = current_cache.get("id") assert not cached def test_read_all_cache(lang_type, lang_data_many, service, identity, cache): - """ read_all method should return all languages created in this scope. """ - items = service.read_all(identity, fields=['id'], - type='languages', cache=True) + """read_all method should return all languages created in this scope.""" + items = service.read_all(identity, fields=["id"], type="languages", cache=True) assert set(lang_data_many).issubset(set([i["id"] for i in items])) cached = current_cache.get("languages__id") assert cached is not None def test_read_many(lang_type, lang_data_many, service, identity, es_clear): - """ read_many method should return all requested languages. """ - ids_ = ['fr', 'tr', 'es'] - items = service.read_many(identity, type='languages', ids=ids_, fields=[]) + """read_many method should return all requested languages.""" + ids_ = ["fr", "tr", "es"] + items = service.read_many(identity, type="languages", ids=ids_, fields=[]) item_ids = [i.id for i in items._results] - assert {'fr', 'tr', 'es'} == set(item_ids) + assert {"fr", "tr", "es"} == set(item_ids) def test_indexed_at_query(app, db, service, identity, lang_type, lang_data): @@ -173,12 +168,16 @@ def test_indexed_at_query(app, db, service, identity, lang_type, lang_data): # there is previous to before res = service.search( - identity, q=f"indexed_at:[* TO {before}]", type="languages", + identity, + q=f"indexed_at:[* TO {before}]", + type="languages", ) assert res.total == 0 # there is previous to now res = service.search( - identity, q=f"indexed_at:[* TO {now}]", type="languages", + identity, + q=f"indexed_at:[* TO {now}]", + type="languages", ) assert res.total == 1 diff --git a/tests/test_alembic.py b/tests/test_alembic.py index cba732a0..80cc2511 100644 --- a/tests/test_alembic.py +++ b/tests/test_alembic.py @@ -18,48 +18,50 @@ def assert_alembic(alembic, table_excludes): This method allows omitting tables dynamically created for tests. """ - assert not list(filter( - # x[0] is the operation and x[1] is the table - lambda x: x[0] == 'add_table' and x[1].name not in table_excludes, - alembic.compare_metadata() - )) + assert not list( + filter( + # x[0] is the operation and x[1] is the table + lambda x: x[0] == "add_table" and x[1].name not in table_excludes, + alembic.compare_metadata(), + ) + ) def test_alembic(app, database): """Test alembic recipes.""" db = database - ext = app.extensions['invenio-db'] + ext = app.extensions["invenio-db"] - if db.engine.name == 'sqlite': - raise pytest.skip('Upgrades are not supported on SQLite.') + if db.engine.name == "sqlite": + raise pytest.skip("Upgrades are not supported on SQLite.") # Check that this package's SQLAlchemy models have been properly registered tables = [x.name for x in db.get_tables_for_bind()] - assert 'vocabularies_metadata' in tables - assert 'vocabularies_types' in tables - assert 'vocabularies_schemes' in tables + assert "vocabularies_metadata" in tables + assert "vocabularies_types" in tables + assert "vocabularies_schemes" in tables # Specific vocabularies models - assert 'subject_metadata' in tables - assert 'affiliation_metadata' in tables - assert 'name_metadata' in tables - assert 'funder_metadata' in tables - assert 'award_metadata' in tables + assert "subject_metadata" in tables + assert "affiliation_metadata" in tables + assert "name_metadata" in tables + assert "funder_metadata" in tables + assert "award_metadata" in tables # Check that Alembic agrees that there's no further tables to create. - assert_alembic(ext.alembic, ['mock_metadata']) + assert_alembic(ext.alembic, ["mock_metadata"]) # Drop everything and recreate tables all with Alembic db.drop_all() drop_alembic_version_table() ext.alembic.upgrade() - assert_alembic(ext.alembic, ['mock_metadata']) + assert_alembic(ext.alembic, ["mock_metadata"]) # Try to upgrade and downgrade ext.alembic.stamp() - ext.alembic.downgrade(target='96e796392533') + ext.alembic.downgrade(target="96e796392533") ext.alembic.upgrade() - assert_alembic(ext.alembic, ['mock_metadata']) + assert_alembic(ext.alembic, ["mock_metadata"]) # Cleanup drop_alembic_version_table() diff --git a/tests/test_cli.py b/tests/test_cli.py index 9f5a3311..65de7651 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -15,18 +15,21 @@ from invenio_access.permissions import system_identity from invenio_records_resources.proxies import current_service_registry -from invenio_vocabularies.cli import _process_vocab, get_config_for_ds, \ - vocabularies -from invenio_vocabularies.config import VOCABULARIES_DATASTREAM_TRANSFORMERS, \ - VOCABULARIES_DATASTREAM_WRITERS +from invenio_vocabularies.cli import _process_vocab, get_config_for_ds, vocabularies +from invenio_vocabularies.config import ( + VOCABULARIES_DATASTREAM_TRANSFORMERS, + VOCABULARIES_DATASTREAM_WRITERS, +) from invenio_vocabularies.contrib.names.api import Name -from invenio_vocabularies.contrib.names.datastreams import \ - VOCABULARIES_DATASTREAM_TRANSFORMERS as NAMES_TRANSFORMERS -from invenio_vocabularies.contrib.names.datastreams import \ - VOCABULARIES_DATASTREAM_WRITERS as NAMES_WRITERS +from invenio_vocabularies.contrib.names.datastreams import ( + VOCABULARIES_DATASTREAM_TRANSFORMERS as NAMES_TRANSFORMERS, +) +from invenio_vocabularies.contrib.names.datastreams import ( + VOCABULARIES_DATASTREAM_WRITERS as NAMES_WRITERS, +) -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def app_config(app_config): """Mimic an instance's configuration.""" app_config["VOCABULARIES_DATASTREAM_TRANSFORMERS"] = { @@ -41,39 +44,39 @@ def app_config(app_config): return app_config -@pytest.fixture(scope='module') +@pytest.fixture(scope="module") def name_xml(): return ( '\n' '\n' - ' \n' - ' https://orcid.org/0000-0001-8135-3489\n' # noqa - ' 0000-0001-8135-3489\n' - ' orcid.org\n' - ' \n' + " \n" + " https://orcid.org/0000-0001-8135-3489\n" # noqa + " 0000-0001-8135-3489\n" + " orcid.org\n" + " \n" ' \n' ' \n' # noqa - ' Lars Holm' # noqa - ' Nielsen\n' # noqa - ' \n' + " Lars Holm" # noqa + " Nielsen\n" # noqa + " \n" ' \n' # noqa - ' \n' + " \n" ' \n' # noqa ' \n' # noqa - ' \n' - ' \n' - ' \n' - ' CERN\n' - ' \n' - ' \n' - ' \n' - ' \n' - ' \n' - '\n' + " \n" + " \n" + " \n" + " CERN\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n" ) -@pytest.fixture(scope='function') +@pytest.fixture(scope="function") def names_tar_file(name_xml): """Creates a Tar file with three files (two yaml) inside. @@ -83,7 +86,7 @@ def names_tar_file(name_xml): filename = Path("cli_test.tar.gz") with tarfile.open(filename, "w:gz") as tar: inner_filename = Path("lnielsen_name.xml") - with open(inner_filename, 'w') as file: + with open(inner_filename, "w") as file: file.write(name_xml) tar.add(inner_filename) inner_filename.unlink() @@ -95,17 +98,12 @@ def names_tar_file(name_xml): def test_process(app, names_tar_file): service = current_service_registry.get("names") - config = get_config_for_ds( - vocabulary="names", origin=names_tar_file.absolute() - ) + config = get_config_for_ds(vocabulary="names", origin=names_tar_file.absolute()) _process_vocab(config) Name.index.refresh() orcid = "0000-0001-8135-3489" - results = service.search( - system_identity, - q=f"identifiers.identifier:{orcid}" - ) + results = service.search(system_identity, q=f"identifiers.identifier:{orcid}") assert results.total == 1 assert list(results.hits)[0]["identifiers"][0]["identifier"] == orcid @@ -116,6 +114,6 @@ def test_update_cmd(app, names_tar_file): runner = app.test_cli_runner() result = runner.invoke( vocabularies, - ['update', '-v', 'names', '--origin', names_tar_file.absolute()], + ["update", "-v", "names", "--origin", names_tar_file.absolute()], ) assert result.exit_code == 0