missingness¶
This rule identifies the missingness values that a column can take on, and reports the columns that can’t take on any at all.
A column can take on missingness values when the missingnessSet column
in the dictionary has a value for it. The allowed values are then the
members of that set, as listed in the sets sheet. For example, a column
with a missingnessSet of nrNAMissingnessSet can take on NA and
nr, while a column with a missingnessSet of genMissingnessSet can
take on any of the dictionary’s missingness values.
A value that a column can take on is a statement that the value is missing, rather than a value of the column’s own domain, which is why it is exempt from the other validation rules.
A value that the column can not take on is not a missingness value
in that column, and this rule therefore has nothing to say about it. It
is left to the other validation rules to decide whether it is valid, the
same way as any other value. A column of country codes whose missingness
set only holds NULL is a good example: NA is not a missingness value
there, it is the country code of Namibia, and the rules that constrain
the shape of a value get to judge it.
A primary key is the exception. It identifies an entry and can therefore never be missing, so a column that is the primary key of a table can’t take on any missingness value, and every missingness value in it is reported by this rule. This holds even when the column has a missingness set, and even when the same column is not the primary key of another table.
Consider a sites table where siteID is the primary key, geoLat has
a missingnessSet of nrNAMissingnessSet and country has one that
only holds nr. The following ODM dataset snippet would fail
validation, because the primary key siteID can’t be missing,
Invalid Sites Table ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ country ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ NA │ 1 │ CA │ └────────────────────────────────────┴────────────────────────────────────┴───────────────────────────────────────┘
The following dataset snippet would pass validation. NA and nr are
missingness values that geoLat can take on, nr is one that country
can take on, and the NA in country is not a missingness value there,
but a country code,
Valid Sites Table ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ country ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ NA │ NA │ │ 2 │ nr │ nr │ └────────────────────────────────────┴────────────────────────────────────┴───────────────────────────────────────┘
The same siteID column is a foreign key in the samples table, where
it is not the primary key. It can take on the missingness values of its
genMissingnessSet, so the following dataset snippet would pass
validation as well,
Valid Samples Table ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ NA │ │ nan │ │ nr │ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Error report¶
The error report will have the following fields
errorType: missingness
tableName: The name of the table with the invalid missingness value
columnName: The name of the column with the invalid missingness value
invalidValue: The invalid missingness value
rowNumber: The index of the table row with the error
row: The dictionary containing the row
validationRuleFields: The ODM data dictionary rows used to generate this rule
message: Invalid missingness value <invalid_value> found in row <row_index> for column <column_name> in table <table_name>. The allowed missingness values are <allowed_missingness_values>
The error report for the invalid dataset is shown below. The allowed
missingness values are reported as none, since a primary key can’t be
missing,
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'missingness', │ │ │ 'tableName': 'sites', │ │ │ 'columnName': 'siteID', │ │ │ 'invalidValue': 'NA', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'siteID': 'NA', │ │ │ │ 'geoLat': '1', │ │ │ │ 'country': 'CA' │ │ │ }, │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'siteID', │ │ │ │ │ 'sites': 'pK', │ │ │ │ │ 'sitesRequired': 'mandatory', │ │ │ │ │ 'missingnessSet': 'genMissingnessSet' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ 'partType': 'missingness' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'nan', │ │ │ │ │ 'partType': 'missingness' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ 'partType': 'missingness' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'missingness rule violated in table sites, column siteID, row(s) 1: Invalid missingness value "NA", the allowed missingness values are none' │ │ } │ ], │ 'warnings': [] }
Relation to the other validation rules¶
A missingness value is a placeholder for a value rather than a value of
the column’s own domain. An allowed missingness value is therefore
exempt from the rules that constrain the shape of a value:
invalid_type,
invalid_category,
less_than_min_value,
greater_than_max_value,
less_than_min_length,
greater_than_max_length and
duplicate_entries_found. It is also
exempt from type coercion. A value of NA in the float column geoLat
above is valid and is left as-is, instead of being reported as a type
error.
A value that violates this rule is exempt from those rules as well, so that a single invalid missingness value isn’t reported twice.
A value that the column can’t take on is not exempt, since it isn’t
a missingness value in that column. It is validated by those rules like
any other value: a nan in the country column above is reported by
greater_than_max_length, because a
country code is at most two characters long, and not by this rule.
A missingness value states why a value is absent, which is a valid way of populating a mandatory column, so missing_values_found is not triggered by one either. That rule only reports a mandatory column that has been left empty. An identifier that is missing is reported by this rule instead, since a primary key has no allowed missingness values.
Rule metadata¶
The metadata for this rule is contained in both the parts and the sets sheet in the data dictionary. The steps involved are:
For each column, get the missingness set id from its
missingnessSetcolumn. Skip the column if it doesn’t have one and it isn’t the primary key of the table.Get the missingness values of that set from the sets sheet
Filter the sets to only include those whose
setTypecolumn ismissingnessSetsand whosesetIDcolumn is the missingness set idThe
partIDcolumn has the missingness value
If the column is the primary key of the table, then it has no allowed missingness values, and the forbidden values are all of the dictionary’s missingness values, which are the parts whose
partTypecolumn ismissingnessEvery other column has no forbidden values, since a value outside its missingness set isn’t a missingness value in that column
Add this rule for the column
For example, the ODM snippets below will be used to generate the validation schema for the examples above,
Parts v2 ┏━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓ ┃ partID ┃ partTy… ┃ status ┃ sites ┃ sitesR… ┃ sampl… ┃ sample… ┃ dataT… ┃ maxLen… ┃ missi… ┃ firstR… ┃ lastU… ┃ ┡━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩ │ NA │ missin… │ active │ NA │ NA │ NA │ NA │ varch… │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ nan │ missin… │ active │ NA │ NA │ NA │ NA │ varch… │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ nr │ missin… │ active │ NA │ NA │ NA │ NA │ varch… │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ sites │ tables │ active │ NA │ NA │ NA │ NA │ NA │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ samples │ tables │ active │ NA │ NA │ NA │ NA │ NA │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ siteID │ attrib… │ active │ pK │ mandat… │ fK │ option… │ varch… │ NA │ genMi… │ 1.0.0 │ 2.0.0 │ │ geoLat │ attrib… │ active │ header │ mandat… │ NA │ NA │ float │ NA │ nrNAM… │ 1.0.0 │ 2.0.0 │ │ geoLong │ attrib… │ active │ header │ option… │ NA │ NA │ float │ NA │ NA │ 1.0.0 │ 2.0.0 │ │ country │ attrib… │ active │ header │ option… │ NA │ NA │ varch… │ 2 │ nrMis… │ 1.0.0 │ 2.0.0 │ └─────────┴─────────┴────────┴────────┴─────────┴────────┴─────────┴────────┴─────────┴────────┴─────────┴────────┘
Sets v2 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ ┃ setID ┃ setType ┃ partID ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩ │ genMissingnessSet │ missingnessSets │ NA │ active │ 1.0.0 │ 2.0.0 │ │ genMissingnessSet │ missingnessSets │ nan │ active │ 1.0.0 │ 2.0.0 │ │ genMissingnessSet │ missingnessSets │ nr │ active │ 1.0.0 │ 2.0.0 │ │ nrNAMissingnessSet │ missingnessSets │ NA │ active │ 1.0.0 │ 2.0.0 │ │ nrNAMissingnessSet │ missingnessSets │ nr │ active │ 1.0.0 │ 2.0.0 │ │ nrMissingnessSet │ missingnessSets │ nr │ active │ 1.0.0 │ 2.0.0 │ └───────────────────────────┴───────────────────────┴───────────┴───────────┴────────────────────┴────────────────┘
The rule is added to the siteID, geoLat and country columns, but
not to the geoLong column, which neither has a missingness set nor is
a primary key.
Cerberus Schema¶
Cerberus does not have support for this rule. We need to extend the
cerberus
validator
with a custom rule called missingness. Its constraint has two fields,
which partition the dictionary’s missingness values into the ones the
column accepts and the ones it doesn’t:
allowed: The missingness values the column can take on
forbidden: The missingness values that trigger this rule, which is everything for a primary key and nothing for the other columns
Both fields are needed, because the validator has to be able to tell a missingness value that is reported apart from one that is exempted. A value in neither field is left alone. The custom rule is evaluated before the other cerberus rules for the column, so that it can exempt the allowed missingness values from them.
The cerberus schema for the ODM dictionary snippets above is shown below,
{ │ 'schemaVersion': '2.0.0', │ 'schema': { │ │ 'sites': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'siteID': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [], │ │ │ │ │ │ │ 'forbidden': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nan', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'siteID', │ │ │ │ │ │ │ │ │ │ 'sites': 'pK', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'mandatory', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nan', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ }, │ │ │ │ │ 'geoLat': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'mandatory', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ }, │ │ │ │ │ 'country': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'country', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'optional', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'nrMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ }, │ │ 'samples': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'siteID': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nan', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'siteID', │ │ │ │ │ │ │ │ │ │ 'samples': 'fK', │ │ │ │ │ │ │ │ │ │ 'samplesRequired': 'optional', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nan', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'samples', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
The meta field for this rule should have multiple entries,
the row from the parts sheet for the column. The entry should include the
partID, the<table_name>, the<table_name>Requiredand themissingnessSetfields.and an entry per missingness value in the set. This entry should include the
partIDand thesetIDcolumn. For a primary key, whose constraint comes from the missingness parts rather than from a set, the entries are the forbidden missingness parts instead, and they should include thepartIDand thepartTypecolumn.
ODM Version 1¶
For version 1 validation schemas, we add this rule to only those version 2 columns which have a version 1 equivalent part.
For the ODM snippet below,
Parts v1 ┏━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┳━━━━━━┳━━━━━━━┓ ┃ part… ┃ part… ┃ stat… ┃ sit… ┃ site… ┃ sam… ┃ samp… ┃ dat… ┃ maxL… ┃ mis… ┃ vers… ┃ ver… ┃ vers… ┃ fir… ┃ last… ┃ ┡━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━╇━━━━━━╇━━━━━━━┩ │ NA │ miss… │ acti… │ NA │ NA │ NA │ NA │ var… │ NA │ NA │ NA │ NA │ NA │ 1.0… │ 2.0.0 │ │ nan │ miss… │ acti… │ NA │ NA │ NA │ NA │ var… │ NA │ NA │ NA │ NA │ NA │ 1.0… │ 2.0.0 │ │ nr │ miss… │ acti… │ NA │ NA │ NA │ NA │ var… │ NA │ NA │ NA │ NA │ NA │ 1.0… │ 2.0.0 │ │ sites │ tabl… │ acti… │ NA │ NA │ NA │ NA │ NA │ NA │ NA │ tabl… │ Site │ NA │ 1.0… │ 2.0.0 │ │ samp… │ tabl… │ acti… │ NA │ NA │ NA │ NA │ NA │ NA │ NA │ tabl… │ Sam… │ NA │ 1.0… │ 2.0.0 │ │ site… │ attr… │ acti… │ pK │ mand… │ fK │ opti… │ var… │ NA │ gen… │ vari… │ Sit… │ site… │ 1.0… │ 2.0.0 │ │ geoL… │ attr… │ acti… │ hea… │ mand… │ NA │ NA │ flo… │ NA │ nrN… │ vari… │ Site │ lati… │ 1.0… │ 2.0.0 │ │ geoL… │ attr… │ acti… │ hea… │ opti… │ NA │ NA │ flo… │ NA │ NA │ vari… │ Site │ long… │ 1.0… │ 2.0.0 │ │ coun… │ attr… │ acti… │ hea… │ opti… │ NA │ NA │ var… │ 2 │ nrM… │ vari… │ Site │ coun… │ 1.0… │ 2.0.0 │ └───────┴───────┴───────┴──────┴───────┴──────┴───────┴──────┴───────┴──────┴───────┴──────┴───────┴──────┴───────┘
The corresponding cerberus schema would be,
{ │ 'schemaVersion': '1.0.0', │ 'schema': { │ │ 'Site': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'siteID': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [], │ │ │ │ │ │ │ 'forbidden': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nan', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'siteID', │ │ │ │ │ │ │ │ │ │ 'sites': 'pK', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'mandatory', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site;Sample', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'siteID', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nan', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'partType': 'missingness' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ }, │ │ │ │ │ 'latitude': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'mandatory', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'latitude', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrNAMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ }, │ │ │ │ │ 'country': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'country', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'sitesRequired': 'optional', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'country', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'nrMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'nrMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Site' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ }, │ │ 'Sample': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'siteID': { │ │ │ │ │ │ 'missingness': { │ │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ │ 'NA', │ │ │ │ │ │ │ │ 'nan', │ │ │ │ │ │ │ │ 'nr' │ │ │ │ │ │ │ ], │ │ │ │ │ │ │ 'forbidden': [] │ │ │ │ │ │ }, │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'missingness', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'siteID', │ │ │ │ │ │ │ │ │ │ 'samples': 'fK', │ │ │ │ │ │ │ │ │ │ 'samplesRequired': 'optional', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site;Sample', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'siteID', │ │ │ │ │ │ │ │ │ │ 'missingnessSet': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'NA', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nan', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'nr', │ │ │ │ │ │ │ │ │ │ 'setID': 'genMissingnessSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'samples', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Sample' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
The meta field for version 1 includes everything in version 2 but should also include the following columns for the entry for the column,
version1Locationversion1Tableversion1Variable
Note that the ODM only defines missingness sets from version 2.0.0 onwards, since the rows of the sets sheet that define the missingness sets are not part of version 1. A version 1 schema generated from a version 2 dictionary therefore only has missingness rules for its primary keys, whose constraint doesn’t come from a set.