Skip to content

Commit 33d578d

Browse files
authored
Add reading API key from env vars (#28)
1 parent e028ecc commit 33d578d

File tree

14 files changed

+61
-7
lines changed

14 files changed

+61
-7
lines changed

src/abstract_api/avatars/avatars.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
from ..core.bases import BaseService
24
from ..core.exceptions import ClientRequestError
35
from ..core.validators import numerical
@@ -14,6 +16,7 @@ class Avatars(BaseService[AvatarsResponse]):
1416
_subdomain: Avatars service subdomain.
1517
"""
1618
_subdomain = "avatars"
19+
_service_name_env_var: ClassVar[str] = "AVATARS"
1720

1821
@staticmethod
1922
def _validate_params(**kwargs) -> None:

src/abstract_api/company_enrichment/company_enrichment.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterable
1+
from typing import ClassVar, Iterable
22

33
from ..core.bases import BaseService
44
from ..core.mixins import ResponseFieldsMixin
@@ -20,6 +20,7 @@ class CompanyEnrichment(
2020
"""
2121
_subdomain = "companyenrichment"
2222
_response_fields = RESPONSE_FIELDS
23+
_service_name_env_var: ClassVar[str] = "COMPANY_ENRICHMENT"
2324

2425
def check(
2526
self,

src/abstract_api/core/bases/base_service.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import os
12
from functools import lru_cache
23
from io import BytesIO
3-
from typing import TYPE_CHECKING, Any, Final, Generic, Type, TypeVar
4+
from typing import TYPE_CHECKING, Any, ClassVar, Final, Generic, Type, TypeVar
45

56
import requests
67
from requests import codes
@@ -28,13 +29,37 @@ class BaseService(Generic[BaseResponseT]):
2829
"""
2930
__base_url: Final[str] = "https://{subdomain}.abstractapi.com/v1/"
3031
_subdomain: str
32+
_service_name_env_var: ClassVar[str]
3133

32-
def __init__(self, api_key: str) -> None:
34+
@classmethod
35+
def _read_api_key_from_env(cls) -> str | None:
36+
"""Reads service API key from environment variables.
37+
38+
API key exposed as an environment variable must be exposed using a
39+
variable name with the pattern:
40+
ABSTRACTAPI_{SERVICE_NAME}_API_KEY
41+
Where SERVICE_NAME is the service name that the API key is for.
42+
(service_name must be uppercase.)
43+
44+
Returns: API key read from environment variable.
45+
"""
46+
pattern = "ABSTRACTAPI_{service_name}_API_KEY"
47+
return os.environ.get(
48+
pattern.format(service_name=cls._service_name_env_var)
49+
)
50+
51+
def __init__(self, api_key: str | None = None) -> None:
3352
"""Constructs a BaseService.
3453
3554
Args:
3655
api_key: API key to be used to authenticate with AbstractAPI.
3756
"""
57+
api_key = api_key or self._read_api_key_from_env()
58+
if api_key is None:
59+
raise ValueError(
60+
"API key was not provided nor exposed as an"
61+
" environment variable"
62+
)
3863
self._api_key: str = api_key
3964

4065
@lru_cache(maxsize=5)

src/abstract_api/email_validation/email_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
from ..core.bases import BaseService
24
from .email_validation_response import EmailValidationResponse
35

@@ -11,6 +13,7 @@ class EmailValidation(BaseService[EmailValidationResponse]):
1113
_subdomain: Email validation service subdomain.
1214
"""
1315
_subdomain = "emailvalidation"
16+
_service_name_env_var: ClassVar[str] = "EMAIL_VALIDATION"
1417

1518
def check(
1619
self,

src/abstract_api/exchange_rates/exchange_rates.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterable
1+
from typing import ClassVar, Iterable
22

33
from ..core.bases import BaseService
44
from ..core.validators import numerical
@@ -18,6 +18,7 @@ class ExchangeRates(BaseService):
1818
_subdomain: Exchange rates service subdomain.
1919
"""
2020
_subdomain = "exchange-rates"
21+
_service_name_env_var: ClassVar[str] = "EXCHANGE_RATES"
2122

2223
@staticmethod
2324
def _target_as_param(target: Iterable[str] | None = None) -> str | None:

src/abstract_api/holidays/holidays.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
from ..core.bases import BaseService
24
from ..core.validators import numerical
35
from .holidays_response import HolidaysResponse
@@ -13,6 +15,7 @@ class Holidays(BaseService[HolidaysResponse]):
1315
_subdomain: Holidays service subdomain.
1416
"""
1517
_subdomain = "holidays"
18+
_service_name_env_var: ClassVar[str] = "HOLIDAYS"
1619

1720
@staticmethod
1821
def _validate_params(**kwargs) -> None:

src/abstract_api/iban_validation/iban_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
from ..core.bases import BaseService
24
from .iban_validation_response import IBANValidationResponse
35

@@ -11,6 +13,7 @@ class IBANValidation(BaseService[IBANValidationResponse]):
1113
_subdomain: IBAN validation service subdomain.
1214
"""
1315
_subdomain = "ibanvalidation"
16+
_service_name_env_var: ClassVar[str] = "IBAN_VALIDATION"
1417

1518
def check(self, iban: str) -> IBANValidationResponse:
1619
"""Validates an IBAN.

src/abstract_api/image_processing/image_processing.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from typing import Any, BinaryIO
2+
from typing import Any, BinaryIO, ClassVar
33

44
from ..core.bases import BaseService
55
from ..core.exceptions import ClientRequestError
@@ -17,6 +17,7 @@ class ImageProcessing(BaseService[ImageProcessingResponse]):
1717
_subdomain: Image processing service subdomain.
1818
"""
1919
_subdomain = "images"
20+
_service_name_env_var: ClassVar[str] = "IMAGE_PROCESSING"
2021

2122
def upload(
2223
self,

src/abstract_api/ip_geolocation/ip_geolocation.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Iterable
1+
from typing import ClassVar, Iterable
22

33
from ..core.bases import BaseService
44
from ..core.mixins import ResponseFieldsMixin
@@ -17,6 +17,7 @@ class IPGeolocation(ResponseFieldsMixin, BaseService[IPGeolocationResponse]):
1717
Geolocation service endpoint.
1818
"""
1919
_subdomain = "ipgeolocation"
20+
_service_name_env_var: ClassVar[str] = "IP_GEOLOCATION"
2021
_response_fields = RESPONSE_FIELDS
2122

2223
def check(

src/abstract_api/phone_validation/phone_validation.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
from ..core.bases import BaseService
24
from .phone_validation_response import PhoneValidationResponse
35

@@ -11,6 +13,7 @@ class PhoneValidation(BaseService[PhoneValidationResponse]):
1113
_subdomain: Phone validation service subdomain.
1214
"""
1315
_subdomain = "phonevalidation"
16+
_service_name_env_var: ClassVar[str] = "PHONE_VALIDATION"
1417

1518
def check(self, phone: str) -> PhoneValidationResponse:
1619
"""Validates and verifies a phone number.

0 commit comments

Comments
 (0)