From df176e8ec3d3e602db0450709c0f2e864be6444d Mon Sep 17 00:00:00 2001 From: Ronald Krist Date: Wed, 21 Jun 2023 01:08:38 +0200 Subject: [PATCH 1/4] ext refactor --- .../datatypes/components/__init__.py | 3 +- .../datatypes/components/model/__init__.py | 2 ++ .../datatypes/components/model/app.py | 4 +-- .../components/model/ext_resource.py | 35 +++++++++++++++++++ .../datatypes/components/model/marshmallow.py | 2 +- .../datatypes/components/model/service.py | 3 +- oarepo_model_builder/invenio/__init__.py | 1 + .../invenio/invenio_api_views.py | 4 +++ .../invenio/invenio_app_views.py | 4 +++ .../invenio/invenio_ext_resource.py | 11 ++++++ .../invenio/invenio_proxies.py | 4 +++ .../invenio/templates/api_views.py.jinja2 | 8 ++--- .../invenio/templates/app_views.py.jinja2 | 6 ++-- .../invenio/templates/ext.py.jinja2 | 22 +----------- .../invenio/templates/ext_resource.py.jinja2 | 23 ++++++++++++ .../invenio/templates/proxies.py.jinja2 | 4 +-- setup.cfg | 1 + 17 files changed, 101 insertions(+), 36 deletions(-) create mode 100644 oarepo_model_builder/datatypes/components/model/ext_resource.py create mode 100644 oarepo_model_builder/invenio/invenio_ext_resource.py create mode 100644 oarepo_model_builder/invenio/templates/ext_resource.py.jinja2 diff --git a/oarepo_model_builder/datatypes/components/__init__.py b/oarepo_model_builder/datatypes/components/__init__.py index ba2c5912..90bc356b 100644 --- a/oarepo_model_builder/datatypes/components/__init__.py +++ b/oarepo_model_builder/datatypes/components/__init__.py @@ -31,7 +31,7 @@ SearchOptionsModelComponent, ServiceModelComponent, UIMarshmallowModelComponent, - UIModelComponent, + UIModelComponent, ExtResourceModelComponent, ) from .sample import ArraySampleComponent, RegularSampleComponent from .ui import ObjectUIComponent, RegularUIComponent @@ -72,4 +72,5 @@ NestedFacetsComponent, RegularFacetsComponent, ArrayFacetsComponent, + ExtResourceModelComponent, ] diff --git a/oarepo_model_builder/datatypes/components/model/__init__.py b/oarepo_model_builder/datatypes/components/model/__init__.py index 2c2dee50..eff509fc 100644 --- a/oarepo_model_builder/datatypes/components/model/__init__.py +++ b/oarepo_model_builder/datatypes/components/model/__init__.py @@ -1,6 +1,7 @@ from .app import AppModelComponent from .blueprints import BlueprintsModelComponent from .defaults import DefaultsModelComponent +from .ext_resource import ExtResourceModelComponent from .facets import FacetsModelComponent from .jsonschema import JSONSchemaModelComponent from .mapping import MappingModelComponent @@ -40,4 +41,5 @@ "UIModelComponent", "DefaultsModelComponent", "ProxyModelComponent", + "ExtResourceModelComponent", ] diff --git a/oarepo_model_builder/datatypes/components/model/app.py b/oarepo_model_builder/datatypes/components/model/app.py index 949fc2ef..c9236762 100644 --- a/oarepo_model_builder/datatypes/components/model/app.py +++ b/oarepo_model_builder/datatypes/components/model/app.py @@ -81,9 +81,9 @@ def before_model_prepare(self, datatype, **kwargs): ext.setdefault("generate", True) ext_module = ext.setdefault("module", f"{module}.ext") - ext.setdefault("class", f"{ext_module}.{prefix}Ext") + ext.setdefault("class", f"{ext_module}.{module.capitalize()}Ext") ext.setdefault("base-classes", []) ext.setdefault("extra_code", "") - ext.setdefault("alias", alias) + ext.setdefault("alias", module) ext.setdefault("imports", []) convert_config_to_qualified_name(ext) diff --git a/oarepo_model_builder/datatypes/components/model/ext_resource.py b/oarepo_model_builder/datatypes/components/model/ext_resource.py new file mode 100644 index 00000000..a5ade094 --- /dev/null +++ b/oarepo_model_builder/datatypes/components/model/ext_resource.py @@ -0,0 +1,35 @@ +from oarepo_model_builder.datatypes import DataTypeComponent, ModelDataType +import marshmallow as ma + +from oarepo_model_builder.datatypes.components.model.utils import set_default + + +class ExtResourceSchema(ma.Schema): + generate = ma.fields.Bool() + skip = ma.fields.Bool() + + class Meta: + unknown = ma.RAISE +class ExtResourceModelComponent(DataTypeComponent): + eligible_datatypes = [ModelDataType] + class ModelSchema(ma.Schema): + ext_resource = ma.fields.Nested( + ExtResourceSchema, + attribute="ext-resource", + data_key="ext-resource", + ) + def process_ext_resource(self, datatype, section, **kwargs): + if self.is_record_profile: + cfg = section.config + cfg["ext-service-name"] = "service_records" + cfg["ext-resource-name"] = "resource_records" + + def before_model_prepare(self, datatype, *, context, **kwargs): + self.is_record_profile = context["profile"] == "record" + if not self.is_record_profile: + return + ext = set_default(datatype, "ext-resource", {}) + + ext.setdefault("generate", True) + ext.setdefault("skip", False) + diff --git a/oarepo_model_builder/datatypes/components/model/marshmallow.py b/oarepo_model_builder/datatypes/components/model/marshmallow.py index aa7e6f6f..eddd59d0 100644 --- a/oarepo_model_builder/datatypes/components/model/marshmallow.py +++ b/oarepo_model_builder/datatypes/components/model/marshmallow.py @@ -74,7 +74,7 @@ def marshmallow_register_class_names(self, *, datatype, classes, **kwargs): marshmallow_def = dict_get(datatype.definition, self.model_marshmallow_section) classes[marshmallow_def["class"]].append((True, datatype)) - def before_model_prepare(self, datatype, **kwargs): + def before_model_prepare(self, datatype, *, context, **kwargs): prefix = datatype.definition["module"]["prefix"] services_module = parent_module(datatype.definition["service"]["module"]) diff --git a/oarepo_model_builder/datatypes/components/model/service.py b/oarepo_model_builder/datatypes/components/model/service.py index ff262ee1..dc614510 100644 --- a/oarepo_model_builder/datatypes/components/model/service.py +++ b/oarepo_model_builder/datatypes/components/model/service.py @@ -104,7 +104,6 @@ def before_model_prepare(self, datatype, *, context, **kwargs): module = datatype.definition["module"]["qualified"] module_base_upper = datatype.definition["module"]["base-upper"] record_prefix = datatype.definition["module"]["prefix"] - flask_extension_name = datatype.definition["ext"]["alias"] service_package = f"{module}.services.{profile_module}" @@ -124,7 +123,7 @@ def before_model_prepare(self, datatype, *, context, **kwargs): f"{config_module}.{record_prefix}ServiceConfig", ) config.setdefault("extra-code", "") - config.setdefault("service-id", flask_extension_name) + config.setdefault("service-id", datatype.definition["module"]["suffix-snake"]) config.setdefault( "base-classes", ["PermissionsPresetsConfigMixin", "InvenioRecordServiceConfig"], diff --git a/oarepo_model_builder/invenio/__init__.py b/oarepo_model_builder/invenio/__init__.py index 07ace11d..c4691cb7 100644 --- a/oarepo_model_builder/invenio/__init__.py +++ b/oarepo_model_builder/invenio/__init__.py @@ -20,4 +20,5 @@ "pid-provider": "templates/pid_provider.py.jinja2", # utils and included "imports": "templates/imports.py.jinja2", + "ext-resource": "templates/ext_resource.py.jinja2" } diff --git a/oarepo_model_builder/invenio/invenio_api_views.py b/oarepo_model_builder/invenio/invenio_api_views.py index e5da9c05..449cd5dc 100644 --- a/oarepo_model_builder/invenio/invenio_api_views.py +++ b/oarepo_model_builder/invenio/invenio_api_views.py @@ -5,3 +5,7 @@ class InvenioAPIViewsBuilder(InvenioBaseClassPythonBuilder): TYPE = "invenio_api_views" section = "api-blueprint" template = "api-views" + + def finish(self, **extra_kwargs): + ext = getattr(self.current_model, "section_ext_resource").config + super().finish(ext=ext, **extra_kwargs) \ No newline at end of file diff --git a/oarepo_model_builder/invenio/invenio_app_views.py b/oarepo_model_builder/invenio/invenio_app_views.py index 811dd553..b407564d 100644 --- a/oarepo_model_builder/invenio/invenio_app_views.py +++ b/oarepo_model_builder/invenio/invenio_app_views.py @@ -5,3 +5,7 @@ class InvenioAPPViewsBuilder(InvenioBaseClassPythonBuilder): TYPE = "invenio_app_views" section = "app-blueprint" template = "app-views" + + def finish(self, **extra_kwargs): + ext = getattr(self.current_model, "section_ext_resource").config + super().finish(ext=ext, **extra_kwargs) diff --git a/oarepo_model_builder/invenio/invenio_ext_resource.py b/oarepo_model_builder/invenio/invenio_ext_resource.py new file mode 100644 index 00000000..7022c9ed --- /dev/null +++ b/oarepo_model_builder/invenio/invenio_ext_resource.py @@ -0,0 +1,11 @@ +from .invenio_base import InvenioBaseClassPythonBuilder + + +class InvenioExtResourceBuilder(InvenioBaseClassPythonBuilder): + TYPE = "invenio_ext_resource" + section = "ext" + template = "ext-resource" + + def finish(self, **extra_kwargs): + ext = getattr(self.current_model, "section_ext_resource").config + super().finish(ext=ext, **extra_kwargs) \ No newline at end of file diff --git a/oarepo_model_builder/invenio/invenio_proxies.py b/oarepo_model_builder/invenio/invenio_proxies.py index df55ac8a..02c98d43 100644 --- a/oarepo_model_builder/invenio/invenio_proxies.py +++ b/oarepo_model_builder/invenio/invenio_proxies.py @@ -5,3 +5,7 @@ class InvenioProxiesBuilder(InvenioBaseClassPythonBuilder): TYPE = "invenio_proxies" section = "proxy" template = "proxies" + + def finish(self, **extra_kwargs): + ext = getattr(self.current_model, "section_ext_resource").config + super().finish(ext=ext, **extra_kwargs) diff --git a/oarepo_model_builder/invenio/templates/api_views.py.jinja2 b/oarepo_model_builder/invenio/templates/api_views.py.jinja2 index a27d1cd5..3ee5b9f9 100644 --- a/oarepo_model_builder/invenio/templates/api_views.py.jinja2 +++ b/oarepo_model_builder/invenio/templates/api_views.py.jinja2 @@ -2,7 +2,7 @@ from flask import Blueprint def {{ vars.api_blueprint.function|base_name }}(app): """Create {{ vars.record.class|base_name }} blueprint.""" - blueprint = app.extensions["{{ vars.ext.alias }}"].resource.as_blueprint() + blueprint = app.extensions["{{ vars.ext.alias }}"].{{ ext.ext_resource_name }}.as_blueprint() blueprint.record_once(init_{{ vars.api_blueprint.function|base_name }}) #calls record_once for all other functions starting with "init_addons_" @@ -22,14 +22,14 @@ def init_{{ vars.api_blueprint.function|base_name }}(state): {% if not vars.service_config.skip %} # register service sregistry = app.extensions["invenio-records-resources"].registry - sregistry.register(ext.service, service_id="{{ vars.service_config.service_id }}") + sregistry.register(ext.{{ ext.ext_service_name }}, service_id=ext.{{ ext.ext_service_name }}.config.service_id) {% endif %} {% if not vars.mapping_settings.skip %} # Register indexer - if hasattr(ext.service, "indexer"): + if hasattr(ext.{{ ext.ext_service_name }}, "indexer"): iregistry = app.extensions["invenio-indexer"].registry - iregistry.register(ext.service.indexer, indexer_id="{{ vars.ext.alias }}") + iregistry.register(ext.{{ ext.ext_service_name }}.indexer, indexer_id=ext.{{ ext.ext_service_name }}.config.service_id) {% endif %} {{ vars.api_blueprint.extra_code }} \ No newline at end of file diff --git a/oarepo_model_builder/invenio/templates/app_views.py.jinja2 b/oarepo_model_builder/invenio/templates/app_views.py.jinja2 index fd32c4f0..e2716d43 100644 --- a/oarepo_model_builder/invenio/templates/app_views.py.jinja2 +++ b/oarepo_model_builder/invenio/templates/app_views.py.jinja2 @@ -21,14 +21,14 @@ def init_{{ vars.app_blueprint.function|base_name }}(state): {% if not vars.service_config.skip %} # register service sregistry = app.extensions["invenio-records-resources"].registry - sregistry.register(ext.service, service_id="{{ vars.service_config.service_id }}") + sregistry.register(ext.{{ ext.ext_service_name }}, service_id=ext.{{ ext.ext_service_name }}.config.service_id) {% endif %} {% if not vars.mapping_settings.skip %} # Register indexer - if hasattr(ext.service, "indexer"): + if hasattr(ext.{{ ext.ext_service_name }}, "indexer"): iregistry = app.extensions["invenio-indexer"].registry - iregistry.register(ext.service.indexer, indexer_id="{{ vars.ext.alias }}") + iregistry.register(ext.{{ ext.ext_service_name }}.indexer, indexer_id=ext.{{ ext.ext_service_name }}.config.service_id) {% endif %} {{ vars.app_blueprint.extra_code }} \ No newline at end of file diff --git a/oarepo_model_builder/invenio/templates/ext.py.jinja2 b/oarepo_model_builder/invenio/templates/ext.py.jinja2 index 82c6e050..08434d38 100644 --- a/oarepo_model_builder/invenio/templates/ext.py.jinja2 +++ b/oarepo_model_builder/invenio/templates/ext.py.jinja2 @@ -5,9 +5,6 @@ import re class {{ vars.ext|class_header }}: def __init__(self, app=None): - """Extension initialization.""" - {% if not vars.resource.skip %}self.resource = None{% endif %} - {% if not vars.service.skip %}self.service = None{% endif %} {% if vars.ext.base_classes %} super().__init__(app=None) {% endif %} @@ -21,7 +18,6 @@ class {{ vars.ext|class_header }}: {% endif %} self.init_config(app) if not self.is_inherited(): - {% if not vars.resource.skip or not vars.service.skip %}self.init_resource(app){% endif %} self.register_flask_extension(app) def register_flask_extension(self, app): @@ -30,29 +26,13 @@ class {{ vars.ext|class_header }}: {% endif %} app.extensions["{{ vars.ext.alias }}"] = self - def init_resource(self, app): - """Initialize vocabulary resources.""" - {% if not vars.service.skip %} - self.service = app.config["{{ vars.service.config_key }}"]( - config=app.config["{{ vars.service_config.config_key }}"](), - {% if vars.service.additional_args %} - {{ vars.service.additional_args|generate_list }} - {% endif %} - ) - {% endif %} - {% if not vars.resource.skip %} - self.resource = app.config["{{ vars.resource.config_key }}"]( - {% if not vars.service.skip %}service=self.service,{% endif %} - config=app.config["{{ vars.resource_config.config_key }}"](), - ) - {% endif %} - def init_config(self, app): """Initialize configuration.""" for identifier in dir(config): if re.match('^[A-Z_0-9]*$', identifier) and not identifier.startswith('_'): app.config.setdefault(identifier, getattr(config, identifier)) + def is_inherited(self): from importlib_metadata import entry_points diff --git a/oarepo_model_builder/invenio/templates/ext_resource.py.jinja2 b/oarepo_model_builder/invenio/templates/ext_resource.py.jinja2 new file mode 100644 index 00000000..efeb30a9 --- /dev/null +++ b/oarepo_model_builder/invenio/templates/ext_resource.py.jinja2 @@ -0,0 +1,23 @@ +from functools import cached_property +{{ vars.config.module|generate_import(alias='config') }} + +class {{ vars.ext|class_header }}: + {% if not vars.service.skip %} + @cached_property + def {{ ext.ext_service_name }}(self): + return config.{{ vars.service.config_key }}( + config=config.{{ vars.service_config.config_key }}(), + {% if vars.service.additional_args %} + {{ vars.service.additional_args|generate_list }} + {% endif %} + ) + {% endif %} + + {% if not vars.resource.skip %} + @cached_property + def {{ ext.ext_resource_name }}(self): + return config.{{ vars.resource.config_key }}( + service=self.{{ ext.ext_service_name }}, + config=config.{{ vars.resource_config.config_key }}(), + ) + {% endif %} \ No newline at end of file diff --git a/oarepo_model_builder/invenio/templates/proxies.py.jinja2 b/oarepo_model_builder/invenio/templates/proxies.py.jinja2 index f0da0119..546b33dc 100644 --- a/oarepo_model_builder/invenio/templates/proxies.py.jinja2 +++ b/oarepo_model_builder/invenio/templates/proxies.py.jinja2 @@ -6,11 +6,11 @@ def _ext_proxy(attr): lambda: getattr(current_app.extensions["{{ vars.ext.alias }}"], attr)) {% if not vars.service.skip %} -{{ vars.service.proxy }} = _ext_proxy('service') +{{ vars.service.proxy }} = _ext_proxy('{{ ext.ext_service_name }}') """Proxy to the instantiated vocabulary service.""" {% endif %} {% if not vars.resource.skip %} -{{ vars.resource.proxy }} = _ext_proxy('resource') +{{ vars.resource.proxy }} = _ext_proxy('{{ ext.ext_resource_name }}') """Proxy to the instantiated vocabulary resource.""" {% endif %} diff --git a/setup.cfg b/setup.cfg index 33befe41..7731213a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -148,6 +148,7 @@ oarepo_model_builder.builders.record = 0430-ui_serializer = oarepo_model_builder.invenio.invenio_record_ui_serializer:InvenioRecordUISerializerBuilder 0500-invenio_config = oarepo_model_builder.invenio.invenio_config:InvenioConfigBuilder 0600-invenio_ext = oarepo_model_builder.invenio.invenio_ext:InvenioExtBuilder + 0605-invenio_ext_resource = oarepo_model_builder.invenio.invenio_ext_resource:InvenioExtResourceBuilder 0610-invenio_ext_setup_cfg = oarepo_model_builder.invenio.invenio_ext_setup_cfg:InvenioExtSetupCfgBuilder 0700-invenio_ext = oarepo_model_builder.invenio.invenio_proxies:InvenioProxiesBuilder 0910-invenio_record_metadata_alembic_setup_cfg = oarepo_model_builder.invenio.invenio_record_metadata_alembic_setup_cfg:InvenioRecordMetadataAlembicSetupCfgBuilder From b5f5f5ffcdb0e3cfdcfe096774bc425cd4a3f005 Mon Sep 17 00:00:00 2001 From: Ronald Krist Date: Tue, 27 Jun 2023 09:09:14 +0200 Subject: [PATCH 2/4] tests, format and some minor edits --- oarepo_model_builder/builders/mapping.py | 2 +- .../datatypes/components/__init__.py | 3 +- .../datatypes/components/facets/__init__.py | 2 +- .../datatypes/components/model/app.py | 5 +- .../datatypes/components/model/defaults.py | 10 +++- .../components/model/ext_resource.py | 7 ++- oarepo_model_builder/invenio/__init__.py | 2 +- .../invenio/invenio_api_views.py | 4 +- .../invenio/invenio_app_views.py | 2 +- .../invenio/invenio_ext_resource.py | 4 +- .../invenio/invenio_proxies.py | 2 +- tests/test_datatype_prepare.py | 17 +++---- tests/test_model_saver.py | 50 ++++++++++--------- tests/test_simple_builders.py | 28 +++-------- 14 files changed, 69 insertions(+), 69 deletions(-) diff --git a/oarepo_model_builder/builders/mapping.py b/oarepo_model_builder/builders/mapping.py index 997ed768..3893f6f7 100644 --- a/oarepo_model_builder/builders/mapping.py +++ b/oarepo_model_builder/builders/mapping.py @@ -44,7 +44,7 @@ def generate_model(self, node): generated = self.generate(node) generated.pop("enabled", None) generated.pop("type", None) - node.section_global_mapping.config.pop('properties', None) + node.section_global_mapping.config.pop("properties", None) return {**node.section_global_mapping.config, "mappings": generated} diff --git a/oarepo_model_builder/datatypes/components/__init__.py b/oarepo_model_builder/datatypes/components/__init__.py index 90bc356b..bbdd8c48 100644 --- a/oarepo_model_builder/datatypes/components/__init__.py +++ b/oarepo_model_builder/datatypes/components/__init__.py @@ -15,6 +15,7 @@ AppModelComponent, BlueprintsModelComponent, DefaultsModelComponent, + ExtResourceModelComponent, FacetsModelComponent, JSONSchemaModelComponent, MappingModelComponent, @@ -31,7 +32,7 @@ SearchOptionsModelComponent, ServiceModelComponent, UIMarshmallowModelComponent, - UIModelComponent, ExtResourceModelComponent, + UIModelComponent, ) from .sample import ArraySampleComponent, RegularSampleComponent from .ui import ObjectUIComponent, RegularUIComponent diff --git a/oarepo_model_builder/datatypes/components/facets/__init__.py b/oarepo_model_builder/datatypes/components/facets/__init__.py index ab0dea24..8f155bcd 100644 --- a/oarepo_model_builder/datatypes/components/facets/__init__.py +++ b/oarepo_model_builder/datatypes/components/facets/__init__.py @@ -16,7 +16,7 @@ def update(self, facet_section): # searchable not set up, so take it from argument self.searchable = facet_section.get("searchable", None) - def set_field(self, facet_section, arguments, field_class = None): + def set_field(self, facet_section, arguments, field_class=None): field = facet_section.get("field") if field: self.field = field diff --git a/oarepo_model_builder/datatypes/components/model/app.py b/oarepo_model_builder/datatypes/components/model/app.py index c9236762..074eaac7 100644 --- a/oarepo_model_builder/datatypes/components/model/app.py +++ b/oarepo_model_builder/datatypes/components/model/app.py @@ -66,9 +66,8 @@ class ModelSchema(ma.Schema): ) def before_model_prepare(self, datatype, **kwargs): - prefix = datatype.definition["module"]["prefix"] - alias = datatype.definition["module"]["alias"] module = datatype.definition["module"]["qualified"] + base_title = datatype.definition["module"]["base-title"] config = set_default(datatype, "config", {}) @@ -81,7 +80,7 @@ def before_model_prepare(self, datatype, **kwargs): ext.setdefault("generate", True) ext_module = ext.setdefault("module", f"{module}.ext") - ext.setdefault("class", f"{ext_module}.{module.capitalize()}Ext") + ext.setdefault("class", f"{ext_module}.{base_title}Ext") ext.setdefault("base-classes", []) ext.setdefault("extra_code", "") ext.setdefault("alias", module) diff --git a/oarepo_model_builder/datatypes/components/model/defaults.py b/oarepo_model_builder/datatypes/components/model/defaults.py index f781ef86..d69ff383 100644 --- a/oarepo_model_builder/datatypes/components/model/defaults.py +++ b/oarepo_model_builder/datatypes/components/model/defaults.py @@ -33,7 +33,11 @@ class Meta: data_key="base-upper", metadata={"doc": "Uppercase of the base name"}, ) - + base_title = ma.fields.String( + attribute="base-title", + data_key="base-title", + metadata={"doc": "Capitalized base name"}, + ) kebab_module = ma.fields.String( attribute="kebab-module", data_key="kebab-module", @@ -95,6 +99,10 @@ def get_model_name(_): "base-upper", module_base.upper(), ) + module_container.setdefault( + "base-title", + module_base.capitalize(), + ) module_container.setdefault( "kebab-module", module.replace(".", "-").replace("_", "-"), diff --git a/oarepo_model_builder/datatypes/components/model/ext_resource.py b/oarepo_model_builder/datatypes/components/model/ext_resource.py index a5ade094..9d011639 100644 --- a/oarepo_model_builder/datatypes/components/model/ext_resource.py +++ b/oarepo_model_builder/datatypes/components/model/ext_resource.py @@ -1,6 +1,6 @@ -from oarepo_model_builder.datatypes import DataTypeComponent, ModelDataType import marshmallow as ma +from oarepo_model_builder.datatypes import DataTypeComponent, ModelDataType from oarepo_model_builder.datatypes.components.model.utils import set_default @@ -10,14 +10,18 @@ class ExtResourceSchema(ma.Schema): class Meta: unknown = ma.RAISE + + class ExtResourceModelComponent(DataTypeComponent): eligible_datatypes = [ModelDataType] + class ModelSchema(ma.Schema): ext_resource = ma.fields.Nested( ExtResourceSchema, attribute="ext-resource", data_key="ext-resource", ) + def process_ext_resource(self, datatype, section, **kwargs): if self.is_record_profile: cfg = section.config @@ -32,4 +36,3 @@ def before_model_prepare(self, datatype, *, context, **kwargs): ext.setdefault("generate", True) ext.setdefault("skip", False) - diff --git a/oarepo_model_builder/invenio/__init__.py b/oarepo_model_builder/invenio/__init__.py index c4691cb7..09926d70 100644 --- a/oarepo_model_builder/invenio/__init__.py +++ b/oarepo_model_builder/invenio/__init__.py @@ -20,5 +20,5 @@ "pid-provider": "templates/pid_provider.py.jinja2", # utils and included "imports": "templates/imports.py.jinja2", - "ext-resource": "templates/ext_resource.py.jinja2" + "ext-resource": "templates/ext_resource.py.jinja2", } diff --git a/oarepo_model_builder/invenio/invenio_api_views.py b/oarepo_model_builder/invenio/invenio_api_views.py index 449cd5dc..3a63bfa7 100644 --- a/oarepo_model_builder/invenio/invenio_api_views.py +++ b/oarepo_model_builder/invenio/invenio_api_views.py @@ -7,5 +7,5 @@ class InvenioAPIViewsBuilder(InvenioBaseClassPythonBuilder): template = "api-views" def finish(self, **extra_kwargs): - ext = getattr(self.current_model, "section_ext_resource").config - super().finish(ext=ext, **extra_kwargs) \ No newline at end of file + ext = self.current_model.section_ext_resource.config + super().finish(ext=ext, **extra_kwargs) diff --git a/oarepo_model_builder/invenio/invenio_app_views.py b/oarepo_model_builder/invenio/invenio_app_views.py index b407564d..6ba8d70f 100644 --- a/oarepo_model_builder/invenio/invenio_app_views.py +++ b/oarepo_model_builder/invenio/invenio_app_views.py @@ -7,5 +7,5 @@ class InvenioAPPViewsBuilder(InvenioBaseClassPythonBuilder): template = "app-views" def finish(self, **extra_kwargs): - ext = getattr(self.current_model, "section_ext_resource").config + ext = self.current_model.section_ext_resource.config super().finish(ext=ext, **extra_kwargs) diff --git a/oarepo_model_builder/invenio/invenio_ext_resource.py b/oarepo_model_builder/invenio/invenio_ext_resource.py index 7022c9ed..3f134ef4 100644 --- a/oarepo_model_builder/invenio/invenio_ext_resource.py +++ b/oarepo_model_builder/invenio/invenio_ext_resource.py @@ -7,5 +7,5 @@ class InvenioExtResourceBuilder(InvenioBaseClassPythonBuilder): template = "ext-resource" def finish(self, **extra_kwargs): - ext = getattr(self.current_model, "section_ext_resource").config - super().finish(ext=ext, **extra_kwargs) \ No newline at end of file + ext = self.current_model.section_ext_resource.config + super().finish(ext=ext, **extra_kwargs) diff --git a/oarepo_model_builder/invenio/invenio_proxies.py b/oarepo_model_builder/invenio/invenio_proxies.py index 02c98d43..ddaf73de 100644 --- a/oarepo_model_builder/invenio/invenio_proxies.py +++ b/oarepo_model_builder/invenio/invenio_proxies.py @@ -7,5 +7,5 @@ class InvenioProxiesBuilder(InvenioBaseClassPythonBuilder): template = "proxies" def finish(self, **extra_kwargs): - ext = getattr(self.current_model, "section_ext_resource").config + ext = self.current_model.section_ext_resource.config super().finish(ext=ext, **extra_kwargs) diff --git a/tests/test_datatype_prepare.py b/tests/test_datatype_prepare.py index 284f051f..407e449a 100644 --- a/tests/test_datatype_prepare.py +++ b/tests/test_datatype_prepare.py @@ -31,14 +31,6 @@ def test_prepare_datatype(): "imports": [], "module": "my.test.views.records.api", }, - "app-blueprint": { # NOSONAR - "alias": "my_test_record", - "extra_code": "", - "function": "my.test.views.records.app.create_app_blueprint", - "generate": True, - "imports": [], - "module": "my.test.views.records.app", - }, "config": { "extra_code": "", "generate": True, @@ -46,7 +38,7 @@ def test_prepare_datatype(): "module": "my.test.config", }, "ext": { - "alias": "my_test_record", + "alias": "my.test", "base-classes": [], "class": "my.test.ext.TestExt", "extra_code": "", @@ -54,6 +46,10 @@ def test_prepare_datatype(): "imports": [], "module": "my.test.ext", }, + "ext-resource": { + "generate": True, + "skip": False, + }, "facets": { "extra-code": "", "generate": True, @@ -98,6 +94,7 @@ def test_prepare_datatype(): "alias": "my_test_record", "base": "test", "base-upper": "TEST", + "base-title": "Test", "kebab-module": "my-test", "path": "my/test", "prefix": "Test", @@ -277,7 +274,7 @@ def test_prepare_datatype(): }, ], "module": "my.test.services.records.config", - "service-id": "my_test_record", + "service-id": "test", }, "type": "model", "ui": { diff --git a/tests/test_model_saver.py b/tests/test_model_saver.py index 5dad88a2..dc154c3a 100644 --- a/tests/test_model_saver.py +++ b/tests/test_model_saver.py @@ -41,6 +41,7 @@ def test_model_saver(): }, ) assert data[0]["model"] == { + "type": "model", "searchable": True, "module": { "qualified": "test", @@ -48,6 +49,7 @@ def test_model_saver(): "path": "test", "base": "test", "base-upper": "TEST", + "base-title": "Test", "kebab-module": "test", "prefix": "Test", "prefix-upper": "TEST", @@ -56,9 +58,9 @@ def test_model_saver(): "suffix-upper": "TEST", "suffix-snake": "test", }, - "type": "model", "sample": {"file": "data/sample_data.yaml"}, "model-name": "Test", + "ext-resource": {"generate": True, "skip": False}, "search-options": { "generate": True, "module": "test.services.records.search", @@ -378,26 +380,35 @@ def test_model_saver_invenio(): ) print(repr(data[0])) assert data[0]["model"] == { + "marshmallow": { + "imports": [{"import": "oarepo_runtime.marshmallow.BaseRecordSchema"}], + "base-classes": ["BaseRecordSchema"], + "generate": True, + "module": "test.services.records.schema", + "class": "test.services.records.schema.TestSchema", + "extra-code": "", + }, "ui": { "marshmallow": { - "base-classes": ["InvenioUISchema"], "imports": [ {"import": "oarepo_runtime.ui.marshmallow.InvenioUISchema"} ], + "base-classes": ["InvenioUISchema"], "generate": True, "module": "test.services.records.ui_schema", "class": "test.services.records.ui_schema.TestUISchema", "extra-code": "", } }, - "type": "model", "searchable": True, + "type": "model", "module": { "qualified": "test", "alias": "test", "path": "test", "base": "test", "base-upper": "TEST", + "base-title": "Test", "kebab-module": "test", "prefix": "Test", "prefix-upper": "TEST", @@ -406,16 +417,9 @@ def test_model_saver_invenio(): "suffix-upper": "TEST", "suffix-snake": "test", }, - "marshmallow": { - "base-classes": ["BaseRecordSchema"], - "imports": [{"import": "oarepo_runtime.marshmallow.BaseRecordSchema"}], - "generate": True, - "module": "test.services.records.schema", - "class": "test.services.records.schema.TestSchema", - "extra-code": "", - }, "sample": {"file": "data/sample_data.yaml"}, "model-name": "Test", + "ext-resource": {"generate": True, "skip": False}, "search-options": { "generate": True, "module": "test.services.records.search", @@ -628,32 +632,32 @@ def test_model_saver_invenio(): }, "properties": { "$schema": { - "sample": {"skip": True}, "facets": {"searchable": True}, - "ui": {"marshmallow": {"read": False, "write": False}}, "type": "keyword", - "marshmallow": {"read": False, "write": False}, + "sample": {"skip": True}, + "marshmallow": {"write": False, "read": False}, + "ui": {"marshmallow": {"write": False, "read": False}}, }, "created": { - "sample": {"skip": True}, "facets": {"searchable": True}, - "ui": {"marshmallow": {"read": False, "write": False}}, "type": "datetime", - "marshmallow": {"read": False, "write": False}, + "sample": {"skip": True}, + "marshmallow": {"write": False, "read": False}, + "ui": {"marshmallow": {"write": False, "read": False}}, }, "id": { - "sample": {"skip": True}, "facets": {"searchable": True}, - "ui": {"marshmallow": {"read": False, "write": False}}, "type": "keyword", - "marshmallow": {"read": False, "write": False}, + "sample": {"skip": True}, + "marshmallow": {"write": False, "read": False}, + "ui": {"marshmallow": {"write": False, "read": False}}, }, "updated": { - "sample": {"skip": True}, "facets": {"searchable": True}, - "ui": {"marshmallow": {"read": False, "write": False}}, "type": "datetime", - "marshmallow": {"read": False, "write": False}, + "sample": {"skip": True}, + "marshmallow": {"write": False, "read": False}, + "ui": {"marshmallow": {"write": False, "read": False}}, }, }, } diff --git a/tests/test_simple_builders.py b/tests/test_simple_builders.py index 753da42b..5f5b25d8 100644 --- a/tests/test_simple_builders.py +++ b/tests/test_simple_builders.py @@ -185,10 +185,8 @@ def test_ext_builder(): class TestExt: + def __init__(self, app=None): - """Extension initialization.""" - self.resource = None - self.service = None if app: self.init_app(app) @@ -198,29 +196,19 @@ def init_app(self, app): self.init_config(app) if not self.is_inherited(): - self.init_resource(app) self.register_flask_extension(app) def register_flask_extension(self, app): app.extensions["test"] = self - def init_resource(self, app): - """Initialize vocabulary resources.""" - self.service = app.config["TEST_RECORD_SERVICE_CLASS"]( - config=app.config["TEST_RECORD_SERVICE_CONFIG"](), - ) - self.resource = app.config["TEST_RECORD_RESOURCE_CLASS"]( - service=self.service, - config=app.config["TEST_RECORD_RESOURCE_CONFIG"](), - ) - def init_config(self, app): """Initialize configuration.""" for identifier in dir(config): if re.match('^[A-Z_0-9]*$', identifier) and not identifier.startswith('_'): app.config.setdefault(identifier, getattr(config, identifier)) + def is_inherited(self): from importlib_metadata import entry_points @@ -254,10 +242,10 @@ def _ext_proxy(attr): return LocalProxy( lambda: getattr(current_app.extensions["test"], attr)) -current_service = _ext_proxy('service') +current_service = _ext_proxy('service_records') """Proxy to the instantiated vocabulary service.""" -current_resource = _ext_proxy('resource') +current_resource = _ext_proxy('resource_records') """Proxy to the instantiated vocabulary resource.""" ''' ) @@ -432,7 +420,7 @@ def test_api_views_builder(): def create_api_blueprint(app): """Create TestRecord blueprint.""" - blueprint = app.extensions["test"].resource.as_blueprint() + blueprint = app.extensions["test"].resource_records.as_blueprint() blueprint.record_once(init_create_api_blueprint) #calls record_once for all other functions starting with "init_addons_" @@ -451,12 +439,12 @@ def init_create_api_blueprint(state): # register service sregistry = app.extensions["invenio-records-resources"].registry - sregistry.register(ext.service, service_id="test") + sregistry.register(ext.service_records, service_id=ext.service_records.config.service_id) # Register indexer - if hasattr(ext.service, "indexer"): + if hasattr(ext.service_records, "indexer"): iregistry = app.extensions["invenio-indexer"].registry - iregistry.register(ext.service.indexer, indexer_id="test") + iregistry.register(ext.service_records.indexer, indexer_id=ext.service_records.config.service_id) ''' ) From 136294f6e8382b35b9d84e65ddba52dc1431d90d Mon Sep 17 00:00:00 2001 From: Ronald Krist <34395689+SilvyPuzzlewell@users.noreply.github.com> Date: Tue, 27 Jun 2023 09:11:38 +0200 Subject: [PATCH 3/4] version bump --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 7731213a..497b5b9d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = oarepo-model-builder -version = 4.0.19 +version = 4.0.20 description = A utility library that generates OARepo required data model files from a JSON specification file authors = Miroslav Bauer , Miroslav Simek readme = README.md From b097b7042662eeb3ab95afb351ba5276331700a1 Mon Sep 17 00:00:00 2001 From: Ronald Krist Date: Tue, 27 Jun 2023 09:17:23 +0200 Subject: [PATCH 4/4] code smell fix --- tests/test_datatype_prepare.py | 93 +++++++++++++++++----------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/tests/test_datatype_prepare.py b/tests/test_datatype_prepare.py index 407e449a..c93b126f 100644 --- a/tests/test_datatype_prepare.py +++ b/tests/test_datatype_prepare.py @@ -2,6 +2,7 @@ def test_prepare_datatype(): + module = "my.test" model = ModelSchema( "", { @@ -16,7 +17,7 @@ def test_prepare_datatype(): "record": { "type": "model", "model-name": "My Test Record", - "module": {"qualified": "my.test"}, + "module": {"qualified": f"{module}"}, "properties": {"metadata": {"type": "object"}}, }, }, @@ -26,25 +27,25 @@ def test_prepare_datatype(): "api-blueprint": { "alias": "my_test_record", "extra_code": "", - "function": "my.test.views.records.api.create_api_blueprint", + "function": f"{module}.views.records.api.create_api_blueprint", "generate": True, "imports": [], - "module": "my.test.views.records.api", + "module": f"{module}.views.records.api", }, "config": { "extra_code": "", "generate": True, "imports": [], - "module": "my.test.config", + "module": f"{module}.config", }, "ext": { - "alias": "my.test", + "alias": f"{module}", "base-classes": [], - "class": "my.test.ext.TestExt", + "class": f"{module}.ext.TestExt", "extra_code": "", "generate": True, "imports": [], - "module": "my.test.ext", + "module": f"{module}.ext", }, "ext-resource": { "generate": True, @@ -53,19 +54,19 @@ def test_prepare_datatype(): "facets": { "extra-code": "", "generate": True, - "module": "my.test.services.records.facets", + "module": f"{module}.services.records.facets", }, "json-schema-settings": { "alias": "my_test_record", "file": "my/test/records/jsonschemas/test-1.0.0.json", "generate": True, - "module": "my.test.records.jsonschemas", + "module": f"{module}.records.jsonschemas", "name": "test-1.0.0.json", "version": "1.0.0", }, "json-serializer": { "base-classes": ["MarshmallowSerializer"], - "class": "my.test.resources.records.ui.TestUIJSONSerializer", + "class": f"{module}.resources.records.ui.TestUIJSONSerializer", "extra-code": "", "generate": True, "imports": [ @@ -73,21 +74,21 @@ def test_prepare_datatype(): {"import": "flask_resources.MarshmallowSerializer"}, {"import": "flask_resources.serializers.JSONSerializer"}, ], - "module": "my.test.resources.records.ui", + "module": f"{module}.resources.records.ui", }, "mapping-settings": { "alias": "my_test_record", "file": "my/test/records/mappings/os-v2/my_test_record/test-1.0.0.json", "generate": True, "index": "my_test_record-test-1.0.0", - "module": "my.test.records.mappings", + "module": f"{module}.records.mappings", }, "marshmallow": { "base-classes": ["ma.Schema"], # NOSONAR - "class": "my.test.services.records.schema.TestSchema", + "class": f"{module}.services.records.schema.TestSchema", "extra-code": "", "generate": True, - "module": "my.test.services.records.schema", + "module": f"{module}.services.records.schema", }, "model-name": "My Test Record", "module": { @@ -100,20 +101,20 @@ def test_prepare_datatype(): "prefix": "Test", "prefix-snake": "test", "prefix-upper": "TEST", - "qualified": "my.test", + "qualified": f"{module}", "suffix": "test", "suffix-snake": "test", "suffix-upper": "TEST", }, "permissions": { "base-classes": ["RecordPermissionPolicy"], - "class": "my.test.services.records.permissions.TestPermissionPolicy", + "class": f"{module}.services.records.permissions.TestPermissionPolicy", "extra-code": "", "generate": True, "imports": [ {"import": "invenio_records_permissions.RecordPermissionPolicy"} ], - "module": "my.test.services.records.permissions", + "module": f"{module}.services.records.permissions", "presets": ["everyone"], }, "pid": { @@ -130,37 +131,37 @@ def test_prepare_datatype(): }, {"import": "invenio_pidstore.providers.recordid_v2.RecordIdProviderV2"}, ], - "module": "my.test.records.api", + "module": f"{module}.records.api", "provider-base-classes": ["RecordIdProviderV2"], - "provider-class": "my.test.records.api.TestIdProvider", + "provider-class": f"{module}.records.api.TestIdProvider", "type": "mytcrd", }, "properties": { "metadata": { "marshmallow": { "base-classes": ["ma.Schema"], - "class": "my.test.services.records.schema.TestMetadataSchema", + "class": f"{module}.services.records.schema.TestMetadataSchema", "extra-code": "", "generate": True, - "module": "my.test.services.records.schema", + "module": f"{module}.services.records.schema", }, "properties": {}, "type": "object", "ui": { "marshmallow": { "base-classes": ["ma.Schema"], - "class": "my.test.services.records.ui_schema.TestMetadataUISchema", + "class": f"{module}.services.records.ui_schema.TestMetadataUISchema", "extra-code": "", "generate": True, - "module": "my.test.services.records.ui_schema", + "module": f"{module}.services.records.ui_schema", } }, } }, - "proxy": {"module": "my.test.proxies", "generate": True}, + "proxy": {"module": f"{module}.proxies", "generate": True}, "record": { "base-classes": ["InvenioRecord"], - "class": "my.test.records.api.TestRecord", + "class": f"{module}.records.api.TestRecord", "extra-code": "", "generate": True, "imports": [ @@ -169,65 +170,65 @@ def test_prepare_datatype(): "import": "invenio_records_resources.records.api.Record", } ], - "module": "my.test.records.api", + "module": f"{module}.records.api", }, "record-dumper": { "base-classes": ["SearchDumper"], - "class": "my.test.records.dumper.TestDumper", + "class": f"{module}.records.dumper.TestDumper", "extensions": [], "extra-code": "", "generate": True, "imports": [{"import": "invenio_records.dumpers.SearchDumper"}], - "module": "my.test.records.dumper", + "module": f"{module}.records.dumper", }, "record-metadata": { - "alembic": "my.test.alembic", + "alembic": f"{module}.alembic", "alias": "my_test_record", "base-classes": ["db.Model", "RecordMetadataBase"], - "class": "my.test.records.models.TestMetadata", + "class": f"{module}.records.models.TestMetadata", "extra-code": "", "generate": True, "imports": [ {"import": "invenio_records.models.RecordMetadataBase"}, {"import": "invenio_db.db"}, ], - "module": "my.test.records.models", + "module": f"{module}.records.models", "table": "test_metadata", "use-versioning": True, }, "resource": { "base-classes": ["RecordResource"], - "class": "my.test.resources.records.resource.TestResource", + "class": f"{module}.resources.records.resource.TestResource", "config-key": "TEST_RECORD_RESOURCE_CLASS", "extra-code": "", "generate": True, "imports": [ {"import": "invenio_records_resources.resources.RecordResource"} ], - "module": "my.test.resources.records.resource", + "module": f"{module}.resources.records.resource", "proxy": "current_resource", }, "resource-config": { "base-classes": ["RecordResourceConfig"], "base-url": "/my-test/", - "class": "my.test.resources.records.config.TestResourceConfig", + "class": f"{module}.resources.records.config.TestResourceConfig", "config-key": "TEST_RECORD_RESOURCE_CONFIG", "extra-code": "", "generate": True, "imports": [ {"import": "invenio_records_resources.resources.RecordResourceConfig"} ], - "module": "my.test.resources.records.config", + "module": f"{module}.resources.records.config", }, "sample": {"file": "data/sample_data.yaml"}, "saved-model": { "alias": "my_test_record", "file": "my/test/models/records.json", - "module": "my.test.models", + "module": f"{module}.models", }, "search-options": { "base-classes": ["InvenioSearchOptions"], - "class": "my.test.services.records.search.TestSearchOptions", + "class": f"{module}.services.records.search.TestSearchOptions", "extra-code": "", "generate": True, "imports": [ @@ -236,12 +237,12 @@ def test_prepare_datatype(): "import": "invenio_records_resources.services.SearchOptions", } ], - "module": "my.test.services.records.search", + "module": f"{module}.services.records.search", }, "searchable": True, "service": { "base-classes": ["InvenioRecordService"], - "class": "my.test.services.records.service.TestService", + "class": f"{module}.services.records.service.TestService", "config-key": "TEST_RECORD_SERVICE_CLASS", "extra-code": "", "generate": True, @@ -251,7 +252,7 @@ def test_prepare_datatype(): "import": "invenio_records_resources.services.RecordService", } ], - "module": "my.test.services.records.service", + "module": f"{module}.services.records.service", "proxy": "current_service", }, "service-config": { @@ -259,7 +260,7 @@ def test_prepare_datatype(): "PermissionsPresetsConfigMixin", "InvenioRecordServiceConfig", ], - "class": "my.test.services.records.config.TestServiceConfig", + "class": f"{module}.services.records.config.TestServiceConfig", "components": [], "config-key": "TEST_RECORD_SERVICE_CONFIG", "extra-code": "", @@ -273,29 +274,29 @@ def test_prepare_datatype(): "import": "oarepo_runtime.config.service.PermissionsPresetsConfigMixin" }, ], - "module": "my.test.services.records.config", + "module": f"{module}.services.records.config", "service-id": "test", }, "type": "model", "ui": { "marshmallow": { "base-classes": ["InvenioUISchema"], - "class": "my.test.services.records.ui_schema.TestUISchema", + "class": f"{module}.services.records.ui_schema.TestUISchema", "extra-code": "", "generate": True, "imports": [ {"import": "oarepo_runtime.ui.marshmallow.InvenioUISchema"} ], - "module": "my.test.services.records.ui_schema", + "module": f"{module}.services.records.ui_schema", } }, "app-blueprint": { "alias": "my_test_record", "extra_code": "", - "function": "my.test.views.records.app.create_app_blueprint", + "function": f"{module}.views.records.app.create_app_blueprint", "generate": True, "imports": [], - "module": "my.test.views.records.app", + "module": f"{module}.views.records.app", }, }