Skip to content

Commit

Permalink
Base TCF v3 Mapping (#167)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Sachs <[email protected]>
Co-authored-by: Rachel Silver <[email protected]>
  • Loading branch information
3 people authored Sep 14, 2023
1 parent 1da0a0c commit 034b399
Show file tree
Hide file tree
Showing 8 changed files with 399 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The types of changes are:

## [Unreleased](https://github.com/ethyca/fideslang/compare/2.0.4...main)

### Added

- Added GVL mappings and utility functions [#167](https://github.com/ethyca/fideslang/pull/167)


## [2.0.4](https://github.com/ethyca/fideslang/compare/2.0.3...2.0.4)
Expand Down
11 changes: 11 additions & 0 deletions src/fideslang/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

from ._version import __version__

# export our GVL utilities
from .gvl import (
GVL_PURPOSES,
GVL_SPECIAL_PURPOSES,
MAPPED_PURPOSES,
MAPPED_PURPOSES_BY_DATA_USE,
MAPPED_SPECIAL_PURPOSES,
data_use_to_purpose,
purpose_to_data_use,
)

# Export the Models
from .models import (
DataCategory,
Expand Down
111 changes: 111 additions & 0 deletions src/fideslang/gvl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import os
from json import load
from os.path import dirname, join
from typing import Dict, List, Optional

from .models import Feature, MappedPurpose, Purpose

PURPOSE_MAPPING_FILE = join(
dirname(__file__),
"",
"gvl_data_use_mapping.json",
)

FEATURE_MAPPING_FILE = join(
dirname(__file__),
"",
"gvl_feature_mapping.json",
)


GVL_PURPOSES: Dict[int, Purpose] = {}
MAPPED_PURPOSES: Dict[int, MappedPurpose] = {}

GVL_SPECIAL_PURPOSES: Dict[int, Purpose] = {}
MAPPED_SPECIAL_PURPOSES: Dict[int, MappedPurpose] = {}

GVL_FEATURES: Dict[int, Feature] = {}
GVL_SPECIAL_FEATURES: Dict[int, Feature] = {}
FEATURES_BY_NAME: Dict[str, Feature] = {}

MAPPED_PURPOSES_BY_DATA_USE: Dict[str, MappedPurpose] = {}


def _load_data() -> None:
with open(
os.path.join(os.curdir, PURPOSE_MAPPING_FILE), encoding="utf-8"
) as mapping_file:
data = load(mapping_file)
for raw_purpose in data["purposes"].values():
purpose = Purpose.parse_obj(raw_purpose)
mapped_purpose = MappedPurpose.parse_obj(raw_purpose)
GVL_PURPOSES[purpose.id] = purpose
MAPPED_PURPOSES[mapped_purpose.id] = mapped_purpose
for data_use in mapped_purpose.data_uses:
MAPPED_PURPOSES_BY_DATA_USE[data_use] = mapped_purpose

for raw_special_purpose in data["specialPurposes"].values():
special_purpose = Purpose.parse_obj(raw_special_purpose)
mapped_special_purpose = MappedPurpose.parse_obj(raw_special_purpose)
GVL_SPECIAL_PURPOSES[special_purpose.id] = special_purpose
MAPPED_SPECIAL_PURPOSES[mapped_special_purpose.id] = mapped_special_purpose
for data_use in mapped_special_purpose.data_uses:
MAPPED_PURPOSES_BY_DATA_USE[data_use] = mapped_special_purpose

with open(
os.path.join(os.curdir, FEATURE_MAPPING_FILE), encoding="utf-8"
) as feature_mapping_file:
feature_data = load(feature_mapping_file)

for raw_feature in feature_data["features"].values():
feature = Feature.parse_obj(raw_feature)
GVL_FEATURES[feature.id] = feature
FEATURES_BY_NAME[feature.name] = feature

for raw_special_feature in feature_data["specialFeatures"].values():
special_feature = Feature.parse_obj(raw_special_feature)
GVL_SPECIAL_FEATURES[special_feature.id] = special_feature
FEATURES_BY_NAME[special_feature.name] = special_feature


def purpose_to_data_use(purpose_id: int, special_purpose: bool = False) -> List[str]:
"""
Utility function to return the fideslang data uses associated with the
given GVL purpose (or special purpose) ID.
By default, the given ID is treated as a purpose ID. The `special_purpose`
argument can be set to `True` if looking up special purpose IDs.
Raises a KeyError if an invalid purpose ID is provided.
"""
purpose_map = MAPPED_SPECIAL_PURPOSES if special_purpose else MAPPED_PURPOSES
return purpose_map[purpose_id].data_uses


def data_use_to_purpose(data_use: str) -> Optional[Purpose]:
"""
Utility function to return the GVL purpose (or special purpose) associated
with the given fideslang data use.
Returns None if no associated purpose (or special purpose) is found
"""
return MAPPED_PURPOSES_BY_DATA_USE.get(data_use, None)


def feature_name_to_feature(feature_name: str) -> Optional[Feature]:
"""Utility function to return a GVL feature (or special feature) given the feature's name"""
return FEATURES_BY_NAME.get(feature_name, None)


def feature_id_to_feature_name(
feature_id: int, special_feature: bool = False
) -> Optional[str]:
"""Utility function to return a GVL feature/special feature name given the feature/special feature's id"""
feature_map = GVL_SPECIAL_FEATURES if special_feature else GVL_FEATURES
feature = feature_map.get(feature_id, None)
if not feature:
return None
return feature.name


_load_data()
Loading

0 comments on commit 034b399

Please sign in to comment.