mosaic-python-client 0.2.0__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.
@@ -0,0 +1,290 @@
1
+ Metadata-Version: 2.4
2
+ Name: mosaic-python-client
3
+ Version: 0.2.0
4
+ Summary: Zeep client for interacting with the SOAP interfaces provided by E-PIX and gPAS of the MOSAIC suite by the THS Greifswald.
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Keywords: client,soap,e-pix,epix,gpas,mosaic,zeep
8
+ Author: Maximilian Jugl
9
+ Requires-Python: >=3.11,<4
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Healthcare Industry
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Natural Language :: English
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
25
+ Classifier: Typing :: Typed
26
+ Requires-Dist: marshmallow (>=4.3.1,<5.0.0)
27
+ Requires-Dist: zeep (>=4.3.3,<5.0.0)
28
+ Project-URL: Repository, https://github.com/ul-mds/mosaic-python-client
29
+ Description-Content-Type: text/markdown
30
+
31
+ [![PyPI](https://img.shields.io/pypi/v/mosaic-python-client?cacheSeconds=0&label=PyPI)](https://pypi.org/project/mosaic-python-client/)
32
+ [![Python Versions](https://img.shields.io/pypi/pyversions/mosaic-python-client?cacheSeconds=0&label=Python)](https://pypi.org/project/mosaic-python-client/)
33
+ ![Code Coverage](https://img.shields.io/badge/Coverage-96%25-brightgreen.svg)
34
+ [![License](https://img.shields.io/pypi/l/mosaic-python-client?cacheSeconds=0&label=License)](https://pypi.org/project/mosaic-python-client/)
35
+ [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white)](https://conventionalcommits.org)
36
+
37
+ # MOSAIC Client
38
+
39
+ The `mosaic_client` library provides wrappers around the SOAP (**S**imple **O**bject **A**ccess **P**rotocol) interfaces
40
+ of E-PIX and gPAS by the [THS Greifswald](https://www.ths-greifswald.de/en/projekte/mosaic-project/).
41
+ The main entrypoints are `mosaic_client.EPIXClient` and `mosaic_client.GPASClient`, which are classes that simply take
42
+ the URLs to the WSDL endpoints of their respective services and expose functions to interact with these services.
43
+ Both client classes are implemented as [Zeep](https://docs.python-zeep.org/en/master/) clients while validation is
44
+ leveraged by [marshmallow](https://marshmallow.readthedocs.io/en/latest/).
45
+
46
+ ## Installation
47
+
48
+ To install the client, Python 3.11 or higher is required.
49
+
50
+ ```shell
51
+ pip install mosaic-python-client
52
+ ```
53
+
54
+ ## Getting started
55
+
56
+ Both E-PIX and gPAS client can be either instantiated by passing the WSDL URLs as strings or by passing your own
57
+ `zeep.Client` instance.
58
+ This section briefly demonstrates the usage of both clients.
59
+ For more information, have a look at the clients available methods and the respective docstrings.
60
+
61
+ ### E-PIX client
62
+
63
+ As a very first step, we need to instantiate the client.
64
+ `EPIXClient` expects a WSDL URL for the regular E-PIX service which enables operations like requesting an MPI
65
+ (**M**aster **P**atient **I**ndex) or deactivating/deleting identities and a WSDL URL for the management service which
66
+ leverages the management of domains.
67
+
68
+ ```python
69
+ from mosaic_client import EPIXClient
70
+
71
+ epix = EPIXClient(
72
+ client="http://localhost:8081/epix/epixService?wsdl",
73
+ management_client="http://localhost:8081/epix/epixManagementService?wsdl",
74
+ )
75
+ ```
76
+
77
+ To be able to request an MPI, we first need to create a data domain where the identity we want an MPI for is saved.
78
+ We name that new data domain `default`.
79
+ Note that E-PIX comes with a data source named `dummy_safe_source` and an identifier domain named `MPI` by default.
80
+
81
+ ```python
82
+ from mosaic_client import EPIXClient
83
+ from mosaic_client.epix import Domain
84
+
85
+ epix = EPIXClient(
86
+ client="http://localhost:8081/epix/epixService?wsdl",
87
+ management_client="http://localhost:8081/epix/epixManagementService?wsdl",
88
+ )
89
+
90
+ epix.add_domain(
91
+ domain=Domain(
92
+ name="default",
93
+ label="default",
94
+ mpi_domain=epix.get_identifier_domain(identifier_domain_name="MPI"),
95
+ safe_source=epix.get_source(source_name="dummy_safe_source"),
96
+ )
97
+ )
98
+ ```
99
+
100
+ Now, it is possible to request an MPI for an identity.
101
+ The default configuration of a data domain assumes that first and last name, gender and birthdate are required for new
102
+ identities.
103
+
104
+ ```python
105
+ from dataclasses import asdict
106
+ import datetime
107
+ import json
108
+ from mosaic_client import EPIXClient
109
+ from mosaic_client.epix import Identity
110
+
111
+ epix = EPIXClient(
112
+ client="http://localhost:8081/epix/epixService?wsdl",
113
+ management_client="http://localhost:8081/epix/epixManagementService?wsdl",
114
+ )
115
+
116
+ mpi_response = epix.request_mpi(
117
+ domain_name="default",
118
+ source_name="dummy_safe_source",
119
+ identity=Identity(
120
+ first_name="Foo",
121
+ last_name="Bar",
122
+ gender="f",
123
+ birth_date=datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC),
124
+ ),
125
+ )
126
+
127
+ print(json.dumps(asdict(mpi_response), indent=2, default=str))
128
+ ```
129
+
130
+ ```text
131
+ {
132
+ "match_status": "NO_MATCH",
133
+ "person": {
134
+ "deactivated": false,
135
+ "mpi_id": {
136
+ "value": "1001000000011",
137
+ "identifier_domain": {
138
+ "name": "MPI",
139
+ "label": "MPI",
140
+ "oid": "1.2.276.0.76.3.1.132.1.1.1",
141
+ "description": null,
142
+ "entry_date": "2026-09-29 15:57:00.492000+02:00",
143
+ "update_date": "2026-09-29 15:57:00.492000+02:00"
144
+ },
145
+ "entry_date": "2026-09-29 15:57:43.496000+02:00",
146
+ "description": "generated MPI id",
147
+ "fresh": false
148
+ },
149
+ "person_created": "2026-09-29 15:57:43.496000+02:00",
150
+ "person_id": 1,
151
+ "person_last_edited": "2026-09-29 15:57:43.496000+02:00",
152
+ "other_identities": [],
153
+ "reference_identity": {
154
+ "birth_date": "1970-01-01 01:00:00+01:00",
155
+ "birth_place": null,
156
+ "civil_status": null,
157
+ "degree": null,
158
+ "external_date": null,
159
+ "first_name": "Foo",
160
+ "gender": "F",
161
+ "identifiers": [],
162
+ "last_name": "Bar",
163
+ "middle_name": null,
164
+ "mother_tongue": null,
165
+ "mothers_maiden_name": null,
166
+ "nationality": null,
167
+ "vital_status": null,
168
+ "death_date": null,
169
+ "prefix": null,
170
+ "race": null,
171
+ "religion": null,
172
+ "suffix": null,
173
+ "value_1": null,
174
+ "value_2": null,
175
+ "value_3": null,
176
+ "value_4": null,
177
+ "value_5": null,
178
+ "value_6": null,
179
+ "value_7": null,
180
+ "value_8": null,
181
+ "value_9": null,
182
+ "value_10": null,
183
+ "contacts": [],
184
+ "deactivated": false,
185
+ "identity_created": "2026-09-29 15:57:43.496000+02:00",
186
+ "identity_id": 1,
187
+ "identity_last_edited": "2026-09-29 15:57:43.496000+02:00",
188
+ "identity_version": 1,
189
+ "person_id": 1,
190
+ "source": {
191
+ "name": "dummy_safe_source",
192
+ "description": "dummy because of the default-property \"safe_source\" in table domain",
193
+ "label": "dummy_safe_source",
194
+ "entry_date": "2026-09-29 15:57:00.531000+02:00",
195
+ "update_date": "2026-09-29 15:57:00.531000+02:00"
196
+ }
197
+ },
198
+ "domain_name": "default"
199
+ },
200
+ "mpi_error_code": null
201
+ }
202
+ ```
203
+
204
+ ### gPAS client
205
+
206
+ As before, we first need to instantiate the client.
207
+ `GPASClient` expects a WSDL URL for the regular gPAS service which enables operations like creating pseudonyms and a
208
+ WSDL URL for the domain service which leverages the management of domains.
209
+
210
+ ```python
211
+ from mosaic_client import GPASClient
212
+
213
+ gpas = GPASClient(
214
+ client="http://localhost:8080/gpas/gpasService?wsdl",
215
+ domain_client="http://localhost:8080/gpas/DomainService?wsdl",
216
+ )
217
+ ```
218
+
219
+ To be able to create pseudonyms, we first need to create a new domain since pseudonyms are organized in domains.
220
+ We name that new domain `default`.
221
+
222
+ ```python
223
+ from mosaic_client import GPASClient
224
+ from mosaic_client.gpas import Domain
225
+
226
+ gpas = GPASClient(
227
+ client="http://localhost:8080/gpas/gpasService?wsdl",
228
+ domain_client="http://localhost:8080/gpas/DomainService?wsdl",
229
+ )
230
+
231
+ gpas.add_domain(domain=Domain(name="default", label="default"))
232
+ ```
233
+
234
+ Now, we are able to create a new pseudonym for the value `value123`.
235
+
236
+ ```python
237
+ from mosaic_client import GPASClient
238
+
239
+ gpas = GPASClient(
240
+ client="http://localhost:8080/gpas/gpasService?wsdl",
241
+ domain_client="http://localhost:8080/gpas/DomainService?wsdl",
242
+ )
243
+
244
+ pseudonym = gpas.get_or_create_pseudonym_for(domain_name="default", value="value123")
245
+
246
+ print(f"Pseudonym: {pseudonym}")
247
+ ```
248
+
249
+ ```text
250
+ Pseudonym: 199799437
251
+ ```
252
+
253
+ ## Running tests
254
+
255
+ This library implements its tests via [pytest](https://docs.pytest.org/en/stable/).
256
+ In order to run integration tests, a running instance of E-PIX and gPAS are needed.
257
+ The first option is to spin up the services independently and direct pytest to it.
258
+ Have a look at the provided docker compose file `./tests/docker/docker-compose.yml` for a quick solution.
259
+ For more sophisticated deployments, please read the documentation of
260
+ [E-PIX](https://www.ths-greifswald.de/forscher/e-pix/) and [gPAS](https://www.ths-greifswald.de/forscher/gpas/).
261
+ Alternatively, pytest can start Docker test-containers for the duration of the test run.
262
+ Since containers are started and stopped for each run individually, such a test run takes more time.
263
+
264
+ The following table shows all available options to configure pytest.
265
+
266
+ | **Environment variable** | **Description** | **Default** |
267
+ |----------------------------------------------|-----------------------------------------------------|-------------|
268
+ | PYTEST_USE_TESTCONTAINERS | Whether pytest should use test-containers or not | 0 |
269
+ | PYTEST_EPIX_WSDL_URL<sup>1)</sup> | WSDL URL for the E-PIX service | |
270
+ | PYTEST_EPIX_MANAGEMENT_WSDL_URL<sup>1)</sup> | WSDL URL for the E-PIX management service | |
271
+ | PYTEST_EPIX_IMAGE_TAG<sup>2)</sup> | E-PIX image tag that is used for the test-container | latest |
272
+ | PYTEST_GPAS_WSDL_URL<sup>1)</sup> | WSDL URL for the gPAS service | |
273
+ | PYTEST_GPAS_DOMAIN_WSDL_URL<sup>1)</sup> | WSDL URL for the gPAS domain service | |
274
+ | PYTEST_GPAS_IMAGE_TAG<sup>2)</sup> | gPAS image tag that is used for the test-container | latest |
275
+
276
+ <sup>1)</sup> Only needed, if `PYTEST_USE_TESTCONTAINERS` is set to `0`.<br>
277
+ <sup>2)</sup> Only used, if `PYTEST_USE_TESTCONTAINERS` is set to `1`.
278
+
279
+ It is possible to define these variables in a `.env.test` file.
280
+ The `.env.example` file provides a template.
281
+ You can copy the content of `.env.example` to directly get started with pytest using test-containers.
282
+
283
+ ```shell
284
+ cp .env.example .env.test
285
+ ```
286
+
287
+ ## License
288
+
289
+ MIT.
290
+
@@ -0,0 +1,14 @@
1
+ mosaic_client/__init__.py,sha256=QYsFJ_Ly4MWyXpp-w0JE61-RrTNSRIWGZbgnQ8EDQfk,434
2
+ mosaic_client/epix/__init__.py,sha256=bURaboNs-nnwQxa-Sbp4EHNtLBvewqSCrka1GmL0P3o,2453
3
+ mosaic_client/epix/client.py,sha256=v62MSeUlOXIJ-vmOxGMf2OZiH0oIRMsKa2UnTFcJrxU,29664
4
+ mosaic_client/epix/models.py,sha256=6RSrIkGArmJNTz8OduL1r3u9J9S6RBJazJt__B2vnGo,13485
5
+ mosaic_client/epix/schemas.py,sha256=gEGNCilbJbcm4Yl7DOfiJCkm-aIiMwNfrsS1DNrBPvU,14357
6
+ mosaic_client/gpas/__init__.py,sha256=X1raNdUnnIQNYf3OYygN6pd_b7sDIwuYkFprRj_zz48,381
7
+ mosaic_client/gpas/client.py,sha256=XqJ7MD5QCJWRzildfh69arskxg5lov9ZGSdGiaM-gvg,14135
8
+ mosaic_client/gpas/models.py,sha256=SM5dqbZPwwR6z7ydDbsgMdtSv6Xn1raTYB4GuVHULqg,2149
9
+ mosaic_client/gpas/schemas.py,sha256=0JI4C783KF6wmgsvtR6WawrozRLlMyle371aO4gqYCo,2464
10
+ mosaic_client/helpers.py,sha256=dGoZNAEFCLk1PY837lCquToG9Q6qaqV0-GjKD297VzM,3652
11
+ mosaic_python_client-0.2.0.dist-info/METADATA,sha256=zpL7fqxL_p2F_Gpn1Vs4WHKCCVR2lmah9cMhYdPFKBo,11015
12
+ mosaic_python_client-0.2.0.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
13
+ mosaic_python_client-0.2.0.dist-info/licenses/LICENSE,sha256=_pgCj-N77WvEWylNIUTs7Pd9rz_ScYYztpq_tCL7xhA,1118
14
+ mosaic_python_client-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.4.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 University Medical Center Leipzig, Dept. Medical Data Science
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.