Skip to content

archive and unarchive and delete api integration - #39

Open
QeyCoder wants to merge 1 commit into
mainfrom
feature/LABIMP-7954-integrate-ap-is-to-sdk
Open

archive and unarchive and delete api integration#39
QeyCoder wants to merge 1 commit into
mainfrom
feature/LABIMP-7954-integrate-ap-is-to-sdk

Conversation

@QeyCoder

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

Code Review Summary

I've reviewed PR #39 for the archive, unarchive, and delete API integration. Overall, the implementation is functional but there are several issues that should be addressed:

✅ Positives

  • Good test coverage with both unit and integration tests
  • Methods follow existing patterns in the codebase
  • The StrEnum to Enum change is correct for Python 3.7+ compatibility

⚠️ Issues Found

1. Inconsistent Header Casing

The codebase uses lowercase content-type in most places (lines 42, 128, 211, 263, 285, 576, 613, 661), but the new methods use lowercase in one place and uppercase Content-Type exists in some legacy code. Should standardize to lowercase for consistency.

2. Missing request_id Parameter

The import_users method (line 642-643) doesn't pass request_id to make_request, but the new methods do. Should verify if this is intentional or if import_users needs updating.

3. Inconsistent Response Handling

  • import_users: returns response.get("response") (extracts nested data)
  • New methods: return full response object directly
    Should clarify the expected return format and document it.

4. Weak Integration Test Assertions

The integration test wraps calls in try-except but only checks for exceptions. It should:

  • Verify response structure/status codes
  • Check actual state changes (e.g., project is actually archived)
  • Validate error responses

5. Unused Import in Unit Tests

LabellerrUsers is imported but never used (line 5 of test_projects.py)

6. Test Fixture Issue

Integration test fixture has parameter client but creates a new LabellerrClient inside (line 19-22), making the parameter pointless.

7. Code Style Issues

  • Extra blank lines after method definitions (lines 672, 684, 695)
  • Inconsistent with the rest of the file

8. Missing Return Type Hints

Other methods in the codebase lack type hints, but for new code, consider adding them for better IDE support.

9. No Validation of Project State

The delete method doesn't check if project exists or is in a valid state for deletion. Consider adding state validation.

See inline comments for specific locations and suggested fixes.


payload = json.dumps({"project_id": self.project_id})

headers = {"content-type": "application/json"}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Inconsistent header casing: The codebase predominantly uses lowercase content-type (see lines 42, 128, 211, 263, 576, 613). Recommend changing to lowercase for consistency:

Suggested change
headers = {"content-type": "application/json"}
headers = {"content-type": "application/json"}

Comment on lines +672 to +673


Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code style: Extra blank line here is inconsistent with other methods in this file. Should be removed for consistency.

Comment on lines +684 to +685

def delete(self):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code style: Extra blank line should be removed for consistency with other methods.

Comment on lines +694 to +695
url = f"{constants.BASE_URL}/projects/project/{self.project_id}?client_id={self.client.client_id}&uuid={unique_id}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code style: Extra blank line should be removed for consistency.

Comment on lines +665 to +671
return self.client.make_request(
"POST",
url,
extra_headers=headers,
request_id=unique_id,
data=payload,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Inconsistent response handling: This method returns the raw response, but other similar methods like import_users (line 645) return response.get(\"response\"). Should clarify and document the expected return format. Consider either:

  1. Extracting nested response for consistency, or
  2. Documenting why this returns full response object

Comment on lines +701 to +706
return self.client.make_request(
"DELETE",
url,
extra_headers=headers,
request_id=unique_id,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Missing validation: Consider validating:

  1. Project exists before attempting deletion
  2. User has permission to delete
  3. Project isn't already deleted

Also, response handling: Same issue as archive() - should document if full response or nested data should be returned.

from unittest.mock import patch, Mock
import json
from labellerr.core.projects.image_project import ImageProject
from labellerr.core.users.base import LabellerrUsers

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused import: LabellerrUsers is imported but never used in this file. Should be removed.

Comment on lines +36 to +51
def test_archive_project(self, project, client):
"""Test archiving a project"""
mock_response = {"status": "success", "msg": "Project archived"}

with patch.object(client, "make_request", return_value=mock_response) as mock_req:
response = project.archive()

assert response == mock_response

# Verify the request
mock_req.assert_called_once()
args, kwargs = mock_req.call_args
assert args[0] == "POST"
assert "/projects/archive" in args[1]
assert kwargs["data"] is not None
assert '"project_id": "test_project_id"' in kwargs["data"]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test coverage gap: The test only verifies the request was made, but should also verify:

  1. The request includes the correct uuid in the URL
  2. The request_id parameter matches the uuid
  3. The payload is properly formatted JSON

Consider adding these assertions:

assert kwargs.get(\"request_id\") is not None
assert f\"uuid={kwargs['request_id']}\" in args[1]

Comment on lines +58 to +63
# 1. Archive
print(f"Archiving project {project.project_id}...")
try:
project.archive()
except Exception as e:
pytest.fail(f"Failed to archive project: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Weak assertions: The test should verify:

  1. Response status/success indicator
  2. Response structure matches expected format
  3. Consider checking project state via a GET request to confirm it's actually archived

Current implementation only checks that no exception was raised, which is insufficient for integration testing.

Comment on lines +74 to +78
print(f"Deleting project {project.project_id}...")
try:
project.delete()
except Exception as e:
pytest.fail(f"Failed to delete project: {e}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Test completeness: After deleting, the test should:

  1. Verify the delete response indicates success
  2. Optionally attempt to fetch the project and verify it returns a 404 or "not found" error
  3. Check that subsequent operations on the deleted project fail appropriately

This ensures the delete actually worked and wasn't just a no-op.

Comment on lines +6 to +14
from enum import Enum
from typing import List, Literal
from uuid import UUID

from .base import DatasetDataType
from pydantic import BaseModel, Field, field_validator


class DataSetScope(StrEnum):
class DataSetScope(str, Enum):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Good fix: Changing from StrEnum (Python 3.11+) to str, Enum is correct for maintaining Python 3.7+ compatibility as specified in pyproject.toml. The behavior is equivalent and this ensures backward compatibility. ✅

@QeyCoder
QeyCoder marked this pull request as ready for review December 22, 2025 17:06
payload = json.dumps({"project_id": self.project_id})

headers = {"content-type": "application/json"}
if self.client.api_key:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

no need for this check, it will always be there

"""
unique_id = str(uuid.uuid4())

url = f"{constants.BASE_URL}/projects/project/{self.project_id}?client_id={self.client.client_id}&uuid={unique_id}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think the url is incorrect

Comment on lines +700 to +706

return self.client.make_request(
"DELETE",
url,
extra_headers=headers,
request_id=unique_id,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

since we don't allow delete http method, lets use POST

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.

3 participants