Skip to main content

pyOFSC

Oracle Fusion Field Service (formerly Oracle Field Service Cloud, formerly ETAdirect) is a cloud-based field service management platform for scheduling, dispatching, and managing mobile workforces.

pyOFSC is a Python wrapper for its REST API, providing both synchronous and asynchronous clients with Pydantic model-based validation. See the official Oracle Fusion Field Service documentation for API details.

Async Client

Starting with version 2.19, pyOFSC includes an async client (AsyncOFSC) that provides asynchronous API access using httpx and Python's async/await patterns.

Implementation Status: The async client is being implemented progressively. Currently available async methods are marked with [Sync & Async] tags in docs/ENDPOINTS.md.

Usage Example

from ofsc.async_client import AsyncOFSC
async with AsyncOFSC(clientID="...", secret="...", companyName="...") as client:
    workzones = await client.metadata.get_workzones()

Key Features

  • Async/Await Support: Full async/await pattern support for non-blocking I/O
  • Same Models: Reuses all existing Pydantic models from the sync version
  • Context Manager: Must be used as an async context manager to properly manage HTTP client lifecycle
  • Simplified API: Async methods always return Pydantic models (no response_type parameter)
  • Request/Response Logging: Optional httpx event hooks for automatic API call tracing
  • Async Generators: Lazy pagination helpers that yield individual items across all pages (e.g. get_all_workzones, get_all_resources) [Async]

Streaming Daily Extract Downloads

Download large extracts incrementally with core.get_daily_extract_file_stream:

async with AsyncOFSC(clientID="...", secret="...", companyName="...") as client:
    async with client.core.get_daily_extract_file_stream(
        date="2024-01-15", filename="extract.zip", chunk_size=8192
    ) as stream:
        with open("extract.zip", "wb") as output:
            async for chunk in stream:
                output.write(chunk)

The async context keeps the response open while chunks are consumed and closes it on completion, early exit, errors, or cancellation. chunk_size must be positive. Successful downloads are not buffered in full; HTTP error bodies are read to preserve the same typed API exceptions as the buffered download method.

Enabling Request/Response Logging

Pass enable_logging=True to automatically log all HTTP requests and responses via Python's standard logging:

import logging
logging.basicConfig(level=logging.DEBUG)

async with AsyncOFSC(clientID="...", secret="...", companyName="...", enable_logging=True) as client:
    workzones = await client.metadata.get_workzones()
    # DEBUG: Request: GET https://company.fs.ocs.oraclecloud.com/rest/ofscMetadata/v1/workZones
    # DEBUG: Response: GET https://company.fs.ocs.oraclecloud.com/rest/ofscMetadata/v1/workZones 200

Logs are emitted under the ofsc.async_client logger. HTTP errors (4xx/5xx) are also logged at WARNING level. Disabled by default with zero overhead.

HTTP Transport Configuration

Pass an HTTPClientConfig to tune transport behavior — most commonly to cap concurrency against the OFSC tenant, but also to set timeouts, retries, a proxy, and other knobs. All fields are optional; defaults preserve historical behavior. The surface is library-neutral (only scalars) so the underlying HTTP library can change without breaking your code.

from ofsc.async_client import AsyncOFSC, HTTPClientConfig

async with AsyncOFSC(
    clientID="...",
    secret="...",
    companyName="...",
    http_config=HTTPClientConfig(
        max_concurrency=20,   # cap in-flight connections to the tenant
        timeout=30.0,         # seconds, per request
        max_retries=2,        # connection-level retries
    ),
) as client:
    workzones = await client.metadata.get_workzones()

Available fields: max_concurrency, timeout, max_retries, proxy, verify_ssl, http2, follow_redirects, trust_env.

Models

All API entities use Pydantic v2 models. See ofsc/models/ for available models.

Testing

pyOFSC includes a comprehensive test suite with 500+ tests. Tests run in parallel by default using pytest-xdist for 10x faster execution.

Running Tests

# Run all tests (parallel for safe tests, sequential for serial tests)
uv run pytest

# Run tests with specific number of workers
uv run pytest -n 4 -m "not serial"

# Run all tests sequentially (disable parallel execution)
uv run pytest -n 0

# Run only serial tests (sequential execution)
uv run pytest -m serial -n 0

# Run only mocked tests (no API credentials needed)
uv run pytest -m "not uses_real_data"

# Run specific test file
uv run pytest tests/async/test_async_workzones.py

Note: By default, tests marked with @pytest.mark.serial are excluded from parallel execution to prevent conflicts when modifying shared API state. To run all tests including serial ones, use: uv run pytest -m "" -n auto && uv run pytest -m serial -n 0

Test Requirements

  • Mocked tests: No special requirements, use saved API responses
  • Live tests (marked with @pytest.mark.uses_real_data): Require API credentials in .env file:
    OFSC_CLIENT_ID=your_client_id
    OFSC_COMPANY=your_company
    OFSC_CLIENT_SECRET=your_secret
    

