Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 9 additions & 82 deletions .github/skills/ml/fix-pylint/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ description: Automatically fix pylint issues in azure-ai-ml package following Az

This skill automatically fixes pylint warnings in the azure-ai-ml package by analyzing existing code patterns and applying fixes with 100% confidence based on GitHub issues.

> **Scope:** Fix **only mandatory/blocking issues** — warnings that will cause CI to fail. Leave optional/informational warnings as-is.

## Overview

Intelligently fixes pylint issues by:
Expand All @@ -19,12 +21,11 @@ Intelligently fixes pylint issues by:
7. Searching codebase for existing patterns to follow
8. Applying fixes only with 100% confidence
9. Re-running pylint to verify fixes
10. Creating a pull request that references the GitHub issue
11. Providing a summary of what was fixed
10. Providing a summary of what was fixed

## Running Pylint

**Command for entire package:**
**Command for entire package (tox):**
```powershell
cd sdk/ml/azure-ai-ml
tox -e pylint --c ../../../eng/tox/tox.ini --root .
Expand Down Expand Up @@ -146,6 +147,8 @@ Use the existing code patterns to ensure consistency.

### Step 7: Apply Fixes (ONLY if 100% confident)

> **Fix only mandatory/blocking issues.** Skip optional or informational warnings that do not cause CI failure.

**ALLOWED ACTIONS:**
Fix warnings with 100% confidence
Use existing file patterns as reference
Expand All @@ -161,14 +164,14 @@ Use the existing code patterns to ensure consistency.
Change code style without clear reason
Delete code without clear justification

### Step 7: Verify Fixes
### Step 8: Verify Fixes

Re-run pylint to ensure:
- The warning is resolved
- No new warnings were introduced
- The code still functions correctly

### Step 8: Summary
### Step 9: Summary

Provide a summary:
- GitHub issue being addressed
Expand All @@ -177,67 +180,6 @@ Provide a summary:
- Types of fixes applied
- Any warnings that need manual review

### Step 9: Create Pull Request

After successfully fixing pylint issues, create a pull request:

**Stage and commit the changes:**
```powershell
# Stage all modified files
git add .

# Create a descriptive commit message referencing the issue
git commit -m "fix(azure-ai-ml): resolve pylint warnings (#<issue-number>)

- Fixed <list specific types of warnings>
- Updated <files/modules affected>
- All pylint checks now pass

Closes #<issue-number>"
```

**Create pull request using GitHub CLI or MCP server:**

Option 1 - Using GitHub CLI (if available):
```powershell
# Create a new branch
$branchName = "fix/azure-ai-ml-pylint-<issue-number>"
git checkout -b $branchName

# Push the branch
git push origin $branchName

# Create PR using gh CLI
gh pr create `
--title "fix(azure-ai-ml): Resolve pylint warnings (#<issue-number>)" `
--body "## Description
This PR fixes pylint warnings in the azure-ai-ml package as reported in #<issue-number>.

## Changes
- Fixed pylint warnings following Azure SDK Python guidelines
- Ensured consistency with existing code patterns
- Targeted fixes for: <specific files/modules from issue>
- All pylint checks now pass for the affected areas

## Testing
- [x] Ran pylint on affected files and verified all warnings are resolved
- [x] No new warnings introduced
- [x] Verified fixes follow existing code patterns

## Related Issues
Fixes #<issue-number>" `
--base main `
--repo Azure/azure-sdk-for-python
```

Option 2 - Manual PR creation (if GitHub CLI not available):
1. Push branch: `git push origin <branch-name>`
2. Navigate to: https://github.com/Azure/azure-sdk-for-python/compare/main...<branch-name>
3. Create the pull request manually with the description above

Option 3 - Using GitHub MCP server (if available):
Use the GitHub MCP tools to create a pull request programmatically against the Azure/azure-sdk-for-python repository, main branch.

## Common Pylint Issues and Fixes

### Missing Docstrings
Expand Down Expand Up @@ -302,28 +244,14 @@ tox -e pylint --c ../../../eng/tox/tox.ini --root . -- $targetFile
# Cross-reference with GitHub issue #12345

