PySide Best Practices and Coding Standards
pysidepythoncoding-standardsbest-practicescode-organization
Description
This rule enforces best practices and coding standards for developing applications with the PySide library. It covers code organization, performance, security, testing, and common pitfalls to ensure maintainable and robust applications.
Globs
**/*.py
---
description: This rule enforces best practices and coding standards for developing applications with the PySide library. It covers code organization, performance, security, testing, and common pitfalls to ensure maintainable and robust applications.
globs: **/*.py
---
# PySide Best Practices and Coding Standards
This document outlines best practices and coding standards for developing applications with the PySide library. Adhering to these guidelines will promote code readability, maintainability, and robustness.
## 1. General Guidelines
- **Follow PEP 8:** Adhere to the PEP 8 style guide for Python code. This includes:
- Consistent naming conventions (e.g., `snake_case` for functions and variables, `CamelCase` for classes).
- 4 spaces for indentation.
- Maximum line length of 79 characters (or 99 if agreed upon by the team).
- Blank lines separating top-level function and class definitions.
- **Qt and Python Naming Conventions:** Prefer Qt's `CamelCase` naming conventions for methods within classes inheriting from Qt widgets. This promotes consistency with the Qt framework. For example, use `loadItems()` instead of `load_items()`.
- **Avoid Wildcard Imports:** Import specific classes or modules instead of using wildcard imports (`from PySide2.QtWidgets import *`). This keeps the namespace clean and avoids potential conflicts.
- **Use Docstrings and Comments:** Document your methods and classes using docstrings (following PEP 257) to explain their purpose and usage. Use inline comments sparingly to clarify complex code, ensuring they are up-to-date.
- **Use Virtual Environments:** Always use virtual environments (e.g., `venv`, `conda`) to manage dependencies for each project. This isolates project dependencies and avoids conflicts between different projects.
- **Consistent Style:** Maintain a consistent coding style throughout the project. Use a linter and formatter (e.g., `flake8`, `pylint`, `black`, `autopep8`) to enforce the coding style.
- **Meaningful Variable Names:** Choose descriptive and meaningful names for variables, functions, and classes.
## 2. Code Organization and Structure
- **Directory Structure:** A well-defined directory structure is crucial for maintainability. Consider the following structure:
project_name/
├── src/
│ ├── main.py # Entry point of the application
│ ├── gui/
│ │ ├── __init__.py
│ │ ├── main_window.py # Main window class
│ │ ├── widgets/
│ │ │ ├── __init__.py
│ │ │ ├── custom_widget.py # Custom widgets
│ │ ├── models/
│ │ │ ├── __init__.py
│ │ │ ├── data_model.py # Data models
│ ├── core/
│ │ ├── __init__.py
│ │ ├── logic.py # Core application logic
│ ├── resources/
│ │ ├── __init__.py
│ │ ├── icons/
│ │ │ ├── ...
│ │ ├── ui/ # Stores .ui files generated by Qt Designer
│ │ │ ├── main_window.ui
├── tests/
│ ├── __init__.py
│ ├── test_main_window.py # Unit tests for main window
├── requirements.txt # Project dependencies
├── README.md # Project documentation
├── .gitignore # Git ignore file
- **File Naming Conventions:**
- Python files: `snake_case.py` (e.g., `main_window.py`, `custom_widget.py`).
- UI files: `snake_case.ui` (e.g., `main_window.ui`, `settings_dialog.ui`).
- Resource files: Descriptive names (e.g., `app_icons.qrc`).
- **Module Organization:** Organize related classes and functions into modules. This improves code reusability and maintainability.
- Use packages (`__init__.py` files) to group related modules.
- **Component Architecture:** Design the application with a component-based architecture. This promotes modularity and testability.
- Separate the UI (views) from the application logic (controllers and models).
- Use signals and slots for communication between components.
- Use dependency injection to decouple components.
- **Code Splitting:** Split large files into smaller, more manageable files. This makes it easier to understand and maintain the code.
- Group related functions and classes into separate modules.
- Extract common code into utility functions or classes.
- Consider splitting UI logic into separate files (e.g., event handlers, data binding).
## 3. Common Patterns and Anti-Patterns
- **Model-View-Controller (MVC) or Model-View-Presenter (MVP):** Use these patterns to separate the UI from the application logic.
- **Model:** Represents the data and business logic.
- **View:** Displays the data to the user and handles user input.
- **Controller/Presenter:** Acts as an intermediary between the Model and the View, handling user actions and updating the View based on changes in the Model.
- **Signals and Slots:** Leverage Qt's signals and slots mechanism for communication between objects. This is a powerful and flexible way to handle events and notifications.
- Use named signals and slots for better readability and maintainability. Avoid directly connecting signals and slots by string names if possible, prefer member functions.
- Disconnect signals when they are no longer needed to avoid memory leaks.
- **Resource Management:** Properly manage resources (e.g., files, network connections, database connections) to avoid memory leaks and ensure the application runs smoothly.
- Use `with` statements or `try...finally` blocks to ensure resources are released even if exceptions occur.
- Consider using `QScopedPointer` for managing Qt objects.
- **Data Binding:** Use data binding to automatically synchronize data between the Model and the View. This simplifies UI development and reduces boilerplate code.
- PySide supports data binding through `QDataWidgetMapper` and custom models.
- **Anti-Patterns:**
- **God Objects:** Avoid creating classes that are too large and do too much. Split them into smaller, more focused classes.
- **Copy-Pasting Code:** Avoid duplicating code. Extract common code into reusable functions or classes.
- **Ignoring Exceptions:** Don't just catch exceptions and ignore them. Log the exception and handle it appropriately.
- **Tight Coupling:** Avoid tight coupling between components. Use dependency injection and interfaces to decouple components.
- **State Management:**
- Use a central state management system (e.g., Redux-like pattern, or a simple state class) to manage the application's state. This is particularly helpful in large applications.
- Consider making the state immutable for easier debugging and predictability.
- **Error Handling:**
- Use `try...except` blocks to handle exceptions. Catch specific exceptions whenever possible. Log exceptions using Python's `logging` module.
- Provide informative error messages to the user. Consider using message boxes or a status bar to display error messages.
## 4. Performance Considerations
- **Optimization Techniques:**
- **Avoid Blocking the Main Thread:** Long-running operations (e.g., network requests, file I/O) should be performed in a separate thread to avoid blocking the main UI thread.
- Use `QThread` or `QThreadPool` for multithreading. Use signals and slots to communicate between threads.
- **Efficient Data Structures:** Choose the appropriate data structures for the task. For example, use `QHash` instead of `QMap` if order doesn't matter and you need faster lookups.
- **Minimize Widget Creation:** Creating and destroying widgets can be expensive. Reuse widgets whenever possible. Consider using `QStackedWidget` to switch between different views without creating new widgets.
- **Optimize Painting:** Optimize custom painting operations by minimizing the amount of drawing and using caching techniques.
- **Profiling:** Use profiling tools to identify performance bottlenecks. Python's `cProfile` and `line_profiler` can be useful. Qt also offers profiling tools.
- **Memory Management:**
- **Avoid Circular References:** Circular references can prevent objects from being garbage collected. Use `weakref` or manually break the references.
- **Use `QObject` Parenting:** Take advantage of `QObject`'s parenting mechanism for automatic memory management. When a parent object is destroyed, all its children are also destroyed.
- **Delete Objects Manually:** In some cases, you may need to manually delete objects to free memory. Use `del` to delete Python objects, and consider using `QScopedPointer` or manually calling `deleteLater()` on `QObject` instances when appropriate (especially when dealing with C++ objects exposed to Python).
- **Rendering Optimization:**
- **Use Double Buffering:** Enable double buffering to reduce flickering during repainting.
- **Minimize Overlapping Updates:** Reduce the number of times the UI is updated by batching updates together.
- **Use Graphics Effects Sparingly:** Graphics effects can be expensive. Use them sparingly and optimize their settings.
- **Caching:** Cache frequently used resources (e.g., images, fonts) to avoid reloading them repeatedly.
- **Bundle Size Optimization:** (Relevant for deployment using tools like PyInstaller)
- **Minimize Dependencies:** Only include the necessary dependencies in the project. Remove unused dependencies.
- **Use UPX Compression:** UPX can compress the executable file to reduce its size.
- **Exclude Unnecessary Files:** Exclude unnecessary files (e.g., documentation, tests) from the bundle.
- **Lazy Loading:** Delay the loading of resources or components until they are needed. This can improve startup time and reduce memory usage.
- Load UI files on demand.
- Load images or data only when they are visible.
## 5. Security Best Practices
- **Common Vulnerabilities:**
- **Code Injection:** Prevent code injection by validating user input and avoiding the use of `eval()` or `exec()`. Be very cautious about using `pickle` to deserialize data, as it can be exploited for code execution.
- **Cross-Site Scripting (XSS):** If the application displays user-generated content, sanitize the input to prevent XSS attacks. Consider using Qt's built-in functions for HTML encoding.
- **SQL Injection:** If the application uses a database, use parameterized queries to prevent SQL injection attacks. Never concatenate user input directly into SQL queries.
- **Path Traversal:** Validate user-provided file paths to prevent path traversal attacks. Use `QDir::cleanPath()` to sanitize file paths.
- **Denial of Service (DoS):** Implement rate limiting and other measures to protect against DoS attacks.
- **Input Validation:**
- **Validate all user input:** Check that the input is of the correct type, format, and range.
- **Use regular expressions for complex validation:** Regular expressions can be used to validate email addresses, phone numbers, and other complex data formats.
- **Sanitize input:** Remove or encode any potentially harmful characters from the input.
- **Authentication and Authorization:**
- **Use strong passwords:** Enforce strong password policies and use a secure hashing algorithm (e.g., bcrypt, Argon2) to store passwords.
- **Implement proper authentication:** Verify the user's identity before granting access to protected resources.
- **Implement authorization:** Control which users have access to which resources.
- **Use secure communication protocols:** Use HTTPS to encrypt communication between the client and the server.
- **Data Protection:**
- **Encrypt sensitive data:** Encrypt sensitive data (e.g., passwords, credit card numbers) before storing it.
- **Use secure storage:** Store sensitive data in a secure location, such as a hardware security module (HSM) or a secure enclave.
- **Protect against data leaks:** Be careful about logging sensitive data or storing it in temporary files.
- **Secure API Communication:**
- **Use HTTPS:** Always use HTTPS for communication with APIs.
- **Validate API responses:** Verify that the API response is valid and that it hasn't been tampered with.
- **Use API keys or tokens:** Use API keys or tokens to authenticate API requests.
## 6. Testing Approaches
- **Unit Testing:** Test individual components (e.g., classes, functions) in isolation.
- Use a unit testing framework (e.g., `unittest`, `pytest`).
- Mock or stub dependencies to isolate the component being tested.
- Test all possible scenarios, including edge cases and error conditions.
- **Integration Testing:** Test the interaction between different components.
- Verify that the components work together correctly.
- Use real dependencies or integration test environments.
- Test common use cases.
- **End-to-End Testing:** Test the entire application from the user's perspective.
- Simulate user interactions.
- Verify that the application behaves as expected.
- Use an end-to-end testing framework (e.g., Selenium, Playwright).
- **Test Organization:**
- Create a separate `tests` directory for test files.
- Organize test files to mirror the source code structure.
- Use descriptive test names.
- Run tests automatically using a CI/CD pipeline.
- **Mocking and Stubbing:**
- Use mocking to replace dependencies with controlled objects.
- Use stubbing to provide canned responses for dependencies.
- Use a mocking framework (e.g., `unittest.mock`, `pytest-mock`).
- Be careful not to over-mock. Only mock the dependencies that are necessary to isolate the component being tested.
## 7. Common Pitfalls and Gotchas
- **QObject Ownership and Memory Management:** Incorrect object ownership can lead to memory leaks or crashes. Ensure that `QObject` instances have a clear parent-child relationship or are managed with `QScopedPointer`.
- **Event Loop Blocking:** Long-running tasks in the main thread will freeze the UI. Offload these tasks to separate threads using `QThread` or `QThreadPool`.
- **Signal-Slot Connections:** Incorrect signal-slot connections can lead to unexpected behavior. Always check that the signal and slot signatures match.
- **Thread Safety:** Be aware of thread safety issues when accessing shared resources from multiple threads. Use mutexes or other synchronization mechanisms to protect shared data.
- **UI Thread Access:** Only access UI elements from the main thread. Use `QMetaObject::invokeMethod()` to invoke methods on UI objects from other threads.
- **Resource File Paths:** Be careful with resource file paths. Use absolute paths or relative paths that are relative to the application's resource directory. Use `:/` to refer to Qt resources.
- **Unicode Handling:** Ensure that the application correctly handles Unicode characters. Use `QString` for storing and manipulating text.
- **Layout Management:** Understand and use layout managers (`QHBoxLayout`, `QVBoxLayout`, `QGridLayout`, etc.) effectively. Avoid hardcoding widget positions and sizes.
- **Qt Designer Limitations:** Be aware of the limitations of Qt Designer. Some UI elements or behaviors may require manual coding.
- **Event Filters:** Be cautious when using event filters, as they can impact performance and make it harder to debug the application. Only use event filters when necessary.
- **Context Menus and Actions:** When adding actions to context menus ensure you specify the parent to avoid a memory leak.
## 8. Tooling and Environment
- **Recommended Development Tools:**
- **Qt Creator:** An IDE specifically designed for Qt development.
- **PyCharm:** A popular Python IDE with excellent support for Qt and PySide.
- **VS Code:** A lightweight and versatile code editor with support for Python and Qt through extensions.
- **Qt Designer:** A visual tool for designing UI layouts.
- **Build Configuration:**
- **Use `setuptools` or `poetry` for managing dependencies and building the application.**
- **Create a `setup.py` file for the project.**
- **Use a virtual environment to isolate project dependencies.**
- **Linting and Formatting:**
- **Use `flake8`, `pylint`, or `ruff` for linting the code.**
- **Use `black` or `autopep8` for formatting the code.**
- **Configure the linter and formatter to follow the project's coding style.**
- **Deployment:**
- **Use `PyInstaller`, `cx_Freeze`, or similar tools to create standalone executables.**
- **Bundle all necessary dependencies with the executable.**
- **Test the executable on different platforms.**
- **CI/CD Integration:**
- **Use a CI/CD platform (e.g., Jenkins, GitHub Actions, GitLab CI) to automate the build, test, and deployment process.**
- **Run tests automatically on every commit.**
- **Create deployment packages automatically on every release.**
- **Automate code quality checks with linting and formatting tools.**