matelab-python-sdk 0.2.0a3__py3-none-any.whl → 0.2.0a5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
matelab/__init__.py CHANGED
@@ -41,6 +41,7 @@ from matelab.domains.records import (
41
41
  DeletedRecordSummary,
42
42
  EncryptedRecordModules,
43
43
  ExportedRecord,
44
+ PublicRecord,
44
45
  PublicRecordRef,
45
46
  PublicRecordSummary,
46
47
  Record,
@@ -145,6 +146,7 @@ __all__ = [
145
146
  "NotebookShareRef",
146
147
  "NotebookShares",
147
148
  "NotebookSummary",
149
+ "PublicRecord",
148
150
  "PublicRecordRef",
149
151
  "PublicRecordSummary",
150
152
  "PublicationAuthorCandidate",
@@ -11,7 +11,7 @@ from pydantic import ConfigDict, Field, RootModel, SecretStr, StrictBool, Strict
11
11
 
12
12
  from matelab._wire_validation import WireModel
13
13
 
14
- OPENAPI_INFO_VERSION = "2026.10.1"
14
+ OPENAPI_INFO_VERSION = "2026.10.2"
15
15
 
16
16
 
17
17
  class ResponseEnvelope(WireModel):
@@ -1433,6 +1433,9 @@ class DeleteNotebookShareRequest(WireModel):
1433
1433
  class PublicRecordListRequest(WireModel):
1434
1434
  model_config = ConfigDict(extra="forbid")
1435
1435
  eln: Annotated[str, Field(min_length=1)]
1436
+ """
1437
+ Public directory name, not the source notebook name or numeric id.
1438
+ """
1436
1439
 
1437
1440
 
1438
1441
  class CreateRecordRequest(WireModel):
@@ -2047,9 +2050,21 @@ class DeleteRecordsRequest(WireModel):
2047
2050
 
2048
2051
  class PublicRecordItem(WireModel):
2049
2052
  id: Annotated[StrictInt, Field(ge=1)]
2053
+ """
2054
+ Public association row identifier; not the record id accepted by readRecord.
2055
+ """
2050
2056
  item_id: Annotated[StrictInt, Field(ge=1)]
2057
+ """
2058
+ Source record identifier; pass as readRecord query id together with this row's eln_id.
2059
+ """
2051
2060
  eln_id: Annotated[StrictInt, Field(ge=1)]
2061
+ """
2062
+ Source notebook identifier; pass as readRecord query eln, not the public directory id.
2063
+ """
2052
2064
  uid: Annotated[str | None, Field(...)]
2065
+ """
2066
+ Nullable UID copied into the association; not required for the numeric readRecord selector.
2067
+ """
2053
2068
  title: Annotated[str | None, Field(...)]
2054
2069
  comm: Annotated[str | None, Field(...)]
2055
2070
  locked: StrictBool
@@ -320,6 +320,8 @@ class RecordSearchMatch:
320
320
 
321
321
  @dataclass(frozen=True, slots=True)
322
322
  class PublicRecordRef:
323
+ """Public association metadata with the paired source IDs used for body reads."""
324
+
323
325
  public_entry_id: int
324
326
  source_notebook_id: int
325
327
  source_record_id: int
@@ -587,6 +589,20 @@ class EncryptedRecordModules:
587
589
  extra: Mapping[str, JsonValue] = field(default_factory=dict[str, JsonValue], repr=False)
588
590
 
589
591
 
592
+ @dataclass(frozen=True, slots=True)
593
+ class PublicRecord:
594
+ """Current content read through a public record association."""
595
+
596
+ source: PublicRecordRef
597
+ title: str | None
598
+ keywords: tuple[str, ...] | None
599
+ modules: tuple[dict[str, JsonValue], ...]
600
+ template_id: int | None
601
+ modified_at_ms: int
602
+ author_name: str | None
603
+ encrypted_modules: EncryptedRecordModules | None = None
604
+
605
+
590
606
  @dataclass(frozen=True, slots=True)
591
607
  class Record:
592
608
  """Current or historical record content with safe attachment references."""
@@ -732,6 +748,18 @@ def _contains_native_attachment_reference(value: JsonValue) -> bool:
732
748
  return False
733
749
 
734
750
 
751
+ def _record_modules(
752
+ response: wire_models.ItemViewResponse,
753
+ ) -> tuple[tuple[dict[str, JsonValue], ...], EncryptedRecordModules | None]:
754
+ if isinstance(response.modules, wire_models.EncryptedRecordModules):
755
+ return (), EncryptedRecordModules(
756
+ ciphertext=response.modules.data,
757
+ algorithm=response.modules.encrypt,
758
+ extra=MappingProxyType(cast(dict[str, JsonValue], response.modules.model_extra or {})),
759
+ )
760
+ return tuple(item.model_dump(mode="json") for item in response.modules), None
761
+
762
+
735
763
  def _record_attachment_refs(
736
764
  modules: Sequence[Mapping[str, JsonValue]], *, source: RecordLocator, version: RecordVersionRef | None
737
765
  ) -> tuple[RecordAttachmentRef, ...]:
@@ -1708,6 +1736,28 @@ class Records:
1708
1736
  )
1709
1737
  return await self._transport.stream(_DOWNLOAD_COMMENT_ATTACHMENT, payload=request, byte_range=byte_range)
1710
1738
 
1739
+ async def read_public(self, source: PublicRecordRef) -> PublicRecord:
1740
+ """Read current content using a public entry's source notebook and record IDs."""
1741
+ request = validate_request(
1742
+ wire_models.ReadRecordParametersQuery,
1743
+ {"eln": source.source_notebook_id, "id": source.source_record_id, "version": 0},
1744
+ "Public record source identity does not satisfy the Integration Contract.",
1745
+ )
1746
+ response = await self._transport.request(_READ_RECORD, payload=request)
1747
+ modules, encrypted_modules = _record_modules(response)
1748
+ return PublicRecord(
1749
+ source=source,
1750
+ title=response.title,
1751
+ keywords=tuple(response.keywords) if response.keywords is not None else None,
1752
+ modules=modules,
1753
+ template_id=response.template_id,
1754
+ modified_at_ms=response.datetime_modify,
1755
+ author_name=response.username.root
1756
+ if response.username is not None and isinstance(response.username.root, str)
1757
+ else None,
1758
+ encrypted_modules=encrypted_modules,
1759
+ )
1760
+
1711
1761
  async def read(self, source: RecordLocator | RecordVersionRef) -> Record:
1712
1762
  if isinstance(source, RecordVersionRef):
1713
1763
  version = source
@@ -1719,16 +1769,7 @@ class Records:
1719
1769
  record_source, version_id=version.version_id if version is not None else None
1720
1770
  )
