Skip to content

Commit c8ded01

Browse files
current
1 parent bbd8a13 commit c8ded01

File tree

31 files changed

+631
-165
lines changed

31 files changed

+631
-165
lines changed

src/aiida/cmdline/commands/cmd_code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def verdi_code():
3535
def create_code(ctx: click.Context, cls, **kwargs) -> None:
3636
"""Create a new `Code` instance."""
3737
try:
38-
instance = cls._from_model(cls.Model(**kwargs))
38+
instance = cls.from_model(cls.Model(**kwargs))
3939
except (TypeError, ValueError) as exception:
4040
echo.echo_critical(f'Failed to create instance `{cls}`: {exception}')
4141

src/aiida/common/datastructures.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,8 @@ class CalcInfo(DefaultFieldsAttributeDict):
167167
max_wallclock_seconds: None | int
168168
max_memory_kb: None | int
169169
rerunnable: bool
170-
retrieve_list: None | list[str | tuple[str, str, str]]
171-
retrieve_temporary_list: None | list[str | tuple[str, str, str]]
170+
retrieve_list: None | list[str | tuple[str, str, int]]
171+
retrieve_temporary_list: None | list[str | tuple[str, str, int]]
172172
local_copy_list: None | list[tuple[str, str, str]]
173173
remote_copy_list: None | list[tuple[str, str, str]]
174174
remote_symlink_list: None | list[tuple[str, str, str]]

src/aiida/common/pydantic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Model(BaseModel):
7575
:param model_to_orm: Optional callable to convert the value of a field from a model instance to an ORM instance.
7676
:param exclude_to_orm: When set to ``True``, this field value will not be passed to the ORM entity constructor
7777
through ``Entity.from_model``.
78-
:param exclude_to_orm: When set to ``True``, this field value will not be exposed on the CLI command that is
78+
:param exclude_from_cli: When set to ``True``, this field value will not be exposed on the CLI command that is
7979
dynamically generated to create a new instance.
8080
:param is_attribute: Whether the field is stored as an attribute.
8181
:param is_subscriptable: Whether the field can be indexed like a list or dictionary.

src/aiida/engine/processes/calcjobs/calcjob.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def validate_additional_retrieve_list(additional_retrieve_list: Any, _: Any) ->
216216
class CalcJob(Process):
217217
"""Implementation of the CalcJob process."""
218218

219-
_node_class = orm.CalcJobNode
219+
_node_class = orm.CalcJobNode # type: ignore[assignment]
220220
_spec_class = CalcJobProcessSpec
221221
link_label_retrieved: str = 'retrieved'
222222
KEY_CACHE_VERSION: str = 'cache_version'

