Skip to content

Commit

Permalink
Merge pull request #255 from shunichironomura/update-readme
Browse files Browse the repository at this point in the history
Update README and examples
  • Loading branch information
shunichironomura authored Jun 29, 2024
2 parents 8b27097 + dc853fd commit 4855dac
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 79 deletions.
147 changes: 77 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand All @@ -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__":
Expand All @@ -83,53 +79,6 @@ if __name__ == "__main__":
<details>
<summary>Example of output <code>pre-run-report.json</code>:</summary>
<pre><code>{
"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://[email protected]/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)",
Expand All @@ -152,7 +101,7 @@ if __name__ == "__main__":
0
],
"hz_actual": [
2904010000,
2904008000,
0
],
"stepping": 5,
Expand Down Expand Up @@ -198,6 +147,7 @@ if __name__ == "__main__":
"lm",
"mca",
"mce",
"md_clear",
"mmx",
"movbe",
"msr",
Expand Down Expand Up @@ -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://[email protected]/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"
}
}
}
}</code></pre>
</details>
Expand All @@ -263,7 +270,7 @@ if __name__ == "__main__":
"function": {
"calculate_pi": {
"file_path": "examples/simple_decorator.py",
"first_line_no": 10,
"first_line_no": 6,
"args": [],
"kwargs": {
"n_samples": 1000
Expand All @@ -272,15 +279,15 @@ if __name__ == "__main__":
},
"inside": 782,
"pi_estimate": 3.128,
"time": {
"execution_time": "0:00:00.000568"
},
"exception": {
"exception": {
"exc_type": null,
"exc_value": null,
"traceback": null
}
},
"time": {
"execution_time": "0:00:00.000658"
}
}</code></pre>
</details>
Expand All @@ -289,9 +296,9 @@ if __name__ == "__main__":
<summary>Example of output <code>post-run-report.json</code>:</summary>
<pre><code>{
"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"
Expand Down
4 changes: 2 additions & 2 deletions examples/calculate_pi_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 14 additions & 3 deletions examples/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions examples/enc_context_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions examples/low_level.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 27 additions & 0 deletions examples/simple_decorator.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 4855dac

Please sign in to comment.