Release notes for pymetadata 0.6.0
We are pleased to release the next version of pymetadata including the
following changes. This is a large release which reorganizes the package, so it
starts with what has to be changed in existing code.
Breaking changes
- python 3.10 support dropped, python >=3.11 is now required
- the generated ontologies moved from
pymetadata.metadatato
pymetadata.ontologies, next to the module which generates them, and the
pymetadata.metadatapackage was removed:
from pymetadata.metadata import SBObecomes
from pymetadata.ontologies import SBO - the modules which query web services are collected in the new
pymetadata.webservicespackage:chebi,unichemandwebservicemoved
there from the top level,olsfrompymetadata.ontologiesandregistry
frompymetadata.identifiers.miriammoved topymetadata.coreand the
pymetadata.identifierspackage was removed:
from pymetadata.identifiers.miriam import BQBbecomes
from pymetadata.core.miriam import BQB - the ontologies are no longer
strenums but classes ofOntologyTerm
attributes, see the feature below. A term is still the identifier, i.e.,
SBO.SIMPLE_CHEMICAL == "SBO_0000247"and serialization are unchanged, and
the lookups of an enum are kept (len, iteration,in,
SBO["SBO_0000247"],SBO("SBO:0000247"),get_name,validate).repr
shows the label now, e.g.,<SBO.SBO_0000247: 'simple chemical'>, and
ENUM_DIRwas renamed toONTOLOGY_DIR ECOis no longer packaged: the evidence terms were not used by the package
and the module was the largest of the generated ones. The ontology can still
be queried through OLS- web service responses are cached on disk by default, i.e.,
pymetadata.CACHE_USEchanged fromFalsetoTrue, so repeated lookups of
the same term do not query OLS, ChEBI or UniChem again. The cache is written
topymetadata.CACHE_PATH(~/.cache/pymetadata), deleting it is always
safe, andpymetadata.CACHE_USE = Falserestores the previous behaviour of
querying the services every time - annotations are normalized to identifiers.org compact identifiers of the form
https://identifiers.org/<prefix>:<accession>(#71);resource_normalized
no longer emits the deprecatedhttps://identifiers.org/<prefix>/<accession>
form for namespaces which are not embedded in the LUI, i.e.,
NCIT:C180619now normalizes tohttps://identifiers.org/ncit:C180619
instead ofhttps://identifiers.org/ncit/C180619 pymetadatano longer configures logging: it adds no handlers and sets no
levels, so messages are formatted and filtered by the application.
log.enable_rich_logging()turns the rich output on for scripts and
examples. Importing the package no longer replaces the interpreter
displayhookviarich.pretty.install()log.get_logger()removed, it only returnedlogging.getLogger(name). Code
which called it changes fromlog.get_logger(__name__)to
logging.getLogger(__name__);pymetadata.logkeepsenable_rich_logging()
andPACKAGE_LOGGERprontois an optional dependency now, installed with
pip install pymetadata[ontology]. It is only used to read ontologies and
generate the modules, not to use the shipped terms, which reduces an
installation from 37 MB to 22 MB and removes the compiledfastoboand
networkxdependenciespymetadata.ontologies.ontologyrenamed to
pymetadata.ontologies._ontology_builder: the module downloads the
ontologies and generates the modules, it is internal tooling for maintainers
and no longer part of the public API or the API reference. Regeneration runs
withpython -m pymetadata.ontologies._ontology_builder- the examples moved out of the package to
examples/in the repository, the
_examplesuffix is gone and the COMBINE archive examples are collected in
examples/omex/together with the archives they use. They run as scripts,
e.g.,python examples/omex/omex.py, instead of
python -m pymetadata.examples.omex_example, and the example data is no
longer shipped in the distribution. Apbpkoexample was added - minimum versions of the dependencies raised to
rich>=15.0.0,
requests>=2.34.2andpydantic>=2.13.5. They are widely used packages and
the current releases are what pymetadata is tested against
Features
- ontology terms carry the information of the ontology release: a term of
SBO,KISAOorPBPKOprovideslabel,definition,synonyms,
deprecated,curieandurl, andget_termresolves a term given as a
string. The terms are declared with their definition as docstring, so an
editor completingSBO.shows what a term means - PBPKO (PBPK ontology) added as a first class ontology (#70), i.e.,
PBPKOis
available frompymetadata.ontologiesand the ontology is updated with the
others. SBO and KISAO were regenerated from the current ontology releases - cached responses expire, instead of being kept forever: the OLS, ChEBI and
UniChem responses after 30 days (CACHE_DURATION_ONTOLOGY), since they
describe the terms of an ontology release, the identifiers.org registry after
24 hours (CACHE_DURATION_REGISTRY), since namespaces and their patterns are
added and corrected continuously - the queries survive an outage: if content has to be refreshed but the service
cannot be reached, the outdated cache is used and a warning is logged instead
of the query failing, so annotating keeps working offline. Only a query which
was never cached fails - web service queries are retried on the transient error responses (429, 500,
502, 503, 504) and time out after 30s. The UniChem, ChEBI, OLS and
identifiers.org queries share a session with these settings webservice.get_json()added, which raises aWebserviceErrorfor the
unreachable service, the error response and the response which is not JSON.
The query modules use it instead of checking the status code themselves, so a
ConnectionErroror aJSONDecodeErrorno longer escapes from a ChEBI, OLS,
UniChem or registry queryOmexcan be used as a context manager, which removes the temporary
directory with the archive content when the block is left- importing pymetadata no longer queries the identifiers.org web service. The
registry and the OLS query object are created on first use and shared, which
makesimport pymetadata.core.annotationwork offline and reduces the import
from ~0.9s to ~0.1s
Fixes
- fix reading a
manifest.xmlwith a singlecontententry, which raised an
AttributeError; an archive with a single file is valid OMEX - fix UniChem queries raising a
JSONDecodeErrorwhen the service answers with
an HTML error page instead of JSON; the status code is checked before the
response is parsed - fix
Ontologystoring the read ontology on the class, so reading a second
ontology replaced the content of the first one - fix the generation processing the previous term again when a term resolved to
neither a relationship nor a term of the ontology - fix the UniChem source cache, which was never shared, so every query object
retrieved the sources again - fix the
validatemethods of the generated ontologies: theisinstance
check compared against a string instead of the class, which would raise a
TypeErrorif that branch were reached - messages are no longer logged twice when the application configures logging
- namespaces without a prefix are skipped when updating the identifiers.org
registry instead of ending up in the registry with aNonekey
Documentation
- documentation restructured (#72): the sources are in
docs/, nothing
rendered is committed any more, and the site is built and published to
https://matthiaskoenig.github.io/pymetadata by a GitHub workflow on every
change. New user guides for COMBINE archives and annotations - documentation migrated from quarto to Zensical, the
static site generator of the Material for MkDocs authors: markdown sources in
docs/, configured inzensical.toml, with the API reference rendered from
the docstrings by mkdocstrings instead of quartodoc. The pages of the site
moved from/omex.htmlto/omex/ - API reference extended from 2 to 14 modules, covering annotations,
qualifiers, cross references, creators, the identifiers.org registry, the
OLS, ChEBI and UniChem queries, ontology generation and caching. It is
structured by package, withpymetadata.coreandpymetadata.webservicesas
subsections. All docstrings converted to google style, so arguments, return
values and errors are rendered instead of appearing as raw text - COMBINE archive documentation and examples improved: the
omexAPI reference
documents arguments, return values, exceptions and examples for every public
method, with the OMEX publications cited; the runnable examples were
rewritten and no longer write into the package - the HARMONY2026 presentation is no longer published with the documentation,
its sources remain inpresentations/
Development
- mypy replaced by ty for type checking (#69); ty runs in CI, in
tox r -e ty
and as a pre-commit hook. All# type: ignorecomments are gone - type annotations modernized to
dict,listandX | None, mutable class
attributes marked asClassVar - more ruff rules (import sorting, docstrings, pyupgrade, bugbear,
comprehensions, simplifications, returns) and additional pre-commit hooks
(toml, json, case conflicts, line endings, forgotten debug statements) - the generated modules are written with plain python instead of a jinja2
template, sojinja2is gone from theontologyextra, which now only needs
pronto, and the template inresources/templateswas removed. Regeneration
downloads only the packaged ontologies instead of all ontologies of
ontology_files xmltodictdependency dropped, the manifest is parsed with the standard
library;lxmlanddepinforemoved as well, both unused- the project urls reach the metadata now: the table was written as
[project_urls]instead of[project.urls], so it was silently ignored and
the pypi page carried no links at all.Documentationpoints to the
documentation site instead of the repository and aChangelogurl was added.
The license metadata follows PEP 639, i.e.,license = "MIT"with
license-files, instead of the deprecatedLicense ::classifier - root configuration cleaned up:
.gitignorelost the entries of tools which
are not used, the unusedpytest-raisesdependency and itsraisesmarker
are gone, as is theinstalltox environment which nothing referenced, and
the pytest configuration moved fromtox.inito[tool.pytest.ini_options]
inpyproject.toml - the draft of the COMBINE archive version 2 moved to the new
pymetadata.oven
package, which collects work in progress: not wired into the package, not
documented, not part of the public API and not shipped in the release
Your pymetadata team