Test Markers

  • @pytest.mark.uses_real_data - Tests that require API credentials
  • @pytest.mark.serial - Tests that must run sequentially (automatically excluded from parallel execution)
  • @pytest.mark.slow - Slow-running tests
  • @pytest.mark.integration - Integration tests

Implemented Functions

197 async endpoints (81% coverage) and 89 sync endpoints (37% coverage) across Core, Metadata, Capacity, Statistics, and Auth modules.

See docs/ENDPOINTS.md for the full implementation status table.

Async core operations

  • core.search_activities(params) returns an ActivityListResponse and accepts the search API's query parameters, including searchInField, searchForValue, date filters, offset and limit.
  • core.move_activity(activity_id, data) sends the action object and returns None for a successful 204 move response.
  • core.bulk_update(BulkUpdateRequest(...)) returns a BulkUpdateResponse. Explicit nulls are preserved, including activityId=None for creation; unset optional fields are omitted. Inspect each result's errors, operations and warnings: bulk updates can partially fail within a successful HTTP response.

core.get_all_activities(...) and core.get_all_properties(...) collect all pages into typed OFSResponseList containers. Activity dates default to seven days before/after the current day; provide both bounds for another range. activity_fields and additional_fields control which fields are fetched. Offsets advance by the number of returned items, and an empty page claiming more data raises OFSCApiError. Both helpers hold the complete result in memory; use core.get_activities or metadata.get_properties for individual pages.

Usage Examples

Sync:

from ofsc import OFSC
instance = OFSC(clientID="...", secret="...", companyName="...")
workzones = instance.metadata.get_workzones()

Async:

from ofsc.async_client import AsyncOFSC
async with AsyncOFSC(clientID="...", secret="...", companyName="...") as client:
    workzones = await client.metadata.get_workzones()

See the examples/ directory for comprehensive sync and async usage examples.

Streaming Daily Extract Downloads

The synchronous client can download large extracts without buffering the full successful response in memory. Use the response as a context manager and choose the chunk size through Requests' iter_content method:

with instance.core.get_daily_extract_file_stream(
    date="2026-01-15", filename="extract.zip", timeout=(5, 60)
) as stream:
    with open("extract.zip", "wb") as destination:
        for chunk in stream.iter_content(chunk_size=8192):
            if chunk:
                destination.write(chunk)

The response closes on context exit, including after an early break or an exception. The optional timeout specifies connect and read timeouts; omitting it preserves Requests' default. With the default auto_raise=True, OFSC JSON errors raise OFSAPIException, and other unsuccessful responses raise requests.HTTPError. If auto_raise=False, check stream.status_code before writing the body. get_daily_extract_file continues to return buffered bytes.

Test History

OFS REST API Version PyOFSC
20C 1.7
21A 1.8, 1.8,1, 1.9
21D 1.15
22B 1.16, 1.17
22D 1.18
24C 2.0
25B 2.12
26A 2.24.0

Future Deprecation Notice - OFSC 3.0

Important: Starting with Oracle Fusion Field Service 3.0, the synchronous client (OFSC) will be deprecated in favor of the async client (AsyncOFSC).

Migration Path

  • The async client (AsyncOFSC) is the recommended approach for all new development
  • OFSC 3.0 will provide a compatibility wrapper to allow existing synchronous code to continue working without modifications
  • The compatibility wrapper will internally use the async client with synchronous adapters
  • We recommend gradually migrating to the async client to take advantage of better performance and scalability

Timeline

  • OFSC 2.x: Both sync and async clients fully supported
  • OFSC 3.0: Sync client deprecated, compatibility wrapper provided
  • OFSC 4.0: Sync client may be removed (compatibility wrapper will remain for at least one major version)

Metadata

Release files for ofsc 2.27.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ofsc 2.27.1
File Size Uploaded Provenance
ofsc-2.27.1.tar.gz 436.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ofsc 2.27.1
File Interpreter ABI Platform
ofsc-2.27.1-py3-none-any.whl Python 3 none any Details

Total release size: 516.2 kB

Release files / ofsc-2.27.1.tar.gz

Download URL ofsc-2.27.1.tar.gz
Size 436.4 kB
Tags Source
SHA-256 checksum
How to use checksums
63598c9abb734f0f9ad138157b5abfd078e93f5f14d251fb94ebb78388761e59
BLAKE2b-256 checksum
How to use checksums
604a9f5fde8ea415cc81de47d5ab67095c544a88c21c926fda7acdef61d80bac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / ofsc-2.27.1-py3-none-any.whl

Download URL ofsc-2.27.1-py3-none-any.whl
Size 79.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2049f324525467db0493d76b29f127a85520cde46ed5fac065218aafafbf0db7
BLAKE2b-256 checksum
How to use checksums
eb959c9c0edd3ce463558de2fbf1f594e395d8524f7cc16802249e3fe6c99214
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for ofsc 2.27.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.27.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page