src/aiida/orm/comments.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,22 @@ class Model(entities.Entity.Model):
8888
is_attribute=False,
8989
exclude_to_orm=True,
9090
)
91-
node: int = MetadataField(
91+
node: Optional[int] = MetadataField(
92+
None,
9293
description='Node PK that the comment is attached to',
9394
is_attribute=False,
9495
orm_class='core.node',
9596
orm_to_model=lambda comment, _: comment.node.pk,
9697
)
97-
user: int = MetadataField(
98+
user: Optional[int] = MetadataField(
99+
None,
98100
description='User PK that created the comment',
99101
is_attribute=False,
100102
orm_class='core.user',
101103
orm_to_model=lambda comment, _: comment.user.pk,
102104
)
103-
content: str = MetadataField(
105+
content: Optional[str] = MetadataField(
106+
None,
104107
description='Content of the comment',
105108
is_attribute=False,
106109
)
@@ -122,7 +125,11 @@ def __init__(
122125
:return: a Comment object associated to the given node and user
123126
"""
124127
backend = backend or get_manager().get_profile_storage()
125-
model = backend.comments.create(node=node.backend_entity, user=user.backend_entity, content=content)
128+
model = backend.comments.create(
129+
node=node.backend_entity,
130+
user=user.backend_entity,
131+
content=content,
132+
)
126133
super().__init__(model)
127134

128135
def __str__(self) -> str:

src/aiida/orm/computers.py

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import logging
1414
import os
15-
from typing import TYPE_CHECKING, Any
15+
from typing import TYPE_CHECKING, Any, Optional
1616

1717
from aiida.common import exceptions
1818
from aiida.common.pydantic import MetadataField
@@ -76,7 +76,8 @@ class Computer(entities.Entity['BackendComputer', ComputerCollection]):
7676
_CLS_COLLECTION = ComputerCollection
7777

7878
class Model(entities.Entity.Model):
79-
uuid: str = MetadataField(
79+
uuid: Optional[str] = MetadataField(
80+
None,
8081
description='The UUID of the computer',
8182
is_attribute=False,
8283
exclude_to_orm=True,
@@ -85,23 +86,28 @@ class Model(entities.Entity.Model):
8586
description='Label for the computer',
8687
is_attribute=False,
8788
)
88-
description: str = MetadataField(
89+
description: Optional[str] = MetadataField(
90+
None,
8991
description='Description of the computer',
9092
is_attribute=False,
9193
)
92-
hostname: str = MetadataField(
94+
hostname: Optional[str] = MetadataField(
95+
None,
9396
description='Hostname of the computer',
9497
is_attribute=False,
9598
)
96-
transport_type: str = MetadataField(
99+
transport_type: Optional[str] = MetadataField(
100+
None,
97101
description='Transport type of the computer',
98102
is_attribute=False,
99103
)
100-
scheduler_type: str = MetadataField(
104+
scheduler_type: Optional[str] = MetadataField(
105+
None,
101106
description='Scheduler type of the computer',
102107
is_attribute=False,
103108
)
104-
metadata: dict[str, Any] = MetadataField(
109+
metadata: Optional[dict[str, Any]] = MetadataField(
110+
None,
105111
description='Metadata of the computer',
106112
is_attribute=False,
107113
)

src/aiida/orm/entities.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,18 @@ def find(
146146
filters: 'FilterType' | None = None,
147147
order_by: 'OrderByType' | None = None,
148148
limit: int | None = None,
149+
offset: int | None = None,
149150
) -> list[EntityType]:
150151
"""Find collection entries matching the filter criteria.
151152
152153
:param filters: the keyword value pair filters to match
153154
:param order_by: a list of (key, direction) pairs specifying the sort order
154155
:param limit: the maximum number of results to return
156+
:param offset: number of initial results to be skipped
155157
156158
:return: a list of resulting matches
157159
"""
158-
query = self.query(filters=filters, order_by=order_by, limit=limit)
160+
query = self.query(filters=filters, order_by=order_by, limit=limit, offset=offset)
159161
return query.all(flat=True)
160162

161163
def all(self) -> list[EntityType]:
@@ -227,7 +229,7 @@ def model_to_orm_field_values(cls, model: Model) -> dict[str, Any]:
227229

228230
return fields
229231

230-
def _to_model(self, repository_path: Path | None = None) -> Model:
232+
def to_model(self, repository_path: Path | None = None) -> Model:
231233
"""Return the entity instance as an instance of its model."""
232234
fields = {}
233235

@@ -240,16 +242,17 @@ def _to_model(self, repository_path: Path | None = None) -> Model:
240242
return self.Model(**fields)
241243

242244
@classmethod
243-
def _from_model(cls: type[EntityType], model: Model) -> EntityType:
245+
def from_model(cls: type[EntityType], model: Model) -> EntityType:
244246
"""Return an entity instance from an instance of its model."""
245247
fields = cls.model_to_orm_field_values(model)
246248
return cls(**fields)
247249

248-
def serialize(self, repository_path: Path | None = None) -> dict[str, Any]:
250+
def serialize(self, repository_path: Path | None = None, serialize_files: bool = False) -> dict[str, Any]:
249251
"""Serialize the entity instance to JSON.
250252
251253
:param repository_path: If the orm node has files in the repository, this path is used to dump the repository
252254
files to. If no path is specified a temporary path is created using the entities pk.
255+
:param serialize_files: Whether to include files in the serialization. If False, only metadata is serialized.
253256
"""
254257
self.logger.warning(
255258
'Serialization through pydantic is still an experimental feature and might break in future releases.'
@@ -264,15 +267,19 @@ def serialize(self, repository_path: Path | None = None) -> dict[str, Any]:
264267
raise ValueError(f'The repository_path `{repository_path}` does not exist.')
265268
if not repository_path.is_dir():
266269
raise ValueError(f'The repository_path `{repository_path}` is not a directory.')
267-
return self._to_model(repository_path).model_dump()
270+
271+
exclude = set()
272+
if not serialize_files:
273+
exclude.add('repository_content')
274+
return self.to_model(repository_path).model_dump(exclude=exclude)
268275

269276
@classmethod
270277
def from_serialized(cls: type[EntityType], **kwargs: dict[str, Any]) -> EntityType:
271278
"""Construct an entity instance from JSON serialized data."""
272279
cls._logger.warning(
273280
'Serialization through pydantic is still an experimental feature and might break in future releases.'
274281
)
275-
return cls._from_model(cls.Model(**kwargs)) # type: ignore[arg-type]
282+
return cls.from_model(cls.Model(**kwargs)) # type: ignore[arg-type]
276283

277284
@classproperty
278285
def objects(cls: type[EntityType]) -> CollectionType: # noqa: N805

src/aiida/orm/fields.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,10 @@ class QbFields:
354354
def __init__(self, fields: t.Optional[t.Dict[str, QbField]] = None):
355355
self._fields = fields or {}
356356

357+
def keys(self) -> list[str]:
358+
"""Return the field keys, prefixed with 'attribute.' if field is an attribute."""
359+
return [field.backend_key for field in self._fields.values()]
360+
357361
def __repr__(self) -> str:
358362
return pformat({key: str(value) for key, value in self._fields.items()})
359363

@@ -464,7 +468,7 @@ def __init__(cls, name, bases, classdict):
464468
for key, field in cls.Model.model_fields.items():
465469
fields[key] = add_field(
466470
key,
467-
alias=get_metadata(field, 'alias', None),
471+
alias=field.alias,
468472
dtype=field.annotation,
469473
doc=field.description,
470474
is_attribute=get_metadata(field, 'is_attribute', False),

src/aiida/orm/groups.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,42 @@ class Group(entities.Entity['BackendGroup', GroupCollection]):
112112
__type_string: ClassVar[str | None]
113113

114114
class Model(entities.Entity.Model):
115-
uuid: str = MetadataField(description='The UUID of the group', is_attribute=False, exclude_to_orm=True)
116-
type_string: str = MetadataField(description='The type of the group', is_attribute=False, exclude_to_orm=True)
117-
user: int = MetadataField(
115+
uuid: Optional[str] = MetadataField(
116+
None,
117+
description='The UUID of the group',
118+
is_attribute=False,
119+
exclude_to_orm=True,
120+
)
121+
type_string: Optional[str] = MetadataField(
122+
None,
123+
description='The type of the group',
124+
is_attribute=False,
125+
exclude_to_orm=True,
126+
)
127+
user: Optional[int] = MetadataField(
128+
None,
118129
description='The group owner',
119130
is_attribute=False,
120131
orm_class='core.user',
121132
orm_to_model=lambda group, _: group.user.pk, # type: ignore[attr-defined]
122133
)
123134
time: Optional[datetime.datetime] = MetadataField(
124-
description='The creation time of the node', is_attribute=False
135+
None,
136+
description='The creation time of the node',
137+
is_attribute=False,
138+
)
139+
label: Optional[str] = MetadataField(
140+
None,
141+
description='The group label',
142+
is_attribute=False,
143+
)
144+
description: Optional[str] = MetadataField(
145+
None,
146+
description='The group description',
147+
is_attribute=False,
125148
)
126-
label: str = MetadataField(description='The group label', is_attribute=False)
127-
description: Optional[str] = MetadataField(description='The group description', is_attribute=False)
128149
extras: Optional[dict[str, Any]] = MetadataField(
150+
None,
129151
description='The group extras',
130152
is_attribute=False,
131153
is_subscriptable=True,
@@ -165,7 +187,11 @@ def __init__(
165187
type_check(user, users.User)
166188

167189
model = backend.groups.create(
168-
label=label, user=user.backend_entity, description=description, type_string=self._type_string, time=time
190+
label=label,
191+
user=user.backend_entity,
192+
description=description,
193+
type_string=self._type_string,
194+
time=time,
169195
)
170196
super().__init__(model)
171197
if extras is not None:

src/aiida/orm/logs.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,35 @@ class Log(entities.Entity['BackendLog', LogCollection]):
132132
_CLS_COLLECTION = LogCollection
133133

134134
class Model(entities.Entity.Model):
135-
uuid: str = MetadataField(description='The UUID of the node', is_attribute=False, exclude_to_orm=True)
136-
loggername: str = MetadataField(description='The name of the logger', is_attribute=False)
137-
levelname: str = MetadataField(description='The name of the log level', is_attribute=False)
138-
message: str = MetadataField(description='The message of the log', is_attribute=False)
139-
time: datetime = MetadataField(description='The time at which the log was created', is_attribute=False)
140-
metadata: dict[str, Any] = MetadataField(description='The metadata of the log', is_attribute=False)
141-
dbnode_id: int = MetadataField(description='Associated node', is_attribute=False)
135+
uuid: str = MetadataField(
136+
description='The UUID of the node',
137+
is_attribute=False,
138+
exclude_to_orm=True,
139+
)
140+
loggername: str = MetadataField(
141+
description='The name of the logger',
142+
is_attribute=False,
143+
)
144+
levelname: str = MetadataField(
145+
description='The name of the log level',
146+
is_attribute=False,
147+
)
148+
message: str = MetadataField(
149+
description='The message of the log',
150+
is_attribute=False,
151+
)
152+
time: datetime = MetadataField(
153+
description='The time at which the log was created',
154+
is_attribute=False,
155+
)
156+
metadata: dict[str, Any] = MetadataField(
157+
description='The metadata of the log',
158+
is_attribute=False,
159+
)
160+
dbnode_id: int = MetadataField(
161+
description='Associated node',
162+
is_attribute=False,
163+
)
142164

143165
def __init__(
144166
self,

0 commit comments

Comments
 (0)