Skip to content

Commit

Permalink
Move some methods into registry.py
Browse files Browse the repository at this point in the history
  • Loading branch information
hugorodgerbrown committed Sep 24, 2023
1 parent 2db5ac2 commit 327d210
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 31 deletions.
14 changes: 3 additions & 11 deletions anonymiser/management/commands/display_model_anonymisation.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,16 @@
from typing import Any

from django.apps import apps
from django.core.management.base import BaseCommand
from django.db.models import Model
from django.template.loader import render_to_string

from anonymiser.registry import get_model_anonymiser
from anonymiser import registry


class Command(BaseCommand):
def get_models(self) -> list[type[Model]]:
"""Force alphabetical order of models."""
return sorted(apps.get_models(), key=lambda m: m._meta.label)

def handle(self, *args: Any, **options: Any) -> None:
for model in self.get_models():
if anonymiser := get_model_anonymiser(model):
data = anonymiser.get_model_field_summary()
model_fields = registry.get_all_model_fields()
out = render_to_string(
"display_model_anonymisation.md",
{"anonymised_models": data},
{"model_fields": model_fields},
)
self.stdout.write(out)
4 changes: 2 additions & 2 deletions anonymiser/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ class RedacterBase(_ModelBase):
custom_field_redactions: dict[str, Any] = {}

class FieldRedactionStratgy(StrEnum):
AUTO = "auto"
CUSTOM = "custom"
AUTO = "AUTO"
CUSTOM = "CUSTOM"
NONE = ""

def is_field_redaction_auto(self, field: models.Field) -> bool:
Expand Down
29 changes: 28 additions & 1 deletion anonymiser/registry.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import logging
import threading
from collections import defaultdict

from django.apps import apps
from django.db import models

from .models import ModelAnonymiser
from .models import ModelAnonymiser, ModelFieldSummary

lock = threading.Lock()
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -47,3 +49,28 @@ def get_model_anonymiser(
if anonymiser := _registry.get(model):
return anonymiser()
return None


def get_all_model_fields(
anonymised_only: bool = False,
) -> dict[str, list[ModelFieldSummary]]:
"""
Return all models and their fields as ModelFieldSummary.
The return dict uses the `app.Model` string format as the dict key,
with a list of all fields as the value. This method includes all
models by default unless the `anonymised_only`
param is True.
"""
models = sorted(apps.get_models(), key=lambda m: m._meta.label)
output = defaultdict(list)
for m in models:
anonymiser = get_model_anonymiser(m)
if anonymised_only and not anonymiser:
continue
for f in m._meta.get_fields():
output[m._meta.label].append(ModelFieldSummary(m, f, anonymiser))
# sort fields by type then name - easier to scan.
output[m._meta.label].sort(key=lambda d: f"{d.field_type}.{d.field_name}")
return dict(output)
11 changes: 2 additions & 9 deletions anonymiser/templates/display_model_anonymisation.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# Model Anonymisation Snapshot

## Registered model anonymisers
Model | Anonymiser
--- | ---{% for model,anonymiser in model_anonymisers.items %}
{{ model }} | {{ anonymiser|default:"-" }} {% endfor %}

## Model field anonymisation
App | Model | Field | Type | Anonymise | Redacte
--- | --- | --- | --- | --- | ---{% for field in anonymised_models %}
{{ field.app }} | {{ field.model }} | {{ field.field_name }} | {{ field.field_type }} | {% if field.is_anonymised %}X{% else %}-{% endif %} | {{ field.redaction_strategy|default:"-" }}{% endfor %}
--- | --- | --- | --- | --- | ---{% for model,fields in anonymised_models.items %}{% for field in fields %}
{{ field.app }} | {{ field.model }} | {{ field.field_name }} | {{ field.field_type }} | {{ field.is_anonymised|default:"-" }} | {{ field.redaction_strategy|default:"-"|upper }}{% endfor %}{% endfor %}
16 changes: 8 additions & 8 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ def test_model_fields_summary(user_anonymiser: UserAnonymiser) -> None:


def test_model_fields_data(user_anonymiser: UserAnonymiser) -> None:
fsd = ModelFieldSummary(User, User._meta.get_field("first_name"), user_anonymiser)
assert fsd.app == "tests"
assert fsd.model == "User"
assert fsd.field_name == "first_name"
assert fsd.field_type == "CharField"
assert fsd.is_anonymised is True
assert fsd.is_redacted is True
assert fsd.redaction_strategy == user_anonymiser.FieldRedactionStratgy.AUTO
mfs = ModelFieldSummary(User, User._meta.get_field("first_name"), user_anonymiser)
assert mfs.app == "tests"
assert mfs.model == "User"
assert mfs.field_name == "first_name"
assert mfs.field_type == "CharField"
assert mfs.is_anonymised is True
assert mfs.is_redacted is True
assert mfs.redaction_strategy == user_anonymiser.FieldRedactionStratgy.CUSTOM


@pytest.mark.django_db
Expand Down

0 comments on commit 327d210

Please sign in to comment.