dapla-toolbelt-metadata
dapla-toolbelt-metadata er en Python-pakke for å jobbe med metadatasystemene på Dapla. Pakken gir brukeren et Python-grensesnitt for å jobbe mot Datadoc og Vardef.
Forberedelser
dapla-toolbelt-metadata kan installeres i tjenester på Dapla Lab. Siden det er en Python-pakke så må den installeres i en tjeneste der Python er installert. Deretter gjør du følgende:
- Åpne en tjeneste på Dapla Lab med Python installert. Før du åpner tjenesten må du velge å representere team og tilgangsgruppe som har tilgang til dataene som skal dokumenteres.
- Installer pakken i et ssb-project på følgende måte:
Terminal
poetry add dapla-toolbelt-metadata
Etter det er du klar for bruke funksjonaliteten i dapla-toolbelt-metadata i en notebook.
I Dapla Lab velger man hvilket team og tilgangsgruppe man skal representere før man åpner en tjeneste. Hvis man f.eks. skal dokumentere et datasett i datatilstanden inndata for et team som heter dapla-felles, så må man logge seg inn i en tjeneste som dapla-felles-developers, hvis ikke har man ikke tilgang til datasettet.
I tillegg så benytter Vardef bl.a. informasjon om hvilket team og tilgangsgruppe du logget deg inn som, for definere hvilket team som blir eier av en nyopprettet variabeldefinisjon. På samme måte bruker Vardef denne informasjonen til å avgjøre om en bruker har tilgang til å endre en definisjon. F.eks. vil en bruker som logger seg inn som dapla-felles-developers og oppretter en ny definisjon, så vil dapla-felles stå som eier av definisjonen og det vil kun være medlemmer av dette teamet som kan gjøre endringer i definisjonen.
Datadoc
Datadoc er SSBs system for dokumentasjon av datasett. Første gang man skal dokumentere et datasett i Datadoc så er det anbefalt å bruke det grafiske grensesnittet i Datadoc-editor. I løpende produksjon er det dermed anbefalt å benytte en programmatisk tilnærming gjennom Datadoc
-klassen i Python-pakken dapla-toolbelt-metadata.
Dokumentere ny periode
Hvis man har dokumentert datasett for periode t med Datadoc-editor, så kan man programmatisk dokumentere periode t+1 ved å benytte Datadoc
-klassen i dapla-toolbelt-metadata. Det forutsetter at det kun nye data som har kommet til og at det er den eneste endringen i dataene. Da kan man dokumentere den nye perioden på følgende måte:
Notebook
from dapla_metadata.datasets import Datadoc
= Datadoc(
meta 1="gs://ssb-dapla-felles-data-produkt-prod/datadoc/sykefratot/klargjorte_data/person_testdata_p2022_v1.parquet",
dataset_path2="gs://ssb-dapla-felles-data-produkt-prod/datadoc/sykefratot/klargjorte_data/person_testdata_p2021_v1__DOC.json",
metadata_document_path
)3 meta.write_metadata_document()
- 1
-
dataset_path
angir det nye datasettet som skal dokumenteres. - 2
-
metadata_document_path
angir sti til tidligere periodes metadata. - 3
-
write_metadata_document
er kommandoen som produserer de nye metadataene og skriver de til filengs://ssb-dapla-felles-data-produkt-prod/datadoc/sykefratot/klargjorte_data/person_testdata_p2022_v1__DOC.json
.
Det veldig viktig at man ikke bruker denne metoden hvis det er endringer i hvilke kolonner som finnes i datasettet eller andre større endringer. Metoden over antar at den eneste informasjonen som har endret seg er den som kan leses ut av filstien. Ved større endringer i selve dataene bør man heller gjøre en manuell gjennomgang av metadataene med Datadoc-editor
Vardef (WIP👷♂️)
Vardef er SSBs system for dokumentasjon av variabler. Vardef består av et sentralt datalager som man kan interagere med via et API. Statistikere og forskere i SSB kan benytte seg av API-et gjennom Vardef
-klassen i Python-pakken dapla-toolbelt-metadata, som er et mer brukervennlig grensesnitt tilpasset Dapla Lab. Pakken lar brukeren bl.a. gjøre følgende:
- Liste ut alle definisjoner.
- Migrere definisjoner fra Vardok1.
- Opprette ny definisjon
- Endre eksisterende definisjon
Eksemplene under forutsetter at du har gjort følgende importer i en notebook på Dapla Lab:
Notebook
from dapla_metadata.variable_definitions import Vardef, models
Liste ut variabeldefinisjoner
For å lese inn alle variabeldefinisjoner fra Vardef kan man bruke list_variable_definitions()
-funksjonen:
Notebook
= Vardef.list_variable_definitions()
variable_definitions variable_definitions
list_variable_definitions()
returnerer en liste med dictionaries med alle variabeldefinisjoner i Vardef, inkludert Utkast, Publisert internt og Publisert eksternt. Under er det noen kode-eksempler på hvordan man kan kan filtrere eller endre på denne listen med Python for de som måtte ønske det.
Filtrere enkeltfelt for alle definisjoner
Bruk følgende kode for å liste ut ID, navn, kortnavn, definisjon, eierteam og status for alle definisjoner i Vardef:
Notebook
for variable in variable_definitions:
print(
f"Id: {variable.id}\n"
f"Navn: {variable.name}\n"
f"Kortnavn: {variable.short_name}\n"
f"Definisjon: {variable.definition}\n"
f"Eier: {variable.owner}\n"
f"Status: {variable.variable_status}\n"
)
Notebook
5eC5YUVR
Id: 'nb': 'test navn', 'nn': 'test namn', 'en': 'test name'}
Navn: {
Kortnavn: test_shortname2'nb': 'Skriv en definisjonstekst på norsk bokmål.', 'nn': 'Skriv ein definisjonstekst på nynorsk.', 'en': 'Write a definition text in english.'}
Definisjon: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Eier: {
Status: VariableStatus.PUBLISHED_INTERNAL
Id: fDun32UF'nb': 'test navn', 'nn': 'test namn', 'en': 'test name'}
Navn: {
Kortnavn: test_shortname_obr'nb': 'Skriv en definisjonstekst på norsk bokmål.', 'nn': 'Skriv ein definisjonstekst på nynorsk.', 'en': 'Write a definition text in english.'}
Definisjon: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Eier: {
Status: VariableStatus.DRAFT
Id: Xww0Swou'nb': 'Inntekt etter skatt', 'nn': None, 'en': 'After-tax income'}
Navn: {
Kortnavn: wies'nb': 'Yrkesinntekter, kapitalinntekter, skattepliktige og skattefrie overføringer, i løpet av kalenderåret. Utlignet skatt og negative overføringer er trukket i fra.', 'nn': None, 'en': 'After-tax income is calculated as the sum of wages and salaries, income from self-employment, property income and transfers received minus total assessed taxes and negative transfers.'}
Definisjon: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Eier: {
Status: VariableStatus.DRAFT
Id: ouMrO8E6'nb': 'test navn', 'nn': 'test namn', 'en': 'test name'}
Navn: {
Kortnavn: test_shortname'nb': 'Skriv en definisjonstekst på norsk bokmål.', 'nn': 'Skriv ein definisjonstekst på nynorsk.', 'en': 'Write a definition text in english.'}
Definisjon: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Eier: { Status: VariableStatus.DRAFT
Filtrere på ID
Hvis man vet ID-en til definisjon i Vardef så kan man hente ut variabeldefinisjonen med følgende kode:
Notebook
= Vardef.get_variable_definition("fDun32UF")
single_definition print(single_definition)
I eksempelet printes all feltene i definisjonen med ID fDun32UF.
Notebook
{"id": "fDun32UF",
"patch_id": 1,
"name": {
"nb": "test navn",
"nn": "test namn",
"en": "test name"
},"short_name": "test_shortname_obr",
"definition": {
"nb": "Skriv en definisjonstekst på norsk bokmål.",
"nn": "Skriv ein definisjonstekst på nynorsk.",
"en": "Write a definition text in english."
},"classification_reference": "91",
"unit_types": [
"01"
],"subject_fields": [
"al"
],"contains_special_categories_of_personal_data": false,
"variable_status": "DRAFT",
"measurement_type": null,
"valid_from": "2024-12-18",
"valid_until": null,
"external_reference_uri": null,
"comment": null,
"related_variable_definition_uris": null,
"owner": {
"team": "dapla-felles",
"groups": [
"dapla-felles-developers"
]
},"contact": null,
"created_at": "2025-02-03T13:15:44.366000",
"created_by": "obr@ssb.no",
"last_updated_at": "2025-02-03T13:15:44.366000",
"last_updated_by": "obr@ssb.no"
}
Filtrere på gyldighetsperiode
Siden alle definisjoner i Vardef er versjonert og har en gyldighetsperiode, så kan man filtrere hvilke definisjoner som var gyldig på et gitt tidspunkt:
Notebook
from datetime import date
= date(2030,2,24)
desired_validity = Vardef.list_variable_definitions(desired_validity) filtered_variable_definitions
I koden over hentes alle som definert som gyldig per 24. februar 2030, inkludert definisjoner som ikke har en sluttdato. Vi importerer også datetime-pakken for å sikre at datoformatet blir riktig.
Vi kan igjen printe spesifikk informasjon om felter vi er interessert i:
Notebook
print(f"Valid at {desired_validity}:\n")
for variable in filtered_variable_definitions:
print(
f"Id: {variable.id}\n"
f"Name: {variable.name}\n"
f"Short name: {variable.short_name}\n"
f"Definition: {variable.definition}\n"
f"Owner: {variable.owner}\n"
f"Valid: {variable.valid_from} to {variable.valid_until}\n"
)
Notebook
2030-02-24:
Valid at
Id: fDun32UF'nb': 'test navn', 'nn': 'test namn', 'en': 'test name'}
Name: {
Short name: test_shortname_obr'nb': 'Skriv en definisjonstekst på norsk bokmål.', 'nn': 'Skriv ein definisjonstekst på nynorsk.', 'en': 'Write a definition text in english.'}
Definition: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Owner: {2024-12-18 to None
Valid:
Id: Xww0Swou'nb': 'Inntekt etter skatt', 'nn': None, 'en': 'After-tax income'}
Name: {
Short name: wies'nb': 'Yrkesinntekter, kapitalinntekter, skattepliktige og skattefrie overføringer, i løpet av kalenderåret. Utlignet skatt og negative overføringer er trukket i fra.', 'nn': None, 'en': 'After-tax income is calculated as the sum of wages and salaries, income from self-employment, property income and transfers received minus total assessed taxes and negative transfers.'}
Definition: {'team': 'dapla-felles', 'groups': ['dapla-felles-developers']}
Owner: {1993-01-01 to None Valid:
Filtrere på eierteam
Man kan filtrere ut alle definisjoner som eies av speisifikt team. I eksempelet under listes det ut hvilke definisjoner som eies av team dapla-felles:
Notebook
= "dapla-felles"
owner_team print(f"\nFiltrer etter eierteam {owner_team}: \n")
= [variable for variable in variable_definitions if variable.owner["team"] == owner_team]
my_team_variables
for variable in my_team_variables:
print(f"Id: {variable.id}\nName: {variable.name['nb']}\nShort name: {variable.short_name}\nDefinition: {variable.definition['nb']}\nOwner: {variable.owner['team']}\n")
Notebook
-felles:
Filtrer etter eierteam dapla
Id: fDun32UF
Name: test navn
Short name: test_shortname_obr
Definition: Skriv en definisjonstekst på norsk bokmål.-felles
Owner: dapla
Id: Xww0Swou
Name: Inntekt etter skatt
Short name: wies
Definition: Yrkesinntekter, kapitalinntekter, skattepliktige og skattefrie overføringer, i løpet av kalenderåret. Utlignet skatt og negative overføringer er trukket i fra.-felles Owner: dapla
Filtrere etter status
Man kan filtrere etter status for en definisjon. Her filtrerer vi ut alle definisjoner med status Draft:
Notebook
print("\nFiltrer etter status `DRAFT`: ")
= [variable for variable in variable_definitions if variable.variable_status == models.VariableStatus.DRAFT]
draft_variables print(draft_variables)
På samme måte kan vi filtrere ut definisjoner som er publisert internt:
Notebook
print("\nFiltrer etter status `PUBLISHED INTERNAL`: ")
= [variable for variable in variable_definitions if variable.variable_status == models.VariableStatus.PUBLISHED_INTERNAL]
published_intern_variables
print(published_intern_variables)
Enkeltfelter i en definisjon
Hvis man kun ønsker å hente ut verdien til et enkeltfelt i en variabeldefinisjon kan man gjøre det på følgende måte:
Notebook
= next(variable for variable in variable_definitions if variable.short_name == "wies")
wies_vardef = wies_vardef.definition["nb"]
wies_definition_nb wies_definition_nb
Notebook
'Yrkesinntekter, kapitalinntekter, skattepliktige og skattefrie overføringer, i løpet av kalenderåret. Utlignet skatt og negative overføringer er trukket i fra.'
I koden over hentes beskrivelsen av variabelen med kortnavn wies på norsk bokmål. Spørring returnerer en string-objekt.
Opprette ny definisjon
Når man skal opprette en ny definisjon i Vardef, så må man forholde seg til hvordan eierskapet til definisjonen blir definert. Nye definisjoner kan kun opprettes fra en tjeneste på Dapla Lab med Python installert, og teamet man velger å representere når man logger seg inn i tjenesten, blir automatisk satt som eier av definisjonen i Vardef. Dette kan endres senere, men det letteste er at noen fra teamet som skal eie definisjonen gjør opprettelsen fra Dapla Lab.
Stegene for å opprette en ny variabeldefinisjon er som følger:
- Opprette et utkast (draft) av definisjonen med all obligatorisk informasjon.
- Publisere variabelen internt eller eksternt.
Publisering av en definisjon internt at det kun vil være SSB-ansatte som får tilgang til den. Å publisere eksternt betyr at den er tilgjengelige for andre også. Før man publiserer et utkast er det god praksis at informasjonen er kvalitetssikret av flere personen, spesielt siden en publisert definisjon aldri kan slettes. Endringer i en definisjon genererer kun en ny versjon eller mindre endring.
Opprette et utkast
Første steg for å publisere en ny variabeldefinisjon til Vardef er å opprette et utkast eller draft. Et utkast må inneholde all obligatorisk informasjon for en variabeldefinisjon. Et viktig poeng her er at utkastet også lagres datalageret til Vardef, og det sjekkes derfor ved opprettelse om all obligatorisk informasjon er fylt ut. Men når en variabel har status utkast i Vardef så er det tillatt å endre alle felter uten at en ny versjon opprettes.
Man kan opprette en ny definisjon ved å bruke Draft
-funksjonen models
-klassen:
Notebook
= models.Draft(
utkast = {
name "nb": "test navn",
"nn": "test namn",
"en": "test name",
},= "test_shortname",
short_name= {
definition"nb": "Skriv en definisjonstekst på norsk bokmål.",
"nn": "Skriv ein definisjonstekst på nynorsk.",
"en": "Write a definition text in english.",
},="91",
classification_reference=[
unit_types"01",
],=[
subject_fields"al",
],=False,
contains_special_categories_of_personal_data=None,
measurement_type=date(2024,12,18),
valid_from=None,
external_reference_uri=None,
comment=None,
related_variable_definition_uris=None,
contact
)
= Vardef.create_draft(utkast) my_draft
I koden over så har vi fylt inn all obligatorisk informasjon for de nye variabeldefinisjon i utkast
-variabelen. Deretter har vi publisert den til datalageret til Vardef med create_draft
-funksjonen. I tillegg ble den nye variabelen lagret i en variabel kalt my_draft
for å lettere kunne endre på variabelen senere.
Vi kan innholdet i variabelen som vi har lagret i datalageret til Vardef på følgende måte:
Notebook
print(my_draft)
Vi kan også aksessere enkeltfelter via dette objektet. F.eks. kan vi hente ut det maskingenererte feltet created_by for å validere brukerens navn er registrert:
Notebook
print(my_draft.created_by)
Publisere et utkast
Etter at informasjonen i et utkast er kvalitetssikret og ferdig, kan den publiseres internt (kun SSB-ansatte) eller eksternt (åpent for alle). Det er verdt å merke seg at en definisjon som er publisert eksternt ikke kan endres til å kun være publisert internt.
Når man publiserer en definisjon er det anbefalt å bruke VariableStatus
-klassen for å minimere sannsynligheten for skrivefeil i dette viktige steget.
Notebook
= models.UpdateDraft(
update_status =models.VariableStatus.PUBLISHED_INTERNAL,
variable_status
)
my_draft.update_draft(update_status)
Lister man ut alle variabeldefinisjoner vil man nå se at denne variabelen har fått
"variable_status": "PUBLISHED_INTERNAL"
.
Endre eksisterende definisjon
Variabeldefinisjoner i Vardef har enten status som publisert internt, publisert eksternt eller utkast. En definisjon med status utkast kan endres av eierteamet på en enkel måte. Men endringer i variablerdefinisjoner som er publisert internt eller eksternt omfattes av prinsippet om uforanderlighet i Vardef. En definisjon som har blitt publisert slettes aldri, og endringer kan kun skje ved å opprette nye versjoner. Det finnes to typer av versjoner i Vardef:
- Mindre endringer (patches)
Mindre endringer som ikke betyr noen innholdsmessige endring i beskrivelsen av variabelen. F.eks. retting av skrivefeil, legge til en oversettelse eller legge tilsubject_field
. - Større endringer
Endringer som innebærer innholdsmessige endringer i variabelen. F.eks. en ny skatteregel krever at beskrivelsen for en skattevariabel må oppdateres.
Slette et utkast
Man kan slette et utkast på følgende måte:
Notebook
my_vardok_draft.delete_draft()
Dette kan kun gjøres på definisjoner med status utkast/draft.
Mindre endringer
Mindre endringer, kalt patches i Vardef, er mindre endringer som ikke krever en ny gyldighetsperiode for variabelen. Under er det noen eksempler på slike endringer og hvordan de gjøres:
Endre eierteam
Notebook
from dapla_metadata.variable_definitions.generated.vardef_client.models.owner import (
Owner,
)from dapla_metadata.variable_definitions.generated.vardef_client.models.patch import (
Patch,
)
= Patch(
new_owner =Owner(
owner="dapla-felles",
team=[
groups"dapla-felles-developers",
"play-enhjoern-a-developers",
],
),
)
my_draft.create_patch(new_owner)
= Vardef.get_variable_definition(my_draft.id)
my_draft
print(my_draft.owner)
Større endringer
For å opprette en ny gyldighetsperiode må inndataene inneholde oppdatert beskrivelsestekst for alle gjeldende språk og en ny gyldig fra dato. En ny gyldighetsperiode bør kun opprettes når den grunnleggende definisjonen av variabelen har endret seg.
Notebook
= models.ValidityPeriod(
valid_validity_period ={
definition"nb": "ny definisjon2",
"nn": "ny definisjon2",
"en": "new definition2",
},=date(2040,4,5),
valid_from
) my_draft.create_validity_period(valid_validity_period)
Migrere definisjon fra Vardok
Eksternt publiserte variabeldefinisjoner fra Vardok kan migreres til Vardef med funksjonen migrate_from_vardok()
-funksjonen i dapla-toolbelt-metadata. For å migrere en variabeldefinisjon må man referere til variabelens ID i Vardok. Siden alle definisjoner er eid av en seksjon så har alle seksjoner en oversikt over hvilke definisjoner de er ansvarlig for, med tilhørende ID, og skal kun migrere disse definisjonene.
migrate_from_vardok()
-funksjonen migrerer alle feltene fra Vardok som skal videreføres til Vardef, oppdaterer felter automatisk der det er mulig, og publiserer den som et Utkast i Vardef. Deretter må hvert fagansvarlig gå gjennom all informasjon, gjøre nødvendige endringer og kvalitetssikre informasjonen, før den kan publiseres. Husk at eierteamet for definisjon blir bestemt av hvilket team man representerer i Dapla Lab når migrate_from_vardok()
-funksjonen kjøres.
I koden under vises et eksempel der definisjonen for Spesifisert registreringstype migreres fra Vardok til Vardef. ID-en til variabelen er 90 og derfor er det denne det refereres til i funksjonen:
Notebook
= Vardef.migrate_from_vardok("90")
my_vardok_draft print(my_vardok_draft)
Alle definisjoner i Vardef må ha et gyldig kortnavn,. Hvis en definisjon som migreres fra Vardok ikke har et kortnavn så vil det genereres et midlertidig kortnavn ved migrering. Dette kortnavnet må endres før definisjonen publiseres internt eller eksternt. Automatisk genererte kortnavn starter alltid med generert. Man kan liste ut alle definisjoner i Vardef med et generert kortnavn for et gitt Dapla-team, med følgende kode:
Notebook
= Vardef.migrate_from_vardok("123")
my_vardok_missing_short_name
= "dapla-felles"
my_owner_team
= [
my_team_variables_generert_kortnavn id}
{variable.short_name, variable.for variable in Vardef.list_variable_definitions()
if variable.owner["team"] == my_owner_team and variable.short_name.startswith("generert")
]
print(my_team_variables_generert_kortnavn)
En definisjon i Vardok kan kun migreres en gang. Hvis noen flere prøver å migrere en variabel vil man få en feilmelding i dapla-toolbelt-pseudo. Hvis den migrerte definisjonen har status Utkast, så er det mulig for eierteamet å slette utkastet, slik at et annet team kan migrere definisjonen. Eierteamet kan også overføre eierskapet til en definisjon i Vardef til et annet team.
Fotnoter
Vardok er SSBs tidligere system for variabeldefinisjoner og som erstattes av Vardef.↩︎