Releases: btoron/pyOFSC
Releases · btoron/pyOFSC
v2.21.0 - Async Metadata API Phase 2
pyOFSC v2.21.0 - Async Metadata API Phase 2
Release Date: December 30, 2025
Highlights: 9 new async API modules, 31 methods, comprehensive type safety improvements
🎯 Major Features
Async Metadata API - Phase 2 Implementation
This release completes Phase 2 of the async metadata API implementation, adding async support for 9 critical OFSC metadata modules.
1. Applications API
get_applications()- List all applicationsget_application(label)- Get application detailsget_application_api_accesses(label)- List API accessesget_application_api_access(label, accessId)- Get specific API access
2. Capacity Areas API
get_capacity_areas()- List all capacity areasget_capacity_area(label)- Get capacity area details
3. Capacity Categories API
get_capacity_categories(offset, limit)- List with paginationget_capacity_category(label)- Get category details
4. Forms API
get_forms(offset, limit)- List forms with paginationget_form(label)- Get form details
5. Map Layers API
get_map_layers(offset, limit)- List map layers with paginationget_map_layer(label)- Get map layer details
6. Plugins API
import_plugin_file(file_path)- Import plugin from XML fileimport_plugin(plugin_xml)- Import plugin from XML string
7. Routing Profiles API (Full CRUD)
get_routing_profiles(offset, limit)- List routing profilesget_routing_plans(profile_label, offset, limit)- List plansexport_routing_plan(profile_label, plan_label)- Export planimport_routing_plan(profile_label, plan_label, data)- Import planreplace_routing_plan(profile_label, plan_label, data)- Replace plancreate_routing_plan(profile_label, plan_label, data)- Create plandelete_routing_plan(profile_label, plan_label)- Delete plan
8. Shifts API
get_shifts(offset, limit)- List shifts with paginationget_shift(label)- Get shift details
9. Work Skills API (Full CRUD)
get_work_skills(offset, limit)- List work skillsget_work_skill(label)- Get work skill detailscreate_or_replace_work_skill(workskill)- Create/update work skilldelete_work_skill(label)- Delete work skillget_work_skill_conditions()- List all conditionsget_work_skill_groups(offset, limit)- List groupsget_work_skill_group(label)- Get group detailscreate_or_replace_work_skill_group(group)- Create/update groupdelete_work_skill_group(label)- Delete group
🔧 Code Quality Improvements
Type Safety Enhancements
- ✅ Replaced
List[]withlist[]- 70 occurrences updated for modern Python typing - ✅ Added pyright to dev dependencies - Static type checking support
- ✅ Fixed all pyright errors - Reduced from 13 errors to 0
- ✅ Added type: ignore annotations - 7 RootModel classes properly annotated
Model Improvements
- ✅ Fixed duplicate Link class - Renamed to
DailyExtractLink - ✅ Made Application fields Optional - Proper type safety
- ✅ Fixed baseUrl property - Correct type annotation
- ✅ Removed invalid
__next__()methods - From response list classes - ✅ Fixed enum type mismatch - In Recurrence model
- ✅ Added None checks - For optional member access and iterables
- ✅ Fixed Property.translations - Changed to
Optional[TranslationList]
Documentation
- ✅ PEP 287 docstrings - All async metadata methods converted to reStructuredText format
- ✅ New scripts/README.md - 504 lines documenting utility scripts
- ✅ Updated ENDPOINTS.md - Current implementation status for all 243 endpoints
Code Organization
- ✅ Reorganized models.py - Application and Routing Profile models in alphabetical regions
- ✅ Deleted empty regions - 4 regions removed for cleaner code
- ✅ Consistent naming - Fixed Workskill/WorkskillGroup inconsistencies
🧪 Testing
New Test Coverage
- 9 new test files with 3,340 lines
- 100+ test cases covering all new functionality
- 50+ saved API responses for validation testing
- All tests passing: 266/266 ✅
Test Structure
- Live tests with
@pytest.mark.uses_real_data - Model validation tests
- Saved response validation tests
- Error handling tests (404, authentication, etc.)
- Comprehensive CRUD operation tests
Coverage Metrics
- Overall: 84% (exceeds 80% target)
- async_client/metadata.py: 95%
- models.py: 87%
- exceptions.py: 100%
🐛 Bug Fixes
Critical Fixes
- RoutingPlanData Validation - Made fields optional for varied API responses
- Optional Member Access - Added None checks before calling methods
- Import Naming - Fixed WorkskillConditionList typo
- Type Annotations - Standardized across all models
Minor Fixes
- Updated capacity area validation test label
- Updated Status enum usage in CapacityArea and Workzone
- Corrected endpoint statuses in documentation
- Removed deprecated routing profiles capture script
📦 New Dependencies
Development
pyright>=1.1.390,<2- Static type checker for Python
📊 Statistics
| Metric | Count |
|---|---|
| Issues Resolved | 9 (#92, #93, #94, #95, #99, #102, #105, #106, #108) |
| API Methods Added | 31 |
| Models Created/Updated | 18 |
| Test Files Created | 9 |
| Test Cases Added | 100+ |
| Saved Responses | 50+ |
| Documentation Lines | 1,050+ |
| Net Lines Added | +5,253 |
🔄 Migration Guide
Breaking Changes
None - All changes are backward compatible.
New Features Usage
from ofsc import AsyncOFSC
async with AsyncOFSC(
clientID="your_client_id",
companyName="your_company",
secret="your_secret"
) as client:
# Applications API
apps = await client.metadata.get_applications()
app = await client.metadata.get_application("app_label")
# Routing Profiles API
profiles = await client.metadata.get_routing_profiles()
plans = await client.metadata.get_routing_plans("profile_label")
plan_data = await client.metadata.export_routing_plan(
"profile_label", "plan_label"
)
# Work Skills API (CRUD)
skills = await client.metadata.get_work_skills()
skill = await client.metadata.get_work_skill("skill_label")
await client.metadata.create_or_replace_work_skill(workskill)
await client.metadata.delete_work_skill("skill_label")
# All other new APIs follow the same pattern
forms = await client.metadata.get_forms()
shifts = await client.metadata.get_shifts()
capacity_areas = await client.metadata.get_capacity_areas()Type Checking Support
# Models now fully support modern Python typing
from ofsc.models import (
Application,
RoutingProfileList,
Workskill,
Form
)
# Use with mypy or pyright for static type checking
apps: list[Application] = [] # Modern syntax supported📝 Documentation
New Documentation
- scripts/README.md - Comprehensive guide for utility scripts
capture_api_responses.py- How to capture API responsesupdate_endpoints_doc.py- How to update endpoint documentation- Usage examples, best practices, troubleshooting
Updated Documentation
- ENDPOINTS.md - Current implementation status (89 sync, 53 async endpoints)
- All async metadata docstrings - Now in PEP 287 reStructuredText format
🚀 What's Next
Phase 3 (Upcoming)
- Remaining metadata endpoints (see issue #109)
- Additional CRUD operations
- Batch operations support
Future Releases
- Async Core API implementation
- Async Capacity API implementation
- OAuth token-based authentication for async client
- Enhanced error handling and retries
- Rate limiting support
🙏 Contributors
- Borja Toron (@btoron) - Primary development
- Claude Sonnet 4.5 - AI pair programming assistance
📋 Full Changelog
Features
- feat: implement async routing profiles API methods and add tests (86db72c)
- feat: implement async methods for capacity areas and add comprehensive tests (3448768)
- feat: implement async methods for capacity categories and add comprehensive tests (3dc52d1)
- feat: implement async methods for map layers and add comprehensive tests (aafcf98)
- feat: implement async methods for forms and add comprehensive tests (503377d)
- feat: implement async methods for shifts and add comprehensive tests (9671b40)
- feat: implement async methods for work skills and conditions with comprehensive tests (f87e963)
- feat: Add async applications and plugins API implementation (5db8cf1)
- feat: Add comprehensive README for utility scripts (5ead113)
- feat: add endpoints for work skills in API capture script (52bdbbc)
- feat: add live and model tests for CRUD operations (a7fd98b)
- feat: Update RoutingPlanData model for optional fields (f48d935)
- feat: Refactor metadata models for applications and routing profiles (5383307)
- feat: Add pyright to development dependencies (b9ad391)
- feat: update status fields to use Status enum (f2a77d0)
Bug Fixes
- fix: correct naming inconsistencies for Workskill and WorkskillGroup (7018dfa)
- fix: Correct typo in import statement for WorkskillConditionList (6e64aaa)
- fix: Update endpoint statuses in documentation (5557984)
- test: update expected label for capacity area validation (ff18bed)
Refactoring
- refactor: Replace List with built-in list type (202049d)
- refactor: Simplify model classes and update type hints (de8086f)
- refactor: Docstrings to use reStructuredText (35440fd)
- feat: remove deprecated routing profiles capture script (e2f569e)
Version Updates
- chore: Update version to 2.21.0 (01dfffe)
🔗 Links
Async Client
What's Changed
Full Changelog: v2.18.1...v2.19
v2.18.1
v2.18
v2.17
v2.15
v2.14.1
v2.14
Summary
This release adds comprehensive capacity management functionality to pyOFSC, including:
- New
OFSCapacitymodule for capacity and quota operations - Support for both
getAvailableCapacityandgetQuotaendpoints - Flexible parameter handling with CsvList support
- Generic internal converter function using type inspection
Major Changes
1. New Capacity Module (ofsc/capacity.py)
getAvailableCapacity(): Get available capacity with individual parameters- Supports list, CSV string, and CsvList inputs for areas, dates, categories
- Consistent with
getQuotasignature pattern
getQuota(): Get quota information with flexible parameters- Boolean parameters automatically converted to lowercase strings
- All string array parameters support multiple input formats
_convert_model_to_api_params(): Internal generic converter using inspection- Automatically detects CsvList and boolean fields
- No hardcoded field names - works with any Pydantic model
- DRY implementation shared by both public methods
2. Enhanced Models (ofsc/models.py)
CsvList: Utility model for comma-separated string listsfrom_list()andto_list()conversion methods- Automatic conversion in field validators
CapacityRequest: Updated to use CsvList fields with validatorsGetQuotaRequest: Request model with comprehensive parametersGetQuotaResponseandQuotaAreaItem: Response models for quota data- All models support flexible input formats (list[str], str, CsvList)
3. Module Integration
- Capacity module integrated as top-level API alongside core and metadata
- Access via
ofsc_instance.capacity.getAvailableCapacity()andofsc_instance.capacity.getQuota()
4. Comprehensive Test Suite
- 30+ mocked tests covering all functionality
- 19+ integration tests for real server validation
- Real server responses captured for consistent mocking
- Tests for all input formats and edge cases
- Performance tests included
API Examples
# Get available capacity
response = ofsc.capacity.getAvailableCapacity(
dates=["2025-06-25", "2025-06-26"],
areas=["FLUSA", "CAUSA"],
categories=["EST", "RES"]
)
# Get quota information
response = ofsc.capacity.getQuota(
dates="2025-06-25",
areas=["FLUSA", "CAUSA"],
aggregateResults=True,
categoryLevel=False
)
Breaking Changes
- getAvailableCapacity signature changed from accepting CapacityRequest object to individual parameters
- This aligns with the getQuota pattern for consistency
Testing
- All tests passing (30 mocked, 19 integration)
- Tested with real OFSC server using FLUSA/CAUSA areas
- Performance validated with week-long date ranges