Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/release_stage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Release Stage Build

on:
push:
branches:
- development

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11

- name: Install dependencies
run: sudo apt-get install make

- name: Create virtual environment
run: make venv

- name: Build package
run: |
set -x
source venv/bin/activate
rm -rf build dist *.egg-info
make build ENV=stage

- name: Extract Version from pyproject.toml
id: get_version
run: |
# Extract the version assuming a line like: version = "0.1.0"
VERSION=$(grep -Po '^version\s*=\s*"\K[^"]+' pyproject.toml)
echo "Version extracted: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Create GitHub Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.get_version.outputs.version }}
release_name: Release ${{ steps.get_version.outputs.version }}
draft: false
prerelease: false

- name: Upload Wheel Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./dist/extend-${{ steps.get_version.outputs.version }}-py3-none-any.whl
asset_name: extend-${{ steps.get_version.outputs.version }}-py3-none-any.whl
asset_content_type: application/octet-stream
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export ENV ?= stage
VENV_NAME ?= venv
PIP ?= pip
PYTHON ?= python3.11

venv: $(VENV_NAME)/bin/activate

$(VENV_NAME)/bin/activate: pyproject.toml
@test -d $(VENV_NAME) || $(PYTHON) -m venv $(VENV_NAME)
$(VENV_NAME)/bin/python -m pip install -e .
@touch $(VENV_NAME)/bin/activate

test: venv
$(VENV_NAME)/bin/python -m unittest discover tests

build: venv
cp LICENSE LICENSE.bak
$(VENV_NAME)/bin/python -m build
rm LICENSE.bak
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,23 @@ pip install -e .

```python
import asyncio
from extend import ExtendAPI
from extend import ExtendClient


async def main():
# Initialize the client
client = ExtendAPI(
client = ExtendClient(
api_key="your-api-key",
api_secret="your-api-secret"
)

# Get all virtual cards
cards = await client.get_virtual_cards()
print("Virtual Cards:", cards)
response = await client.virtual_cards.get_virtual_cards()
print("Virtual Cards:", response["virtualCards"])

# Get all transactions
transactions = await client.get_transactions()
print("Transactions:", transactions)
response = await client.transactions.get_transactions()
print("Transactions:", response["transactions"])


# Run the async function
Expand Down
21 changes: 12 additions & 9 deletions extend/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import httpx

from .config import API_HOST, API_VERSION


class APIClient:
"""Client for interacting with the Extend API.
Expand All @@ -17,8 +19,6 @@ class APIClient:
cards = await client.get_virtual_cards()
```
"""
BASE_URL = "https://apiv2.paywithextend.com"
API_VERSION = "application/vnd.paywithextend.v2021-03-12+json"

_shared_instance: Optional["APIClient"] = None

Expand All @@ -33,7 +33,7 @@ def __init__(self, api_key: str, api_secret: str):
self.headers = {
"x-extend-api-key": api_key,
"Authorization": f"Basic {auth_value}",
"Accept": self.API_VERSION
"Accept": API_VERSION
}

@classmethod
Expand Down Expand Up @@ -70,7 +70,8 @@ async def get(self, url: str, params: Optional[Dict] = None) -> Any:
response = await client.get(
self.build_full_url(url),
headers=self.headers,
params=params
params=params,
timeout=httpx.Timeout(30)
)
response.raise_for_status()
return response.json()
Expand All @@ -79,7 +80,7 @@ async def post(self, url: str, data: Dict) -> Any:
"""Make a POST request to the Extend API.

Args:
url (str): The API endpoint path (e.g., "virtualcards")
url (str): The API endpoint path (e.g., "/virtualcards")
data (Dict): The JSON payload to send in the request body

Returns:
Expand All @@ -93,7 +94,8 @@ async def post(self, url: str, data: Dict) -> Any:
response = await client.post(
self.build_full_url(url),
headers=self.headers,
json=data
json=data,
timeout=httpx.Timeout(30)
)
response.raise_for_status()
return response.json()
Expand All @@ -102,7 +104,7 @@ async def put(self, url: str, data: Dict) -> Any:
"""Make a PUT request to the Extend API.

Args:
url (str): The API endpoint path (e.g., "virtualcards/{card_id}")
url (str): The API endpoint path (e.g., "/virtualcards/{card_id}")
data (Dict): The JSON payload to send in the request body

Returns:
Expand All @@ -116,10 +118,11 @@ async def put(self, url: str, data: Dict) -> Any:
response = await client.put(
self.build_full_url(url),
headers=self.headers,
json=data
json=data,
timeout=httpx.Timeout(30)
)
response.raise_for_status()
return response.json()

def build_full_url(self, url: Optional[str]):
return f"{self.BASE_URL}{url or ''}"
return f"https://{API_HOST}{url or ''}"
19 changes: 19 additions & 0 deletions extend/config/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import os

from dotenv import load_dotenv

load_dotenv()

env = os.getenv("ENV", "dev")

if env == "stage":
from .config_stage import API_HOST, API_VERSION
elif env == "prod":
from .config_prod import API_HOST, API_VERSION
else:
from .config_stage import API_HOST, API_VERSION

__all__ = [
"API_HOST",
"API_VERSION"
]
2 changes: 2 additions & 0 deletions extend/config/config_prod.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
API_HOST = "apiv2.paywithextend.com"
API_VERSION = "application/vnd.paywithextend.v2021-03-12+json"
2 changes: 2 additions & 0 deletions extend/config/config_stage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
API_HOST = "apiv2-stage.paywithextend.com"
API_VERSION = "application/vnd.paywithextend.v2021-03-12+json"
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ classifiers = [
]
requires-python = ">=3.8"
dependencies = [
"build",
"httpx>=0.24.0",
"typing-extensions>=4.0.0",
"python-dotenv==1.0.1",
Expand All @@ -41,7 +42,7 @@ dev = [
"jupyter>=1.0.0",
"ipykernel>=6.0.0",
"notebook>=7.0.0",
"pytest-mock==3.14.0"
"pytest-mock==3.14.0",
]

[tool.pytest.ini_options]
Expand Down
9 changes: 0 additions & 9 deletions requirements-dev.txt

This file was deleted.

3 changes: 0 additions & 3 deletions requirements.txt

This file was deleted.

2 changes: 0 additions & 2 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os
from datetime import datetime, timedelta

import httpx
import pytest
from dotenv import load_dotenv

Expand All @@ -26,7 +25,6 @@ def extend():
"""Create a real API client for integration testing"""
api_key = os.getenv("EXTEND_API_KEY")
api_secret = os.getenv("EXTEND_API_SECRET")
timeout = httpx.Timeout(30.0)
return ExtendClient(api_key, api_secret)


Expand Down