Skip to content
Merged
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
10 changes: 10 additions & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Instead of `Optional` use `| None`
- Create a `__init__.py` file in each folder
- Never pass literals, e.g., `error_msg`, directly to `Exceptions`, but instead assign them to variables and pass them to the exception, e.g., `raise FileNotFoundError(error_msg)` instead of `raise FileNotFoundError(f"Thread {thread_id} not found")`
- Always specify `encoding="utf-8"` for all file read and write operations (e.g., `Path.read_text()`, `Path.write_text()`, `open()`, etc.) to ensure proper handling of Unicode characters across all platforms

## FastAPI
- Instead of defining `response_model` within route annotation, use the model as the response type in the function signature
Expand All @@ -16,6 +17,15 @@
# Testing
- Use `pytest-mock` for mocking in tests wherever you need to mock something and pytest-mock can do the job.

# Git
- Never use `git add .` - always explicitly add files that are related to the task using `git add <file1> <file2> ...`
- Use conventional commits format for commit messages (e.g., `feat:`, `fix:`, `docs:`, `style:`, `refactor:`, `test:`, `chore:`)
- Always run linting/pdm commands before committing to ensure code quality. The following commands must pass:
- `pdm run format` - code formatting with ruff (must pass)
- `pdm run lint` - linting with ruff (must pass, or use `pdm run lint:fix` to auto-fix issues)
- `pdm run typecheck:all` - type checking with mypy (may have pre-existing errors from venv/optional dependencies, but should not introduce new errors)
- Alternatively, use `pdm run qa:fix` which runs `typecheck:all`, `format`, and `lint:fix`

# Documentation

## Docstrings
Expand Down
4 changes: 3 additions & 1 deletion src/askui/chat/api/workflows/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ def retrieve(
) -> Workflow:
try:
workflow_path = self._get_workflow_path(workflow_id)
workflow = Workflow.model_validate_json(workflow_path.read_text())
workflow = Workflow.model_validate_json(
workflow_path.read_text(encoding="utf-8")
)

# Check workspace access
if workspace_id is not None and workflow.workspace_id != workspace_id:
Expand Down
2 changes: 1 addition & 1 deletion src/askui/models/askui/ai_element_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def from_json_file(cls, json_file_path: pathlib.Path) -> "AiElement":
image=Image.open(image_path),
image_path=image_path,
json_path=json_file_path,
metadata=json.loads(json_file_path.read_text()),
metadata=json.loads(json_file_path.read_text(encoding="utf-8")),
)


Expand Down
2 changes: 1 addition & 1 deletion src/askui/reporting.py
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ def generate(self) -> None:
f"{random.randint(0, 1000):03}.html"
)
self.report_dir.mkdir(parents=True, exist_ok=True)
report_path.write_text(html)
report_path.write_text(html, encoding="utf-8")


class AllureReporter(Reporter):
Expand Down
4 changes: 2 additions & 2 deletions src/askui/telemetry/anonymous_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def _read_anonymous_id_from_file() -> str | None:
"""Read anonymous ID from file if it exists."""
try:
if _ANONYMOUS_ID_FILE_PATH.exists():
return _ANONYMOUS_ID_FILE_PATH.read_text().strip()
return _ANONYMOUS_ID_FILE_PATH.read_text(encoding="utf-8").strip()
except OSError as e:
logger.warning("Failed to read anonymous ID from file", extra={"error": str(e)})
return None
Expand All @@ -25,7 +25,7 @@ def _write_anonymous_id_to_file(anonymous_id: str) -> bool:
"""Write anonymous ID to file, creating directories if needed."""
try:
_ANONYMOUS_ID_FILE_PATH.parent.mkdir(parents=True, exist_ok=True)
_ANONYMOUS_ID_FILE_PATH.write_text(anonymous_id)
_ANONYMOUS_ID_FILE_PATH.write_text(anonymous_id, encoding="utf-8")
except OSError as e:
logger.warning("Failed to write anonymous ID to file", extra={"error": str(e)})
else:
Expand Down
2 changes: 1 addition & 1 deletion src/askui/tools/askui/askui_controller_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def _find_remote_device_controller_by_component_registry_file(
return None

component_registry = AskUiComponentRegistry.model_validate_json(
self.component_registry_file.read_text()
self.component_registry_file.read_text(encoding="utf-8")
)
return (
component_registry.installed_packages.remote_device_controller_uuid.executables.askui_remote_device_controller # noqa: E501
Expand Down
4 changes: 3 additions & 1 deletion src/askui/tools/testing/execution_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ def list_(self, query: ExecutionListQuery) -> ListResponse[Execution]:
def retrieve(self, execution_id: ExecutionId) -> Execution:
try:
execution_path = self._get_execution_path(execution_id)
return Execution.model_validate_json(execution_path.read_text())
return Execution.model_validate_json(
execution_path.read_text(encoding="utf-8")
)
except FileNotFoundError as e:
error_msg = f"Execution {execution_id} not found"
raise NotFoundError(error_msg) from e
Expand Down
2 changes: 1 addition & 1 deletion src/askui/tools/testing/feature_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def list_(
def retrieve(self, feature_id: FeatureId) -> Feature:
try:
feature_path = self._get_feature_path(feature_id)
return Feature.model_validate_json(feature_path.read_text())
return Feature.model_validate_json(feature_path.read_text(encoding="utf-8"))
except FileNotFoundError as e:
error_msg = f"Feature {feature_id} not found"
raise NotFoundError(error_msg) from e
Expand Down
4 changes: 3 additions & 1 deletion src/askui/tools/testing/scenario_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def list_(self, query: ScenarioListQuery) -> ListResponse[Scenario]:
def retrieve(self, scenario_id: ScenarioId) -> Scenario:
try:
scenario_path = self._get_scenario_path(scenario_id)
return Scenario.model_validate_json(scenario_path.read_text())
return Scenario.model_validate_json(
scenario_path.read_text(encoding="utf-8")
)
except FileNotFoundError as e:
error_msg = f"Scenario {scenario_id} not found"
raise NotFoundError(error_msg) from e
Expand Down