Skip to content

Add Naming & Data Models for Custom Deployment SDK#111

Open
tomerqodo wants to merge 2 commits into
qodo_combined-20260114-qodo-grep-copilot_base_add_naming__data_models_for_custom_deployment_sdk_pr365from
qodo_combined-20260114-qodo-grep-copilot_head_add_naming__data_models_for_custom_deployment_sdk_pr365
Open

Add Naming & Data Models for Custom Deployment SDK#111
tomerqodo wants to merge 2 commits into
qodo_combined-20260114-qodo-grep-copilot_base_add_naming__data_models_for_custom_deployment_sdk_pr365from
qodo_combined-20260114-qodo-grep-copilot_head_add_naming__data_models_for_custom_deployment_sdk_pr365

Conversation

@tomerqodo
Copy link
Copy Markdown

Benchmark PR from qodo-benchmark#365

desertaxle and others added 2 commits January 9, 2026 13:33
This phase adds:

1. Naming utilities (src/prefect/_sdk/naming.py):
   - to_identifier(): Convert arbitrary names to valid Python identifiers
   - to_class_name(): Convert names to PascalCase class names
   - Unicode separator handling (em-dash, non-breaking space become word boundaries)
   - NFKD normalization for accented characters (é → e)
   - Python keyword handling (class → class_ for identifiers, Class for class names)
   - Reserved name detection for SDK surface (run, run_async, with_options, etc.)
   - Collision resolution with numeric suffixes (_2, _3, etc.)

2. Data models (src/prefect/_sdk/models.py):
   - WorkPoolInfo: Work pool name, type, job variables schema
   - DeploymentInfo: Deployment name, flow name, parameter schema, work pool ref
   - FlowInfo: Flow name with list of deployments
   - SDKGenerationMetadata: Generation time, Prefect version, workspace, API URL
   - SDKData: Complete container for SDK generation with convenience methods

3. Comprehensive tests (227 total for _sdk module):
   - Edge cases: emoji, Unicode, keywords, empty strings, collisions
   - Non-ASCII separators, German ß, Unicode digits
   - Deterministic ordering verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

Code Review by Qodo (Alpha)

🐞 Bugs (0) 📘 Rule Violations (3) 📎 Requirement Gaps (0) 💡 Suggestions (0)

Grey Divider


Action Required

1. `deployment_names` returns wrong values 📘 Rule Violation
Description
SDKData.deployment_names is documented as returning deployment full_name values, but it
  actually appends deployment.name, making the property’s behavior inconsistent with its own
  docstring.
• This is misleading/self-non-documenting and can cause downstream code generation to use incomplete
  identifiers (deployment-only names) instead of flow/deployment names.
• The mismatch also undermines deterministic output expectations because the returned values are not
  the intended ones.

correctness

Code

src/prefect/_sdk/models.py[R120-129]

+    def deployment_names(self) -> list[str]:
+        """List of all deployment full names (derived from flows).
+
+        Returns names sorted alphabetically for deterministic code generation.
+        """
+        names: list[str] = []
+        for flow in self.flows.values():
+            for deployment in flow.deployments:
+                names.append(deployment.name)
+        return sorted(names)
Evidence
Compliance requires identifiers to be self-documenting and not misleading. The property docstring
claims it returns full deployment names, but the implementation appends deployment.name instead of
deployment.full_name.

Rule 2: Generic: Meaningful Naming and Self-Documenting Code
src/prefect/_sdk/models.py[120-129]

Agent Prompt
## Issue description
`SDKData.deployment_names` claims to return deployment full names, but it currently appends `deployment.name`.

## Issue Context
This makes the code misleading and can break downstream consumers expecting `flow-name/deployment-name` strings.

