Skip to content

Commit 8a0c11e

Browse files
authored
Merge pull request #212 from FullStackWithLawrence/next
refactor pydantic validations
2 parents 3550fa9 + 647ace4 commit 8a0c11e

File tree

5 files changed

+41
-36
lines changed

5 files changed

+41
-36
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ A REST API implementing each of the [30 example applications](https://platform.o
8484

8585
## Requirements
8686

87+
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). _pre-installed on Linux and macOS_
88+
- [make](https://gnuwin32.sourceforge.net/packages/make.htm). _pre-installed on Linux and macOS._
8789
- [AWS account](https://aws.amazon.com/)
8890
- [AWS Command Line Interface](https://aws.amazon.com/cli/)
8991
- [Terraform](https://www.terraform.io/).

api/terraform/python/openai_api/common/conf.py

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
OpenAIAPIConfigurationError,
2727
OpenAIAPIValueError,
2828
)
29-
from pydantic import Field, SecretStr, ValidationError, validator
29+
from pydantic import Field, SecretStr, ValidationError, ValidationInfo, field_validator
3030
from pydantic_settings import BaseSettings
3131

3232

@@ -400,25 +400,26 @@ class Config:
400400

401401
frozen = True
402402

403-
@validator("aws_profile", pre=True)
403+
@field_validator("aws_profile")
404404
# pylint: disable=no-self-argument,unused-argument
405405
def validate_aws_profile(cls, v, values, **kwargs) -> str:
406406
"""Validate aws_profile"""
407407
if v in [None, ""]:
408408
return SettingsDefaults.AWS_PROFILE
409409
return v
410410

411-
@validator("aws_region", pre=True)
411+
@field_validator("aws_region")
412412
# pylint: disable=no-self-argument,unused-argument
413-
def validate_aws_region(cls, v, values, **kwargs) -> str:
413+
def validate_aws_region(cls, v, values: ValidationInfo, **kwargs) -> str:
414414
"""Validate aws_region"""
415+
valid_regions = values.data.get("aws_regions", [])
415416
if v in [None, ""]:
416417
return SettingsDefaults.AWS_REGION
417-
if "aws_regions" in values and v not in values["aws_regions"]:
418+
if v not in valid_regions:
418419
raise OpenAIAPIValueError(f"aws_region {v} not in aws_regions")
419420
return v
420421

421-
@validator("aws_apigateway_root_domain", pre=True)
422+
@field_validator("aws_apigateway_root_domain")
422423
def validate_aws_apigateway_root_domain(cls, v) -> str:
423424
"""Validate aws_apigateway_root_domain"""
424425
if v in [None, ""]:
@@ -427,7 +428,7 @@ def validate_aws_apigateway_root_domain(cls, v) -> str:
427428
raise OpenAIAPIValueError("Invalid root domain name")
428429
return v
429430

430-
@validator("aws_apigateway_custom_domain_name", pre=True)
431+
@field_validator("aws_apigateway_custom_domain_name")
431432
def validate_aws_apigateway_custom_domain_name(cls, v) -> str:
432433
"""Validate aws_apigateway_custom_domain_name"""
433434
if v in [None, ""]:
@@ -436,42 +437,42 @@ def validate_aws_apigateway_custom_domain_name(cls, v) -> str:
436437
raise OpenAIAPIValueError("Invalid custom domain name")
437438
return v
438439

439-
@validator("aws_apigateway_custom_domain_name", pre=True)
440+
@field_validator("aws_apigateway_custom_domain_name")
440441
def validate_aws_apigateway_custom_domain_name_create(cls, v) -> bool:
441442
"""Validate aws_apigateway_custom_domain_name_create"""
442443
if v in [None, ""]:
443444
return SettingsDefaults.AWS_APIGATEWAY_CUSTOM_DOMAIN_NAME_CREATE
444445
return v
445446

446-
@validator("shared_resource_identifier", pre=True)
447+
@field_validator("shared_resource_identifier")
447448
def validate_shared_resource_identifier(cls, v) -> str:
448449
"""Validate shared_resource_identifier"""
449450
if v in [None, ""]:
450451
return SettingsDefaults.SHARED_RESOURCE_IDENTIFIER
451452
return v
452453

453-
@validator("aws_dynamodb_table_id", pre=True)
454+
@field_validator("aws_dynamodb_table_id")
454455
def validate_table_id(cls, v) -> str:
455456
"""Validate aws_dynamodb_table_id"""
456457
if v in [None, ""]:
457458
return SettingsDefaults.AWS_DYNAMODB_TABLE_ID
458459
return v
459460

460-
@validator("aws_rekognition_collection_id", pre=True)
461+
@field_validator("aws_rekognition_collection_id")
461462
def validate_collection_id(cls, v) -> str:
462463
"""Validate aws_rekognition_collection_id"""
463464
if v in [None, ""]:
464465
return SettingsDefaults.AWS_REKOGNITION_COLLECTION_ID
465466
return v
466467

467-
@validator("aws_rekognition_face_detect_attributes", pre=True)
468+
@field_validator("aws_rekognition_face_detect_attributes")
468469
def validate_face_detect_attributes(cls, v) -> str:
469470
"""Validate aws_rekognition_face_detect_attributes"""
470471
if v in [None, ""]:
471472
return SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_ATTRIBUTES
472473
return v
473474

474-
@validator("debug_mode", pre=True)
475+
@field_validator("debug_mode")
475476
def parse_debug_mode(cls, v) -> bool:
476477
"""Parse debug_mode"""
477478
if isinstance(v, bool):
@@ -480,7 +481,7 @@ def parse_debug_mode(cls, v) -> bool:
480481
return SettingsDefaults.DEBUG_MODE
481482
return v.lower() in ["true", "1", "t", "y", "yes"]
482483

483-
@validator("dump_defaults", pre=True)
484+
@field_validator("dump_defaults")
484485
def parse_dump_defaults(cls, v) -> bool:
485486
"""Parse dump_defaults"""
486487
if isinstance(v, bool):
@@ -489,14 +490,14 @@ def parse_dump_defaults(cls, v) -> bool:
489490
return SettingsDefaults.DUMP_DEFAULTS
490491
return v.lower() in ["true", "1", "t", "y", "yes"]
491492

492-
@validator("aws_rekognition_face_detect_max_faces_count", pre=True)
493+
@field_validator("aws_rekognition_face_detect_max_faces_count")
493494
def check_face_detect_max_faces_count(cls, v) -> int:
494495
"""Check aws_rekognition_face_detect_max_faces_count"""
495496
if v in [None, ""]:
496497
return SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_MAX_FACES_COUNT
497498
return int(v)
498499

499-
@validator("aws_rekognition_face_detect_threshold", pre=True)
500+
@field_validator("aws_rekognition_face_detect_threshold")
500501
def check_face_detect_threshold(cls, v) -> int:
501502
"""Check aws_rekognition_face_detect_threshold"""
502503
if isinstance(v, int):
@@ -505,14 +506,14 @@ def check_face_detect_threshold(cls, v) -> int:
505506
return SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_THRESHOLD
506507
return int(v)
507508

508-
@validator("aws_rekognition_face_detect_quality_filter", pre=True)
509+
@field_validator("aws_rekognition_face_detect_quality_filter")
509510
def check_face_detect_quality_filter(cls, v) -> str:
510511
"""Check aws_rekognition_face_detect_quality_filter"""
511512
if v in [None, ""]:
512513
return SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_QUALITY_FILTER
513514
return v
514515

515-
@validator("langchain_memory_key", pre=True)
516+
@field_validator("langchain_memory_key")
516517
def check_langchain_memory_key(cls, v) -> str:
517518
"""Check langchain_memory_key"""
518519
if isinstance(v, int):
@@ -521,21 +522,21 @@ def check_langchain_memory_key(cls, v) -> str:
521522
return SettingsDefaults.LANGCHAIN_MEMORY_KEY
522523
return v
523524

524-
@validator("openai_api_organization", pre=True)
525+
@field_validator("openai_api_organization")
525526
def check_openai_api_organization(cls, v) -> str:
526527
"""Check openai_api_organization"""
527528
if v in [None, ""]:
528529
return SettingsDefaults.OPENAI_API_ORGANIZATION
529530
return v
530531

531-
@validator("openai_api_key", pre=True)
532+
@field_validator("openai_api_key")
532533
def check_openai_api_key(cls, v) -> SecretStr:
533534
"""Check openai_api_key"""
534535
if v in [None, ""]:
535536
return SettingsDefaults.OPENAI_API_KEY
536537
return v
537538

538-
@validator("openai_endpoint_image_n", pre=True)
539+
@field_validator("openai_endpoint_image_n")
539540
def check_openai_endpoint_image_n(cls, v) -> int:
540541
"""Check openai_endpoint_image_n"""
541542
if isinstance(v, int):
@@ -544,14 +545,14 @@ def check_openai_endpoint_image_n(cls, v) -> int:
544545
return SettingsDefaults.OPENAI_ENDPOINT_IMAGE_N
545546
return int(v)
546547

547-
@validator("openai_endpoint_image_size", pre=True)
548+
@field_validator("openai_endpoint_image_size")
548549
def check_openai_endpoint_image_size(cls, v) -> str:
549550
"""Check openai_endpoint_image_size"""
550551
if v in [None, ""]:
551552
return SettingsDefaults.OPENAI_ENDPOINT_IMAGE_SIZE
552553
return v
553554

554-
@validator("pinecone_api_key", pre=True)
555+
@field_validator("pinecone_api_key")
555556
def check_pinecone_api_key(cls, v) -> SecretStr:
556557
"""Check pinecone_api_key"""
557558
if v in [None, ""]:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
DEBUG_MODE=
2+
AWS_REKOGNITION_FACE_DETECT_MAX_FACES_COUNT=
3+
AWS_REKOGNITION_FACE_DETECT_THRESHOLD=
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
AWS_REGION=
2-
DEBUG_MODE=
32
AWS_DYNAMODB_TABLE_ID=
4-
AWS_REKOGNITION_FACE_DETECT_MAX_FACES_COUNT=
5-
AWS_REKOGNITION_FACE_DETECT_THRESHOLD=
63
AWS_REKOGNITION_FACE_DETECT_ATTRIBUTES=
74
AWS_REKOGNITION_FACE_DETECT_QUALITY_FILTER=
85
AWS_REKOGNITION_COLLECTION_ID=
96
LANGCHAIN_MEMORY_KEY=
10-
OPENAI_ENDPOINT_IMAGE_N=
117
OPENAI_ENDPOINT_IMAGE_SIZE=

api/terraform/python/openai_api/common/tests/test_configuration.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,10 @@ def test_conf_defaults_secrets(self):
8686
# pylint: disable=no-member
8787
self.assertEqual(mock_settings.pinecone_api_key.get_secret_value(), None)
8888

89-
def test_env_nulls(self):
89+
def test_env_legal_nulls(self):
9090
"""Test that settings handles missing .env values."""
9191
os.environ.clear()
92-
env_path = self.env_path(".env.test_nulls")
92+
env_path = self.env_path(".env.test_legal_nulls")
9393
loaded = load_dotenv(env_path)
9494
self.assertTrue(loaded)
9595

@@ -98,10 +98,6 @@ def test_env_nulls(self):
9898
self.assertEqual(mock_settings.aws_region, SettingsDefaults.AWS_REGION)
9999
self.assertEqual(mock_settings.aws_dynamodb_table_id, SettingsDefaults.AWS_DYNAMODB_TABLE_ID)
100100
self.assertEqual(mock_settings.aws_rekognition_collection_id, SettingsDefaults.AWS_REKOGNITION_COLLECTION_ID)
101-
self.assertEqual(
102-
mock_settings.aws_rekognition_face_detect_max_faces_count,
103-
SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_MAX_FACES_COUNT,
104-
)
105101
self.assertEqual(
106102
mock_settings.aws_rekognition_face_detect_attributes,
107103
SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_ATTRIBUTES,
@@ -110,13 +106,20 @@ def test_env_nulls(self):
110106
mock_settings.aws_rekognition_face_detect_quality_filter,
111107
SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_QUALITY_FILTER,
112108
)
113-
self.assertEqual(
114-
mock_settings.aws_rekognition_face_detect_threshold, SettingsDefaults.AWS_REKOGNITION_FACE_DETECT_THRESHOLD
115-
)
116109
self.assertEqual(mock_settings.langchain_memory_key, SettingsDefaults.LANGCHAIN_MEMORY_KEY)
117110
self.assertEqual(mock_settings.openai_endpoint_image_n, SettingsDefaults.OPENAI_ENDPOINT_IMAGE_N)
118111
self.assertEqual(mock_settings.openai_endpoint_image_size, SettingsDefaults.OPENAI_ENDPOINT_IMAGE_SIZE)
119112

113+
def test_env_illegal_nulls(self):
114+
"""Test that settings handles missing .env values."""
115+
os.environ.clear()
116+
env_path = self.env_path(".env.test_illegal_nulls")
117+
loaded = load_dotenv(env_path)
118+
self.assertTrue(loaded)
119+
120+
with self.assertRaises(PydanticValidationError):
121+
Settings()
122+
120123
def test_env_overrides(self):
121124
"""Test that settings takes custom .env values."""
122125
os.environ.clear()

0 commit comments

Comments
 (0)