DomoLibrary Classes Implementation Guidelines
This document outlines best practices for designing and implementing classes in DomoLibrary. It is divided into several sections to guide you through naming conventions, structure, integration with API route functions, error handling, and overall code style.
1. Overview
DomoLibrary classes encapsulate functionality for different domains (e.g. accounts, jobs, enterprise apps). The guidelines below ensure consistency, maintainability, and clarity across the codebase.
2. Class Naming and Organization
- Naming: Use CamelCase for all class names.
- Organization: Group classes by functionality (such as account classes, job classes, etc.) and store them in their respective modules.
3. Class Structure and Inheritance
- Docstrings: Begin every class with a clear docstring explaining its purpose and main attributes.
- Type Annotations: Use complete type annotations for all attributes and methods.
- Inheritance: Use inheritance only when it adds clarity or reusability; prefer composition when possible.
- Initialization: Keep your
__init__
or__post_init__
methods focused on setting up state.
4. Integration with Route Functions
Classes that interact with Domo API resources must wrap API calls (handled by route functions) inside their asynchronous methods.
Asynchronous Calls: Always use
await
when invoking route functions.Response Validation: Check
res.is_success
after each API call. If the check fails, raise a custom exception.Example:
@classmethod async def from_id(cls, auth: dmda.DomoAuth, entity_id: str) -> "MyEntity": """ Retrieves an entity using a route function. Args: auth (dmda.DomoAuth): The authentication object. entity_id (str): Unique identifier for the entity. Returns: MyEntity: An instance loaded with API response data. Raises: SomeAPIError: If the API call fails. """ = await get_entity_by_id(auth=auth, entity_id=entity_id) # Route function call res if res.is_success: = cls(auth=auth, entity_id=entity_id) instance = res.response instance.data return instance else: raise SomeAPIError("Failed to retrieve entity")
5. Error Handling and Type Annotations
- Response Checks: Always verify API responses (e.g., using
res.is_success
) and handle errors by raising appropriate custom exceptions. - Comprehensive Docstrings: Each function/method should include a docstring that details purpose, parameters, return types, and documented exceptions.
- Type Hints: Specify types for all parameters and return values to improve clarity and catch potential errors earlier.
6. Code Readability and Maintainability
- PEP8 Compliance:
- Use 4 spaces per indentation level.
- Limit lines to 79 characters.
- Prefer descriptive variable names.
- Conciseness: Keep methods focused on a single responsibility. Break down complex logic into smaller helper functions.
- Separation of Concerns: Distinguish between API communication (handled by route functions) and business logic.
7. Expanded Python Style Guide
7.1 Code Organization
- Structure your code into modular, small, single-purpose functions.
- Separate API call logic (route functions) from data processing and business logic.
7.2 Comprehensive Documentation
- Every function and method must have a detailed docstring describing:
- Its purpose.
- Input parameters and their types.
- Return values and their types.
- Any exceptions that could be raised.
- Use inline comments for non-obvious logic.
7.3 Error Handling Best Practices
- Always validate API responses using conditions like
if not res.is_success:
. - Raise exceptions with clear, informative messages that include context such as the Domo instance and function name.
- Use try/except blocks judiciously to manage recoverable errors while allowing unexpected ones to bubble up.
8. Additional Guidance for New Contributors
- Getting Started: Familiarize yourself with this document along with the provided code examples.
- Adopt Best Practices: Use tools like linters (e.g., pylint, flake8) and formatters (e.g., Black) to ensure your code meets the standards.
- Documentation Updates: Keep documentation synchronized with code changes.
- Ask for Help: If any guideline is unclear, reach out to project maintainers.
9. Common Class Methods and Subclassing
Single Entity Classes:
Classes that represent a single Domo entity (e.g., DomoUser, DomoAccount) are typically defined using a singular name and include a classmethodget_by_id
to retrieve an instance via an API call.CRUD Operations:
Common methods provided by these classes include:create
for instantiating new entities,update
for modifying existing entities, anddelete
for removing entities.
Grouped (Plural) Classes:
For managing collections of entities, classes use plural names (e.g., DomoDatasets, DomoAppStudios). These classes usually implement:- A
get()
method to retrieve all entities, - Additional search functionality, and
- An
upsert()
method to update or insert entities based on criteria.
- A
Subclassing for Related Entities:
Some entities are complex and include nested or related data managed in subclasses. For instance:- Domo Datasets are often accompanied by a corresponding Schema class (e.g.,
DomoDataset_Schema
), and - DomoAccounts make use of various AccountConfig classes to manage authentication and configuration details.
In these cases, subclass attributes are typically denoted with a capital letter (e.g.,
Lineage
,Config
), while class-level attributes remain in lowercase.- Domo Datasets are often accompanied by a corresponding Schema class (e.g.,
Reference Implementations:
- The
DomoAccount
class implements aget_by_id
method and delegates configuration management to its various AccountConfig subclasses. - The
DomoDataset
class works in tandem withDomoDataset_Schema
to manage schema details, and its plural counterpart,DomoDatasets
, provides methods for searching and upserting datasets.
- The