Skip to content

Commit 476e144

Browse files
current
1 parent 51044e8 commit 476e144

File tree

31 files changed

+623
-165
lines changed

31 files changed

+623
-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, _: cast('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, _: cast('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
@@ -152,16 +152,18 @@ def find(
152152
filters: 'FilterType' | None = None,
153153
order_by: 'OrderByType' | None = None,
154154
limit: int | None = None,
155+
offset: int | None = None,
155156
) -> list[EntityType]:
156157
"""Find collection entries matching the filter criteria.
157158
158159
:param filters: the keyword value pair filters to match
159160
:param order_by: a list of (key, direction) pairs specifying the sort order
160161
:param limit: the maximum number of results to return
162+
:param offset: number of initial results to be skipped
161163
162164
:return: a list of resulting matches
163165
"""
164-
query = self.query(filters=filters, order_by=order_by, limit=limit)
166+
query = self.query(filters=filters, order_by=order_by, limit=limit, offset=offset)
165167
return query.all(flat=True)
166168

167169
def all(self) -> list[EntityType]:
@@ -233,7 +235,7 @@ def model_to_orm_field_values(cls, model: Model) -> dict[str, Any]:
233235

234236
return fields
235237

236-
def _to_model(self, repository_path: Path | None = None) -> Model:
238+
def to_model(self, repository_path: Path | None = None) -> Model:
237239
"""Return the entity instance as an instance of its model."""
238240
fields = {}
239241

@@ -246,16 +248,17 @@ def _to_model(self, repository_path: Path | None = None) -> Model:
246248
return self.Model(**fields)
247249

248250
@classmethod
249-
def _from_model(cls: type[EntityType], model: Model) -> EntityType:
251+
def from_model(cls: type[EntityType], model: Model) -> EntityType:
250252
"""Return an entity instance from an instance of its model."""
251253
fields = cls.model_to_orm_field_values(model)
252254
return cls(**fields)
253255

254-
def serialize(self, repository_path: Path | None = None) -> dict[str, Any]:
256+
def serialize(self, repository_path: Path | None = None, serialize_files: bool = False) -> dict[str, Any]:
255257
"""Serialize the entity instance to JSON.
256258
257259
:param repository_path: If the orm node has files in the repository, this path is used to dump the repository
258260
files to. If no path is specified a temporary path is created using the entities pk.
261+
:param serialize_files: Whether to include files in the serialization. If False, only metadata is serialized.
259262
"""
260263
self.logger.warning(
261264
'Serialization through pydantic is still an experimental feature and might break in future releases.'
@@ -270,15 +273,19 @@ def serialize(self, repository_path: Path | None = None) -> dict[str, Any]:
270273
raise ValueError(f'The repository_path `{repository_path}` does not exist.')
271274
if not repository_path.is_dir():
272275
raise ValueError(f'The repository_path `{repository_path}` is not a directory.')
273-
return self._to_model(repository_path).model_dump()
276+
277+
exclude = set()
278+
if not serialize_files:
279+
exclude.add('repository_content')
280+
return self.to_model(repository_path).model_dump(exclude=exclude)
274281

275282
@classmethod
276283
def from_serialized(cls: type[EntityType], **kwargs: dict[str, Any]) -> EntityType:
277284
"""Construct an entity instance from JSON serialized data."""
278285
cls._logger.warning(
279286
'Serialization through pydantic is still an experimental feature and might break in future releases.'
280287
)
281-
return cls._from_model(cls.Model(**kwargs)) # type: ignore[arg-type]
288+
return cls.from_model(cls.Model(**kwargs)) # type: ignore[arg-type]
282289

283290
@classproperty
284291
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: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,28 +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(
115+
uuid: Optional[str] = MetadataField(
116+
None,
116117
description='The UUID of the group',
117118
is_attribute=False,
118119
exclude_to_orm=True,
119120
)
120-
type_string: str = MetadataField(
121+
type_string: Optional[str] = MetadataField(
122+
None,
121123
description='The type of the group',
122124
is_attribute=False,
123125
exclude_to_orm=True,
124126
)
125-
user: int = MetadataField(
127+
user: Optional[int] = MetadataField(
128+
None,
126129
description='The group owner',
127130
is_attribute=False,
128131
orm_class='core.user',
129132
orm_to_model=lambda group, _: cast('Group', group).user.pk,
130133
)
131134
time: Optional[datetime.datetime] = MetadataField(
132-
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,
133148
)
134-
label: str = MetadataField(description='The group label', is_attribute=False)
135-
description: Optional[str] = MetadataField(description='The group description', is_attribute=False)
136149
extras: Optional[dict[str, Any]] = MetadataField(
150+
None,
137151
description='The group extras',
138152
is_attribute=False,
139153
is_subscriptable=True,
@@ -173,7 +187,11 @@ def __init__(
173187
type_check(user, users.User)
174188

175189
model = backend.groups.create(
176-
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,
177195
)
178196
super().__init__(model)
179197
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)