## Fix Focus Areas
- src/prefect/_sdk/models.py[120-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. `make_unique_identifier` uses `or` 📘 Rule Violation
Description
make_unique_identifier() is intended to enforce uniqueness and reserved-name avoidance, but its
  availability check uses or, causing it to return base even when it collides with existing or
  is in reserved.
• This breaks collision handling and reserved-name avoidance, creating edge-case failures where
  generated identifiers are not unique or conflict with reserved SDK surface names.
• Because this failure can occur silently, it increases the risk of producing invalid/ambiguous
  generated SDK output without obvious error signals.

correctness

Code

src/prefect/_sdk/naming.py[R253-255]

+    # Check if base is available
+    if base not in existing or base not in reserved:
+        return base
Evidence
Robust edge-case management requires correctly handling collisions and reserved identifiers. The
current or condition returns base if it is not in one set, even if it is present in the other,
defeating both uniqueness and reserved-name checks.

Rule 3: Generic: Robust Error Handling and Edge Case Management
src/prefect/_sdk/naming.py[253-255]

Agent Prompt
## Issue description
`make_unique_identifier()` incorrectly uses `or` when deciding whether `base` is available, allowing collisions or reserved names to slip through.

## Issue Context
This function is responsible for ensuring generated identifiers are both unique and do not conflict with reserved SDK surface names.

## Fix Focus Areas
- src/prefect/_sdk/naming.py[253-263]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation Recommended

3. Deferred import in test 📘 Rule Violation
Description
• A new import is introduced inside test_all_reserved_in_module_context() without an obvious need
  (no circular import avoidance or optional dependency handling).
• This reduces predictability/tooling compatibility and violates the project guidance to keep
  imports at module scope unless required.

reliability

Code

tests/_sdk/test_naming.py[R300-303]

+    def test_all_reserved_in_module_context(self):
+        """Test that 'all' is reserved (normalized form of '__all__')."""
+        from prefect._sdk.naming import RESERVED_MODULE_IDENTIFIERS
+
Evidence
The compliance rule requires imports to remain at module scope unless there is a clear justification
(e.g., circular imports/optional deps). The test introduces an inline import without such
justification.

AGENTS.md
tests/_sdk/test_naming.py[300-305]

Agent Prompt
## Issue description
A deferred import was added inside a test function without a clear need.

## Issue Context
Keeping imports at module scope improves readability and tooling support.

## Fix Focus Areas
- tests/_sdk/test_naming.py[1-14]
- tests/_sdk/test_naming.py[300-305]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +120 to +129
def deployment_names(self) -> list[str]:
"""List of all deployment full names (derived from flows).

Returns names sorted alphabetically for deterministic code generation.
"""
names: list[str] = []
for flow in self.flows.values():
for deployment in flow.deployments:
names.append(deployment.name)
return sorted(names)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

1. deployment_names returns wrong values 📘 Rule Violation

SDKData.deployment_names is documented as returning deployment full_name values, but it
  actually appends deployment.name, making the property’s behavior inconsistent with its own
  docstring.
• This is misleading/self-non-documenting and can cause downstream code generation to use incomplete
  identifiers (deployment-only names) instead of flow/deployment names.
• The mismatch also undermines deterministic output expectations because the returned values are not
  the intended ones.
Agent Prompt
## Issue description
`SDKData.deployment_names` claims to return deployment full names, but it currently appends `deployment.name`.

## Issue Context
This makes the code misleading and can break downstream consumers expecting `flow-name/deployment-name` strings.

## Fix Focus Areas
- src/prefect/_sdk/models.py[120-129]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +253 to +255
# Check if base is available
if base not in existing or base not in reserved:
return base
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action Required

2. make_unique_identifier uses or 📘 Rule Violation

make_unique_identifier() is intended to enforce uniqueness and reserved-name avoidance, but its
  availability check uses or, causing it to return base even when it collides with existing or
  is in reserved.
• This breaks collision handling and reserved-name avoidance, creating edge-case failures where
  generated identifiers are not unique or conflict with reserved SDK surface names.
• Because this failure can occur silently, it increases the risk of producing invalid/ambiguous
  generated SDK output without obvious error signals.
Agent Prompt
## Issue description
`make_unique_identifier()` incorrectly uses `or` when deciding whether `base` is available, allowing collisions or reserved names to slip through.

## Issue Context
This function is responsible for ensuring generated identifiers are both unique and do not conflict with reserved SDK surface names.

## Fix Focus Areas
- src/prefect/_sdk/naming.py[253-263]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread tests/_sdk/test_naming.py
Comment on lines +300 to +303
def test_all_reserved_in_module_context(self):
"""Test that 'all' is reserved (normalized form of '__all__')."""
from prefect._sdk.naming import RESERVED_MODULE_IDENTIFIERS

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation Recommended

3. Deferred import in test 📘 Rule Violation

• A new import is introduced inside test_all_reserved_in_module_context() without an obvious need
  (no circular import avoidance or optional dependency handling).
• This reduces predictability/tooling compatibility and violates the project guidance to keep
  imports at module scope unless required.
Agent Prompt
## Issue description
A deferred import was added inside a test function without a clear need.

## Issue Context
Keeping imports at module scope improves readability and tooling support.

## Fix Focus Areas
- tests/_sdk/test_naming.py[1-14]
- tests/_sdk/test_naming.py[300-305]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants