Skip to content

Commit

Permalink
Merge pull request #50 from ai-cfia/41-correct-phone-number-and-url-f…
Browse files Browse the repository at this point in the history
…ormat

Issue #41: correct phone number and url format in FertilizerInspection
  • Loading branch information
k-allagbe authored Oct 25, 2024
2 parents 5f757f7 + 01a4b50 commit e0eac92
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 49 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -171,5 +171,6 @@ cython_debug/

# Testing artifacts
end_to_end_pipeline_artifacts
reports
logs

logs/
reports/
40 changes: 31 additions & 9 deletions pipeline/inspection.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import re
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator, model_validator

import phonenumbers
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator


class npkError(ValueError):
pass
Expand Down Expand Up @@ -58,10 +61,10 @@ def replace_none_with_empty_list(cls, v):
if v is None:
v = []
return v

@model_validator(mode="after")
def set_is_minimal(self):
pattern = r'\bminim\w*\b'
pattern = r"\bminim\w*\b"
if self.title:
self.is_minimal = re.search(pattern, self.title, re.IGNORECASE) is not None
return self
Expand All @@ -87,11 +90,15 @@ class FertilizerInspection(BaseModel):
company_name: Optional[str] = None
company_address: Optional[str] = None
company_website: Optional[str] = None
company_phone_number: Optional[str] = None
company_phone_number: Optional[str] = Field(
None, description="The distributor's primary phone number. Return only one."
)
manufacturer_name: Optional[str] = None
manufacturer_address: Optional[str] = None
manufacturer_website: Optional[str] = None
manufacturer_phone_number: Optional[str] = None
manufacturer_phone_number: Optional[str] = Field(
None, description="The manufacturer's primary phone number. Return only one."
)
fertiliser_name: Optional[str] = None
registration_number: Optional[str] = None
lot_number: Optional[str] = None
Expand All @@ -107,6 +114,7 @@ class FertilizerInspection(BaseModel):
instructions_fr: List[str] = []
ingredients_en: List[NutrientValue] = []
ingredients_fr: List[NutrientValue] = []
model_config = ConfigDict(populate_by_name=True)

@field_validator("npk", mode="before")
def validate_npk(cls, v):
Expand All @@ -130,14 +138,28 @@ 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]$'
pattern = r"^\d{7}[A-Z]$"
if re.match(pattern, v):
return v
return None

class Config:
populate_by_name = True
@field_validator("company_phone_number", "manufacturer_phone_number", mode="before")
def check_phone_number_format(cls, v):
if v is None:
return

try:
phone_number = phonenumbers.parse(v, "CA")
if not phonenumbers.is_valid_number(phone_number):
return
phone_number = phonenumbers.format_number(
phone_number, phonenumbers.PhoneNumberFormat.E164
)
return phone_number

except phonenumbers.phonenumberutil.NumberParseException:
return
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.4"
version = "0.0.5"
description = "A pipeline for the FertiScan project"
authors = [
{ name = "Albert Bryan Ndjeutcha", email = "[email protected]" }
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ openinference-instrumentation-dspy
python-dotenv
reportlab
setuptools
phonenumbers
# Test dependencies
Levenshtein
pytest
57 changes: 49 additions & 8 deletions tests/test_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

from pipeline.inspection import (
FertilizerInspection,
GuaranteedAnalysis,
NutrientValue,
Specification,
Value,
GuaranteedAnalysis,
)


Expand Down Expand Up @@ -206,26 +206,27 @@ def test_invalid_npk(self):
inspection.npk, f"Expected None for npk with input {npk}"
)


class TestGuaranteedAnalysis(unittest.TestCase):

def setUp(self):
self.nutrient_1 = NutrientValue(nutrient="Nitrogen", value="2", unit="mg/L")
self.nutrient_2 = NutrientValue(nutrient="Organic matter", value="15", unit="mg/L")
self.nutrient_2 = NutrientValue(
nutrient="Organic matter", value="15", unit="mg/L"
)

def test_set_is_minimal(self):
guaranteed_analysis = GuaranteedAnalysis(
title="Guaranteed minimum analysis",
nutrients=[self.nutrient_1, self.nutrient_2]
nutrients=[self.nutrient_1, self.nutrient_2],
)
self.assertTrue(guaranteed_analysis.is_minimal)

def test_set_is_not_minimal(self):
guaranteed_analysis = GuaranteedAnalysis(
title="Guaranteed analysis",
nutrients=[self.nutrient_1, self.nutrient_2]
title="Guaranteed analysis", nutrients=[self.nutrient_1, self.nutrient_2]
)
self.assertFalse(guaranteed_analysis.is_minimal)

def test_is_minimal_in_none(self):
guaranteed_analysis = GuaranteedAnalysis(
nutrients=[self.nutrient_1, self.nutrient_2]
Expand Down Expand Up @@ -268,7 +269,8 @@ def test_replace_none_with_empty_list(self):
self.assertEqual(inspection.ingredients_en, [])
self.assertEqual(inspection.ingredients_fr, [])
self.assertEqual(inspection.weight, [])



class TestFertilizerInspectionRegistrationNumber(unittest.TestCase):
def test_registration_number_with_less_digits(self):
instance = FertilizerInspection(registration_number="1234")
Expand Down Expand Up @@ -299,5 +301,44 @@ def test_registration_number_mixed_format(self):
self.assertIsNone(instance.registration_number)


class TestFertilizerInspectionPhoneNumberFormat(unittest.TestCase):
def test_valid_phone_number_with_country_code(self):
instance = FertilizerInspection(company_phone_number="+1 800 640 9605")
self.assertEqual(instance.company_phone_number, "+18006409605")

def test_valid_phone_number_without_country_code(self):
instance = FertilizerInspection(company_phone_number="800 640 9605")
self.assertEqual(instance.company_phone_number, "+18006409605")

def test_phone_number_with_parentheses(self):
instance = FertilizerInspection(company_phone_number="(757) 321-4567")
self.assertEqual(instance.company_phone_number, "+17573214567")

def test_phone_number_with_extra_characters(self):
instance = FertilizerInspection(company_phone_number="+1 800 321-9605 FAX")
self.assertIsNone(instance.company_phone_number)

def test_phone_number_with_multiple_numbers(self):
instance = FertilizerInspection(
company_phone_number="(757) 123-4567 (800) 456-7890, 1234567890"
)
self.assertIsNone(instance.company_phone_number)

def test_phone_number_from_other_country(self):
instance = FertilizerInspection(manufacturer_phone_number="+44 20 7946 0958")
self.assertEqual(instance.manufacturer_phone_number, "+442079460958")

def test_invalid_phone_number(self):
instance = FertilizerInspection(company_phone_number="invalid phone")
self.assertIsNone(instance.company_phone_number)

def test_phone_number_with_invalid_format(self):
instance = FertilizerInspection(company_phone_number="12345")
self.assertIsNone(instance.company_phone_number)


if __name__ == "__main__":
unittest.main()

if __name__ == "__main__":
unittest.main()
Loading

0 comments on commit e0eac92

Please sign in to comment.