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
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: ci

on:
pull_request:
push:
branches: [master]

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
runs-on: ${{ matrix.runner }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
runner: [ubuntu-latest]
include:
- python-version: '3.7'
runner: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- run: pip install -e ".[dev]"
- run: pytest
40 changes: 40 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: publish

on:
release:
types: [published]

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install build
- run: python -m build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: build
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/sendbee-api
permissions:
id-token: write
attestations: write
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@v1.14
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,7 @@ dmypy.json
/.DS_Store
/tests/example_.py
/tests/example.py

# claude
.claude/
CLAUDE.md
27 changes: 0 additions & 27 deletions .travis.yml

This file was deleted.

9 changes: 0 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
# AI Number Python API Client

[![PyPI version](https://badge.fury.io/py/sendbee-api.svg)](https://badge.fury.io/py/sendbee-api)
[![Build Status](https://travis-ci.org/sendbee/sendbee-python-api-client.svg?branch=master)](https://travis-ci.org/sendbee/sendbee-python-api-client)

![GitHub issues](https://img.shields.io/github/issues/sendbee/sendbee-python-api-client.svg)
![GitHub closed issues](https://img.shields.io/github/issues-closed/sendbee/sendbee-python-api-client.svg)
![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/sendbee/sendbee-python-api-client.svg)

![PyPI - Python Version](https://img.shields.io/pypi/pyversions/sendbee-api.svg)
![GitHub](https://img.shields.io/github/license/sendbee/sendbee-python-api-client.svg?color=blue)
![GitHub last commit](https://img.shields.io/github/last-commit/sendbee/sendbee-python-api-client.svg?color=blue)

## Table of contents

Expand Down
46 changes: 46 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "sendbee_api"
version = "1.7.2"
description = "Python client SDK for Sendbee Public API"
readme = "README.md"
requires-python = ">=3.6"
license = { text = "MIT" }
authors = [{ name = "Sendbee ltd", email = "info@sendbee.io" }]
keywords = ["sendbee", "api", "python"]
classifiers = [
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"click>=7.0",
"requests>=2.20.0",
"dumpit>=0.5.0",
"aenum>=2.1.2",
"ujson>=5.7.0,<6",
"cryptography>=3.2",
"curlify>=2.2.1",
]

[project.optional-dependencies]
dev = ["pytest", "responses>=0.23"]

[project.urls]
Homepage = "https://github.com/sendbee/sendbee-python-client"
Source = "https://github.com/sendbee/sendbee-python-client"

[tool.setuptools.packages.find]
include = ["sendbee_api*"]
exclude = ["tests*"]
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pytest
# Dev/test deps. Source of truth: pyproject.toml [project.optional-dependencies] dev
# Prefer `pip install -e ".[dev]"` for new setups.
pytest
responses>=0.23
47 changes: 0 additions & 47 deletions setup.py

This file was deleted.

Empty file added tests/__init__.py
Empty file.
76 changes: 76 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""Shared fixtures for the sendbee-api test suite.

Tests mock at the `requests` HTTP boundary using the `responses` library. The
SDK's documented `fake_response_path` test seam is not used because its branch
in `bind.py` returns a 2-tuple while `call()` unpacks 3 elements.
"""

import ujson
import pytest
import responses as _responses

from sendbee_api import SendbeeApi


API_KEY = "test-key"
API_SECRET = "test-secret"
BASE_URL = "https://api-v2.sendbee.io"


@pytest.fixture
def api_key():
return API_KEY


@pytest.fixture
def api_secret():
return API_SECRET


@pytest.fixture
def client():
"""Fresh SendbeeApi instance per test."""
return SendbeeApi(API_KEY, API_SECRET)


@pytest.fixture
def json_body():
"""Build a Sendbee-shaped JSON envelope as a string.

The server wraps responses as {"data": ..., "meta": ..., "warning": ...}.
The Json formatter unwraps these keys; tests pass the inner shapes here.
"""
def _build(data=None, meta=None, warning=None):
body = {}
if data is not None:
body["data"] = data
if meta is not None:
body["meta"] = meta
if warning is not None:
body["warning"] = warning
return ujson.dumps(body)
return _build


@pytest.fixture
def register():
"""Register a mocked HTTP response on the Sendbee base URL.

Thin wrapper around responses.add() that prepends BASE_URL so tests stay
terse. Call as register("GET", "/contacts", body=..., status=...).
"""
def _register(method, path, body="", status=200, content_type="application/json"):
method_const = {
"GET": _responses.GET,
"POST": _responses.POST,
"PUT": _responses.PUT,
"DELETE": _responses.DELETE,
}[method.upper()]
_responses.add(
method_const,
BASE_URL + path,
body=body,
status=status,
content_type=content_type,
)
return _register
7 changes: 0 additions & 7 deletions tests/test_api.py

This file was deleted.

Loading
Loading