Vocabularies#
What a property’s value may be, what it means, and what a class descends from. rs-metadata answers none of these itself; they are fetched from upstream and read here.
What each property’s value may be.
Merged from every declared vocabulary by
scripts/vendor_reference_data.py. CodeMeta is authoritative where
both it and schema.org define a property, because it narrows
schema.org for its own profile; schema.org supplies the properties
CodeMeta leaves out of its context.
- rs_metadata.vocabulary.properties.codemeta_terms()[source]#
The CodeMeta 3.1 term index derived from its JSON-LD context.
- rs_metadata.vocabulary.properties.codemeta_types()[source]#
What each CodeMeta property’s value may be, derived from upstream.
- Returns:
dict – Property name mapped to
{"range": [...], "parent": str}, plusbyParentfor the one property CodeMeta types differently depending on where it appears.- Return type:
Notes
Derived by
scripts/vendor_reference_data.pyfrom CodeMeta’s own property table, never transcribed by hand. CodeMeta narrows schema.org for its own profile —maintainerisPersonhere but Person-or-Organization upstream — so its table is the authority.Examples
A range containing
Textmeans a bare string is conformant:>>> codemeta_types()["developmentStatus"]["range"] ['Text']
A range without it means the value must be a node or an absolute URL, because a bare string would expand to an unresolvable relative IRI:
>>> codemeta_types()["license"]["range"] ['CreativeWork', 'URL'] >>> "Text" in codemeta_types()["author"]["range"] False
identifieris typed differently inside aPerson:>>> codemeta_types()["identifier"]["byParent"] {'Person': ['URL']}
- rs_metadata.vocabulary.properties.type_entry(name)[source]#
The type table entry for a property, however it is spelled.
- Parameters:
name (str) – Property name as written in the document, with or without a prefix.
- Returns:
dict or None – The entry, or
Nonewhen neither vocabulary defines the property.- Return type:
Notes
schema:featureListandfeatureListare the same property. CodeMeta leavesfeatureListout of its context, which is exactly why this profile writes it prefixed, and why looking it up by the prefixed spelling has to work.Examples
>>> type_entry("license")["range"] ['CreativeWork', 'URL']
A prefixed spelling resolves to the same entry as the bare one:
>>> type_entry("schema:featureList") == type_entry("featureList") True >>> type_entry("schema:featureList")["range"] ['Text', 'URL']
A property neither vocabulary defines has no entry:
>>> type_entry("somethingInvented") is None True
- rs_metadata.vocabulary.properties.agent_properties()[source]#
Every CodeMeta property whose values are people or organizations.
Notes
Derived from the type table rather than listed by hand. An earlier hand-written list covered four properties and silently missed six that CodeMeta types identically, so the list is now a consequence of the data.
Only properties CodeMeta declares on the record itself are returned.
affiliationis Organization-valued too, but it exists on aPersonrather than on the document, so it is reached by walking into an agent rather than by looking for it at the top level.Examples
>>> properties = agent_properties() >>> len(properties) 10 >>> "author" in properties and "funder" in properties True
The six a hand-written list had missed:
>>> sorted(set(properties) - {"author", "maintainer", "contributor", ... "copyrightHolder"}) ['editor', 'funder', 'producer', 'provider', 'publisher', 'sponsor']
A nested-only property is not one of them:
>>> "affiliation" in properties False
- rs_metadata.vocabulary.properties.allows_text(name)[source]#
Whether a bare scalar is a conformant value for a property.
- Parameters:
name (str) – CodeMeta property name.
- Returns:
bool –
Truewhen the property’s range includes a literal type, and for properties CodeMeta does not define at all — an unknown property gets no type complaint on top of the unknown-property one.- Return type:
Examples
>>> allows_text("developmentStatus"), allows_text("applicationCategory") (True, True) >>> allows_text("license"), allows_text("author") (False, False)
Dates and numbers are literals, so a bare value is right for them — this is not only about
Text:>>> allows_text("datePublished"), allows_text("copyrightYear") (True, True)
URLalone does not qualify, because an arbitrary string is not a URL:>>> allows_text("codeRepository") False
Unknown properties are not second-guessed:
>>> allows_text("somethingInvented") True
schema.org’s class hierarchy.
The hierarchy is what makes subtyping possible. CodeMeta types
citation as CreativeWork; schema.org says a
ScholarlyArticle is an Article is a CreativeWork, so one
belongs there. Without this, accepting only the exact class name is a
false alarm about correct metadata.
- rs_metadata.vocabulary.classes.schema_org_classes()[source]#
schema.org’s class hierarchy, and the properties of the classes in use.
- Returns:
dict – Class name mapped to
ancestors, and for classes any range names, apropertiesmap from property name to its range.- Return type:
Examples
>>> schema_org_classes()["ScholarlyArticle"]["ancestors"] ['Article', 'CreativeWork', 'Thing']
- rs_metadata.vocabulary.classes.subclasses(name)[source]#
Every class schema.org derives from this one, directly or not.
- Parameters:
name (str) – A class name, for example
CreativeWork.- Returns:
tuple of str – Descendant class names, sorted.
- Return type:
Notes
Used to express subtyping in the generated schema: a property typed
CreativeWorkaccepts an@typefrom this list, so onejsonschemapass enforces what would otherwise need the validator.Examples
>>> "ScholarlyArticle" in subclasses("CreativeWork") True >>> "Person" in subclasses("CreativeWork") False >>> subclasses("ComputerLanguage") ()
- rs_metadata.vocabulary.classes.satisfies(declared, expected)[source]#
Whether a node of class
declaredcan stand whereexpectedis asked for.- Parameters:
- Returns:
bool –
Truewhen the classes are the same, or whendeclaredis a subclass ofexpected.- Return type:
Notes
CodeMeta types
citationasCreativeWork. schema.org says aScholarlyArticleis anArticleis aCreativeWork, so one belongs there. Comparing the names alone would reject it, which is a false alarm about correct metadata.Examples
>>> satisfies("CreativeWork", "CreativeWork") True >>> satisfies("ScholarlyArticle", "CreativeWork") True >>> satisfies("SoftwareSourceCode", "CreativeWork") True
Subtyping runs one way only, and unrelated classes stay unrelated:
>>> satisfies("CreativeWork", "ScholarlyArticle") False >>> satisfies("Person", "Organization") False
Schemas, vocabularies and rule data read at runtime.
Two kinds of file live in data/. Vendored ones have an upstream, a
checksum and a refresh script. Project-owned ones are maintained by
hand and the refresh script never touches them; a contract test keeps
the two sets disjoint.
- rs_metadata.vocabulary.documents.codemeta_versions()[source]#
Which
@contextvalues are recognized, and what 2.0 terms became.- Returns:
dict –
current,currentMajor, and acontextsmap from context URL to version.- Return type:
Examples
Every 3.x context denotes the current vocabulary — 3.0 and 3.1 resolve to byte-identical documents, so a 3.0 record is not out of date:
>>> versions = codemeta_versions() >>> versions["contexts"]["https://w3id.org/codemeta/3.0"] '3.0' >>> versions["currentMajor"] '3'
Earlier CodeMeta is not listed, and is reported as an unrecognized context:
>>> any(v.startswith("2") for v in versions["contexts"].values()) False
- rs_metadata.vocabulary.documents.cff_schema()[source]#
The official Citation File Format 1.2.0 JSON Schema.
- rs_metadata.vocabulary.documents.codemeta_crosswalks()[source]#
CodeMeta’s own crosswalk tables, keyed by the mapping id that uses them.
Each entry is
{"source", "format", "properties"}, wherepropertiesmaps a CodeMeta property to the source fields CodeMeta says correspond to it. Vendored so a mapping’s claim about its own provenance can be checked rather than believed.
- rs_metadata.vocabulary.documents.report_schema()[source]#
The JSON schema describing rs-metadata’s own report format.
- rs_metadata.vocabulary.documents.spdx_licenses()[source]#
SPDX identifiers mapped to name, deprecation status and OSI approval.
- rs_metadata.vocabulary.documents.vocabularies()[source]#
Controlled vocabularies with no stable machine-readable upstream form.
- rs_metadata.vocabulary.documents.provenance()[source]#
Where each vendored file came from, and when.
- rs_metadata.vocabulary.documents.PROJECT_OWNED_DATA = ('placeholders.json',)#
Files in
data/that rs-metadata maintains itself.
- rs_metadata.vocabulary.documents.format_hints()[source]#
How other packaging ecosystems spell things rs-metadata maps.
- Returns:
dict –
rLicenseAliasesmapping CRAN license strings to SPDX identifiers, andpyprojectUrlRolesmapping CodeMeta concepts to the PEP 621[project.urls]labels that denote them.- Return type:
Examples
>>> format_hints()["rLicenseAliases"]["aliases"]["gpl-3"] 'GPL-3.0-only' >>> "repository" in format_hints()["pyprojectUrlRoles"]["labels"]["source"] True
- rs_metadata.vocabulary.documents.concept_order()[source]#
The order concepts are reported in.
- Returns:
tuple of str – Mandatory fields first, in the order the profile declares them, then recommended ones. Concepts absent from both sort after these, alphabetically, so adding a property never makes the report unstable.
- Return type:
Notes
Derived from the profile rather than kept in a file of its own: the profile already lists its fields in a deliberate order, identity before provenance before technical detail, and repeating that order elsewhere is one more thing to keep in step.
Examples
>>> concept_order()[:3] ('name', 'description', 'version')
- rs_metadata.vocabulary.documents.placeholders()[source]#
Template values that get left behind, and how to recognize them.
- Returns:
dict –
orcid,doiPrefix,hosts, andpatternscarrying regex sources compiled byrs_metadata.profile.placeholders.- Return type:
Examples
>>> placeholders()["orcid"] '0000-0000-0000-0000' >>> "example.com" in placeholders()["hosts"] True
- rs_metadata.vocabulary.documents.spdx_index()[source]#
Case-insensitive lookup from an SPDX identifier to its canonical case.
SPDX identifiers are case-sensitive by specification, but people write
apache-2.0constantly. Recognising the value and reporting the canonical spelling is more useful than rejecting it outright.
- rs_metadata.vocabulary.documents.profile_field_policy()[source]#
The mandatory and recommended field lists, read from the profile schema.
The schema is the single source of truth. Duplicating these lists in Python would let documentation, validator and schema drift apart.
- Returns:
dict –
mandatory,recommendedandfeatureListAliaseslists.- Return type:
Examples
>>> policy = profile_field_policy() >>> len(policy["mandatory"]) 10 >>> "license" in policy["mandatory"] True >>> "keywords" in policy["recommended"] True
The mandatory list matches the schema’s own
requiredkeyword, which a contract test enforces:>>> set(policy["mandatory"]) <= set(profile_schema()["required"]) True