# 5. Search for existing patterns in codebase
grep -r "similar_pattern" azure/ai/ml/
Get-ChildItem -Recurse azure/ai/ml/ | Select-String "similar_pattern"

# 6. Apply fixes to identified files

# 7. Re-run pylint to verify
tox -e pylint --c ../../../eng/tox/tox.ini --root . -- $targetFile

# 8. Report results

# 9. Create PR referencing the issue
$branchName = "fix/azure-ai-ml-pylint-12345"
git checkout -b $branchName
git add .
git commit -m "fix(azure-ai-ml): resolve pylint warnings (#12345)

Closes #12345"
git push origin $branchName
gh pr create `
--title "fix(azure-ai-ml): Resolve pylint warnings (#12345)" `
--body "Fixes #12345" `
--base main `
--repo Azure/azure-sdk-for-python
```

## Notes
Expand All @@ -333,4 +261,3 @@ gh pr create `
- If unsure about a fix, mark it for manual review
- Some warnings may require architectural changes - don't force fixes
- Test the code after fixing to ensure functionality is preserved
- Always reference the GitHub issue in commits and PRs
Original file line number Diff line number Diff line change
Expand Up @@ -683,9 +683,13 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911

# is it optional?
try:
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore
if any(
a for a in annotation.__args__ if a == type(None)
): # pyright: ignore # pylint: disable=unidiomatic-typecheck
if_obj_deserializer = _get_deserialize_callable_from_annotation(
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
next(a for a in annotation.__args__ if a != type(None)),
module,
rf, # pyright: ignore # pylint: disable=unidiomatic-typecheck
)

return functools.partial(_deserialize_with_optional, if_obj_deserializer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def _get_registry_endpoint(self) -> str:
return f"https://{region}.api.azureml.ms"

except Exception as e:
module_logger.warning("Could not determine registry region dynamically: %s. Using default.", e)
module_logger.debug("Could not determine registry region dynamically: %s. Using default.", e)

# Fallback to default region if unable to determine dynamically
return f"https://int.experiments.azureml-test.net"
Expand Down Expand Up @@ -337,7 +337,7 @@ def get(self, name: str, version: Optional[str] = None, **kwargs: Any) -> Deploy
)
return DeploymentTemplate._from_rest_object(result)
except Exception as e:
module_logger.warning("DeploymentTemplate get operation failed: %s", e)
module_logger.debug("DeploymentTemplate get operation failed: %s", e)
raise ResourceNotFoundError(f"DeploymentTemplate {name}:{version} not found") from e

