Skip to main content

Mash

Mash attempts to solve the mess that is working with data spread between systems and people by making it easy to store your data alongside rich metadata. This brings with it organization, searchability, traceability and many other useful tings.

In practice mash allows you to:

  • Search your data by any criteria from metadata
  • See where your data originated and its history
  • Validate that your data meets the criteria for a specified usage
  • Connect to remote data sources while maintaining all of the above

Batteries-included

Mash comes pre-loaded with useful tools for working with RDF and grid models. The most helpful things for getting started are the profiles, standards and organizations found in the grid module. These can be used to search, validate and describe our data.

Standards-based

All models used in mash are based on widely-implemented standard vocabularies like dcat, prof and prov-o, and can be serialized into RDF following those standards.

Further documentation

Some deeper documentation can be found here:

Examples of usage

(more incoming!)

Define new data using datasets and distributions

import mash

from mash import models
from mash.core.profiles import MetadataProfile
from mash.core.utilities.organizations import make_organization


dist_id = "http://example.com/example#metadata-plaintext"
dataset = models.Dataset(
    identifier="http://example.com/example#metadata",
    title="Example metadata",
    description="Example dataset containing metadata with little",
    conforms_to=[MetadataProfile],  # This is a lie
    information_owner=make_organization("ElBits AS", "931264079"),
    distributions=[models.Distribution(identifier=dist_id, mime_type="text/plain")],
)

mash.save(dataset)
data = b"this is some text"
mash.write_data(data, dist_id)


print(mash.read_data(dist_id).decode())

Write a SPARQL query towards a graph

import mash

rdf_dataset = mash.fetch("urn:uuid:5393e12b-96c3-4fab-8b98-d4ba2e940b94")
m = mash.model_from_dataset(rdf_dataset)
res = m.query("""
    PREFIX cim: <http://iec.ch/TC57/CIM100#>
    SELECT (COUNT(?s) as ?substation_count) WHERE {
        ?s a cim:Substation
    }
""")
print(res)

Mash ORM

Mash features a simple RDF ORM which allows you to extract data from RDF graphs into Pydantic BaseModel classes, and to serialize BaseModel classes into RDF graphs. Using the SemanticModel class and Predicate annotation you can define your own rich metadata classes - either based on existing standards or your own models.

A basic example

from typing import Annotated, ClassVar
from mash import models, serialize, Predicate as P


class Person(models.SemanticModel):
    _type: ClassVar = "foaf:Person"
    name: Annotated[str, P("foaf:name")]
    mail: Annotated[str | None, P("foaf:mbox")] = None
    friends: Annotated[list["Person"], P("mash:friends")] = []


kristoffer_robin = Person(identifier="kr", name="Kristoffer Robin")
ole_brumm = Person(identifier="ob", name="Ole Brumm", mail="ole.brum@100meter.skogen", friends=[kristoffer_robin])
turtle_text = serialize(ole_brumm)
print(turtle_text)
<urn:mash:kr>    a foaf:Person ;
    foaf:name "Kristoffer Robin" .

<urn:mash:ob>    a foaf:Person ;
    mash:friends <urn:mash:kr> ;
    foaf:mbox "ole.brum@100meter.skogen" ;
    foaf:name "Ole Brumm" .

Making data easier to parse with ReverseRelations

Normally in RDF some relations might go in directions that are not pracitical. If you want everything attached to one class rather than to point in all directions from different classes, you can achieve this with ReverseRelations.

Notice how in the previous example Substation has no references to VoltageLevel or SubstationPart since those actually contain the reference to Substation.

from typing import Annotated, ClassVar

import mash

from mash import Predicate as P, ReverseRelation
from mash.grid import get_latest_nemo
from tests.grid.profiles.nemo import IdentifiedObject, VoltageLevel, SubstationPart, NemoProfile


class SubstationEmbed(IdentifiedObject):
    _type: ClassVar = "cim:Substation"
    substation_kind: Annotated[list[str], P("elb:Substation.substationKind")]
    substation_parts: Annotated[list[SubstationPart], ReverseRelation("elb:SubstationPart.Substation")]
    voltage_levels: Annotated[list[VoltageLevel], ReverseRelation("cim:VoltageLevel.Substation")]


latest_nemo = get_latest_nemo()
m = mash.model_from_dataset(latest_nemo)
with NemoProfile:
    substations = mash.instantiate(m, model=SubstationEmbed)
print(substations[0:2])

Use namespaces and models from a profile

You might have conflicting namespaces (links between a prefix like cim and its full URI like http://iec.ch/TC57/CIM100) in different contexts, and you might have different models that represent a resource with the same type.

Using profiles you can group models and namespaces, and tell mash when to use them. This avoids conflicts and confusion in the code.

Looking at a part of the example above, you will see the context manager that activates a profile (with NemoProfile:). Within this block mash will use the namespaces placed on Nemo, and will recognize Nemo models when relevant.

In this particular example the namespaces are important, since the grid module and the NemoProfile have different URI's for the prefix elb.

latest_nemo = get_latest_nemo()
m = mash.model_from_dataset(latest_nemo)
with NemoProfile:
    substations = mash.instantiate_all(m, model=SubstationEmbed)

Data catalog

To open a visual catalog of the data mash has access to, simply run uv run poe catalog and a page will open in your browser.

Metadata

Release files for mash-core 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mash-core 0.9.0
File Size Uploaded
mash_core-0.9.0.tar.gz 270.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mash-core 0.9.0
File Interpreter ABI Platform
mash_core-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 559.9 kB

Release files / mash_core-0.9.0.tar.gz

Download URL mash_core-0.9.0.tar.gz
Size 270.4 kB
Tags Source
SHA-256 checksum
How to use checksums
992de7eec07d5f084680a32869222b443b43918854a842356ed7670c437639ea
BLAKE2b-256 checksum
How to use checksums
47616858188ce19e151cf24d3281cd6edfa02160419083157be3b2e49bac9c27
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log

Release files / mash_core-0.9.0-py3-none-any.whl

Download URL mash_core-0.9.0-py3-none-any.whl
Size 289.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b247e136686b882501d1a004c2268df3a6f5359c5aafc4636562b7be1e207ed0
BLAKE2b-256 checksum
How to use checksums
4c9ccc03563137f5fcc5164922ff33d0d25b90a91c2a9766744f15048a20f991
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 7, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page