Skip to content

Commit

Permalink
Issue #30 : Support for multiple Registration Number (#73)
Browse files Browse the repository at this point in the history
* Add registration number validation and update FertilizerInspection model

* Refactor registration number handling to support structured data format and enhance validation tests

* Improve registration number validation and fix website field assertion in tests

* Update RegistrationNumber model to allow optional fields and improve validation handling

* Fix registration number type validation to use enum member values

* Refactor RegistrationNumber model to use string type for registration number and update validation logic; add initial test for label analysis

* Remove unused import of Enum from inspection.py

* Remove registration number validation from FertilizerInspection and update tests to use RegistrationNumber model

* Bump version to 0.0.9 in pyproject.toml

* Bump version to 0.0.10 in pyproject.toml and ensure workflow configuration is up to date
  • Loading branch information
snakedye authored Dec 2, 2024
1 parent 34a2eee commit 956ed28
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/project-issue-status.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ on:
jobs:
issue-status:
uses: ai-cfia/github-workflows/.github/workflows/workflow-issue-status.yml@main
secrets: inherit
secrets: inherit
7 changes: 6 additions & 1 deletion expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
}
],
"fertiliser_name": "GreenGrow Fertilizer 20-20-20",
"registration_number": "2018007A",
"registration_number": [
{
"identifier": "2018007A",
"type": "fertilizer_product"
}
],
"lot_number": "LOT20240901",
"weight": [
{
Expand Down
30 changes: 21 additions & 9 deletions pipeline/inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,25 @@ def convert_value(cls, v):
return extract_first_number(v)
return None

# class syntax

class RegistrationNumber(BaseModel):
identifier: Optional[str] = Field(..., description="A string composed of 7-digit number followed by an uppercase letter.")
type: Optional[str] = Field(None, description="Type of registration number, either 'ingredient_component' or 'fertilizer_product'.")

@field_validator("identifier", mode="before")
def check_registration_number_format(cls, v):
if v is not None:
pattern = r"^\d{7}[A-Z]$"
if re.match(pattern, v):
return v
return None

@field_validator("type", mode="before")
def check_registration_number_type(cls, v):
if v not in ["ingredient_component", "fertilizer_product"]:
return None
return v

class GuaranteedAnalysis(BaseModel):
title: Optional[str] = None
Expand Down Expand Up @@ -129,7 +148,7 @@ def convert_specification_values(cls, v):
class FertilizerInspection(BaseModel):
organizations: List[Organization] = []
fertiliser_name: Optional[str] = None
registration_number: Optional[str] = None
registration_number: List[RegistrationNumber] = []
lot_number: Optional[str] = None
weight: List[Value] = []
density: Optional[Value] = None
Expand Down Expand Up @@ -160,6 +179,7 @@ def validate_npk(cls, v):
"instructions_fr",
"ingredients_en",
"ingredients_fr",
"registration_number",
"organizations",
"weight",
mode="before",
Expand All @@ -168,11 +188,3 @@ def replace_none_with_empty_list(cls, v):
if v is None:
v = []
return v

@field_validator("registration_number", mode="before")
def check_registration_number_format(cls, v):
if v is not None:
pattern = r"^\d{7}[A-Z]$"
if re.match(pattern, v):
return v
return None
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "fertiscan_pipeline"
version = "0.0.9"
version = "0.0.10"
description = "A pipeline for the FertiScan project"
authors = [
{ name = "Albert Bryan Ndjeutcha", email = "albert.ndjeutcha@inspection.gc.ca" }
Expand Down
101 changes: 86 additions & 15 deletions tests/test_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pipeline.inspection import (
FertilizerInspection,
GuaranteedAnalysis,
RegistrationNumber,
NutrientValue,
Specification,
Organization,
Expand Down Expand Up @@ -234,6 +235,71 @@ def test_invalid_npk(self):
inspection.npk, f"Expected None for npk with input {npk}"
)

class TestRegistrationNumber(unittest.TestCase):
def setUp(self):
self.valid_registration_number_data = [
"1234567A",
"1234567B",
"1234567C",
"1234567D",
"1234567E",
"1234567F",
"1234567G",
"1234567H",
"1234567I",
"1234567J",
"1234567K",
"1234567L",
"1234567M",
"1234567N",
"1234567O",
"1234567P",
"1234567Q",
"1234567R",
"1234567S",
"1234567T",
"1234567U",
"1234567V",
"1234567W",
"1234567X",
"1234567Y",
"1234567Z",
]

self.invalid_registration_number_data = [
"1234567",
"1234567AA",
"1234567A1",
"1234567A ",
"1234567 A",
"1234567A-",
"1234567A.",
"1234567A,",
]

self.invalid_registration_type_data = [
"FERTILIZER",
"INGREDIENT",
"PRODUCT",
"COMPONENT",
]

def test_valid_registration_number(self):
for registration_number in self.valid_registration_number_data:
with self.subTest(registration_number=registration_number):
registration = RegistrationNumber(identifier=registration_number)
self.assertEqual(registration.identifier, registration_number)

def test_invalid_registration_number(self):
for registration_number in self.invalid_registration_number_data:
with self.subTest(registration_number=registration_number):
self.assertIsNone(RegistrationNumber(identifier=registration_number, type="fertilizer_product").identifier)

def test_invalid_registration_type(self):
for registration_type in self.invalid_registration_type_data:
with self.subTest(registration_type=registration_type):
self.assertIsNone(RegistrationNumber(identifier="1234567A", type=registration_type).type)


class TestGuaranteedAnalysis(unittest.TestCase):
def setUp(self):
Expand Down Expand Up @@ -266,7 +332,12 @@ class TestFertilizerInspectionListFields(unittest.TestCase):
def setUp(self):
self.default_data = {
"fertiliser_name": "Test Fertilizer",
"registration_number": "ABC123",
"registration_number": [
{
"identifier": "1234567A",
"type": "fertilizer_product",
}
],
"lot_number": "LOT987",
"npk": "10-5-20",
"guaranteed_analysis_en": None,
Expand All @@ -293,32 +364,32 @@ def test_replace_none_with_empty_list(self):

class TestFertilizerInspectionRegistrationNumber(unittest.TestCase):
def test_registration_number_with_less_digits(self):
instance = FertilizerInspection(registration_number="1234")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="1234")
self.assertIsNone(instance.identifier)

def test_registration_number_less_than_seven_digits(self):
instance = FertilizerInspection(registration_number="12345A")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="12345A")
self.assertIsNone(instance.identifier)

def test_registration_number_seven_digits_no_letter(self):
instance = FertilizerInspection(registration_number="1234567")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="1234567")
self.assertIsNone(instance.identifier)

def test_registration_number_seven_digits_with_lowercase_letter(self):
instance = FertilizerInspection(registration_number="1234567a")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="1234567a")
self.assertIsNone(instance.identifier)

def test_registration_number_correct_format(self):
instance = FertilizerInspection(registration_number="1234567A")
self.assertEqual(instance.registration_number, "1234567A")
instance = RegistrationNumber(identifier="1234567A")
self.assertEqual(instance.identifier, "1234567A")

def test_registration_number_extra_characters(self):
instance = FertilizerInspection(registration_number="12345678B")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="12345678B")
self.assertIsNone(instance.identifier)

def test_registration_number_mixed_format(self):
instance = FertilizerInspection(registration_number="12A34567B")
self.assertIsNone(instance.registration_number)
instance = RegistrationNumber(identifier="12A34567B")
self.assertIsNone(instance.identifier)


class TestOrganizationPhoneNumberFormat(unittest.TestCase):
Expand Down

0 comments on commit 956ed28

Please sign in to comment.