Merged
Conversation
Implements all remaining async metadata write operations: - 8 PUT: create_or_replace for ActivityTypeGroup, ActivityType, Application, CapacityCategory, Form, InventoryType, MapLayer, Shift - 3 DELETE: delete_capacity_category, delete_form, delete_shift - 4 PATCH: update_application_api_access, update_link_template, update_property, update_workzones (bulk) - 7 POST/PUT: generate_application_client_secret, create_link_template, create_map_layer, populate_map_layers, install_plugin, replace_workzones (bulk PUT), populate_workzone_shapes Also adds 33 mocked tests in test_async_metadata_write.py, updates ENDPOINTS.md and README.md with [Async] tags. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… add round-trip tests for async metadata write operations
Add AsyncOFSStatistics module with 3 GET endpoints: - get_activity_duration_stats() — /rest/ofscStatistics/v1/activityDurationStats - get_activity_travel_stats() — /rest/ofscStatistics/v1/activityTravelStats - get_airline_distance_based_travel() — /rest/ofscStatistics/v1/airlineDistanceBasedTravel All methods return paginated Pydantic model responses (OFSResponseList subclasses). Includes 24 mocked tests + 3 live tests, ENDPOINTS.md auto-updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add exclude_none=True to all 3 PATCH methods so null fields (keyId,
resourceId) are not sent in the request body
- Flatten StatisticsPatchResponse to match actual API response shape:
{"status": "200", "updatedRecords": N} instead of nested {"results": {...}}
- Remove StatisticsPatchResult model (not used by the actual API)
- Fix airline distance roundtrip test to send 2 data points (required by
API for company-level updates) with a safe +1 override delta
All 54 statistics tests now pass (48 mocked + 6 live).
Closes #142
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement three async methods on AsyncOFSCoreResourcesMixin for binary file-type custom properties on resources: - get_resource_file_property (CO057G) — GET binary content - set_resource_file_property (CO057U) — PUT binary content - delete_resource_file_property (CO057D) — DELETE property Mirrors the existing user property pattern from users.py. Includes mocked tests (5) and a live roundtrip test with graceful skip when property not configured. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…140) Replace hardcoded 'csign' property label with 'tech_photo' fixture and remove OFSCNotFoundError skip — test now passes unconditionally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…' into release/2.24.0
Implements GET activities/{activityId}/multidaySegments as async method.
Reuses ActivityListResponse model (no new models needed). Adds
segmentable_activity_type and segmentable_activity live test fixtures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ults (#139) Replace ActivityListResponse with MultidaySegmentListResponse (backed by OFSResponseBoundedList) for get_multiday_segments, since the API returns only items/links with no totalResults field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…146) Add OAuthTokenResponse model and implement AsyncOFSOauth2.get_token() backed by /rest/oauthTokenService/v2/token with form-encoded Basic auth. Includes mocked + live tests and retires the NotImplementedError stub. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add access_token field to OFSConfig - Add access_token parameter to AsyncOFSC.__init__ - Replace NotImplementedError with Bearer auth in all 4 async modules - Add E2E test: get token → token-authed client → get_activity_types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Ts (#137) Adds 10 new async GET endpoints to AsyncOFSMetadata: Capacity area sub-resources (ME012G-ME018G): - get_capacity_area_capacity_categories(label) - get_capacity_area_workzones(label) — v2 API - get_capacity_area_workzones_v1(label) — deprecated v1 - get_capacity_area_time_slots(label) - get_capacity_area_time_intervals(label) - get_capacity_area_organizations(label) - get_capacity_area_children(label, status, fields, expand, type) Populate status checks (ME030G, ME057G): - get_populate_map_layers_status(download_id) - get_populate_workzone_shapes_status(download_id) Workzone key (ME059G): - get_workzone_key() Models added: CapacityAreaCapacityCategory/Response, CapacityAreaWorkZone/Response, CapacityAreaWorkZoneV1/Response, CapacityAreaTimeSlot/Response, CapacityAreaTimeInterval/Response, CapacityAreaOrganization/Response, CapacityAreaChildrenResponse, PopulateStatusResponse, WorkZoneKeyElement, WorkZoneKeyResponse Tests: 429 passing, 0 failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sistants, get_resource_plans - get_calendars: add resources, date_from, date_to (API requires all three) - get_resource_assistants: add date_from, date_to (API requires both; range ≤ 14 days) - get_resource_plans: add date_from, date_to (API requires both) - Fix capture script: correct params for all three endpoints, fix activity link path (start_before → starts_after), rename 3 mislabeled *_200_success files that returned 404 to *_404_not_supported - Add live tests and saved-response validation tests for the three fixed methods 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merges fix for get_calendars, get_resource_assistants, and get_resource_plans methods that were missing required API parameters. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add missing fields detected by live API audit: - Shift: links - ResourceType: translations, links - CapacityCategory: links - InventoryType: name, unitOfMeasurement, links - Form: links - MapLayer: links - Tighten 13 models from extra="allow" to extra="ignore": Shift, ResourceType, CapacityCategory, InventoryType, Form, MapLayer, ActivityTypeFeatures, Link, ApiMethod, ApiEntity, ApplicationApiAccessListResponse, RoutingProfile, RoutingPlan - Add 24 live audit tests that detect unmapped __pydantic_extra__ fields - Fix test_model.py to compare links as Link model instances Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…h valid credentials
- Introduced a comprehensive markdown report detailing test execution metrics, including total tests, pass rates, code coverage, and failure analysis. - Included breakdowns by directory and marker distribution, along with root cause analysis for test failures. - Provided recommendations for new tests and improvements to existing coverage, addressing critical gaps and issues identified during testing.
… response handling
…=allow Merges metadata model improvements from issue #149: - Tighten Pydantic models in ofsc/models/metadata.py with extra=allow - Add comprehensive model audit tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…k_instance fixture - Add @pytest.mark.uses_real_data to ~75 unmarked tests that make real API calls (async TestAsyncGet* classes, sync test_base/test_model/metadata tests) - Add credentials-free mock_instance fixture to tests/async/conftest.py using dummy credentials so mocked tests run without .env file - Migrate ~200+ mocked tests from async_instance to mock_instance across 18 files — any test that sets _client.X = AsyncMock(...) no longer needs real credentials for fixture setup - Result: pytest -m "not uses_real_data" passes 455 tests with 0 failures and no .env required; uses_real_data collection grows to 449 tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Register a new pytest marker `uses_local_data` for tests that load files from tests/saved_responses/ (gitignored, unavailable in CI). Apply it to 23 TestAsync*SavedResponses classes and update the GitHub Actions workflow to exclude both uses_real_data and uses_local_data markers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace async_instance with mock_instance in all mocked tests across 8 test files. These tests already mock the HTTP client internally, so they don't need real API credentials. Using async_instance caused KeyError on companyName in CI environments without a .env file. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…fensive validator - Add uses_local_data marker to test_import_plugin_file_success to skip in CI (test reads tests/test.xml before mock intercepts, file is gitignored) - Add uses_real_data markers to all sync tests in test_users.py, test_applications.py, and test_workzones.py that require API credentials - Add pytest import to test_users.py and test_applications.py - Make OFSConfig.set_base_URL validator defensive using .get() to avoid KeyError when companyName validation fails before baseURL is processed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run ruff format on all source and test files to establish a consistent code style baseline now that ruff is a tracked dev dependency. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release 2.24.0
Summary
AsyncOFSMetadata) covering workzones, workskills, properties, activity types, workskill groups, routing profiles, workskill conditions, service windows, capacity categories, and org unitstest_async_metadata_roundtrip.py) and write tests (test_async_metadata_write.py)AsyncOFSStatistics) with 3 endpoints: activity duration stats, activity travel stats, airline distance based traveltech_photofixtureaccess_tokenparam +useToken=True)get_calendars,get_resource_assistants, andget_resource_plansasync methodscreate_link_templateto use collection URL and correcten-USlanguage codeofsc/models/metadata.pywithextra=ignoredocs/ENDPOINTS.mdandREADME.mdChanges
ofsc/async_client/metadata.py— 22 new async write methods (create, update, delete); fix create_link_template URLofsc/async_client/statistics.py— newAsyncOFSStatisticsmodule with 3 GET + 3 PATCH methodsofsc/models/statistics.py— Pydantic models for Statistics APIofsc/models/metadata.py— tighten 13 models from extra=allow to extra=ignore; add missing fieldsofsc/async_client/core/resources.py— CO057G/U/D file property methods + fixed required paramsofsc/async_client/core/_base.py— miscellaneous GET methods including get_multiday_segments with dedicated MultidaySegmentListResponseofsc/async_client/__init__.py—access_tokenparameter for token-based authofsc/models/_base.py—access_tokenfield inOFSConfigtests/async/test_async_metadata_write.py— mocked write operation teststests/async/test_async_metadata_roundtrip.py— round-trip integration teststests/async/test_async_statistics.py— 48 mocked + 6 live statistics teststests/async/test_async_resources_write.py— live roundtrip test for file propertiestests/async/test_async_activities.py— tests for miscellaneous activity GET operationstests/async/test_async_oauth.py— OAuth token tests + E2E token auth testtests/async/test_async_resources_get.py— tests for fixed resource methodstests/async/test_metadata_model_audit.py— 24 live audit tests for unmapped model fieldsdocs/ENDPOINTS.md— updated implementation statusREADME.md— updated method tagsCloses #137
Closes #138
Closes #139
Closes #140
Closes #141
Closes #142
Closes #146
Closes #149
🤖 Generated with Claude Code