Skip to main content

Python SDK for the CommonGrants protocol

Project description

CommonGrants Python SDK

A Python SDK for interacting with the CommonGrants protocol, providing a type-safe interface for managing grant opportunities.

Features

  • Type-Safe Models: Built with Pydantic v2 for robust data validation and serialization
  • Comprehensive Schema Support: Full implementation of the CommonGrants protocol schemas
  • Modern Python: Requires Python 3.11+ for optimal performance and type safety
  • Extensible: Easy to extend with custom fields and validation

Installation

# Using pip
pip install common-grants-sdk

# Using Poetry
poetry add common-grants-sdk

Quick Start

from datetime import datetime, date, UTC
from uuid import uuid4

from common_grants_sdk.schemas.pydantic import (
    Event,
    Money,
    OpportunityBase,
    OppFunding,
    OppStatus,
    OppStatusOptions,
    OppTimeline,
)

# Create a new opportunity
opportunity = OpportunityBase(
    id=uuid4(),
    title="Research Grant 2024",
    description="Funding for innovative research projects",
    status=OppStatus(
        value=OppStatusOptions.OPEN,
        description="This opportunity is currently accepting applications"
    ),
    created_at=datetime.now(UTC),
    last_modified_at=datetime.now(UTC),
    funding=OppFunding(
        total_amount_available=Money(amount="100000.00", currency="USD"),
        min_award_amount=Money(amount="10000.00", currency="USD"),
        max_award_amount=Money(amount="50000.00", currency="USD"),
        estimated_award_count=5
    ),
    key_dates=OppTimeline(
        app_opens=Event(
            name="Application Opens",
            date=date(2024, 1, 1),
            description="Applications open"
        ),
        app_deadline=Event(
            name="Application Deadline",
            date=date(2024, 3, 31),
            description="Applications close"
        )
    )
)

# Serialize to JSON
json_data = opportunity.dump_json()

# Deserialize from JSON
loaded_opportunity = OpportunityBase.from_json(json_data)

Core Components

Base Model

  • CommonGrantsBaseModel: Base class for all models, provides common serialization and validation methods
  • SystemMetadata: Tracks creation and modification timestamps for records

Opportunity Models

  • OpportunityBase: Core opportunity model
  • OppFunding: Funding details and constraints
  • OppStatus & OppStatusOptions: Opportunity status tracking
  • OppTimeline: Key dates and milestones

Field Types

  • Money: Represents monetary amounts with currency
  • DecimalString: Validated string representing a decimal number
  • Event: Union of event types
  • EventType: Enum for event type discrimination
  • SingleDateEvent: Event with a single date
  • DateRangeEvent: Event with a start and end date
  • OtherEvent: Event with a custom description or recurrence
  • CustomField: Flexible field type for custom data
  • CustomFieldType: Enum for custom field value types
  • ISODate: Alias for datetime.date (ISO 8601 date)
  • ISOTime: Alias for datetime.time (ISO 8601 time)
  • UTCDateTime: Alias for datetime.datetime (UTC timestamp)

Transformation Utilities

The SDK includes a utility for transforming data according to a mapping specification:

  • transform_from_mapping() supports extracting fields, switching on values, and reshaping data dictionaries

Example: Data Transformation

from common_grants_sdk.utils.transformation import transform_from_mapping

source_data = {
    "opportunity_id": 12345,
    "opportunity_title": "Research into ABC",
    "opportunity_status": "posted",
    "summary": {
        "award_ceiling": 100000,
        "award_floor": 10000,
        "forecasted_close_date": "2025-07-15",
        "forecasted_post_date": "2025-05-01",
    },
}

mapping = {
    "id": { "field": "opportunity_id" },
    "title": { "field": "opportunity_title" },
    "status": { 
        "switch": {
            "field": "opportunity_status",
            "case": {
                "posted": "open",
                "closed": "closed",
            },
            "default": "custom",
        }
    },
    "funding": {
        "minAwardAmount": {
            "amount": { "field": "summary.award_floor" },
            "currency": "USD",
        },
        "maxAwardAmount": {
            "amount": { "field": "summary.award_ceiling" },
            "currency": "USD",
        },
    },
    "keyDates": {
        "appOpens": { "field": "summary.forecasted_post_date" },
        "appDeadline": { "field": "summary.forecasted_close_date" },
    },
}

transformed_data = transform_from_mapping(source_data, mapping)

assert transformed_data == {
    "id": uuid4(),
    "title": "Research into ABC",
    "status": "open",
    "funding": {
        "minAwardAmount": { "amount": 10000, "currency": "USD" },
        "maxAwardAmount": { "amount": 100000, "currency": "USD" },
    },
    "keyDates": {
        "appOpens": "2025-05-01",
        "appDeadline": "2025-07-15",
    },
}

HTTP Client

The SDK includes a type-safe HTTP client for interacting with CommonGrants Protocol-compliant APIs. The client provides a Pythonic interface with automatic authentication, request/response parsing, and pagination support.

from common_grants_sdk.client import Client, Auth
from common_grants_sdk.client.config import Config

