diff --git a/README.md b/README.md index 1a5b81d..1340059 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ pip install paysgator ## Usage ```python -from paysgator import PaysgatorClient - -client = PaysgatorClient(api_key="YOUR_API_KEY") +import os; from paysgator import PaysgatorClient +# WARNING: Never hardcode API keys. Use environment variables. +client = PaysgatorClient(api_key=os.getenv("PAYSGATOR_API_KEY")) # Create a payment payment = client.payments.create( diff --git a/pyproject.toml b/pyproject.toml index ff08145..68cc74a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ authors = [ ] description = "Official Python SDK for Paysgator API" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", diff --git a/src/paysgator/__init__.py b/src/paysgator/__init__.py index d0cf227..b9ae5d7 100644 --- a/src/paysgator/__init__.py +++ b/src/paysgator/__init__.py @@ -1,4 +1,4 @@ -from .client import PaysgatorClient +from .client import PaysgatorClient, Payments, Subscriptions from .exceptions import PaysgatorError, AuthenticationError, APIError -__all__ = ["PaysgatorClient", "PaysgatorError", "AuthenticationError", "APIError"] +__all__ = ["PaysgatorClient", "Payments", "Subscriptions", "PaysgatorError", "AuthenticationError", "APIError"] diff --git a/src/paysgator/client.py b/src/paysgator/client.py index a067367..18ce640 100644 --- a/src/paysgator/client.py +++ b/src/paysgator/client.py @@ -50,10 +50,11 @@ def get_balance(self) -> WalletBalanceResponse: return WalletBalanceResponse(**response_data) class PaysgatorClient: - BASE_URL = "https://paysgator.com/api/v1" def __init__(self, api_key: str): self.api_key = api_key + self.base_url = "https://paysgator.com/api/v1" + self.session = requests.Session() self.session.headers.update({ "X-Api-Key": self.api_key, @@ -66,11 +67,11 @@ def __init__(self, api_key: str): self.wallet = Wallet(self) def set_base_url(self, url: str): - self.BASE_URL = url + self.base_url = url def request(self, method: str, endpoint: str, data: Optional[dict] = None) -> dict: - url = f"{self.BASE_URL}{endpoint}" - response = self.session.request(method, url, json=data) + url = f"{self.base_url}{endpoint}" + response = self.session.request(method, url, json=data, timeout=30) if response.status_code >= 400: raise APIError(response.status_code, response.text) diff --git a/src/paysgator/exceptions.py b/src/paysgator/exceptions.py index 3067741..d7d7f27 100644 --- a/src/paysgator/exceptions.py +++ b/src/paysgator/exceptions.py @@ -1,6 +1,10 @@ class PaysgatorError(Exception): """Base exception for Paysgator SDK""" - pass + def __init__(self, message: str = "", endpoint=None, method=None, response_body=None): + self.endpoint = endpoint + self.method = method + self.response_body = response_body + super().__init__(message) class AuthenticationError(PaysgatorError): """Raised when authentication fails""" @@ -8,7 +12,7 @@ class AuthenticationError(PaysgatorError): class APIError(PaysgatorError): """Raised when the API returns an error""" - def __init__(self, status_code: int, message: str): + def __init__(self, status_code: int, message: str, endpoint=None, method=None, response_body=None): self.status_code = status_code self.message = message - super().__init__(f"API Error {status_code}: {message}") + super().__init__(f"API Error {status_code}: {message}", endpoint, method, response_body) diff --git a/src/paysgator/models.py b/src/paysgator/models.py index 8863e2d..de53545 100644 --- a/src/paysgator/models.py +++ b/src/paysgator/models.py @@ -7,8 +7,8 @@ class Mode(str, Enum): TEST = "TEST" class PaymentCreateRequest(BaseModel): - amount: float - currency: str + amount: float = Field(..., gt=0) + currency: str = Field(..., min_length=3, max_length=3) external_transaction_id: Optional[str] = Field(None, alias="externalTransactionId") payment_methods: Optional[List[str]] = Field(None, alias="payment_methods") fields: Optional[List[str]] = None @@ -62,8 +62,8 @@ class SubscriptionResponse(BaseModel): class TransactionResponse(BaseModel): id: str - amount: float - currency: str + amount: float = Field(..., gt=0) + currency: str = Field(..., min_length=3, max_length=3) status: str method: Optional[str] = None description: Optional[str] = None @@ -72,6 +72,6 @@ class TransactionResponse(BaseModel): class WalletBalanceResponse(BaseModel): wallet_id: str = Field(..., alias="walletId") - currency: str + currency: str = Field(..., min_length=3, max_length=3) balance: str mode: str diff --git a/test_sdk.py b/test_sdk.py index 7ee8b76..4078c13 100644 --- a/test_sdk.py +++ b/test_sdk.py @@ -1,10 +1,10 @@ -from src.paysgator.client import PaysgatorClient - +from paysgator.client import PaysgatorClient +import os #Mpesa direct charge test -api_key = "" +api_key = os.getenv("PAYSGATOR_API_KEY", "") -wallet_id = "" +wallet_id = os.getenv("PAYSGATOR_WALLET_ID", "") client = PaysgatorClient(api_key, wallet_id)