Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwood committed Dec 12, 2024
1 parent 1438d1b commit 136eb6e
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 137 deletions.
26 changes: 26 additions & 0 deletions cove/cove_360/fixtures/duration_errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"grants": [
{
"id": "360G-sampletrust-105177/Z/14/Z",
"awardDate": "2024-12-30",
"amountAwarded": 10,
"url": "http://example.com",
"title": "test",
"currency": "GBP",
"description": "test",
"recipientOrganization": [
{
"id": "GB-323242-test",
"name": "Example Project Limited"
}
],
"plannedDates": [],
"fundingOrganization": [
{
"id": "GB-323242-test",
"name": "Example Project Limited"
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h4>{{category}}</h4>
<table class="table">
<thead>
<tr>
<th>{% trans 'Passed' %}</th>
<th>{% trans 'Failed' %}</th>
<th>{% trans 'Check Description' %} </th>
<th>{% trans 'First 3 Locations' %}</th>
</tr>
Expand All @@ -45,7 +45,9 @@ <h4>{{category}}</h4>
<tr>
<td>
<div style="border-radius: 3px; background-color: hsl(var(--teal-dark-hsl), 1); width:100%; height:20px; min-width:90px">
<div style="border-radius: 3px; background-color: hsl(var(--red-hsl), 1); height: 20px; width: {{message.percentage|multiply:100}}%; min-width:5px"></div>
<div style="border-radius: 3px; background-color: hsl(var(--red-hsl), 1); height: 20px; width: {{message.percentage|multiply:100}}%; min-width:5px;">
<span style="color: white;" class="margin-left:1">{{message.percentage|multiply:100}}%</span>
</div>
</div>
</td>
<td>
Expand Down
9 changes: 8 additions & 1 deletion cove/cove_360/templatetags/cove_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ def cove_360_modal_list(**context):

@register.filter("multiply")
def multiply(a, b):
return a*b
""" Multiple a,b if result is less than one output 1 decimal place otherwise as a rounded int"""
res = a*b

if res < 1:
return f"{(a*b):.1f}"

return int(round(res))

13 changes: 11 additions & 2 deletions cove/cove_360/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,17 @@ def explore_360(request, pk, template='cove_360/explore.html'):
import pprint
pprint.pprint(context, stream=open("/tmp/dqt.py", "w"), indent=2)

context["usefulness_categories"] = set([message["category"] for message, a, b in context["usefulness_checks"]])
context["quality_accuracy_categories"] = set([message["category"] for message, a, b in context["quality_accuracy_checks"]])
try:
context["usefulness_categories"] = set([message["category"] for message, a, b in context["usefulness_checks"]])
except TypeError:
# if no usefulness_checks the iteration will fail
context["usefulness_categories"] = []

try:
context["quality_accuracy_categories"] = set([message["category"] for message, a, b in context["quality_accuracy_checks"]])
except TypeError:
# if no quality quality_accuracy categories the iteration will fail
context["quality_accuracy_categories"] = []

try:
context["quality_accuracy_checks_passed"] = create_passed_tests_context_data(context["quality_accuracy_checks"], TEST_CLASSES["quality_accuracy"])
Expand Down
110 changes: 110 additions & 0 deletions lib360dataquality/additional_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

class TestType(object):
QUALITY_TEST_CLASS = "quality_accuracy"
USEFULNESS_TEST_CLASS = "usefulness"


class TestRelevance(object):
RECIPIENT_ANY = ""
RECIPIENT_ORGANISATION = "recipient organisation"
RECIPIENT_INDIVIDUAL = "recipient individual"


class TestCategories(object):
GRANTS = "Grants"
ORGANISATIONS = "Organisations"
DATA_PROTECTION = "Data Protection"
DATES = "Dates"
LOCATION = "Location"
METADATA = "Metadata"


class AdditionalTest(object):
category = TestCategories.GRANTS

def __init__(self, **kw):
self.grants = kw["grants"]
self.aggregates = kw["aggregates"]
self.grants_percentage = 0
self.json_locations = []
self.failed = False
self.count = 0
self.heading = None
self.message = None
# Default to the most common type
self.relevant_grant_type = TestRelevance.RECIPIENT_ANY

def process(self, grant, path_prefix):
pass

def produce_message(self):
return {
"heading": self.heading,
"message": self.message,
"type": self.__class__.__name__,
"count": self.count,
"percentage": self.grants_percentage,
"category": self.__class__.category,
}

def get_heading_count(self, test_class_type):
# The total grants is contextual e.g. a test may fail for a recipient org-id
# this is only relevant to grants to organisations and not individuals
if self.relevant_grant_type == TestRelevance.RECIPIENT_ANY:
total = self.aggregates["count"]
elif self.relevant_grant_type == TestRelevance.RECIPIENT_ORGANISATION:
total = self.aggregates["count"] - self.aggregates["recipient_individuals_count"]
elif self.relevant_grant_type == TestRelevance.RECIPIENT_INDIVIDUAL:
# if there are no individuals in this data then reset the count
if self.aggregates["recipient_individuals_count"] == 0:
self.count = 0
total = self.aggregates["recipient_individuals_count"]

# Guard against a division by 0
if total < 1:
total = 1

self.grants_percentage = self.count / total

# Return conditions

if test_class_type == TestType.QUALITY_TEST_CLASS:
return self.count

if self.aggregates["count"] == 1 and self.count == 1:
self.grants_percentage = 1.0
return f"1 {self.relevant_grant_type}".strip()

if self.count <= 5:
return f"{self.count} {self.relevant_grant_type}".strip()

return f"{round(self.grants_percentage*100)}% of {self.relevant_grant_type}".strip()

def format_heading_count(self, message, test_class_type=None, verb="have"):
"""Build a string with count of grants plus message
The grant count phrase for the test is pluralized and
prepended to message, eg: 1 grant has + message,
2 grants have + message or 3 grants contain + message.
"""
noun = "grant" if self.count == 1 else "grants"

# Positive result - "what is working well"
# Avoid double negative
if not message.startswith("not have") and message.startswith("not") and self.count == 0:
message = message[len("not"):]
if message.startswith("not have") and self.count == 0:
verb = "do"
# End positive result flip

if verb == "have":
verb = "has" if self.count == 1 else verb
elif verb == "do":
verb = "does" if self.count == 1 else verb
else:
# Naively!
verb = verb + "s" if self.count == 1 else verb

return "{} {} {} {}".format(
self.get_heading_count(test_class_type), noun, verb, message
)
4 changes: 2 additions & 2 deletions lib360dataquality/check_field_present.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from lib360dataquality.cove.threesixtygiving import AdditionalTest, RECIPIENT_INDIVIDUAL
from lib360dataquality.additional_test import AdditionalTest, TestRelevance
from functools import wraps


Expand Down Expand Up @@ -109,7 +109,7 @@ class IndividualsCodeListsNotPresent(FieldNotPresentBase):

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.relevant_grant_type = RECIPIENT_INDIVIDUAL
self.relevant_grant_type = TestRelevance.RECIPIENT_INDIVIDUAL

def check_field(self, grant):
# Not relevant
Expand Down
Loading

0 comments on commit 136eb6e

Please sign in to comment.