-
Notifications
You must be signed in to change notification settings - Fork 1
[SILO-598] feat: Handcrafted SDK v0.2.0 #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Introduced new test scripts for comprehensive testing of various SDK functionalities.
- Updated README.md to reflect changes and added a link to the documentation.
- Enhanced model configurations to allow extra fields in Pydantic models.
- Added LICENSE file for project licensing.
|
Linked to Plane Work Item(s) This comment was auto-generated by Plane |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughReplaces 100+ autogenerated OpenAPI Markdown docs with a curated Plane Python SDK: adds MIT LICENSE, updates README and agents architecture for PlaneClient/Pydantic v2, adds examples and setup guides, updates package exports in Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Dev as Developer
participant Client as PlaneClient
participant Res as BaseResource
participant HTTP as HTTP Layer
participant API as Plane API
rect #E8F4FF
Note right of Client: New high-level SDK entrypoint\n(PlaneClient + typed models)
Dev->>Client: instantiate(base_url, api_key | access_token)
end
rect #FFF7E6
Client->>Res: call resource.method(params)
Res->>HTTP: build request (URL, headers, body ← Pydantic)
HTTP->>API: send HTTP request (sync)
API-->>HTTP: response (200 / 4xx / 5xx)
HTTP-->>Res: parse JSON → Pydantic model or raise HttpError
Res-->>Client: return model instance or raise PlaneError
Client-->>Dev: return value / propagate error
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
agents.md (1)
287-317: Clarify type hint for timeout in Configuration.The
timeoutparameter on line 309 should use a more specific type hint to match the README patterns and improve clarity for SDK users.Update line 309 to be explicit about the tuple structure:
def __init__( self, *, base_path: str, api_key: str | None = None, access_token: str | None = None, - timeout: float | tuple | None = 30.0, + timeout: float | tuple[float, float] | None = 30.0, retry: RetryConfig | None = None, ) -> None:This matches the timeout type shown in README.md (line 781:
float \| tuple[float, float]) and provides clearer guidance for requests timeout handling (connect timeout, read timeout).README.md (1)
56-56: Add language identifier to fenced code block.The code fence on line 56 lacks a language specifier, impacting markdown rendering and syntax highlighting clarity.
Apply this diff:
-``` +``` # v0.1.x (OpenAPI-generated)(Add
pythonor appropriate language identifier after the opening fence.)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (101)
.gitignore(1 hunks)LICENSE(1 hunks)README.md(1 hunks)agents.md(1 hunks)docs/AccessBd4Enum.md(0 hunks)docs/AccessEnum.md(0 hunks)docs/AssetsApi.md(0 hunks)docs/Cycle.md(0 hunks)docs/CycleCreateRequest.md(0 hunks)docs/CycleIssue.md(0 hunks)docs/CycleIssueRequestRequest.md(0 hunks)docs/CycleLite.md(0 hunks)docs/CyclesApi.md(0 hunks)docs/EntityTypeEnum.md(0 hunks)docs/Epic.md(0 hunks)docs/EpicsApi.md(0 hunks)docs/GenericAssetUploadRequest.md(0 hunks)docs/GetWorkspaceMembers200ResponseInner.md(0 hunks)docs/GroupEnum.md(0 hunks)docs/IntakeApi.md(0 hunks)docs/IntakeIssue.md(0 hunks)docs/IntakeIssueCreateRequest.md(0 hunks)docs/IntakeIssueStatusEnum.md(0 hunks)docs/IntakeWorkItemStatusEnum.md(0 hunks)docs/Issue.md(0 hunks)docs/IssueActivity.md(0 hunks)docs/IssueAttachment.md(0 hunks)docs/IssueAttachmentUploadRequest.md(0 hunks)docs/IssueComment.md(0 hunks)docs/IssueCommentCreateRequest.md(0 hunks)docs/IssueDetail.md(0 hunks)docs/IssueExpand.md(0 hunks)docs/IssueForIntakeRequest.md(0 hunks)docs/IssueLink.md(0 hunks)docs/IssueLinkCreateRequest.md(0 hunks)docs/IssuePropertyAPI.md(0 hunks)docs/IssuePropertyAPIRelationTypeEnum.md(0 hunks)docs/IssuePropertyAPIRequest.md(0 hunks)docs/IssuePropertyOptionAPI.md(0 hunks)docs/IssuePropertyOptionAPIRequest.md(0 hunks)docs/IssuePropertyValueAPI.md(0 hunks)docs/IssuePropertyValueAPIDetail.md(0 hunks)docs/IssuePropertyValueAPIRequest.md(0 hunks)docs/IssueRelation.md(0 hunks)docs/IssueRelationCreateRelationTypeEnum.md(0 hunks)docs/IssueRelationCreateRequest.md(0 hunks)docs/IssueRelationRemoveRequest.md(0 hunks)docs/IssueRelationResponse.md(0 hunks)docs/IssueRequest.md(0 hunks)docs/IssueSearch.md(0 hunks)docs/IssueSearchItem.md(0 hunks)docs/IssueTypeAPI.md(0 hunks)docs/IssueTypeAPIRequest.md(0 hunks)docs/IssueWorkLogAPI.md(0 hunks)docs/IssueWorkLogAPIRequest.md(0 hunks)docs/Label.md(0 hunks)docs/LabelCreateUpdateRequest.md(0 hunks)docs/LabelLite.md(0 hunks)docs/LabelsApi.md(0 hunks)docs/MembersApi.md(0 hunks)docs/Module.md(0 hunks)docs/ModuleCreateRequest.md(0 hunks)docs/ModuleIssue.md(0 hunks)docs/ModuleIssueRequestRequest.md(0 hunks)docs/ModuleLite.md(0 hunks)docs/ModuleStatusEnum.md(0 hunks)docs/ModulesApi.md(0 hunks)docs/NetworkEnum.md(0 hunks)docs/NullEnum.md(0 hunks)docs/PageCreateAPI.md(0 hunks)docs/PageCreateAPIAccessEnum.md(0 hunks)docs/PageCreateAPIRequest.md(0 hunks)docs/PageDetailAPI.md(0 hunks)docs/PageDetailAPIRequest.md(0 hunks)docs/PagesApi.md(0 hunks)docs/PaginatedArchivedCycleResponse.md(0 hunks)docs/PaginatedArchivedModuleResponse.md(0 hunks)docs/PaginatedCycleIssueResponse.md(0 hunks)docs/PaginatedCycleResponse.md(0 hunks)docs/PaginatedEpicResponse.md(0 hunks)docs/PaginatedIntakeIssueResponse.md(0 hunks)docs/PaginatedIssueActivityDetailResponse.md(0 hunks)docs/PaginatedIssueActivityResponse.md(0 hunks)docs/PaginatedIssueCommentResponse.md(0 hunks)docs/PaginatedIssueLinkDetailResponse.md(0 hunks)docs/PaginatedIssueLinkResponse.md(0 hunks)docs/PaginatedLabelResponse.md(0 hunks)docs/PaginatedModuleIssueResponse.md(0 hunks)docs/PaginatedModuleResponse.md(0 hunks)docs/PaginatedProjectResponse.md(0 hunks)docs/PaginatedStateResponse.md(0 hunks)docs/PaginatedWorkItemResponse.md(0 hunks)docs/PatchedAssetUpdateRequest.md(0 hunks)docs/PatchedCycleUpdateRequest.md(0 hunks)docs/PatchedGenericAssetUpdateRequest.md(0 hunks)docs/PatchedIntakeIssueUpdateRequest.md(0 hunks)docs/PatchedIssueCommentCreateRequest.md(0 hunks)docs/PatchedIssueLinkUpdateRequest.md(0 hunks)docs/PatchedIssuePropertyAPIRequest.md(0 hunks)docs/PatchedIssuePropertyOptionAPIRequest.md(0 hunks)docs/PatchedIssueRequest.md(0 hunks)
⛔ Files not processed due to max files limit (43)
- docs/PatchedIssueTypeAPIRequest.md
- docs/PatchedIssueWorkLogAPIRequest.md
- docs/PatchedLabelCreateUpdateRequest.md
- docs/PatchedModuleUpdateRequest.md
- docs/PatchedProjectUpdateRequest.md
- docs/PatchedStateRequest.md
- docs/PriorityEnum.md
- docs/Project.md
- docs/ProjectCreateRequest.md
- docs/ProjectWorklogSummary.md
- docs/ProjectsApi.md
- docs/PropertyTypeEnum.md
- docs/RelationTypeEnum.md
- docs/RetrieveIssueAttachment400Response.md
- docs/RetrieveWorkItemAttachment400Response.md
- docs/State.md
- docs/StateLite.md
- docs/StateRequest.md
- docs/StatesApi.md
- docs/TimezoneEnum.md
- docs/TransferCycleIssueRequestRequest.md
- docs/TransferCycleIssues200Response.md
- docs/TransferCycleIssues400Response.md
- docs/TransferCycleWorkItems200Response.md
- docs/TransferCycleWorkItems400Response.md
- docs/TypeEnum.md
- docs/UserAssetUploadRequest.md
- docs/UserLite.md
- docs/UsersApi.md
- docs/WorkItemActivityApi.md
- docs/WorkItemAttachmentsApi.md
- docs/WorkItemCommentsApi.md
- docs/WorkItemLinksApi.md
- docs/WorkItemPropertiesApi.md
- docs/WorkItemTypesApi.md
- docs/WorkItemWorklogsApi.md
- docs/WorkItemsApi.md
- docs/WorkspacesApi.md
- git_push.sh
- openapitools.json
- plane/init.py
- plane/api/init.py
- plane/api/assets_api.py
💤 Files with no reviewable changes (97)
- docs/EpicsApi.md
- docs/PaginatedCycleResponse.md
- docs/ModuleIssue.md
- docs/IssueExpand.md
- docs/IssueActivity.md
- docs/IssueLink.md
- docs/ModuleCreateRequest.md
- docs/PaginatedEpicResponse.md
- docs/GetWorkspaceMembers200ResponseInner.md
- docs/PageDetailAPI.md
- docs/IssuePropertyAPIRequest.md
- docs/IssueCommentCreateRequest.md
- docs/PaginatedArchivedCycleResponse.md
- docs/PatchedGenericAssetUpdateRequest.md
- docs/IssuePropertyOptionAPIRequest.md
- docs/IssueTypeAPIRequest.md
- docs/EntityTypeEnum.md
- docs/PaginatedStateResponse.md
- docs/PageCreateAPI.md
- docs/PaginatedIssueActivityDetailResponse.md
- docs/LabelCreateUpdateRequest.md
- docs/IssuePropertyAPI.md
- docs/Label.md
- docs/Epic.md
- docs/IssueRelationResponse.md
- docs/PatchedAssetUpdateRequest.md
- docs/PaginatedModuleIssueResponse.md
- docs/IssueDetail.md
- docs/Issue.md
- docs/AccessBd4Enum.md
- docs/PageCreateAPIAccessEnum.md
- docs/LabelLite.md
- docs/IssueRelationCreateRelationTypeEnum.md
- docs/PaginatedIssueActivityResponse.md
- docs/PatchedIntakeIssueUpdateRequest.md
- docs/NullEnum.md
- docs/IntakeIssue.md
- docs/IssueRelation.md
- docs/PaginatedLabelResponse.md
- docs/ModuleStatusEnum.md
- docs/PatchedIssuePropertyAPIRequest.md
- docs/IssueWorkLogAPIRequest.md
- docs/PatchedIssueCommentCreateRequest.md
- docs/IssueWorkLogAPI.md
- docs/PageDetailAPIRequest.md
- docs/PatchedIssueRequest.md
- docs/ModulesApi.md
- docs/IssuePropertyValueAPI.md
- docs/IssueRelationRemoveRequest.md
- docs/CyclesApi.md
- docs/PatchedCycleUpdateRequest.md
- docs/IssueRequest.md
- docs/IssueTypeAPI.md
- docs/PatchedIssuePropertyOptionAPIRequest.md
- docs/PaginatedCycleIssueResponse.md
- docs/PaginatedIssueLinkResponse.md
- docs/PaginatedIssueLinkDetailResponse.md
- docs/LabelsApi.md
- docs/PaginatedModuleResponse.md
- docs/IssueForIntakeRequest.md
- docs/IssueComment.md
- docs/MembersApi.md
- docs/GenericAssetUploadRequest.md
- docs/ModuleIssueRequestRequest.md
- docs/IntakeIssueCreateRequest.md
- docs/IssueSearchItem.md
- docs/IssueLinkCreateRequest.md
- docs/GroupEnum.md
- docs/CycleIssue.md
- docs/CycleLite.md
- docs/IssuePropertyOptionAPI.md
- docs/CycleCreateRequest.md
- docs/IssuePropertyAPIRelationTypeEnum.md
- docs/AssetsApi.md
- docs/PaginatedIssueCommentResponse.md
- docs/Module.md
- docs/PaginatedWorkItemResponse.md
- docs/IssuePropertyValueAPIDetail.md
- docs/IssuePropertyValueAPIRequest.md
- docs/PaginatedProjectResponse.md
- docs/IssueSearch.md
- docs/PatchedIssueLinkUpdateRequest.md
- docs/IssueRelationCreateRequest.md
- docs/IntakeApi.md
- docs/PaginatedArchivedModuleResponse.md
- docs/PagesApi.md
- docs/IssueAttachmentUploadRequest.md
- docs/PaginatedIntakeIssueResponse.md
- docs/AccessEnum.md
- docs/CycleIssueRequestRequest.md
- docs/IntakeIssueStatusEnum.md
- docs/NetworkEnum.md
- docs/IssueAttachment.md
- docs/PageCreateAPIRequest.md
- docs/ModuleLite.md
- docs/IntakeWorkItemStatusEnum.md
- docs/Cycle.md
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T18:13:46.240Z
Learnt from: Prashant-Surya
PR: makeplane/plane-python-sdk#5
File: plane/oauth/api.py:84-87
Timestamp: 2025-08-30T18:13:46.240Z
Learning: In the Plane Python SDK, the new ApiClient requires absolute URLs (host + path) to be passed to call_api() method, not relative paths. When using the new client, construct full URLs like f"{self.base_url}/auth/o/token/" rather than just "/auth/o/token/".
Applied to files:
README.md
🪛 LanguageTool
agents.md
[grammar] ~254-~254: Ensure spelling is correct
Context: ...e use. - Pyupgrade (UP): - Prefer builtin generics: list[str], dict[str, Any]...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~259-~259: Ensure spelling is correct
Context: ... MutableMapping, Set). - Prefer builtin concrete containers (list, dict, `s...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
README.md
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
🔇 Additional comments (9)
.gitignore (1)
67-72: LGTM!The new ignore patterns are appropriate for a Python SDK project. The inclusion of
.DS_Store,*.pem(protecting certificate/key files), and.historyfollows standard practices. Thetsconfig.tsbuildinfopattern is atypical for a Python project but harmless.LICENSE (1)
1-7: LGTM!Standard MIT license format; clearly establishes licensing terms for Plane Software, Inc.
agents.md (1)
514-597: Approve AI agent guidelines section.The Rules for AI Agents and Models section (lines 514–597) clearly articulates SDK standards: strict type annotations, Pydantic v2 models, REST conventions, endpoint structure, naming rules, and testing requirements. This will help maintain consistency across future development.
README.md (6)
15-66: Comprehensive breaking changes section.The breaking changes section (lines 15–66) clearly contrasts v0.1.x and v0.2.0, covering authentication, headers, resource paths, method names, models, pagination, query parameters, errors, imports, and trailing slashes. This will help users understand the migration path and new patterns.
124-157: Practical quick-start examples.The quick-start section (lines 124–157) provides clear, runnable examples for authentication, basic operations (list, create, retrieve, update, delete), and query parameters. Well-structured for new users.
159-207: Clear architecture and type-safety documentation.The architecture section explains PlaneClient structure, resource organization, and Pydantic v2 model conventions with good context for developers on why the SDK is designed this way.
209-362: Comprehensive resource and sub-resource examples.The available resources section (lines 209–362) covers all major resources (users, workspaces, projects, work items, cycles, modules, states, labels, work item types/properties) with practical CRUD examples and sub-resource patterns. Well-organized and actionable.
786-890: Strong end-to-end workflow examples.The examples section (lines 786–890) demonstrates real-world workflows (project creation, state/label setup, work item creation with relationships, cycles with work items, comments/attachments). These showcase SDK patterns and build confidence for users.
931-1003: Development and project structure well-documented.The development section (lines 931–1003) covers setup, testing, code quality tooling (Black, Ruff, MyPy, Pytest), and project structure. Aligns with agents.md guidance and clarifies contributor expectations.
- Introduced `create_work_items.py` to demonstrate project creation, state and label setup, and work item management. - Added `setup_project.py` for comprehensive project setup including work item types, states, and labels. - Created `README.md` to provide an overview and usage instructions for examples. - Added `SETUP.md` for environment setup guidance and troubleshooting tips.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
examples/README.md (1)
171-172: Format URLs as markdown links.The bare URLs should be formatted as proper markdown links for better readability and to comply with markdown best practices.
Apply this diff:
-- **API documentation:** https://docs.plane.so -- **Support:** dev@plane.so +- **API documentation:** [https://docs.plane.so](https://docs.plane.so) +- **Support:** [dev@plane.so](mailto:dev@plane.so)examples/SETUP.md (2)
120-124: Specify language for fenced code block or use plain text.The fenced code block showing the URL structure doesn't need to be in a code fence since it's illustrative text, not executable code.
Apply this diff to remove the fence or add a language identifier:
-``` -https://app.plane.so/<workspace-slug>/projects - ^^^^^^^^^^^^^^^^^ - This is your workspace slug -``` +Example URL structure: + + https://app.plane.so/<workspace-slug>/projects + ^^^^^^^^^^^^^^^^^ + This is your workspace slug
216-217: Format URLs as markdown links.The bare URLs should be formatted as proper markdown links.
Apply this diff:
-- [Plane API Documentation](https://docs.plane.so) -- [Plane Website](https://plane.so) +- [Plane API Documentation](https://docs.plane.so) +- [Plane Website](https://plane.so)Note: The URLs are already properly formatted with markdown link syntax. The linter warning appears to be a false positive. However, if line 227 contains a bare URL elsewhere, please format it appropriately.
examples/setup_project.py (1)
24-30: Consider adding early validation for required environment variables.While
PlaneClientwill raise aConfigurationErrorif authentication is missing,workspace_slugcan beNone, leading to less clear error messages when API calls fail later in the script.Apply this diff to add early validation:
workspace_slug = os.environ.get("WORKSPACE_SLUG") + + if not workspace_slug: + print("✗ Error: WORKSPACE_SLUG environment variable is required") + print("Please set it using: export WORKSPACE_SLUG='your-workspace-slug'") + return print("=" * 60)examples/create_work_items.py (1)
24-30: Consider adding early validation for required environment variables.While
PlaneClientwill raise aConfigurationErrorif authentication is missing,workspace_slugcan beNone, leading to less clear error messages when API calls fail later in the script.Apply this diff to add early validation:
workspace_slug = os.environ.get("WORKSPACE_SLUG") + + if not workspace_slug: + print("✗ Error: WORKSPACE_SLUG environment variable is required") + print("Please set it using: export WORKSPACE_SLUG='your-workspace-slug'") + return print("=" * 60)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
examples/README.md(1 hunks)examples/SETUP.md(1 hunks)examples/create_work_items.py(1 hunks)examples/setup_project.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
examples/setup_project.py (6)
tests/unit/conftest.py (4)
client(43-52)base_url(13-18)api_key(22-24)workspace_slug(34-39)plane/client.py (1)
PlaneClient(19-55)plane/models/labels.py (1)
CreateLabel(28-39)plane/models/projects.py (1)
CreateProject(60-85)plane/models/states.py (1)
CreateState(42-55)plane/models/work_item_types.py (1)
CreateWorkItemType(30-41)
examples/create_work_items.py (6)
tests/unit/conftest.py (4)
client(43-52)base_url(13-18)api_key(22-24)workspace_slug(34-39)plane/client.py (1)
PlaneClient(19-55)plane/models/labels.py (1)
CreateLabel(28-39)plane/models/projects.py (1)
CreateProject(60-85)plane/models/states.py (1)
CreateState(42-55)plane/models/work_items.py (1)
CreateWorkItem(126-153)
🪛 markdownlint-cli2 (0.18.1)
examples/SETUP.md
120-120: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
227-227: Bare URL used
(MD034, no-bare-urls)
examples/README.md
171-171: Bare URL used
(MD034, no-bare-urls)
172-172: Bare URL used
(MD034, no-bare-urls)
- Changed all instances of `BASE_URL`, `API_KEY`, and `ACCESS_TOKEN` to `PLANE_BASE_URL`, `PLANE_API_KEY`, and `PLANE_ACCESS_TOKEN` respectively across test scripts and README files. - Updated usage instructions to reflect the new environment variable names for consistency and clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (1)
agents.md (1)
517-607: AI agent rules are comprehensive and establish clear conventions.The rules codify naming, architecture, testing, and documentation standards. One minor enhancement: clarify or link the "Never use the word Issue" rule (line 559) to the broader API terminology standard (e.g., add a note that this applies to API responses, parameters, and documentation to avoid confusion).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
agents.md(1 hunks)
🧰 Additional context used
🪛 LanguageTool
agents.md
[grammar] ~254-~254: Ensure spelling is correct
Context: ...e use. - Pyupgrade (UP): - Prefer builtin generics: list[str], dict[str, Any]...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~259-~259: Ensure spelling is correct
Context: ... MutableMapping, Set). - Prefer builtin concrete containers (list, dict, `s...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
agents.md
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (4)
agents.md (4)
13-52: Solid client initialization pattern with resource composition.The
PlaneClientexample demonstrates a clean resource-first API and proper configuration injection. Type hints are precise and follow the stated guidelines.
94-183: BaseResource implementation is well-architected for centralized HTTP logic.The approach—with session pooling, retry configuration, unified response handling, and clear error semantics—aligns well with the stated development goals and reduces boilerplate across resources. The trailing-slash normalization in
_build_url(lines 154–155) is a good touch for consistency.
243-268: Development guidelines are comprehensive and follow modern Python standards.The ruff lint rules section is clear and actionable, covering imports, type hints, naming conventions, and error handling. Enforcing these rules via pre-commit will maintain consistency across the codebase.
445-474: Pydantic v2 model patterns are well-defined and appropriate.The separation of response models (with
extra="allow"for forward compatibility) from Create/Update DTOs (withextra="ignore"to reject unknown fields) is a sound practice. Field validation rules are clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
agents.md (1)
56-56: Add language specifier to fenced code block.The folder structure block should declare a language identifier to satisfy markdown linting and improve syntax highlighting. Use
textorplaintextsince it represents a directory structure, not executable code.-``` +```text plane/ __init__.py
🧹 Nitpick comments (1)
examples/SETUP.md (1)
120-124: Add language specifier to code block.The example URL pattern block is missing a language identifier. Since it represents plain text output rather than executable code, use
```text.-``` +```text https://app.plane.so/<workspace-slug>/projects ^^^^^^^^^^^^^^^^^ This is your workspace slug -``` +```
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
agents.md(1 hunks)examples/SETUP.md(1 hunks)
🧰 Additional context used
🪛 LanguageTool
agents.md
[grammar] ~254-~254: Ensure spelling is correct
Context: ...e use. - Pyupgrade (UP): - Prefer builtin generics: list[str], dict[str, Any]...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~259-~259: Ensure spelling is correct
Context: ... MutableMapping, Set). - Prefer builtin concrete containers (list, dict, `s...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
🪛 markdownlint-cli2 (0.18.1)
agents.md
56-56: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
examples/SETUP.md
120-120: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (1)
examples/SETUP.md (1)
29-92: The test fixtures have already been updated to usePLANE_BASE_URL,PLANE_API_KEY, andPLANE_ACCESS_TOKENconsistently. No naming inconsistencies remain—users following the SETUP.md guide will set the correct environment variables that the tests expect.
- Introduced `OAuthClient` for handling OAuth 2.0 flows including authorization code and client credentials. - Added examples demonstrating OAuth usage in `oauth_example.py`. - Updated `README.md` to include OAuth authentication details and usage instructions. - Enhanced `examples/README.md` to guide users on running the OAuth examples. - Implemented token management features such as refresh and revoke in the OAuth client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
README.md(1 hunks)examples/README.md(1 hunks)examples/oauth_example.py(1 hunks)plane/__init__.py(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T18:13:46.240Z
Learnt from: Prashant-Surya
Repo: makeplane/plane-python-sdk PR: 5
File: plane/oauth/api.py:84-87
Timestamp: 2025-08-30T18:13:46.240Z
Learning: In the Plane Python SDK, the new ApiClient requires absolute URLs (host + path) to be passed to call_api() method, not relative paths. When using the new client, construct full URLs like f"{self.base_url}/auth/o/token/" rather than just "/auth/o/token/".
Applied to files:
README.mdplane/__init__.py
🧬 Code graph analysis (2)
plane/__init__.py (3)
tests/unit/conftest.py (1)
client(43-52)plane/client/oauth_client.py (6)
OAuthAuthorizationParams(26-35)OAuthClient(77-360)OAuthClientCredentialsParams(61-73)OAuthRefreshTokenParams(50-58)OAuthToken(14-23)OAuthTokenExchangeParams(38-47)plane/client/plane_client.py (1)
PlaneClient(19-55)
examples/oauth_example.py (2)
plane/client/oauth_client.py (7)
OAuthClient(77-360)OAuthToken(14-23)get_authorization_url(160-191)exchange_code(193-220)refresh_token(222-242)get_client_credentials_token(244-272)revoke_token(274-299)plane/client/plane_client.py (1)
PlaneClient(19-55)
🪛 markdownlint-cli2 (0.18.1)
README.md
1026-1026: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
1064-1064: Bare URL used
(MD034, no-bare-urls)
examples/README.md
199-199: Bare URL used
(MD034, no-bare-urls)
200-200: Bare URL used
(MD034, no-bare-urls)
🪛 Ruff (0.14.2)
plane/__init__.py
23-45: __all__ is not sorted
Apply an isort-style sorting to __all__
(RUF022)
examples/oauth_example.py
162-162: Possible hardcoded password assigned to argument: "access_token"
(S106)
163-163: Possible hardcoded password assigned to argument: "refresh_token"
(S106)
164-164: Possible hardcoded password assigned to argument: "token_type"
(S106)
177-177: Do not catch blind exception: Exception
(BLE001)
241-241: Do not catch blind exception: Exception
(BLE001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Cursor Bugbot
- Modified `oauth_example.py` to replace workspace listing with project listing using the `workspace_slug` environment variable. - Updated print statements to reflect the number of projects found instead of workspaces. - Added documentation for the new `WORKSPACE_SLUG` environment variable requirement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
examples/oauth_example.py(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-30T18:13:46.240Z
Learnt from: Prashant-Surya
Repo: makeplane/plane-python-sdk PR: 5
File: plane/oauth/api.py:84-87
Timestamp: 2025-08-30T18:13:46.240Z
Learning: In the Plane Python SDK, the new ApiClient requires absolute URLs (host + path) to be passed to call_api() method, not relative paths. When using the new client, construct full URLs like f"{self.base_url}/auth/o/token/" rather than just "/auth/o/token/".
Applied to files:
examples/oauth_example.py
🧬 Code graph analysis (1)
examples/oauth_example.py (2)
plane/client/oauth_client.py (7)
OAuthClient(77-360)OAuthToken(14-23)get_authorization_url(160-191)exchange_code(193-220)refresh_token(222-242)get_client_credentials_token(244-272)revoke_token(274-299)plane/client/plane_client.py (1)
PlaneClient(19-55)
🪛 Ruff (0.14.2)
examples/oauth_example.py
165-165: Possible hardcoded password assigned to argument: "access_token"
(S106)
166-166: Possible hardcoded password assigned to argument: "refresh_token"
(S106)
167-167: Possible hardcoded password assigned to argument: "token_type"
(S106)
180-180: Do not catch blind exception: Exception
(BLE001)
245-245: Do not catch blind exception: Exception
(BLE001)
🔇 Additional comments (5)
examples/oauth_example.py (5)
1-10: LGTM: Clean imports and clear documentation.The module docstring and imports are well-structured and appropriate for the OAuth examples.
153-182: LGTM: Clear token management demonstration.The example effectively demonstrates token refresh and revocation patterns. The hardcoded token strings flagged by static analysis are appropriate placeholders for example code.
189-212: LGTM: Excellent demonstration of context manager pattern.This example clearly shows automatic session cleanup through context manager usage, which is a best practice for resource management.
219-248: LGTM: Comprehensive error handling demonstration.This example effectively demonstrates the error hierarchy with ConfigurationError, HttpError, and general Exception handling. The empty string defaults (lines 228-229) are well-suited for triggering errors in this demonstration context.
250-268: LGTM: Well-structured main block with helpful guidance.The commented-out examples and clear environment variable documentation provide excellent developer experience. Users can safely run the file and selectively enable examples.
| workspace_slug = os.environ.get("WORKSPACE_SLUG", "your-workspace-slug") | ||
| plane_client = PlaneClient( | ||
| base_url=os.environ.get("PLANE_BASE_URL", "https://api.plane.so"), | ||
| access_token=token.access_token, | ||
| ) | ||
|
|
||
| # Now you can use the plane_client to make API calls | ||
| projects = plane_client.projects.list(workspace_slug) | ||
| print(f"Found {len(projects.results)} projects") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace placeholder defaults with fail-fast environment variable access.
Multiple examples use os.environ.get("WORKSPACE_SLUG", "your-workspace-slug") with a placeholder default. This pattern creates poor developer experience because:
- The placeholder value causes API calls to fail with unclear 404/authorization errors rather than immediate, actionable KeyError
- It gives false confidence that the code might work without proper configuration
This partially addresses a past review concern about missing workspace_slug in the bot_token_example (lines 138-146), but the placeholder default still leads to delayed failures.
Consider either:
- Preferred: Use
os.environ["WORKSPACE_SLUG"]for immediate failure with clear error message - Alternative: Keep the current pattern but add prominent comments explaining these are non-functional placeholders
Apply this diff pattern across affected examples:
- workspace_slug = os.environ.get("WORKSPACE_SLUG", "your-workspace-slug")
+ workspace_slug = os.environ["WORKSPACE_SLUG"]Then update the main block documentation (line 266) to emphasize WORKSPACE_SLUG is required:
- print(" - WORKSPACE_SLUG (required for API calls)")
+ print(" - WORKSPACE_SLUG (required)")Also applies to: 100-108, 137-145, 202-209
🤖 Prompt for AI Agents
In examples/oauth_example.py around lines 56-64 (and also apply the same change
to ranges 100-108, 137-145, 202-209), the code uses
os.environ.get("WORKSPACE_SLUG", "your-workspace-slug") which masks missing
configuration; replace these get-with-default calls with
os.environ["WORKSPACE_SLUG"] so the process fails fast with a clear KeyError if
the env var is missing (or if you prefer to keep placeholders, add a prominent
inline comment stating the default is non-functional and must be replaced); also
update the main block documentation at line 266 to explicitly state that
WORKSPACE_SLUG is required and the examples will error if it is not set.
Description
Complete rewrite replacing OpenAPI-generated code with a hand-crafted, type-safe SDK.
Developer experience
Architecture
Coverage
Breaking change: Not backward compatible. See README.md for migration guide.
Type of Change
Test Scenarios
Verified by running test suite at tests/ folder
References
SILO-598
Summary by CodeRabbit
Note
Replaces OpenAPI-generated client with a resource-first, Pydantic v2–typed SDK, reorganizes models/resources, updates packaging, and adds comprehensive tests (breaking).
PlaneClient(Python 3.10+, Pydantic v2).query_params.py,pagination.py).work_items,projects,labels,states,modules,cycles,epics,pages,users,workspaces,customers,intake,work_item_types,work_item_properties.enums.py.pyproject.toml(new name/version), modern tooling (black/ruff/mypy), and simplified dependencies (requests,pydantic).setup.py,rest.py, tox/poetry configs.tests/for end‑to‑end workflows.Written by Cursor Bugbot for commit e610057. This will update automatically on new commits. Configure here.