mex.backend package¶
Subpackages¶
- mex.backend.auxiliary package
- mex.backend.cache package
- Submodules
- mex.backend.cache.base module
BaseCacheConnectorBaseCacheConnector._delete()BaseCacheConnector._flush()BaseCacheConnector._get()BaseCacheConnector._info()BaseCacheConnector._set()BaseCacheConnector.delete_value()BaseCacheConnector.flush()BaseCacheConnector.get_status()BaseCacheConnector.get_value()BaseCacheConnector.metrics()BaseCacheConnector.set_value()
- mex.backend.cache.memory module
- mex.backend.cache.registry module
- mex.backend.cache.valkey module
- Module contents
BaseCacheConnectorBaseCacheConnector._delete()BaseCacheConnector._flush()BaseCacheConnector._get()BaseCacheConnector._info()BaseCacheConnector._set()BaseCacheConnector.delete_value()BaseCacheConnector.flush()BaseCacheConnector.get_status()BaseCacheConnector.get_value()BaseCacheConnector.metrics()BaseCacheConnector.set_value()
MemoryCacheConnectorValkeyCacheConnectorget_cache_connector()register_cache_connector()
- mex.backend.extracted package
- mex.backend.graph package
- Submodules
- mex.backend.graph.connector module
GraphConnectorGraphConnector.__init__()GraphConnector._check_connectivity_and_authentication()GraphConnector._check_merge_preconditions_tx()GraphConnector._fetch_extracted_or_rule_items()GraphConnector._init_driver()GraphConnector._merge_items_tx()GraphConnector._run_ingest_in_transaction()GraphConnector._seed_constraints()GraphConnector._seed_data()GraphConnector._seed_indices()GraphConnector.close()GraphConnector.commit()GraphConnector.delete_item()GraphConnector.delete_rule_set()GraphConnector.exists_item()GraphConnector.fetch_extracted_items()GraphConnector.fetch_identities()GraphConnector.fetch_merged_items()GraphConnector.fetch_rule_items()GraphConnector.fetch_rule_set_response()GraphConnector.flush()GraphConnector.flush_data()GraphConnector.ingest_items()GraphConnector.merge_items()GraphConnector.pick_anchor_filter()
get_graph_status()
- mex.backend.graph.constants module
- mex.backend.graph.exceptions module
- mex.backend.graph.models module
- mex.backend.graph.query module
- mex.backend.graph.transform module
- Module contents
- mex.backend.identity package
- mex.backend.ingest package
- mex.backend.ldap package
- mex.backend.merged package
- mex.backend.preview package
- mex.backend.publishable_merged package
- mex.backend.rules package
- mex.backend.seed package
- mex.backend.system package
- mex.backend.testing package
Submodules¶
mex.backend.exceptions module¶
- exception mex.backend.exceptions.BackendError¶
Bases:
MExErrorBase backend error that offer details on underlying pydantic errors.
- errors() list[ErrorDetails]¶
Details about underlying pydantic errors.
- is_retryable() bool¶
Whether the error is retryable.
- class mex.backend.exceptions.DebuggingInfo(*, errors: list[dict[str, Any]], scope: DebuggingScope)¶
Bases:
BaseModelDebugging information for error responses.
- errors: list[dict[str, Any]]¶
- model_config = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- scope: DebuggingScope¶
- class mex.backend.exceptions.DebuggingScope(*, http_version: str, method: str, path: str, path_params: dict[str, Any], query_string: str, scheme: str)¶
Bases:
BaseModelScope for debugging info of error responses.
- http_version: str¶
- method: str¶
- model_config = {'extra': 'ignore'}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- path: str¶
- path_params: dict[str, Any]¶
- query_string: str¶
- scheme: str¶
- class mex.backend.exceptions.DetailedError(*args, **kwargs)¶
Bases:
ProtocolProtocol for errors that offer details.
- errors() list[ErrorDetails]¶
Details about each underlying error.
- class mex.backend.exceptions.ErrorResponse(*, message: str, debug: DebuggingInfo)¶
Bases:
BaseModelResponse model for user and system errors.
- debug: DebuggingInfo¶
- message: str¶
- model_config = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- mex.backend.exceptions.handle_detailed_error(request: Request, exc: Exception) Response¶
Handle detailed errors and provide debugging info.
- mex.backend.exceptions.handle_uncaught_exception(request: Request, exc: Exception) Response¶
Handle uncaught errors and provide debugging info.
mex.backend.helpers module¶
- mex.backend.helpers.build_reference_filters(reference_field: ReferenceFieldName | None = None, referenced_identifier: Sequence[Identifier] | None = None, stable_target_id: Identifier | None = None) list[ReferenceFilter]¶
Convert deprecated reference parameters to ReferenceFilter objects.
- Parameters:
reference_field – Deprecated query parameter for reference field name
referenced_identifier – Deprecated query parameter for identifiers
stable_target_id – Deprecated query parameter for stableTargetId
- Raises:
HTTPException – If only one of the two parameters is provided
- Returns:
list with a single ReferenceFilter, or empty list if neither parameter provided
mex.backend.logging module¶
mex.backend.main module¶
- mex.backend.main.lifespan(_: FastAPI) AsyncIterator[None]¶
Async context manager to execute startup and teardown of the FastAPI app.
mex.backend.models module¶
- class mex.backend.models.APIKeyDatabase(*, read: list[APIKey] = [], write: list[APIKey] = [])¶
Bases:
BaseModelA lookup from access level to list of allowed APIKeys.
- model_config = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class mex.backend.models.ReferenceFilter(*, field: ReferenceFieldName, identifiers: Annotated[list[Identifier | None], MinLen(min_length=1), MaxLen(max_length=100)])¶
Bases:
BaseModelReference filter definition with a field and list of identifiers.
- field: ReferenceFieldName¶
- identifiers: Annotated[list[Identifier | None], FieldInfo(annotation=NoneType, required=True, metadata=[MinLen(min_length=1), MaxLen(max_length=100)])]¶
- model_config = {}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
mex.backend.security module¶
- mex.backend.security.has_read_access(api_key: ~typing.Annotated[str, ~fastapi.params.Depends(dependency=<fastapi.security.api_key.APIKeyHeader object at 0x7ff354accc20>, use_cache=True, scope=None)]) None¶
Verify if api key has read access or write access.
- Raises:
HTTPException if APIKey has no read access. –
- Parameters:
api_key – the API key
- mex.backend.security.has_write_access(api_key: ~typing.Annotated[str, ~fastapi.params.Depends(dependency=<fastapi.security.api_key.APIKeyHeader object at 0x7ff354accc20>, use_cache=True, scope=None)]) None¶
Verify if provided api key has write access.
- Raises:
HTTPException if APIKey has no write access. –
- Parameters:
api_key – the API key
- mex.backend.security.is_ldap_authenticated(credentials: ~typing.Annotated[~fastapi.security.http.HTTPBasicCredentials, ~fastapi.params.Depends(dependency=<fastapi.security.http.HTTPBasic object at 0x7ff354accd70>, use_cache=True, scope=None)]) str¶
Authenticate against LDAP.
- Raises:
HTTPException if credentials have no LDAP write access. –
- Parameters:
credentials – username and password
- Returns:
username
mex.backend.settings module¶
- class mex.backend.settings.BackendSettings(_env_file: Path | str | Sequence[Path | str] | None = PosixPath('.'), _env_file_encoding: str | None = None, _env_nested_delimiter: str | None = None, _secrets_dir: str | Path | None = None, *, MEX_DEBUG: bool = False, MEX_SINK: list[Sink] = [Sink.NDJSON], MEX_ASSETS_DIR: Path = PosixPath('/home/runner/work/mex-backend/mex-backend/assets'), MEX_OPS_DIR: Path = PosixPath('/home/runner/work/mex-backend/mex-backend/ops'), MEX_WORK_DIR: Path = PosixPath('/home/runner/work/mex-backend/mex-backend'), MEX_IDENTITY_PROVIDER: IdentityProvider = IdentityProvider.GRAPH, MEX_ASSETS_CONNECTOR: AssetsConnectorType = AssetsConnectorType.FILESYSTEM, MEX_BACKEND_API_URL: HttpUrl = HttpUrl('http://localhost:8080/'), MEX_BACKEND_API_KEY: SecretStr = SecretStr('**********'), MEX_BACKEND_API_PARALLELIZATION: int = 1, MEX_BACKEND_API_CHUNK_SIZE: int = 25, MEX_VERIFY_SESSION: bool | OpsPath = True, MEX_ORGANIGRAM_PATH: str = 'raw-data/organigram/organizational_units.json', MEX_PRIMARY_SOURCES_PATH: str = 'raw-data/primary-sources/primary-sources.json', MEX_LDAP_URL: SecretStr = SecretStr('**********'), MEX_LDAP_SEARCH_BASE: str = 'dc=ldapmock,dc=local', MEX_WIKI_API_URL: HttpUrl = HttpUrl('http://wikidata/'), MEX_WEB_USER_AGENT: str = 'rki/mex', MEX_ORCID_API_URL: HttpUrl = HttpUrl('https://orcid/'), MEX_BACKEND_HOST: Annotated[str, MinLen(min_length=1), MaxLen(max_length=250)] = 'localhost', MEX_BACKEND_PORT: Annotated[int, Gt(gt=0), Lt(lt=65536)] = 8080, MEX_BACKEND_ROOT_PATH: str = '', MEX_BACKEND_GRACEFUL_SHUTDOWN_TIMEOUT: Annotated[int, Gt(gt=0)] = 30, MEX_GRAPH_URL: str = 'neo4j://localhost:7687', MEX_GRAPH_NAME: str = 'neo4j', MEX_GRAPH_USER: SecretStr = SecretStr('**********'), MEX_GRAPH_PASSWORD: SecretStr = SecretStr('**********'), MEX_GRAPH_MAX_CONNECTION_POOL_SIZE: Annotated[int, Gt(gt=0)] = 100, MEX_GRAPH_TX_TIMEOUT: int | float = 15.0, MEX_GRAPH_SESSION_TIMEOUT: int | float = 45.0, MEX_BACKEND_NON_MERGEABLE_TYPES: list[MergedType] = [MergedType.MERGED_CONSENT, MergedType.MERGED_PERSON], MEX_BACKEND_API_KEY_DATABASE: APIKeyDatabase = APIKeyDatabase(read=[], write=[]), MEX_BACKEND_CACHE_CONNECTOR: CacheConnectorType = CacheConnectorType.MEMORY, MEX_BACKEND_VALKEY_URL: SecretStr = SecretStr('**********'))¶
Bases:
BaseSettingsSettings definition for the backend server.
Validate that a shared cache is configured if parallelization is > 1.
Rationale: We cache identities to make sure that multiple calls for getting an identifier receive the same identifier, even if the item with this identifier is not yet ingested in our database. If we use multiple backend instances, they must use a shared cache for storing these identities. The only shared cache is valkey, hence we make sure that valkey is configured if parallelization > 1.
- assert_identity_provider_is_graph() Self¶
Validate that the graph identity provider is configured.
Rationale: The backend is the service that owns the graph database and is therefore the only component that can assign and resolve identities in it. Any other provider would either delegate back to the backend itself (BACKEND) or hand out identifiers that are lost on restart (MEMORY), so we make sure the backend always uses the graph identity provider.
- backend_api_key_database: APIKeyDatabase¶
- backend_graceful_shutdown_timeout: int¶
- backend_host: str¶
- backend_port: int¶
- backend_root_path: str¶
- cache_connector: CacheConnectorType¶
- graph_db: str¶
- graph_max_connection_pool_size: int¶
- graph_password: SecretStr¶
- graph_session_timeout: int | float¶
- graph_tx_timeout: int | float¶
- graph_url: str¶
- graph_user: SecretStr¶
- identity_provider: IdentityProvider¶
- model_config = {'arbitrary_types_allowed': True, 'case_sensitive': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_exit_on_error': True, 'cli_flag_prefix_char': '-', 'cli_hide_none_type': False, 'cli_ignore_unknown_args': False, 'cli_implicit_flags': False, 'cli_kebab_case': False, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_prefix': '', 'cli_prog_name': None, 'cli_shortcuts': None, 'cli_show_env_vars': False, 'cli_use_class_docs_for_groups': False, 'enable_decoding': True, 'env_file': '.env', 'env_file_encoding': 'utf-8', 'env_ignore_empty': False, 'env_nested_delimiter': '__', 'env_nested_max_split': None, 'env_parse_enums': None, 'env_parse_none_str': None, 'env_prefix': 'mex_', 'env_prefix_target': 'variable', 'extra': 'ignore', 'json_file': None, 'json_file_encoding': None, 'nested_model_default_partial_update': False, 'populate_by_name': True, 'protected_namespaces': ('model_validate', 'model_dump', 'settings_customise_sources'), 'secrets_dir': None, 'toml_file': None, 'validate_assignment': True, 'validate_by_alias': True, 'validate_by_name': True, 'validate_default': True, 'yaml_config_section': None, 'yaml_file': None, 'yaml_file_encoding': None}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- non_mergeable_types: list[MergedType]¶
- valkey_url: SecretStr¶
mex.backend.types module¶
- class mex.backend.types.APIKey(secret_value: SecretType)¶
Bases:
SecretStrAn API Key used for authenticating and authorizing a client.
- class mex.backend.types.AccessLevel(*values)¶
Bases:
EnumEnum of access level.
- READ = 'read'¶
- WRITE = 'write'¶
- class mex.backend.types.CacheConnectorType(*values)¶
Bases:
EnumChoice of available cache connectors.
- MEMORY = 'memory'¶
- VALKEY = 'valkey'¶
- class mex.backend.types.DynamicStrEnum(name: str, bases: tuple[type], dct: EnumDict)¶
Bases:
EnumTypeMetaclass to dynamically populate an enumeration from a list of strings.
- class mex.backend.types.ExtractedType(*values)¶
Bases:
EnumEnumeration of possible types for extracted items.
- EXTRACTED_ACCESS_PLATFORM = 'ExtractedAccessPlatform'¶
- EXTRACTED_ACTIVITY = 'ExtractedActivity'¶
- EXTRACTED_BIBLIOGRAPHIC_RESOURCE = 'ExtractedBibliographicResource'¶
- EXTRACTED_CONSENT = 'ExtractedConsent'¶
- EXTRACTED_CONTACT_POINT = 'ExtractedContactPoint'¶
- EXTRACTED_DISTRIBUTION = 'ExtractedDistribution'¶
- EXTRACTED_ORGANIZATION = 'ExtractedOrganization'¶
- EXTRACTED_ORGANIZATIONAL_UNIT = 'ExtractedOrganizationalUnit'¶
- EXTRACTED_PERSON = 'ExtractedPerson'¶
- EXTRACTED_PRIMARY_SOURCE = 'ExtractedPrimarySource'¶
- EXTRACTED_RESOURCE = 'ExtractedResource'¶
- EXTRACTED_RESOURCE_SERIES = 'ExtractedResourceSeries'¶
- EXTRACTED_VARIABLE = 'ExtractedVariable'¶
- EXTRACTED_VARIABLE_GROUP = 'ExtractedVariableGroup'¶
- class mex.backend.types.MergedType(*values)¶
Bases:
EnumEnumeration of possible types for merged items.
- MERGED_ACCESS_PLATFORM = 'MergedAccessPlatform'¶
- MERGED_ACTIVITY = 'MergedActivity'¶
- MERGED_BIBLIOGRAPHIC_RESOURCE = 'MergedBibliographicResource'¶
- MERGED_CONSENT = 'MergedConsent'¶
- MERGED_CONTACT_POINT = 'MergedContactPoint'¶
- MERGED_DISTRIBUTION = 'MergedDistribution'¶
- MERGED_ORGANIZATION = 'MergedOrganization'¶
- MERGED_ORGANIZATIONAL_UNIT = 'MergedOrganizationalUnit'¶
- MERGED_PERSON = 'MergedPerson'¶
- MERGED_PRIMARY_SOURCE = 'MergedPrimarySource'¶
- MERGED_RESOURCE = 'MergedResource'¶
- MERGED_RESOURCE_SERIES = 'MergedResourceSeries'¶
- MERGED_VARIABLE = 'MergedVariable'¶
- MERGED_VARIABLE_GROUP = 'MergedVariableGroup'¶
- class mex.backend.types.ReferenceFieldName(*values)¶
Bases:
EnumEnumeration of possible field names that contain references.
- ACCESS_PLATFORM = 'accessPlatform'¶
- ACCESS_SERVICE = 'accessService'¶
- AFFILIATION = 'affiliation'¶
- ANALYTICS = 'analytics'¶
- BELONGS_TO = 'belongsTo'¶
- CONTACT = 'contact'¶
- CONTAINED_BY = 'containedBy'¶
- CONTRIBUTING_UNIT = 'contributingUnit'¶
- CONTRIBUTOR = 'contributor'¶
- CREATOR = 'creator'¶
- DISTRIBUTION = 'distribution'¶
- EDITOR = 'editor'¶
- EDITOR_OF_SERIES = 'editorOfSeries'¶
- EXTERNAL_ASSOCIATE = 'externalAssociate'¶
- EXTERNAL_PARTNER = 'externalPartner'¶
- FUNDER_OR_COMMISSIONER = 'funderOrCommissioner'¶
- HAD_PRIMARY_SOURCE = 'hadPrimarySource'¶
- HAS_DATA_SUBJECT = 'hasDataSubject'¶
- INVOLVED_PERSON = 'involvedPerson'¶
- INVOLVED_UNIT = 'involvedUnit'¶
- IN_SERIES = 'inSeries'¶
- IN_SERIES_FIRST_RESOURCE = 'inSeriesFirstResource'¶
- IN_SERIES_LAST_RESOURCE = 'inSeriesLastResource'¶
- IS_PART_OF = 'isPartOf'¶
- IS_PART_OF_ACTIVITY = 'isPartOfActivity'¶
- MEMBER_OF = 'memberOf'¶
- PARENT_UNIT = 'parentUnit'¶
- PUBLICATION = 'publication'¶
- PUBLISHER = 'publisher'¶
- RELATED_ACTIVITY = 'relatedActivity'¶
- RELATED_RESOURCE = 'relatedResource'¶
- RESPONSIBLE_UNIT = 'responsibleUnit'¶
- SAMPLE = 'sample'¶
- SOURCE = 'source'¶
- STABLE_TARGET_ID = 'stableTargetId'¶
- SUCCEEDS = 'succeeds'¶
- SUPERSEDED_BY = 'supersededBy'¶
- UNIT_IN_CHARGE = 'unitInCharge'¶
- UNIT_OF = 'unitOf'¶
- USED_IN = 'usedIn'¶
- WAS_GENERATED_BY = 'wasGeneratedBy'¶
- class mex.backend.types.RuleType(*values)¶
Bases:
EnumEnumeration of possible types for rule items.
- ADDITIVE_ACCESS_PLATFORM = 'AdditiveAccessPlatform'¶
- ADDITIVE_ACTIVITY = 'AdditiveActivity'¶
- ADDITIVE_BIBLIOGRAPHIC_RESOURCE = 'AdditiveBibliographicResource'¶
- ADDITIVE_CONSENT = 'AdditiveConsent'¶
- ADDITIVE_CONTACT_POINT = 'AdditiveContactPoint'¶
- ADDITIVE_DISTRIBUTION = 'AdditiveDistribution'¶
- ADDITIVE_ORGANIZATION = 'AdditiveOrganization'¶
- ADDITIVE_ORGANIZATIONAL_UNIT = 'AdditiveOrganizationalUnit'¶
- ADDITIVE_PERSON = 'AdditivePerson'¶
- ADDITIVE_PRIMARY_SOURCE = 'AdditivePrimarySource'¶
- ADDITIVE_RESOURCE = 'AdditiveResource'¶
- ADDITIVE_RESOURCE_SERIES = 'AdditiveResourceSeries'¶
- ADDITIVE_VARIABLE = 'AdditiveVariable'¶
- ADDITIVE_VARIABLE_GROUP = 'AdditiveVariableGroup'¶
- PREVENTIVE_ACCESS_PLATFORM = 'PreventiveAccessPlatform'¶
- PREVENTIVE_ACTIVITY = 'PreventiveActivity'¶
- PREVENTIVE_BIBLIOGRAPHIC_RESOURCE = 'PreventiveBibliographicResource'¶
- PREVENTIVE_CONSENT = 'PreventiveConsent'¶
- PREVENTIVE_CONTACT_POINT = 'PreventiveContactPoint'¶
- PREVENTIVE_DISTRIBUTION = 'PreventiveDistribution'¶
- PREVENTIVE_ORGANIZATION = 'PreventiveOrganization'¶
- PREVENTIVE_ORGANIZATIONAL_UNIT = 'PreventiveOrganizationalUnit'¶
- PREVENTIVE_PERSON = 'PreventivePerson'¶
- PREVENTIVE_PRIMARY_SOURCE = 'PreventivePrimarySource'¶
- PREVENTIVE_RESOURCE = 'PreventiveResource'¶
- PREVENTIVE_RESOURCE_SERIES = 'PreventiveResourceSeries'¶
- PREVENTIVE_VARIABLE = 'PreventiveVariable'¶
- PREVENTIVE_VARIABLE_GROUP = 'PreventiveVariableGroup'¶
- SUBTRACTIVE_ACCESS_PLATFORM = 'SubtractiveAccessPlatform'¶
- SUBTRACTIVE_ACTIVITY = 'SubtractiveActivity'¶
- SUBTRACTIVE_BIBLIOGRAPHIC_RESOURCE = 'SubtractiveBibliographicResource'¶
- SUBTRACTIVE_CONSENT = 'SubtractiveConsent'¶
- SUBTRACTIVE_CONTACT_POINT = 'SubtractiveContactPoint'¶
- SUBTRACTIVE_DISTRIBUTION = 'SubtractiveDistribution'¶
- SUBTRACTIVE_ORGANIZATION = 'SubtractiveOrganization'¶
- SUBTRACTIVE_ORGANIZATIONAL_UNIT = 'SubtractiveOrganizationalUnit'¶
- SUBTRACTIVE_PERSON = 'SubtractivePerson'¶
- SUBTRACTIVE_PRIMARY_SOURCE = 'SubtractivePrimarySource'¶
- SUBTRACTIVE_RESOURCE = 'SubtractiveResource'¶
- SUBTRACTIVE_RESOURCE_SERIES = 'SubtractiveResourceSeries'¶
- SUBTRACTIVE_VARIABLE = 'SubtractiveVariable'¶
- SUBTRACTIVE_VARIABLE_GROUP = 'SubtractiveVariableGroup'¶
- WORKFLOW_ACCESS_PLATFORM = 'WorkflowAccessPlatform'¶
- WORKFLOW_ACTIVITY = 'WorkflowActivity'¶
- WORKFLOW_BIBLIOGRAPHIC_RESOURCE = 'WorkflowBibliographicResource'¶
- WORKFLOW_CONSENT = 'WorkflowConsent'¶
- WORKFLOW_CONTACT_POINT = 'WorkflowContactPoint'¶
- WORKFLOW_DISTRIBUTION = 'WorkflowDistribution'¶
- WORKFLOW_ORGANIZATION = 'WorkflowOrganization'¶
- WORKFLOW_ORGANIZATIONAL_UNIT = 'WorkflowOrganizationalUnit'¶
- WORKFLOW_PERSON = 'WorkflowPerson'¶
- WORKFLOW_PRIMARY_SOURCE = 'WorkflowPrimarySource'¶
- WORKFLOW_RESOURCE = 'WorkflowResource'¶
- WORKFLOW_RESOURCE_SERIES = 'WorkflowResourceSeries'¶
- WORKFLOW_VARIABLE = 'WorkflowVariable'¶
- WORKFLOW_VARIABLE_GROUP = 'WorkflowVariableGroup'¶