Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional documentation, we greatly value feedback and contributions from our community.
Please read through this document before submitting any issues or pull requests to ensure we have all the necessary information to effectively respond to your bug report or contribution.
Install hatch.
These are all the checks you would typically do as you prepare a PR:
# just test
hatch test
# coverage
hatch run test:cov
# type checks
hatch run types:check
# static analysis
hatch fmt
There is a convenience script for the above that you can run from the root of the repo as you prepare your PR:
ops/ci-checks.sh
Consistency is important for maintainability. Please adhere to the house-style of the repo, unless there's a really good reason to break pattern.
- Follow the Python Style Guide by Google in general.
- Standardize to ruff formatting and linting rules. CI checks enforce these too.
- Avoid pulling in extra runtime dependencies. The only dependency is boto3. The reason is that this SDK adds size to the AWS Lambda function of the consumer, so we should keep it as light as possible.
- Never use
RLockwhenLockwould do. The reason is to highlight recursive calls that have the potential for deadlocking immediately, so that RLock is a deliberate and considered decision after having considered deadlocking concerns, rather than just the default.
- Do not allow circular references, even if you can get away with it by using
if TYPE_CHECKING. Circular references are a sign that the structure of the code is not clear enough. It makes for inefficient memory management and it makes the code harder to understand and follow. Do useconfigandtypesas the lowest-level import if you run into circular reference issues. - Do not use
__init__files for any meaningful code or even just type declarations. Why? Because the purpose of init is not to serve as a grab-bag of code that doesn't otherwise have a home. - Do not introduce
utilsorhelperstyle modules as a grab-bag of ad hoc functions. Introduce domain-specific classes to encapsulate and model logic.
-
Model data structure with immutable classes and precise type hints. (In other words, use frozen dataclasses with exact, narrow type hints.) Do not rely on unstructured dicts. Why immutable? These are inherently thread-safe, and it forces you to think carefully about when and where you need to mutate values.
-
A rare exception to the general rule to prefer immutable classes wherever possible, is
state.ExecutionState, which maintains the state of the on-going Durable Execution and encapsulates thread-safe state mutations as the execution progresses. -
Rely on exact and explicit type declarations rather than duck typing. Why? Yes, duck typing is very pythonic. However, this is a complex code-base, and exact and explicit type declarations signal intent clearly so that the type checker can help you catch errors more quickly. LLMs have an easier time understanding the intent of the code with the type hints, and it makes it easier for you to spot mistaken assumptions that the LLMs might make about the code. The other reason is that it makes the experience of developers much easier with intelligent and context-aware autocomplete hints in an IDE.
-
Declare a type definition wherever you declare a variable, even within a function scope and even where it's implied. For example, even though the
strmight be implied because of thecallreturn type, make it explicit:
def my_function() -> str:
my_var: str = arb.call(1, 2, 3)
return f"arb result: {my_var}"
- To update a field in a frozen dataclass, prefer to use a
cloneorwith_fieldclass method constructor or reinitialization, rather than dataclassreplace. There is no big technical reason for this, it's more a soft pattern. The philosophy of an update should be more about thoughfully and purposefully creating a new instance than "in-place editing" an existing one.
- Class constructors must be light and not do more than initialize the class. In a dataclass you shouldn't even need an
__init__. Use a@classmethodfactory method instead to encapsulate more advanced logic. For example, if a class depends on logic that might fail, encapsulate this in acreateclassmethod:
@dataclass(frozen=True)
class MyClass:
id: str
name: str
timeout: int
@classmethod
def create(cls, name: str, timeout: int = 30) -> Config:
"""Factory contains """
if timeout <= 0:
raise ValueError("timeout must be positive")
# Generate unique ID
config_id: str = f"cfg_{uuid.uuid4().hex[:8]}"
return cls(id=config_id, name=name, timeout=timeout)- Encapsulate conversion logic in a
from_xfactory andto_xmethod on a class.
@dataclass(frozen=True)
class WaitOptions:
wait_seconds: int = 0
@classmethod
def from_dict(cls, data: MutableMapping[str, Any]) -> WaitOptions:
return cls(wait_seconds=data.get("WaitSeconds", 0))
def to_dict(self) -> MutableMapping[str, Any]:
return {"WaitSeconds": self.wait_seconds}Point your IDE at the hatch virtual environment to have it recognize dependencies and imports.
You can find the path to the hatch Python interpreter like this:
echo "$(hatch env find)/bin/python"
If you're using VS Code, "Python: Select Interpreter" and use the hatch venv Python interpreter
as found with the hatch env find command.
Hatch uses Ruff for static analysis.
You might want to install the Ruff extension for VS Code to have your IDE interactively warn of the same linting and formatting rules.
These settings.json settings are useful:
{
"[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
},
"editor.defaultFormatter": "charliermarsh.ruff"
},
"ruff.nativeServer": "on"
}
To run all tests:
hatch test
To run a single test file:
hatch test tests/path_to_test_module.py
To run a specific test in a module:
hatch test tests/path_to_test_module.py::test_mytestmethod
To run a single test, or a subset of tests:
$ hatch test -k TEST_PATTERN
This will run tests which contain names that match the given string expression (case-insensitive), which can include Python operators that use filenames, class names and function names as variables.
To debug failing tests:
$ hatch test --pdb
This will drop you into the Python debugger on the failed test.
Place test files in the tests/ directory, using file names that end with _test.
Mimic the package structure in the src/aws_durable_execution_sdk_python directory. Name your module so that src/mypackage/mymodule.py has a dedicated unit test file tests/mypackage/mymodule_test.py
hatch run test:cov
Type checking:
hatch run types:check
Static analysis (with auto-fix of known issues):
hatch fmt
To do static analysis without auto-fixes:
hatch fmt --check
We welcome you to use the GitHub issue tracker to report bugs or suggest features.
When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already reported the issue. Please try to include as much information as you can. Details like these are incredibly useful:
- A reproducible test case or series of steps
- The version of our code being used
- Any modifications you've made relevant to the bug
- Anything unusual about your environment or deployment
Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that:
- You are working against the latest source on the main branch.
- You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already.
- You open an issue to discuss any significant work - we would hate for your time to be wasted.
To send us a pull request, please:
- Fork the repository.
- Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change.
- Ensure local tests pass.
- Commit to your fork using clear commit messages.
- Send us a pull request, answering any default questions in the pull request interface.
- Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation.
We follow the Conventional Commits specification for PR titles and commit messages. This helps us maintain a clear project history and enables automated tooling.
Format: type: subject
- type: The type of change (required)
- subject: Brief description of the change (required, max 50 characters)
Valid types:
feat: New featuresfix: Bug fixesdocs: Documentation changestest: Adding or updating testsrefactor: Code refactoring without functional changesperf: Performance improvementsstyle: Code style/formatting changeschore: Maintenance tasksci: CI/CD changesbuild: Build system changesdeps: Dependency updates
Examples:
feat: add retry mechanism for operations
fix: resolve memory leak in execution state
docs: update API documentation for context
test: add integration tests for parallel exec
feat(sdk): implement new callback functionality
fix(examples): correct timeout handling
Requirements:
- Subject line must be 50 characters or less
- Body text should wrap at 72 characters for good terminal display
- Use lowercase for type and scope
- Use imperative mood in subject ("add" not "added" or "adds")
- No period at the end of the subject line
- Use conventional commit message format with clear, concise descriptions
- Body should provide detailed explanation of changes with bullet points when helpful
Full commit message example:
feat: add retry mechanism for operations
- Implement exponential backoff strategy for transient failures
- Add configurable retry limits and timeout settings
- Include comprehensive error logging for debugging
- Update documentation with retry configuration examples
Resolves issue with intermittent network failures causing
execution interruptions in production environments.
The PR title will be used as the commit message when your PR is merged, so please ensure it follows this format.
GitHub provides additional document on forking a repository and creating a pull request.
Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start.
This project has adopted the Amazon Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opensource-codeofconduct@amazon.com with any additional questions or comments.
If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our vulnerability reporting page. Please do not create a public github issue.
See the LICENSE file for our project's licensing. We will ask you to confirm the licensing of your contribution.