diff --git a/README.md b/README.md
index 7d994215..6477b51c 100644
--- a/README.md
+++ b/README.md
@@ -24,41 +24,37 @@ Prepare a `capsula.toml` file in the root directory of your project. An example
```toml
[pre-run]
-# Contexts to be captured before the execution of the decorated function/CLI command.
contexts = [
+ { type = "CwdContext" },
+ { type = "CpuContext" },
+ { type = "GitRepositoryContext", name = "capsula", path = "." },
{ type = "CommandContext", command = "poetry check --lock" },
- { type = "CommandContext", command = "pip freeze --exclude-editable > requirements.txt" },
{ type = "FileContext", path = "pyproject.toml", copy = true },
+ { type = "FileContext", path = "poetry.lock", copy = true },
+ { type = "CommandContext", command = "pip freeze --exclude-editable > requirements.txt" },
{ type = "FileContext", path = "requirements.txt", move = true },
- { type = "GitRepositoryContext", name = "capsula" },
- { type = "CwdContext" },
- { type = "CpuContext" },
]
-# Reporter to be used to report the captured contexts.
reporters = [{ type = "JsonDumpReporter" }]
[in-run]
-# Watchers to be used during the execution of the decorated function/CLI command.
watchers = [{ type = "UncaughtExceptionWatcher" }, { type = "TimeWatcher" }]
-# Reporter to be used to report the execution status.
reporters = [{ type = "JsonDumpReporter" }]
[post-run]
-# Contexts to be captured after the execution of the decorated function/CLI command.
-contexts = [{ type = "FileContext", path = "examples/pi.txt", move = true }]
-# Reporter to be used to report the captured contexts.
reporters = [{ type = "JsonDumpReporter" }]
+
```
-Then, all you need to do is decorate your Python function with the `@capsula.run` decorator and specify the `load_from_config` argument as `True`. The following is an example of a Python script that estimates the value of π using the Monte Carlo method:
+Then, all you need to do is decorate your Python function with the `@capsula.run()` decorator. You can also use the `@capsula.context()` decorator to add a context specific to the function.
+
+The following is an example of a Python script that estimates the value of π using the Monte Carlo method:
```python
import random
-from pathlib import Path
-
import capsula
-@capsula.run(load_from_config=True)
+@capsula.run()
+@capsula.context(capsula.FileContext.default("pi.txt", move=True), mode="post")
def calculate_pi(n_samples: int = 1_000, seed: int = 42) -> None:
random.seed(seed)
xs = (random.random() for _ in range(n_samples))
@@ -73,7 +69,7 @@ def calculate_pi(n_samples: int = 1_000, seed: int = 42) -> None:
capsula.record("pi_estimate", pi_estimate)
print(f"Run name: {capsula.current_run_name()}")
- with (Path(__file__).parent / "pi.txt").open("w") as output_file:
+ with open("pi.txt", "w") as output_file:
output_file.write(f"Pi estimate: {pi_estimate}.")
if __name__ == "__main__":
@@ -83,53 +79,6 @@ if __name__ == "__main__":
Example of output
pre-run-report.json
:{
- "command": {
- "poetry check --lock": {
- "command": "poetry check --lock",
- "cwd": null,
- "returncode": 0,
- "stdout": "All set!\n",
- "stderr": ""
- },
- "pip freeze --exclude-editable > requirements.txt": {
- "command": "pip freeze --exclude-editable > requirements.txt",
- "cwd": null,
- "returncode": 0,
- "stdout": "",
- "stderr": ""
- }
- },
- "file": {
- "pyproject.toml": {
- "copied_to": [
- "vault/calculate_pi_20240225_221901_M7b3/pyproject.toml"
- ],
- "moved_to": null,
- "hash": {
- "algorithm": "sha256",
- "digest": "6c59362587bf43411461b69675980ea338d83a468acddbc8f6cac4f2c17f7605"
- }
- },
- "requirements.txt": {
- "copied_to": [],
- "moved_to": "vault/calculate_pi_20240225_221901_M7b3",
- "hash": {
- "algorithm": "sha256",
- "digest": "99d0dbddd7f27aa25bd2d7ce3e2f4a555cdb48b039d73a6cf01fc5fa33f527e1"
- }
- }
- },
- "git": {
- "capsula": {
- "working_dir": "/home/nomura/ghq/github.com/shunichironomura/capsula",
- "sha": "ff51cb6245e43253d036fcaa0b2af09c0089b783",
- "remotes": {
- "origin": "ssh://git@github.com/shunichironomura/capsula.git"
- },
- "branch": "improve-example",
- "is_dirty": true
- }
- },
"cwd": "/home/nomura/ghq/github.com/shunichironomura/capsula",
"cpu": {
"python_version": "3.8.17.final.0 (64 bit)",
@@ -152,7 +101,7 @@ if __name__ == "__main__":
0
],
"hz_actual": [
- 2904010000,
+ 2904008000,
0
],
"stepping": 5,
@@ -198,6 +147,7 @@ if __name__ == "__main__":
"lm",
"mca",
"mce",
+ "md_clear",
"mmx",
"movbe",
"msr",
@@ -253,6 +203,63 @@ if __name__ == "__main__":
"l1_instruction_cache_size": 196608,
"l2_cache_line_size": 256,
"l2_cache_associativity": 6
+ },
+ "git": {
+ "capsula": {
+ "working_dir": "/home/nomura/ghq/github.com/shunichironomura/capsula",
+ "sha": "db7b86d3ed95e178521cd140505f1c8b25f4f30e",
+ "remotes": {
+ "origin": "ssh://git@github.com/shunichironomura/capsula.git"
+ },
+ "branch": "update-readme",
+ "is_dirty": false
+ }
+ },
+ "command": {
+ "poetry check --lock": {
+ "command": "poetry check --lock",
+ "cwd": null,
+ "returncode": 0,
+ "stdout": "All set!\n",
+ "stderr": ""
+ },
+ "pip freeze --exclude-editable > requirements.txt": {
+ "command": "pip freeze --exclude-editable > requirements.txt",
+ "cwd": null,
+ "returncode": 0,
+ "stdout": "",
+ "stderr": ""
+ }
+ },
+ "file": {
+ "pyproject.toml": {
+ "copied_to": [
+ "vault/calculate_pi_20240630_015823_S3vb/pyproject.toml"
+ ],
+ "moved_to": null,
+ "hash": {
+ "algorithm": "sha256",
+ "digest": "9b2ccc978e950a3a4d2b5f3d29eadab593e1ffe8cd48e7606389e214cb82c8a6"
+ }
+ },
+ "poetry.lock": {
+ "copied_to": [
+ "vault/calculate_pi_20240630_015823_S3vb/poetry.lock"
+ ],
+ "moved_to": null,
+ "hash": {
+ "algorithm": "sha256",
+ "digest": "8d89f9943c8e515340a5c8c16b17a30a749d935ffe765024acaaa81fc1ed5587"
+ }
+ },
+ "requirements.txt": {
+ "copied_to": [],
+ "moved_to": "vault/calculate_pi_20240630_015823_S3vb",
+ "hash": {
+ "algorithm": "sha256",
+ "digest": "b7a36d48fda3efc9374d7d8b0fd4d910234497e2cf229001a1c2c76fce35810c"
+ }
+ }
}
}
post-run-report.json
:
{
"file": {
- "examples/pi.txt": {
+ "pi.txt": {
"copied_to": [],
- "moved_to": "vault/calculate_pi_20240225_221901_M7b3",
+ "moved_to": "vault/calculate_pi_20240630_015823_S3vb",
"hash": {
"algorithm": "sha256",
"digest": "a64c761cb6b6f9ef1bc1f6afa6ba44d796c5c51d14df0bdc9d3ab9ced7982a74"
diff --git a/examples/calculate_pi_cli.py b/examples/calculate_pi_cli.py
index bbd92965..dd48cd44 100644
--- a/examples/calculate_pi_cli.py
+++ b/examples/calculate_pi_cli.py
@@ -33,8 +33,8 @@ def main(n: int, seed: int | None = None) -> None:
logger.info(f"Calculating pi with {n} samples.")
logger.debug(f"Seed: {seed}")
random.seed(seed)
- xs = (random.random() for _ in range(n)) # noqa: S311
- ys = (random.random() for _ in range(n)) # noqa: S311
+ xs = (random.random() for _ in range(n))
+ ys = (random.random() for _ in range(n))
inside = sum(x * x + y * y <= 1.0 for x, y in zip(xs, ys))
pi_estimate = (4.0 * inside) / n
diff --git a/examples/decorator.py b/examples/decorator.py
index 96e97994..dc4bcc60 100644
--- a/examples/decorator.py
+++ b/examples/decorator.py
@@ -9,17 +9,28 @@
logger = logging.getLogger(__name__)
-@capsula.run()
+@capsula.run(ignore_config=True)
@capsula.context(capsula.EnvVarContext("HOME"), mode="pre")
@capsula.context(capsula.EnvVarContext("PATH"), mode="pre")
+@capsula.context(capsula.CwdContext(), mode="pre")
+@capsula.context(capsula.CpuContext(), mode="pre")
+@capsula.context(capsula.GitRepositoryContext.default("capsula"), mode="pre")
+@capsula.context(capsula.CommandContext("poetry check --lock"), mode="pre")
+@capsula.context(capsula.FileContext.default(Path(__file__).parents[1] / "pyproject.toml", copy=True), mode="pre")
+@capsula.context(capsula.FileContext.default(Path(__file__).parents[1] / "poetry.lock", copy=True), mode="pre")
+@capsula.context(capsula.CommandContext("pip freeze --exclude-editable > requirements.txt"), mode="pre")
+@capsula.context(capsula.FileContext.default(Path(__file__).parents[1] / "requirements.txt", move=True), mode="pre")
+@capsula.watcher(capsula.UncaughtExceptionWatcher("Exception"))
+@capsula.watcher(capsula.TimeWatcher("calculation_time"))
@capsula.context(capsula.FileContext.default(Path(__file__).parent / "pi.txt", move=True), mode="post")
+@capsula.reporter(capsula.JsonDumpReporter.default(), mode="all")
@capsula.pass_pre_run_capsule
def calculate_pi(pre_run_capsule: capsula.Capsule, *, n_samples: int = 1_000, seed: int = 42) -> None:
logger.info(f"Calculating pi with {n_samples} samples.")
logger.debug(f"Seed: {seed}")
random.seed(seed)
- xs = (random.random() for _ in range(n_samples)) # noqa: S311
- ys = (random.random() for _ in range(n_samples)) # noqa: S311
+ xs = (random.random() for _ in range(n_samples))
+ ys = (random.random() for _ in range(n_samples))
inside = sum(x * x + y * y <= 1.0 for x, y in zip(xs, ys))
capsula.record("inside", inside)
diff --git a/examples/enc_context_manager.py b/examples/enc_context_manager.py
index e2e62520..358e2469 100644
--- a/examples/enc_context_manager.py
+++ b/examples/enc_context_manager.py
@@ -14,8 +14,8 @@
def calc_pi(n_samples: int, seed: int) -> float:
random.seed(seed)
- xs = (random.random() for _ in range(n_samples)) # noqa: S311
- ys = (random.random() for _ in range(n_samples)) # noqa: S311
+ xs = (random.random() for _ in range(n_samples))
+ ys = (random.random() for _ in range(n_samples))
inside = sum(x * x + y * y <= 1.0 for x, y in zip(xs, ys))
capsula.record("inside", inside)
diff --git a/examples/low_level.py b/examples/low_level.py
index 733ae485..7ca759d0 100644
--- a/examples/low_level.py
+++ b/examples/low_level.py
@@ -87,8 +87,8 @@
logger.info(f"Calculating pi with {N_SAMPLES} samples.")
logger.debug(f"Seed: {SEED}")
random.seed(SEED)
- xs = (random.random() for _ in range(N_SAMPLES)) # noqa: S311
- ys = (random.random() for _ in range(N_SAMPLES)) # noqa: S311
+ xs = (random.random() for _ in range(N_SAMPLES))
+ ys = (random.random() for _ in range(N_SAMPLES))
inside = sum(x * x + y * y <= 1.0 for x, y in zip(xs, ys))
in_run_enc.record("inside", inside)
diff --git a/examples/simple_decorator.py b/examples/simple_decorator.py
new file mode 100644
index 00000000..1b074d0e
--- /dev/null
+++ b/examples/simple_decorator.py
@@ -0,0 +1,27 @@
+import random
+
+import capsula
+
+
+@capsula.run()
+@capsula.context(capsula.FileContext.default("pi.txt", move=True), mode="post")
+def calculate_pi(n_samples: int = 1_000, seed: int = 42) -> None:
+ random.seed(seed)
+ xs = (random.random() for _ in range(n_samples))
+ ys = (random.random() for _ in range(n_samples))
+ inside = sum(x * x + y * y <= 1.0 for x, y in zip(xs, ys))
+
+ # You can record values to the capsule using the `record` method.
+ capsula.record("inside", inside)
+
+ pi_estimate = (4.0 * inside) / n_samples
+ print(f"Pi estimate: {pi_estimate}")
+ capsula.record("pi_estimate", pi_estimate)
+ print(f"Run name: {capsula.current_run_name()}")
+
+ with open("pi.txt", "w") as output_file:
+ output_file.write(f"Pi estimate: {pi_estimate}.")
+
+
+if __name__ == "__main__":
+ calculate_pi(n_samples=1_000)
diff --git a/pyproject.toml b/pyproject.toml
index 7dfce0e2..afccd4a7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -111,6 +111,8 @@ ignore = [
"examples/*" = [
"INP001", # implicit-namespace-package
"T201", # print statement
+ "S311", # suspicious-non-cryptographic-random-usage
+ "PTH123", # builtin-open
]
"capsula/_backport.py" = [
"ANN202", # Missing return type annotation