From 6a0876e62bcf5f7c4acb1321d37911251a65a46d Mon Sep 17 00:00:00 2001 From: Julian Geiger Date: Wed, 20 May 2026 13:04:32 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=91=8C=20`ShellCode`:=20support=20bot?= =?UTF-8?q?h=20`aiida-core`=20model=20APIs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aiida-core PR 6990 restructured the pydantic model layout on `Code` classes: the single nested `Model` class is split into `CommonFields`, `AttributesModel`, and `ConstructorArgsModel`. `ShellCode` overrides these to set `default_calc_job_plugin = 'core.shell'` for attribute loading and the `verdi code create` CLI default. PR 6990 is not in any released `aiida-core` yet (as of 2026-05-20), so keep both code paths: feature-detect the new API via the presence of `aiida.orm.pydantic.OrmMetadataField` (added in 6990) and fall back to the old single-class `Model` shape on releases that predate the refactor. The dependency pin stays at `aiida-core~=2.6,>=2.6.1`. --- src/aiida_shell/data/code.py | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/aiida_shell/data/code.py b/src/aiida_shell/data/code.py index 780d935..04ad516 100644 --- a/src/aiida_shell/data/code.py +++ b/src/aiida_shell/data/code.py @@ -5,6 +5,13 @@ from aiida.orm import InstalledCode +try: + from aiida.orm.pydantic import OrmMetadataField # type: ignore[import-not-found] + + _HAS_NEW_MODEL_API = True +except ImportError: + _HAS_NEW_MODEL_API = False + __all__ = ('ShellCode',) @@ -16,10 +23,33 @@ class ShellCode(InstalledCode): calculation job as well. """ - class Model(InstalledCode.Model): - """Model describing required information to create an instance.""" + if _HAS_NEW_MODEL_API: + + class CommonField(InstalledCode.CommonField): # type: ignore[name-defined,misc] + """Override `default_calc_job_plugin` to default to `core.shell`.""" + + default_calc_job_plugin: t.Optional[str] = OrmMetadataField( + 'core.shell', + alias='input_plugin', + title='Default `CalcJob` plugin', + description=( + 'Entry point name of the default plugin ' '(as listed in `verdi plugin list aiida.calculations`)' + ), + short_name='-P', + ) + + class AttributesModel(CommonField, InstalledCode.AttributesModel): # type: ignore[name-defined,misc] + """Attributes model with ``default_calc_job_plugin`` defaulting to ``core.shell``.""" + + class ConstructorArgsModel(CommonField, InstalledCode.ConstructorArgsModel): # type: ignore[name-defined,misc] + """Constructor arguments model with ``default_calc_job_plugin`` defaulting to ``core.shell``.""" + + else: + + class Model(InstalledCode.Model): + """Model describing required information to create an instance.""" - default_calc_job_plugin: t.Optional[str] = 'core.shell' + default_calc_job_plugin: t.Optional[str] = 'core.shell' def __init__(self, *args: t.Any, default_calc_job_plugin: str = 'core.shell', **kwargs: t.Any) -> None: """Construct a new instance.""" From 9eee6994b2d457a9190cb30029539b637d2e09cf Mon Sep 17 00:00:00 2001 From: Julian Geiger Date: Wed, 20 May 2026 16:49:40 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=91=8C=20`ShellCode`:=20drop=20redund?= =?UTF-8?q?ant=20`Model`=20override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aiida-core PR 6990 restructured the pydantic model layout on `Code` classes: the single nested `Model` class is split into `CommonFields`, `AttributesModel`, and `ConstructorArgsModel`. This broke `ShellCode.Model(InstalledCode.Model)` on releases that include 6990, since `InstalledCode.Model` no longer exists. The override only ever set `default_calc_job_plugin = 'core.shell'`, which is functionally redundant: `_to_orm_field_values` filters `None` values out of the model -> ORM kwargs dict in both the old and new aiida-core layouts, so when no value is passed at the CLI/Pydantic boundary the `ShellCode.__init__` signature default of `'core.shell'` takes over. Dropping the override removes the breakage on 6990 without needing version-specific shims, and works unchanged on every aiida-core that exposes a `_to_orm_field_values`-style filtering step (i.e., every aiida-core that ever had a code Model). The only observable difference is cosmetic: `verdi code create core.code.shell --help` no longer shows `core.shell` as the printed default for `--default-calc-job-plugin`. The constructed code still has it set correctly. --- src/aiida_shell/data/code.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/src/aiida_shell/data/code.py b/src/aiida_shell/data/code.py index 04ad516..31cfa2c 100644 --- a/src/aiida_shell/data/code.py +++ b/src/aiida_shell/data/code.py @@ -5,13 +5,6 @@ from aiida.orm import InstalledCode -try: - from aiida.orm.pydantic import OrmMetadataField # type: ignore[import-not-found] - - _HAS_NEW_MODEL_API = True -except ImportError: - _HAS_NEW_MODEL_API = False - __all__ = ('ShellCode',) @@ -23,34 +16,6 @@ class ShellCode(InstalledCode): calculation job as well. """ - if _HAS_NEW_MODEL_API: - - class CommonField(InstalledCode.CommonField): # type: ignore[name-defined,misc] - """Override `default_calc_job_plugin` to default to `core.shell`.""" - - default_calc_job_plugin: t.Optional[str] = OrmMetadataField( - 'core.shell', - alias='input_plugin', - title='Default `CalcJob` plugin', - description=( - 'Entry point name of the default plugin ' '(as listed in `verdi plugin list aiida.calculations`)' - ), - short_name='-P', - ) - - class AttributesModel(CommonField, InstalledCode.AttributesModel): # type: ignore[name-defined,misc] - """Attributes model with ``default_calc_job_plugin`` defaulting to ``core.shell``.""" - - class ConstructorArgsModel(CommonField, InstalledCode.ConstructorArgsModel): # type: ignore[name-defined,misc] - """Constructor arguments model with ``default_calc_job_plugin`` defaulting to ``core.shell``.""" - - else: - - class Model(InstalledCode.Model): - """Model describing required information to create an instance.""" - - default_calc_job_plugin: t.Optional[str] = 'core.shell' - def __init__(self, *args: t.Any, default_calc_job_plugin: str = 'core.shell', **kwargs: t.Any) -> None: """Construct a new instance.""" self.validate_default_calc_job_plugin(default_calc_job_plugin)