The mosaic_client library provides wrappers around the SOAP (Simple Object Access Protocol) interfaces
of E-PIX and gPAS by the THS Greifswald.
The main entrypoints are mosaic_client.EPIXClient and mosaic_client.GPASClient, which are classes that simply take
the URLs to the WSDL endpoints of their respective services and expose functions to interact with these services.
Both client classes are implemented as Zeep clients while validation is
leveraged by marshmallow.
To install the client, Python 3.11 or higher is required.
pip install mosaic-python-clientBoth E-PIX and gPAS client can be either instantiated by passing the WSDL URLs as strings or by passing your own
zeep.Client instance.
This section briefly demonstrates the usage of both clients.
For more information, have a look at the clients available methods and the respective docstrings.
As a very first step, we need to instantiate the client.
EPIXClient expects a WSDL URL for the regular E-PIX service which enables operations like requesting an MPI
(Master Patient Index) or deactivating/deleting identities and a WSDL URL for the management service which
leverages the management of domains.
from mosaic_client import EPIXClient
epix = EPIXClient(
client="http://localhost:8081/epix/epixService?wsdl",
management_client="http://localhost:8081/epix/epixManagementService?wsdl",
)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.
We name that new data domain default.
Note that E-PIX comes with a data source named dummy_safe_source and an identifier domain named MPI by default.
from mosaic_client import EPIXClient
from mosaic_client.epix import Domain
epix = EPIXClient(
client="http://localhost:8081/epix/epixService?wsdl",
management_client="http://localhost:8081/epix/epixManagementService?wsdl",
)
epix.add_domain(
domain=Domain(
name="default",
label="default",
mpi_domain=epix.get_identifier_domain(identifier_domain_name="MPI"),
safe_source=epix.get_source(source_name="dummy_safe_source"),
)
)Now, it is possible to request an MPI for an identity. The default configuration of a data domain assumes that first and last name, gender and birthdate are required for new identities.
from dataclasses import asdict
import datetime
import json
from mosaic_client import EPIXClient
from mosaic_client.epix import Identity
epix = EPIXClient(
client="http://localhost:8081/epix/epixService?wsdl",
management_client="http://localhost:8081/epix/epixManagementService?wsdl",
)
mpi_response = epix.request_mpi(
domain_name="default",
source_name="dummy_safe_source",
identity=Identity(
first_name="Foo",
last_name="Bar",
gender="f",
birth_date=datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC),
),
)
print(json.dumps(asdict(mpi_response), indent=2, default=str)){
"match_status": "NO_MATCH",
"person": {
"deactivated": false,
"mpi_id": {
"value": "1001000000011",
"identifier_domain": {
"name": "MPI",
"label": "MPI",
"oid": "1.2.276.0.76.3.1.132.1.1.1",
"description": null,
"entry_date": "2026-09-29 15:57:00.492000+02:00",
"update_date": "2026-09-29 15:57:00.492000+02:00"
},
"entry_date": "2026-09-29 15:57:43.496000+02:00",
"description": "generated MPI id",
"fresh": false
},
"person_created": "2026-09-29 15:57:43.496000+02:00",
"person_id": 1,
"person_last_edited": "2026-09-29 15:57:43.496000+02:00",
"other_identities": [],
"reference_identity": {
"birth_date": "1970-01-01 01:00:00+01:00",
"birth_place": null,
"civil_status": null,
"degree": null,
"external_date": null,
"first_name": "Foo",
"gender": "F",
"identifiers": [],
"last_name": "Bar",
"middle_name": null,
"mother_tongue": null,
"mothers_maiden_name": null,
"nationality": null,
"vital_status": null,
"death_date": null,
"prefix": null,
"race": null,
"religion": null,
"suffix": null,
"value_1": null,
"value_2": null,
"value_3": null,
"value_4": null,
"value_5": null,
"value_6": null,
"value_7": null,
"value_8": null,
"value_9": null,
"value_10": null,
"contacts": [],
"deactivated": false,
"identity_created": "2026-09-29 15:57:43.496000+02:00",
"identity_id": 1,
"identity_last_edited": "2026-09-29 15:57:43.496000+02:00",
"identity_version": 1,
"person_id": 1,
"source": {
"name": "dummy_safe_source",
"description": "dummy because of the default-property \"safe_source\" in table domain",
"label": "dummy_safe_source",
"entry_date": "2026-09-29 15:57:00.531000+02:00",
"update_date": "2026-09-29 15:57:00.531000+02:00"
}
},
"domain_name": "default"
},
"mpi_error_code": null
}
As before, we first need to instantiate the client.
GPASClient expects a WSDL URL for the regular gPAS service which enables operations like creating pseudonyms and a
WSDL URL for the domain service which leverages the management of domains.
from mosaic_client import GPASClient
gpas = GPASClient(
client="http://localhost:8080/gpas/gpasService?wsdl",
domain_client="http://localhost:8080/gpas/DomainService?wsdl",
)To be able to create pseudonyms, we first need to create a new domain since pseudonyms are organized in domains.
We name that new domain default.
from mosaic_client import GPASClient
from mosaic_client.gpas import Domain
gpas = GPASClient(
client="http://localhost:8080/gpas/gpasService?wsdl",
domain_client="http://localhost:8080/gpas/DomainService?wsdl",
)
gpas.add_domain(domain=Domain(name="default", label="default"))Now, we are able to create a new pseudonym for the value value123.
from mosaic_client import GPASClient
gpas = GPASClient(
client="http://localhost:8080/gpas/gpasService?wsdl",
domain_client="http://localhost:8080/gpas/DomainService?wsdl",
)
pseudonym = gpas.get_or_create_pseudonym_for(domain_name="default", value="value123")
print(f"Pseudonym: {pseudonym}")Pseudonym: 199799437
This library implements its tests via pytest.
In order to run integration tests, a running instance of E-PIX and gPAS are needed.
The first option is to spin up the services independently and direct pytest to it.
Have a look at the provided docker compose file ./tests/docker/docker-compose.yml for a quick solution.
For more sophisticated deployments, please read the documentation of
E-PIX and gPAS.
Alternatively, pytest can start Docker test-containers for the duration of the test run.
Since containers are started and stopped for each run individually, such a test run takes more time.
The following table shows all available options to configure pytest.
| Environment variable | Description | Default |
|---|---|---|
| PYTEST_USE_TESTCONTAINERS | Whether pytest should use test-containers or not | 0 |
| PYTEST_EPIX_WSDL_URL1) | WSDL URL for the E-PIX service | |
| PYTEST_EPIX_MANAGEMENT_WSDL_URL1) | WSDL URL for the E-PIX management service | |
| PYTEST_EPIX_IMAGE_TAG2) | E-PIX image tag that is used for the test-container | latest |
| PYTEST_GPAS_WSDL_URL1) | WSDL URL for the gPAS service | |
| PYTEST_GPAS_DOMAIN_WSDL_URL1) | WSDL URL for the gPAS domain service | |
| PYTEST_GPAS_IMAGE_TAG2) | gPAS image tag that is used for the test-container | latest |
1) Only needed, if PYTEST_USE_TESTCONTAINERS is set to 0.
2) Only used, if PYTEST_USE_TESTCONTAINERS is set to 1.
It is possible to define these variables in a .env.test file.
The .env.example file provides a template.
You can copy the content of .env.example to directly get started with pytest using test-containers.
cp .env.example .env.testMIT.