neuwo-api


Nameneuwo-api JSON
Version 0.2.0 PyPI version JSON
download
home_pagehttps://neuwo.ai
SummaryNeuwo API SDK - Python SDK client for the Neuwo content classification API.
upload_time2025-10-27 13:10:01
maintainerGrzegorz Malisz
docs_urlNone
authorGrzegorz Malisz
requires_python>=3.8
licenseMIT
keywords neuwo api content classification tagging ai machine-learning iab taxonomy brand-safety
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Neuwo API Python SDK

Python SDK client for the Neuwo content classification API.

[![PyPI version](https://badge.fury.io/py/neuwo-api.svg)](https://pypi.org/project/neuwo-api/)
[![Python versions](https://img.shields.io/pypi/pyversions/neuwo-api.svg)](https://pypi.org/project/neuwo-api/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Support

- **Neuwo**: [https://neuwo.ai](https://neuwo.ai)
- **Documentation**: [https://docs.neuwo.ai](https://docs.neuwo.ai)
- **Repository**: [GitHub](https://github.com/neuwoai/neuwo-api-sdk-python)
- **Issues**: [GitHub Issues](https://github.com/neuwoai/neuwo-api-sdk-python/issues)
- **Email Support**: [neuwo-helpdesk@neuwo.ai](mailto:neuwo-helpdesk@neuwo.ai)

## Installation

Install the package using pip:

```bash
pip install neuwo-api
```

Install with optional development dependencies:

```bash
# For development
pip install neuwo-api[dev]

# For testing
pip install neuwo-api[test]
```

## Requirements

- Python 3.8 or higher
- `requests` library (automatically installed)

## Quick Start

For more detailed examples and use cases, see the [examples folder](examples/) in the repository.

### REST API Client

```python
from neuwo_api import NeuwoRestClient

# Initialize client
client = NeuwoRestClient(
    token="your-rest-api-token",
    base_url="https://custom.api.com",
)

# Analyze text content
response = client.get_ai_topics(
    content="Cats make wonderful pets for modern households.",
    document_id="article-123",
    headline="Why Cats Make Great Pets"
)

# Access results
print(f"Tags: {len(response.tags)}")
for tag in response.tags:
    print(f"  - {tag.value} (score: {tag.score})")

print(f"Brand Safe: {response.brand_safety.is_safe}")
print(f"IAB Categories: {len(response.marketing_categories.iab_tier_1)}")
```

### EDGE API Client

```python
from neuwo_api import NeuwoEdgeClient

# Initialize client
client = NeuwoEdgeClient(
    token="your-edge-api-token",
    base_url="https://custom.api.com",
    origin="https://yourwebsite.com"  # Optional: default origin for requests
)

# Analyze article by URL
response = client.get_ai_topics(url="https://example.com/article")

# Or wait for analysis to complete (with automatic retry)
response = client.get_ai_topics_wait(
    url="https://example.com/new-article",
    max_retries=10,
    retry_interval=6
)

print(f"Found {len(response.tags)} tags for the article")
```

## Configuration

### REST Client Parameters

| Parameter  | Type  | Default      | Description                   |
| ---------- | ----- | ------------ | ----------------------------- |
| `token`    | `str` | **Required** | REST API authentication token |
| `base_url` | `str` | **Required** | Base URL for the API          |
| `timeout`  | `int` | `60`         | Request timeout in seconds    |

**Example:**

```python
client = NeuwoRestClient(
    token="your-token",
    base_url="https://custom.api.com",
    timeout=120
)
```

### EDGE Client Parameters

| Parameter  | Type  | Default      | Description                        |
| ---------- | ----- | ------------ | ---------------------------------- |
| `token`    | `str` | **Required** | EDGE API authentication token      |
| `base_url` | `str` | **Required** | Base URL for the API               |
| `timeout`  | `int` | `60`         | Request timeout in seconds         |
| `origin`   | `str` | `None`       | Default Origin header for requests |

**Example:**

```python
client = NeuwoEdgeClient(
    token="your-token",
    base_url="https://custom.api.com",
    origin="https://yoursite.com",
    timeout=90
)
```

### API Methods

#### REST API

##### Get AI Topics

```python
response = client.get_ai_topics(
    content="Text to analyze",           # Required
    document_id="doc123",                 # Optional: save to database
    lang="en",                            # Optional: ISO 639-1 code
    publication_id="pub1",                # Optional
    headline="Article Headline",          # Optional
    tag_limit=15,                         # Optional: max tags (default: 15)
    tag_min_score=0.1,                    # Optional: min score (default: 0.1)
    marketing_limit=None,                 # Optional
    marketing_min_score=0.3,              # Optional (default: 0.3)
    include_in_sim=True,                  # Optional (default: True)
    article_url="https://example.com"     # Optional
)
```

##### Get Similar Articles

```python
articles = client.get_similar(
    document_id="doc123",                 # Required
    max_rows=10,                          # Optional: limit results
    past_days=30,                         # Optional: limit by date
    publication_ids=["pub1", "pub2"]      # Optional: filter by publication
)
```

##### Update Article

```python
from datetime import date

article = client.update_article(
    document_id="doc123",                 # Required
    published=date(2024, 1, 15),          # Optional
    headline="Updated Headline",          # Optional
    writer="Author Name",                 # Optional
    category="News",                      # Optional
    content="Updated content",            # Optional
    summary="Summary",                    # Optional
    publication_id="pub1",                # Optional
    article_url="https://example.com",    # Optional
    include_in_sim=True                   # Optional
)
```

##### Train AI Topics

```python
training_tags = client.train_ai_topics(
    document_id="doc123",                 # Required
    tags=["tag1", "tag2", "tag3"],        # Required
)
```

#### EDGE API

##### Get AI Topics (Single URL)

```python
response = client.get_ai_topics(
    url="https://example.com/article",    # Required
    origin="https://yoursite.com"         # Optional: override default origin
)
```

##### Get AI Topics with Auto-Retry

```python
response = client.get_ai_topics_wait(
    url="https://example.com/article",    # Required
    origin="https://yoursite.com",        # Optional
    max_retries=10,                       # Optional (default: 10)
    retry_interval=6,                     # Optional (default: 6s)
    initial_delay=2                       # Optional (default: 2s)
)
```

##### Get AI Topics (Multiple URLs)

```python
# From list
results = client.get_ai_topics_list(
    urls=["https://example.com/1", "https://example.com/2"],
    origin="https://yoursite.com"
)

# From file bytes
with open("urls.txt", "rb") as f:
    urls_as_bytes = f.read()
result = client.get_ai_topics_list(urls_as_bytes)
```

##### Get Similar Articles

```python
articles = client.get_similar(
    document_url="https://example.com/article",  # Required
    max_rows=10,                                 # Optional
    past_days=30,                                # Optional
    publication_ids=["pub1", "pub2"],            # Optional
    origin="https://yoursite.com"                # Optional
)
```

#### Raw Response Methods

All methods have `_raw` variants that return the raw `requests.Response` object:

```python
# REST
raw_response = client.get_ai_topics_raw(content="Text")
print(raw_response.status_code)
print(raw_response.text)

# EDGE
raw_response = client.get_ai_topics_raw(url="https://example.com")
print(raw_response.json())
```

## Error Handling

The SDK provides specific exceptions for different error scenarios:

```python
from neuwo_api import (
    NeuwoRestClient,
    ValidationError,
    AuthenticationError,
    NoDataAvailableError,
    ContentNotAvailableError,
    NetworkError
)

client = NeuwoRestClient(
    token="your-token"
    base_url="https://custom.api.com",
)

try:
    response = client.get_ai_topics(content="Your content here")
except ValidationError as e:
    print(f"Invalid input: {e}")
except AuthenticationError as e:
    print(f"Authentication failed: {e}")
except NoDataAvailableError as e:
    print(f"Data not yet available: {e}")
except ContentNotAvailableError as e:
    print(f"Content could not be analyzed: {e}")
except NetworkError as e:
    print(f"Network error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")
```

### Exception Hierarchy

- `NeuwoAPIError` - Base exception for all API errors
  - `AuthenticationError` - Invalid or missing token (401)
  - `ForbiddenError` - Token lacks permissions (403)
  - `NotFoundError` - Resource not found (404)
    - `NoDataAvailableError` - URL not yet processed (404)
  - `BadRequestError` - Malformed request (400)
  - `ValidationError` - Request validation failed (422)
  - `RateLimitError` - Rate limit exceeded (429)
  - `ServerError` - Server error (5xx)
  - `NetworkError` - Network communication failed
  - `ContentNotAvailableError` - Content tagging failed

## Logging

The SDK uses Python's standard logging module. Enable logging to see detailed API communication:

```python
from neuwo_api import setup_logger
import logging

# Enable debug logging
setup_logger(level=logging.DEBUG)

# Or just warnings and errors (default)
setup_logger(level=logging.WARNING)

# Disable logging
from neuwo_api import disable_logger
disable_logger()
```

**Custom logging configuration:**

```python
import logging
from neuwo_api import get_logger

# Get the SDK logger
logger = get_logger()

# Add custom handler
handler = logging.FileHandler('neuwo_api.log')
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
```

## Development

### Setup Development Environment

```bash
# Clone repository
git clone https://github.com/neuwoai/neuwo-api-sdk-python.git
cd neuwo-api-sdk-python

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install in development mode with all dependencies
pip install -e ".[dev]"
```

### Running Tests

```bash
# Run all tests
pytest

# Run with coverage
pytest --cov=neuwo_api --cov-report=html

# Run specific test file
pytest tests/test_rest_client.py

# Run with verbose output
pytest -v
```

<!-- ### Code Quality

```bash
# Format code
black neuwo_api/ tests/

# Sort imports
isort neuwo_api/ tests/

# Lint
flake8 neuwo_api/ tests/

# Type checking
mypy neuwo_api/
``` -->

### Building Distribution

```bash
# Install build tools
pip install build twine

# Build
python -m build

# Upload to PyPI
twine upload dist/*
```

## CI/CD

### Automated Testing

The [Unit Tests Coverage workflow](.github/workflows/unit-tests-coverage.yaml) automatically runs on every push to `main` or `dev` branches and on pull requests:

- **Python versions tested**: 3.8, 3.9, 3.10, 3.11, 3.12
- **Coverage reporting**: Results uploaded to Codecov
- **Test execution**: Full test suite with coverage analysis

### Publishing Pipeline

The [Publish Python Package workflow](.github/workflows/publish-sdk.yaml) enables manual deployment with the following options:

#### Workflow Features:

- Manual trigger via GitHub Actions UI
- Deploy to **TestPyPI** or **PyPI**
- Upload artifacts to **GitHub Packages**
- Auto-create **GitHub releases** with tags
- Automatic version extraction from `pyproject.toml`

#### Setup Requirements:

Add GitHub secrets for API tokens:

- `PYPI_API_TOKEN` - Production PyPI token
- `TEST_PYPI_API_TOKEN` - TestPyPI token

#### Workflow Inputs

| Input               | Type    | Default  | Description                                    |
| ------------------- | ------- | -------- | ---------------------------------------------- |
| `target`            | choice  | TestPyPI | Deploy to `TestPyPI` or `PyPI`                 |
| `publish_to_github` | boolean | false    | Upload artifacts to GitHub                     |
| `create_release`    | boolean | false    | Create GitHub release with tag (only for PyPI) |

#### Usage:

1. **Testing release**:

   - Go to Actions > Publish Python Package > Run workflow
   - Select: TestPyPI
   - Test: `pip install -i https://test.pypi.org/simple/ neuwo-api`

2. **Production release**:
   - Update version in [pyproject.toml](pyproject.toml), [setup.py](setup.py) and [README.md](README.md)
   - Commit changes to repository
   - Go to Actions > Publish Python Package > Run workflow
   - Select: PyPI + Publish to GitHub Packages + Create GitHub release
   - Creates tag (e.g., `v0.2.0`), GitHub release, and publishes to PyPI

3. **Verify**:
   - Check PyPI: https://pypi.org/project/neuwo-api/
   - Check GitHub Release: https://github.com/neuwoai/neuwo-api-sdk-python/releases
   - Check packages appear in repo

#### What gets created:

- PyPI package: https://pypi.org/project/neuwo-api/
- GitHub release with `.whl` and `.tar.gz` files
- Git tag following `v{VERSION}` format
- Package artifacts in GitHub Actions

**Versioning:**

Follow [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`):

- **MAJOR**: Breaking changes
- **MINOR**: New features (backward compatible)
- **PATCH**: Bug fixes (backward compatible)

## License

This project is licensed under the MIT License - see the [LICENCE](LICENCE) file for details.

            

Raw data

            {
    "_id": null,
    "home_page": "https://neuwo.ai",
    "name": "neuwo-api",
    "maintainer": "Grzegorz Malisz",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "Grzegorz Malisz <grzegorz.malisz@neuwo.ai>",
    "keywords": "neuwo, api, content, classification, tagging, ai, machine-learning, iab, taxonomy, brand-safety",
    "author": "Grzegorz Malisz",
    "author_email": "Grzegorz Malisz <grzegorz.malisz@neuwo.ai>",
    "download_url": "https://files.pythonhosted.org/packages/2f/74/8014572ff4f251edbbac95d33ec02206e92e5bedcbb9414b161df1645fa0/neuwo_api-0.2.0.tar.gz",
    "platform": null,
    "description": "# Neuwo API Python SDK\n\nPython SDK client for the Neuwo content classification API.\n\n[![PyPI version](https://badge.fury.io/py/neuwo-api.svg)](https://pypi.org/project/neuwo-api/)\n[![Python versions](https://img.shields.io/pypi/pyversions/neuwo-api.svg)](https://pypi.org/project/neuwo-api/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n## Support\n\n- **Neuwo**: [https://neuwo.ai](https://neuwo.ai)\n- **Documentation**: [https://docs.neuwo.ai](https://docs.neuwo.ai)\n- **Repository**: [GitHub](https://github.com/neuwoai/neuwo-api-sdk-python)\n- **Issues**: [GitHub Issues](https://github.com/neuwoai/neuwo-api-sdk-python/issues)\n- **Email Support**: [neuwo-helpdesk@neuwo.ai](mailto:neuwo-helpdesk@neuwo.ai)\n\n## Installation\n\nInstall the package using pip:\n\n```bash\npip install neuwo-api\n```\n\nInstall with optional development dependencies:\n\n```bash\n# For development\npip install neuwo-api[dev]\n\n# For testing\npip install neuwo-api[test]\n```\n\n## Requirements\n\n- Python 3.8 or higher\n- `requests` library (automatically installed)\n\n## Quick Start\n\nFor more detailed examples and use cases, see the [examples folder](examples/) in the repository.\n\n### REST API Client\n\n```python\nfrom neuwo_api import NeuwoRestClient\n\n# Initialize client\nclient = NeuwoRestClient(\n    token=\"your-rest-api-token\",\n    base_url=\"https://custom.api.com\",\n)\n\n# Analyze text content\nresponse = client.get_ai_topics(\n    content=\"Cats make wonderful pets for modern households.\",\n    document_id=\"article-123\",\n    headline=\"Why Cats Make Great Pets\"\n)\n\n# Access results\nprint(f\"Tags: {len(response.tags)}\")\nfor tag in response.tags:\n    print(f\"  - {tag.value} (score: {tag.score})\")\n\nprint(f\"Brand Safe: {response.brand_safety.is_safe}\")\nprint(f\"IAB Categories: {len(response.marketing_categories.iab_tier_1)}\")\n```\n\n### EDGE API Client\n\n```python\nfrom neuwo_api import NeuwoEdgeClient\n\n# Initialize client\nclient = NeuwoEdgeClient(\n    token=\"your-edge-api-token\",\n    base_url=\"https://custom.api.com\",\n    origin=\"https://yourwebsite.com\"  # Optional: default origin for requests\n)\n\n# Analyze article by URL\nresponse = client.get_ai_topics(url=\"https://example.com/article\")\n\n# Or wait for analysis to complete (with automatic retry)\nresponse = client.get_ai_topics_wait(\n    url=\"https://example.com/new-article\",\n    max_retries=10,\n    retry_interval=6\n)\n\nprint(f\"Found {len(response.tags)} tags for the article\")\n```\n\n## Configuration\n\n### REST Client Parameters\n\n| Parameter  | Type  | Default      | Description                   |\n| ---------- | ----- | ------------ | ----------------------------- |\n| `token`    | `str` | **Required** | REST API authentication token |\n| `base_url` | `str` | **Required** | Base URL for the API          |\n| `timeout`  | `int` | `60`         | Request timeout in seconds    |\n\n**Example:**\n\n```python\nclient = NeuwoRestClient(\n    token=\"your-token\",\n    base_url=\"https://custom.api.com\",\n    timeout=120\n)\n```\n\n### EDGE Client Parameters\n\n| Parameter  | Type  | Default      | Description                        |\n| ---------- | ----- | ------------ | ---------------------------------- |\n| `token`    | `str` | **Required** | EDGE API authentication token      |\n| `base_url` | `str` | **Required** | Base URL for the API               |\n| `timeout`  | `int` | `60`         | Request timeout in seconds         |\n| `origin`   | `str` | `None`       | Default Origin header for requests |\n\n**Example:**\n\n```python\nclient = NeuwoEdgeClient(\n    token=\"your-token\",\n    base_url=\"https://custom.api.com\",\n    origin=\"https://yoursite.com\",\n    timeout=90\n)\n```\n\n### API Methods\n\n#### REST API\n\n##### Get AI Topics\n\n```python\nresponse = client.get_ai_topics(\n    content=\"Text to analyze\",           # Required\n    document_id=\"doc123\",                 # Optional: save to database\n    lang=\"en\",                            # Optional: ISO 639-1 code\n    publication_id=\"pub1\",                # Optional\n    headline=\"Article Headline\",          # Optional\n    tag_limit=15,                         # Optional: max tags (default: 15)\n    tag_min_score=0.1,                    # Optional: min score (default: 0.1)\n    marketing_limit=None,                 # Optional\n    marketing_min_score=0.3,              # Optional (default: 0.3)\n    include_in_sim=True,                  # Optional (default: True)\n    article_url=\"https://example.com\"     # Optional\n)\n```\n\n##### Get Similar Articles\n\n```python\narticles = client.get_similar(\n    document_id=\"doc123\",                 # Required\n    max_rows=10,                          # Optional: limit results\n    past_days=30,                         # Optional: limit by date\n    publication_ids=[\"pub1\", \"pub2\"]      # Optional: filter by publication\n)\n```\n\n##### Update Article\n\n```python\nfrom datetime import date\n\narticle = client.update_article(\n    document_id=\"doc123\",                 # Required\n    published=date(2024, 1, 15),          # Optional\n    headline=\"Updated Headline\",          # Optional\n    writer=\"Author Name\",                 # Optional\n    category=\"News\",                      # Optional\n    content=\"Updated content\",            # Optional\n    summary=\"Summary\",                    # Optional\n    publication_id=\"pub1\",                # Optional\n    article_url=\"https://example.com\",    # Optional\n    include_in_sim=True                   # Optional\n)\n```\n\n##### Train AI Topics\n\n```python\ntraining_tags = client.train_ai_topics(\n    document_id=\"doc123\",                 # Required\n    tags=[\"tag1\", \"tag2\", \"tag3\"],        # Required\n)\n```\n\n#### EDGE API\n\n##### Get AI Topics (Single URL)\n\n```python\nresponse = client.get_ai_topics(\n    url=\"https://example.com/article\",    # Required\n    origin=\"https://yoursite.com\"         # Optional: override default origin\n)\n```\n\n##### Get AI Topics with Auto-Retry\n\n```python\nresponse = client.get_ai_topics_wait(\n    url=\"https://example.com/article\",    # Required\n    origin=\"https://yoursite.com\",        # Optional\n    max_retries=10,                       # Optional (default: 10)\n    retry_interval=6,                     # Optional (default: 6s)\n    initial_delay=2                       # Optional (default: 2s)\n)\n```\n\n##### Get AI Topics (Multiple URLs)\n\n```python\n# From list\nresults = client.get_ai_topics_list(\n    urls=[\"https://example.com/1\", \"https://example.com/2\"],\n    origin=\"https://yoursite.com\"\n)\n\n# From file bytes\nwith open(\"urls.txt\", \"rb\") as f:\n    urls_as_bytes = f.read()\nresult = client.get_ai_topics_list(urls_as_bytes)\n```\n\n##### Get Similar Articles\n\n```python\narticles = client.get_similar(\n    document_url=\"https://example.com/article\",  # Required\n    max_rows=10,                                 # Optional\n    past_days=30,                                # Optional\n    publication_ids=[\"pub1\", \"pub2\"],            # Optional\n    origin=\"https://yoursite.com\"                # Optional\n)\n```\n\n#### Raw Response Methods\n\nAll methods have `_raw` variants that return the raw `requests.Response` object:\n\n```python\n# REST\nraw_response = client.get_ai_topics_raw(content=\"Text\")\nprint(raw_response.status_code)\nprint(raw_response.text)\n\n# EDGE\nraw_response = client.get_ai_topics_raw(url=\"https://example.com\")\nprint(raw_response.json())\n```\n\n## Error Handling\n\nThe SDK provides specific exceptions for different error scenarios:\n\n```python\nfrom neuwo_api import (\n    NeuwoRestClient,\n    ValidationError,\n    AuthenticationError,\n    NoDataAvailableError,\n    ContentNotAvailableError,\n    NetworkError\n)\n\nclient = NeuwoRestClient(\n    token=\"your-token\"\n    base_url=\"https://custom.api.com\",\n)\n\ntry:\n    response = client.get_ai_topics(content=\"Your content here\")\nexcept ValidationError as e:\n    print(f\"Invalid input: {e}\")\nexcept AuthenticationError as e:\n    print(f\"Authentication failed: {e}\")\nexcept NoDataAvailableError as e:\n    print(f\"Data not yet available: {e}\")\nexcept ContentNotAvailableError as e:\n    print(f\"Content could not be analyzed: {e}\")\nexcept NetworkError as e:\n    print(f\"Network error: {e}\")\nexcept Exception as e:\n    print(f\"Unexpected error: {e}\")\n```\n\n### Exception Hierarchy\n\n- `NeuwoAPIError` - Base exception for all API errors\n  - `AuthenticationError` - Invalid or missing token (401)\n  - `ForbiddenError` - Token lacks permissions (403)\n  - `NotFoundError` - Resource not found (404)\n    - `NoDataAvailableError` - URL not yet processed (404)\n  - `BadRequestError` - Malformed request (400)\n  - `ValidationError` - Request validation failed (422)\n  - `RateLimitError` - Rate limit exceeded (429)\n  - `ServerError` - Server error (5xx)\n  - `NetworkError` - Network communication failed\n  - `ContentNotAvailableError` - Content tagging failed\n\n## Logging\n\nThe SDK uses Python's standard logging module. Enable logging to see detailed API communication:\n\n```python\nfrom neuwo_api import setup_logger\nimport logging\n\n# Enable debug logging\nsetup_logger(level=logging.DEBUG)\n\n# Or just warnings and errors (default)\nsetup_logger(level=logging.WARNING)\n\n# Disable logging\nfrom neuwo_api import disable_logger\ndisable_logger()\n```\n\n**Custom logging configuration:**\n\n```python\nimport logging\nfrom neuwo_api import get_logger\n\n# Get the SDK logger\nlogger = get_logger()\n\n# Add custom handler\nhandler = logging.FileHandler('neuwo_api.log')\nhandler.setLevel(logging.DEBUG)\nformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')\nhandler.setFormatter(formatter)\nlogger.addHandler(handler)\n```\n\n## Development\n\n### Setup Development Environment\n\n```bash\n# Clone repository\ngit clone https://github.com/neuwoai/neuwo-api-sdk-python.git\ncd neuwo-api-sdk-python\n\n# Create virtual environment\npython -m venv venv\nsource venv/bin/activate  # On Windows: venv\\Scripts\\activate\n\n# Install in development mode with all dependencies\npip install -e \".[dev]\"\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npytest\n\n# Run with coverage\npytest --cov=neuwo_api --cov-report=html\n\n# Run specific test file\npytest tests/test_rest_client.py\n\n# Run with verbose output\npytest -v\n```\n\n<!-- ### Code Quality\n\n```bash\n# Format code\nblack neuwo_api/ tests/\n\n# Sort imports\nisort neuwo_api/ tests/\n\n# Lint\nflake8 neuwo_api/ tests/\n\n# Type checking\nmypy neuwo_api/\n``` -->\n\n### Building Distribution\n\n```bash\n# Install build tools\npip install build twine\n\n# Build\npython -m build\n\n# Upload to PyPI\ntwine upload dist/*\n```\n\n## CI/CD\n\n### Automated Testing\n\nThe [Unit Tests Coverage workflow](.github/workflows/unit-tests-coverage.yaml) automatically runs on every push to `main` or `dev` branches and on pull requests:\n\n- **Python versions tested**: 3.8, 3.9, 3.10, 3.11, 3.12\n- **Coverage reporting**: Results uploaded to Codecov\n- **Test execution**: Full test suite with coverage analysis\n\n### Publishing Pipeline\n\nThe [Publish Python Package workflow](.github/workflows/publish-sdk.yaml) enables manual deployment with the following options:\n\n#### Workflow Features:\n\n- Manual trigger via GitHub Actions UI\n- Deploy to **TestPyPI** or **PyPI**\n- Upload artifacts to **GitHub Packages**\n- Auto-create **GitHub releases** with tags\n- Automatic version extraction from `pyproject.toml`\n\n#### Setup Requirements:\n\nAdd GitHub secrets for API tokens:\n\n- `PYPI_API_TOKEN` - Production PyPI token\n- `TEST_PYPI_API_TOKEN` - TestPyPI token\n\n#### Workflow Inputs\n\n| Input               | Type    | Default  | Description                                    |\n| ------------------- | ------- | -------- | ---------------------------------------------- |\n| `target`            | choice  | TestPyPI | Deploy to `TestPyPI` or `PyPI`                 |\n| `publish_to_github` | boolean | false    | Upload artifacts to GitHub                     |\n| `create_release`    | boolean | false    | Create GitHub release with tag (only for PyPI) |\n\n#### Usage:\n\n1. **Testing release**:\n\n   - Go to Actions > Publish Python Package > Run workflow\n   - Select: TestPyPI\n   - Test: `pip install -i https://test.pypi.org/simple/ neuwo-api`\n\n2. **Production release**:\n   - Update version in [pyproject.toml](pyproject.toml), [setup.py](setup.py) and [README.md](README.md)\n   - Commit changes to repository\n   - Go to Actions > Publish Python Package > Run workflow\n   - Select: PyPI + Publish to GitHub Packages + Create GitHub release\n   - Creates tag (e.g., `v0.2.0`), GitHub release, and publishes to PyPI\n\n3. **Verify**:\n   - Check PyPI: https://pypi.org/project/neuwo-api/\n   - Check GitHub Release: https://github.com/neuwoai/neuwo-api-sdk-python/releases\n   - Check packages appear in repo\n\n#### What gets created:\n\n- PyPI package: https://pypi.org/project/neuwo-api/\n- GitHub release with `.whl` and `.tar.gz` files\n- Git tag following `v{VERSION}` format\n- Package artifacts in GitHub Actions\n\n**Versioning:**\n\nFollow [Semantic Versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`):\n\n- **MAJOR**: Breaking changes\n- **MINOR**: New features (backward compatible)\n- **PATCH**: Bug fixes (backward compatible)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENCE](LICENCE) file for details.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Neuwo API SDK - Python SDK client for the Neuwo content classification API.",
    "version": "0.2.0",
    "project_urls": {
        "Documentation": "https://docs.neuwo.ai",
        "Homepage": "https://neuwo.ai",
        "Repository": "https://github.com/neuwoai/neuwo-api-sdk-python"
    },
    "split_keywords": [
        "neuwo",
        " api",
        " content",
        " classification",
        " tagging",
        " ai",
        " machine-learning",
        " iab",
        " taxonomy",
        " brand-safety"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e58e33f7f4c17cb1fed93d0b2464335ccf1a94115fda3b4db729eb0d3ae1c1df",
                "md5": "1f8806617ec8214bb274611e5199dc57",
                "sha256": "169b233835bc500e8b7d615985002eba276ba6dc0a6ff0bddb03b92015842637"
            },
            "downloads": -1,
            "filename": "neuwo_api-0.2.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1f8806617ec8214bb274611e5199dc57",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 25820,
            "upload_time": "2025-10-27T13:10:01",
            "upload_time_iso_8601": "2025-10-27T13:10:01.147339Z",
            "url": "https://files.pythonhosted.org/packages/e5/8e/33f7f4c17cb1fed93d0b2464335ccf1a94115fda3b4db729eb0d3ae1c1df/neuwo_api-0.2.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2f748014572ff4f251edbbac95d33ec02206e92e5bedcbb9414b161df1645fa0",
                "md5": "efb2e20ae252f92cabf6c0210a3d372e",
                "sha256": "c26fa9757f7fe6c62bdf0eeee4ff3b5ecc310ddcfbe4bdc5e369109b9448f538"
            },
            "downloads": -1,
            "filename": "neuwo_api-0.2.0.tar.gz",
            "has_sig": false,
            "md5_digest": "efb2e20ae252f92cabf6c0210a3d372e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 45616,
            "upload_time": "2025-10-27T13:10:01",
            "upload_time_iso_8601": "2025-10-27T13:10:01.969800Z",
            "url": "https://files.pythonhosted.org/packages/2f/74/8014572ff4f251edbbac95d33ec02206e92e5bedcbb9414b161df1645fa0/neuwo_api-0.2.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-27 13:10:01",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "neuwoai",
    "github_project": "neuwo-api-sdk-python",
    "github_not_found": true,
    "lcname": "neuwo-api"
}
        
Elapsed time: 0.52319s