# Initialize client
config = Config(base_url="https://api.example.org")
client = Client(config=config, auth=Auth.api_key("YOUR_API_KEY"))

# Get a specific opportunity
opportunity = client.opportunity.get("<opportunity_id>")
print(opportunity.title)

# List opportunities
response = client.opportunity.list(page=1)
for opp in response.items:
    print(opp.id, opp.title)

For detailed documentation, examples, and configuration options, see the HTTP Client README.

License

See LICENSE

Custom Fields Extensions

The SDK provides utilities for extending schemas with typed custom fields, allowing developers to add domain-specific fields while maintaining type safety.

Extending Schemas with Custom Fields

from datetime import datetime
from uuid import uuid4
from common_grants_sdk.schemas.pydantic import (
    OpportunityBase,
    CustomFieldType,
    OppStatus,
    OppStatusOptions,
)
from common_grants_sdk.extensions.specs import CustomFieldSpec

fields = {
    "legacyId": CustomFieldSpec(field_type=CustomFieldType.INTEGER, value=int),
    "groupName": CustomFieldSpec(field_type=CustomFieldType.STRING, value=str),
}
Opportunity = OpportunityBase.with_custom_fields(
    custom_fields=fields, model_name="Opportunity"
)

opp_data = {
    "id": uuid4(),
    "title": "Foo bar",
    "status": OppStatus(value=OppStatusOptions.OPEN),
    "description": "Example opportunity",
    "createdAt": datetime.fromisoformat("2024-01-01T00:00:00+00:00"),
    "lastModifiedAt": datetime.fromisoformat("2024-01-01T00:00:00+00:00"),
    "customFields": {
        "legacyId": {
            "name": "legacyId",
            "fieldType": "integer",
            "value": 12345,
        },
        "groupName": {
            "name": "groupName",
            "fieldType": "string",
            "value": "TEST_GROUP",
        },
        "ignoredForNow": {"type": "string", "value": "noop"},
    },
}

opp = Opportunity.model_validate(opp_data)


print(opp.custom_fields.legacy_id.value)

Retrieving Custom Field Values

Because retrieving custom field values can be cumbersome there is a get_custom_field_value function inside of the utils folder. Simply add this utility function to any existing pydantic object by using a wrapper function.

    def get_custom_field_value(self, key: str, value_type: type[V]) -> Optional[V]:
        """Returns custom field object specified by key"""

        return get_custom_field_value(self, key=key, value_type=value_type)

Developers can then call the wrapper function like so.

from pydantic import BaseModel
from datetime import datetime
from uuid import uuid4
from common_grants_sdk.schemas.pydantic import (
    OpportunityBase,
    CustomFieldType,
    OppStatus,
    OppStatusOptions,
)


class LegacyIdValue(BaseModel):
    system: str
    id: int


opp_data = {
    "id": uuid4(),
    "title": "Foo bar",
    "status": OppStatus(value=OppStatusOptions.OPEN),
    "description": "Example opportunity",
    "createdAt": datetime.fromisoformat("2024-01-01T00:00:00+00:00"),
    "lastModifiedAt": datetime.fromisoformat("2024-01-01T00:00:00+00:00"),
    "customFields": {
        "legacyId": {
            "name": "legacyId",
            "fieldType": CustomFieldType.OBJECT,
            "value": {"system": "legacy", "id": 123},
        },
        "groupName": {
            "name": "groupName",
            "fieldType": CustomFieldType.STRING,
            "value": "test group",
        },
    },
}

opp = OpportunityBase.model_validate(opp_data)

print(opp.custom_fields["legacyId"])

legacy = opp.get_custom_field_value("legacyId", LegacyIdValue)

print(legacy.id)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

common_grants_sdk-0.5.0.tar.gz (29.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

common_grants_sdk-0.5.0-py3-none-any.whl (46.4 kB view details)

Uploaded Python 3

File details

Details for the file common_grants_sdk-0.5.0.tar.gz.

File metadata

  • Download URL: common_grants_sdk-0.5.0.tar.gz
  • Upload date:
  • Size: 29.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.11.14 Linux/6.14.0-1017-azure

File hashes

Hashes for common_grants_sdk-0.5.0.tar.gz
Algorithm Hash digest
SHA256 213ba3715981d4c9c3928aae409a33d362107c359eb2eb348889142dcb800668
MD5 57948a345af5dc97a7a76cf2d1dca561
BLAKE2b-256 0c2c358fed202c19c0ee850dbb070961c9549819e81fcb0b59ca72b69c301723

See more details on using hashes here.

File details

Details for the file common_grants_sdk-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: common_grants_sdk-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 46.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.2 CPython/3.11.14 Linux/6.14.0-1017-azure

File hashes

Hashes for common_grants_sdk-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d8f0820ed7551d7dca807c8e29862777f03e08fc1fb1b90fe1ac9386688cc23e
MD5 7696c5a91107c0de64244c3f644d8041
BLAKE2b-256 a67818fb6ff1ac11b10d3cd9d28306af67e9d74b47812f8b41cb8a062c2133a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page