@distributed_trace
Expand All @@ -351,31 +351,27 @@ def create_or_update(self, deployment_template: DeploymentTemplate, **kwargs: An
:return: DeploymentTemplate object representing the created or updated resource.
:rtype: ~azure.ai.ml.entities.DeploymentTemplate
"""
try:
# Ensure we have a DeploymentTemplate object
if not isinstance(deployment_template, DeploymentTemplate):
raise ValueError("deployment_template must be a DeploymentTemplate object")
# Ensure we have a DeploymentTemplate object
if not isinstance(deployment_template, DeploymentTemplate):
raise ValueError("deployment_template must be a DeploymentTemplate object")

if hasattr(self._service_client, "deployment_templates"):
endpoint = self._get_registry_endpoint()
if hasattr(self._service_client, "deployment_templates"):
endpoint = self._get_registry_endpoint()

rest_object = deployment_template._to_rest_object()
self._service_client.deployment_templates.begin_create(
endpoint=endpoint,
subscription_id=self._operation_scope.subscription_id,
resource_group_name=self._operation_scope.resource_group_name,
registry_name=self._operation_scope.registry_name,
name=deployment_template.name,
version=deployment_template.version,
body=rest_object,
**kwargs,
)
return deployment_template
else:
raise RuntimeError("DeploymentTemplate service not available")
except Exception as e:
module_logger.error("DeploymentTemplate create_or_update operation failed: %s", e)
raise
rest_object = deployment_template._to_rest_object()
self._service_client.deployment_templates.begin_create(
endpoint=endpoint,
subscription_id=self._operation_scope.subscription_id,
resource_group_name=self._operation_scope.resource_group_name,
registry_name=self._operation_scope.registry_name,
name=deployment_template.name,
version=deployment_template.version,
body=rest_object,
**kwargs,
)
return deployment_template
else:
raise RuntimeError("DeploymentTemplate service not available")

@distributed_trace
@monitor_with_telemetry_mixin(ops_logger, "DeploymentTemplate.Delete", ActivityType.PUBLICAPI)
Expand Down Expand Up @@ -407,7 +403,7 @@ def delete(self, name: str, version: Optional[str] = None, **kwargs: Any) -> Non
except ResourceNotFoundError:
raise
except Exception as e:
module_logger.error("DeploymentTemplate delete operation failed: %s", e)
module_logger.debug("DeploymentTemplate delete operation failed: %s", e)
raise

@distributed_trace
Expand All @@ -423,18 +419,14 @@ def archive(self, name: str, version: Optional[str] = None, **kwargs: Any) -> De
:rtype: ~azure.ai.ml.entities.DeploymentTemplate
:raises: ~azure.core.exceptions.ResourceNotFoundError if deployment template not found.
"""
try:
# Get the existing template
template = self.get(name=name, version=version, **kwargs)
# Get the existing template
template = self.get(name=name, version=version, **kwargs)

# Set stage to Archived
template.stage = "Archived"
# Set stage to Archived
template.stage = "Archived"

# Update the template using create_or_update
return self.create_or_update(template, **kwargs)
except Exception as e:
module_logger.error("DeploymentTemplate archive operation failed: %s", e)
raise
# Update the template using create_or_update
return self.create_or_update(template, **kwargs)

@distributed_trace
@monitor_with_telemetry_mixin(ops_logger, "DeploymentTemplate.Restore", ActivityType.PUBLICAPI)
Expand All @@ -449,15 +441,11 @@ def restore(self, name: str, version: Optional[str] = None, **kwargs: Any) -> De
:rtype: ~azure.ai.ml.entities.DeploymentTemplate
:raises: ~azure.core.exceptions.ResourceNotFoundError if deployment template not found.
"""
try:
# Get the existing template
template = self.get(name=name, version=version, **kwargs)
# Get the existing template
template = self.get(name=name, version=version, **kwargs)

# Set stage to Development
template.stage = "Development"
# Set stage to Development
template.stage = "Development"

# Update the template using create_or_update
return self.create_or_update(template, **kwargs)
except Exception as e:
module_logger.error("DeploymentTemplate restore operation failed: %s", e)
raise
# Update the template using create_or_update
return self.create_or_update(template, **kwargs)
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def test_batch_endpoint_create(self, client: MLClient, rand_batch_name: Callable
try:
client.batch_endpoints.get(name=name)
except Exception as e:
assert type(e) is ResourceNotFoundError
assert isinstance(e, ResourceNotFoundError)
return

raise Exception(f"Batch endpoint {name} is supposed to be deleted.")
Expand Down Expand Up @@ -62,7 +62,7 @@ def test_mlflow_batch_endpoint_create_and_update(
try:
client.batch_endpoints.get(name=name)
except Exception as e:
assert type(e) is ResourceNotFoundError
assert isinstance(e, ResourceNotFoundError)
return

raise Exception(f"Batch endpoint {name} is supposed to be deleted.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def test_workspace_connections_create_update_and_delete_ai_search(
wps_connection = client.connections.create_or_update(workspace_connection=wps_connection)
client.connections.delete(name=wps_connection_name)

assert type(wps_connection) == AzureAISearchConnection
assert isinstance(wps_connection, AzureAISearchConnection)
assert wps_connection.name == wps_connection_name
assert wps_connection.credentials.type == camel_to_snake(ConnectionAuthType.API_KEY)
# assert wps_connection.api_key == "3333" # TODO add api key retrieval everywhere
Expand Down
Loading