1721
1771
 
1722
- encrypted_modules = None
1723
- if isinstance(response.modules, wire_models.EncryptedRecordModules):
1724
- encrypted_modules = EncryptedRecordModules(
1725
- ciphertext=response.modules.data,
1726
- algorithm=response.modules.encrypt,
1727
- extra=MappingProxyType(cast(dict[str, JsonValue], response.modules.model_extra or {})),
1728
- )
1729
- modules: tuple[dict[str, JsonValue], ...] = ()
1730
- else:
1731
- modules = tuple(item.model_dump(mode="json") for item in response.modules)
1772
+ modules, encrypted_modules = _record_modules(response)
1732
1773
  return Record(
1733
1774
  source=record_source,
1734
1775
  version=version,
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.5
2
+ Name: matelab-python-sdk
3
+ Version: 0.2.0a5
4
+ Summary: Reusable async Python client for the Matelab Integration Contract
5
+ Author: CMPDC, Institute of Physics, Chinese Academy of Sciences
6
+ License-Expression: Apache-2.0
7
+ License-File: LICENSE
8
+ License-File: NOTICE
9
+ Keywords: asyncio,electronic-lab-notebook,eln,matelab,sdk
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Framework :: AsyncIO
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: >=3.11
23
+ Requires-Dist: httpx2>=2.13.1
24
+ Requires-Dist: jsonschema>=4.26.0
25
+ Requires-Dist: pydantic>=2.13.5
26
+ Requires-Dist: typing-extensions>=4.16.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # matelab-python-sdk
30
+
31
+ Async Python client for the Matelab Integration Contract, with typed interfaces for authentication,
32
+ notebooks, records, attachments, cloud files, templates, and literature. Requires Python 3.11 or newer.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ uv add matelab-python-sdk
38
+ ```
39
+
40
+ Or use `python -m pip install matelab-python-sdk`.
41
+
42
+ ## Quick start
43
+
44
+ Replace the example credentials with your own:
45
+
46
+ ```python
47
+ import asyncio
48
+
49
+ from matelab import AsyncMatelab
50
+
51
+
52
+ async def main() -> None:
53
+ async with AsyncMatelab() as client:
54
+ await client.authenticate("user@example.org", "password")
55
+ notebooks = await client.notebooks.list()
56
+ for notebook in notebooks.owned:
57
+ print(notebook.ref)
58
+
59
+
60
+ asyncio.run(main())
61
+ ```
62
+
63
+ `AsyncMatelab()` uses `https://matelab.iphy.ac.cn/api` by default. Pass another API root as its first argument.
64
+
65
+ ## Documentation
66
+
67
+ - [API reference](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/api.md): Session persistence, errors, examples, and Provider limits.
68
+ - [Operation coverage](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/operation-coverage.yaml): supported operations.
69
+ - [Development and releases](https://github.com/tiannianzhu/matelab-python-sdk/blob/main/docs/development.md): checks, Provider smoke, versioning, and builds.
@@ -1,4 +1,4 @@
1
- matelab/__init__.py,sha256=C3CXRwVFMfaeyb55jl-MsNJtyUURKfuvVNlb_0mLxwM,5055
1
+ matelab/__init__.py,sha256=cJgzpDJiKJ9-XANRfRAjiRNoFVc3EovfxO-M2vu-HwU,5093
2
2
  matelab/_hashes.py,sha256=ImrLHx9wvcU6R-xGOrUCVDN_30sYA2UMn-NLwFrmFtU,163
3
3
  matelab/_transport.py,sha256=hdDxNsVnEYoZvhtkD4hQLzsVhlOTKsU4wvCdOpHVDuI,14863
4
4
  matelab/_wire_validation.py,sha256=Z_PpxwLS0S18kCC8ah6CmxUEjzvQ-iP8_XBOoQ46Wt4,4752
@@ -8,19 +8,19 @@ matelab/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
8
8
  matelab/session.py,sha256=D8i9uyAt32-bADotS-Lrb7RpmWRNYNIkIpZUijTYvy4,899
9
9
  matelab/streaming.py,sha256=36epH2josWk87Ors_JY0YsjNmtiq3NZa2iB9djLmlnY,3792
10
10
  matelab/_generated/__init__.py,sha256=jmGbXLLe3JorsGU7OUdF8iKGewFMRqkCzgyFAw7C15w,79
11
- matelab/_generated/models.py,sha256=TzVbDt0NRx8R9i6GvRe5PVZpRKBgVDg5miKl6oNWKxc,168733
11
+ matelab/_generated/models.py,sha256=U3SS83szvXoxBHfL8yMwYm5hKCZ52DOyhG_RuB8lmAA,169243
12
12
  matelab/domains/__init__.py,sha256=C34IWsGoCAwP7r6uYKJ79DJkToZyrZ4LWA87ufc1i0Q,65
13
13
  matelab/domains/_attachment_content.py,sha256=z26hwFpdgAk2x1w8EGe00XBLtJ3QFDX8BPS35Zc5SoE,1461
14
14
  matelab/domains/cloud_drive.py,sha256=EoqAYWvLVUfVOsic3g-TxsQEtAI3wTp5h0_vB79KpwY,10406
15
15
  matelab/domains/groups.py,sha256=H8-Da2WTm2Ui4m3Nr1bhMNMn7stbzbRa3EmpkTRmkBU,1300
16
16
  matelab/domains/literature.py,sha256=1KZPakc20ExorVV4gsBlcQJ9CspZY3KkdF77Z0WO5rk,27485
17
17
  matelab/domains/notebooks.py,sha256=_SvffaViECSEOkN5iwXtSv6El3fK2OYaR4RJvUCXfGk,13477
18
- matelab/domains/records.py,sha256=n-YfsBbGZOjj1j2keqjHyckHAJ6ZLfYB9J1bto__q9g,92322
18
+ matelab/domains/records.py,sha256=AWWw1_Zb67t1pGfXIR9jhvmwgJZ2Ug9Bw-Hs3XcEpwg,93984
19
19
  matelab/domains/templates.py,sha256=AsnayIc72J9pPTgcFpo8IfaM2a2C-acL6k8sdRH3rt8,17386
20
20
  matelab/domains/uploads.py,sha256=J9YveZIHq03YQuWwRZwayP1-tz7cE0F17RIgWByLcvc,7368
21
21
  matelab/domains/users.py,sha256=ZhlLzC_AadwYqNqxQrqkUBgIUqL7MJ6FgMyxwq-az8s,1445
22
- matelab_python_sdk-0.2.0a3.dist-info/METADATA,sha256=wdiO0RLndPd6fjQHtHo7WfW63JYLQYtey1BiVvZ4yeo,1086
23
- matelab_python_sdk-0.2.0a3.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
24
- matelab_python_sdk-0.2.0a3.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
25
- matelab_python_sdk-0.2.0a3.dist-info/licenses/NOTICE,sha256=Hc4scCJTof5VL3JCPI2aaewnnzCejIHUGuBVYBf-klc,98
26
- matelab_python_sdk-0.2.0a3.dist-info/RECORD,,
22
+ matelab_python_sdk-0.2.0a5.dist-info/METADATA,sha256=dcxCPmz1lx0uAD7ds1DgDHWF0zbltUv-Ox4GaIXwVos,2436
23
+ matelab_python_sdk-0.2.0a5.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
24
+ matelab_python_sdk-0.2.0a5.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
25
+ matelab_python_sdk-0.2.0a5.dist-info/licenses/NOTICE,sha256=Hc4scCJTof5VL3JCPI2aaewnnzCejIHUGuBVYBf-klc,98
26
+ matelab_python_sdk-0.2.0a5.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: matelab-python-sdk
3
- Version: 0.2.0a3
4
- Summary: Reusable async Python client for the Matelab Integration Contract
5
- Author: CMPDC, Institute of Physics, Chinese Academy of Sciences
6
- License-Expression: Apache-2.0
7
- License-File: LICENSE
8
- License-File: NOTICE
9
- Keywords: asyncio,electronic-lab-notebook,eln,matelab,sdk
10
- Classifier: Development Status :: 3 - Alpha
11
- Classifier: Framework :: AsyncIO
12
- Classifier: Operating System :: OS Independent
13
- Classifier: Programming Language :: Python :: 3
14
- Classifier: Programming Language :: Python :: 3 :: Only
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
18
- Classifier: Programming Language :: Python :: 3.14
19
- Classifier: Topic :: Scientific/Engineering
20
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
- Classifier: Typing :: Typed
22
- Requires-Python: >=3.11
23
- Requires-Dist: httpx2<3,>=2.13.1
24
- Requires-Dist: jsonschema<5,>=4.26.0
25
- Requires-Dist: pydantic<3,>=2.13.5
26
- Requires-Dist: typing-extensions<5,>=4.16.0