programasweights 0.4.7__tar.gz → 0.4.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. {programasweights-0.4.7 → programasweights-0.4.9}/CHANGELOG.md +12 -0
  2. {programasweights-0.4.7 → programasweights-0.4.9}/PKG-INFO +15 -12
  3. {programasweights-0.4.7 → programasweights-0.4.9}/PYPI_README.md +14 -11
  4. {programasweights-0.4.7 → programasweights-0.4.9}/README.md +14 -11
  5. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/__init__.py +8 -4
  6. {programasweights-0.4.7 → programasweights-0.4.9}/pyproject.toml +11 -1
  7. programasweights-0.4.7/.cursor/rules/releases.mdc +0 -17
  8. programasweights-0.4.7/.github/workflows/release.yml +0 -72
  9. programasweights-0.4.7/.github/workflows/test.yml +0 -94
  10. programasweights-0.4.7/.readthedocs.yaml +0 -13
  11. programasweights-0.4.7/AGENTS.md +0 -291
  12. programasweights-0.4.7/RELEASING.md +0 -82
  13. programasweights-0.4.7/docs/adr/001-llama-cpp-over-pytorch.md +0 -21
  14. programasweights-0.4.7/docs/adr/002-q4_0-adapter-format.md +0 -32
  15. programasweights-0.4.7/docs/adr/003-single-spec-field.md +0 -26
  16. programasweights-0.4.7/docs/adr/004-compiler-naming.md +0 -32
  17. programasweights-0.4.7/docs/adr/005-vllm-hidden-states.md +0 -24
  18. programasweights-0.4.7/docs/adr/006-email-api-key-auth.md +0 -41
  19. programasweights-0.4.7/docs/advanced/adrs.md +0 -67
  20. programasweights-0.4.7/docs/advanced/architecture.md +0 -47
  21. programasweights-0.4.7/docs/api-reference/cli.md +0 -110
  22. programasweights-0.4.7/docs/api-reference/python-sdk.md +0 -363
  23. programasweights-0.4.7/docs/api-reference/rest-api.md +0 -200
  24. programasweights-0.4.7/docs/architecture.md +0 -38
  25. programasweights-0.4.7/docs/case-studies/alien-taboo.md +0 -117
  26. programasweights-0.4.7/docs/case-studies/log-monitoring.md +0 -132
  27. programasweights-0.4.7/docs/case-studies/semantic-search.md +0 -146
  28. programasweights-0.4.7/docs/case-studies/site-navigation.md +0 -127
  29. programasweights-0.4.7/docs/case-studies/tool-calling.md +0 -477
  30. programasweights-0.4.7/docs/getting-started/first-program.md +0 -88
  31. programasweights-0.4.7/docs/getting-started/installation.md +0 -57
  32. programasweights-0.4.7/docs/getting-started/naming-programs.md +0 -78
  33. programasweights-0.4.7/docs/guide/browser-inference.md +0 -141
  34. programasweights-0.4.7/docs/guide/how-it-works.md +0 -47
  35. programasweights-0.4.7/docs/guide/local-inference.md +0 -48
  36. programasweights-0.4.7/docs/guide/writing-good-specs.md +0 -11
  37. programasweights-0.4.7/docs/hub/browsing-programs.md +0 -37
  38. programasweights-0.4.7/docs/hub/feedback-cases.md +0 -34
  39. programasweights-0.4.7/docs/hub/publishing-programs.md +0 -31
  40. programasweights-0.4.7/docs/index.md +0 -96
  41. programasweights-0.4.7/docs/requirements.txt +0 -2
  42. programasweights-0.4.7/examples/flask_app.py +0 -52
  43. programasweights-0.4.7/examples/jupyter_notebook.py +0 -52
  44. programasweights-0.4.7/examples/langchain_integration.py +0 -52
  45. programasweights-0.4.7/examples/paw_monitor.py +0 -180
  46. programasweights-0.4.7/examples/replace_openai.py +0 -44
  47. programasweights-0.4.7/mkdocs.yml +0 -87
  48. programasweights-0.4.7/scripts/release_metadata.py +0 -156
  49. programasweights-0.4.7/tests/test_api_errors.py +0 -222
  50. programasweights-0.4.7/tests/test_base_interpreter.py +0 -845
  51. programasweights-0.4.7/tests/test_cli_auth.py +0 -265
  52. programasweights-0.4.7/tests/test_compile_timeouts.py +0 -129
  53. programasweights-0.4.7/tests/test_desktop_sdk.py +0 -1221
  54. programasweights-0.4.7/tests/test_local_program.py +0 -676
  55. programasweights-0.4.7/tests/test_offline_cache.py +0 -97
  56. programasweights-0.4.7/tests/test_release_metadata.py +0 -296
  57. programasweights-0.4.7/tests/test_remote_inference.py +0 -294
  58. programasweights-0.4.7/tests/test_runtime_registry_sdk.py +0 -123
  59. programasweights-0.4.7/tests/test_sdk.py +0 -484
  60. programasweights-0.4.7/tests/test_sdk.sh +0 -89
  61. {programasweights-0.4.7 → programasweights-0.4.9}/.gitignore +0 -0
  62. {programasweights-0.4.7 → programasweights-0.4.9}/LICENSE +0 -0
  63. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_output.py +0 -0
  64. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_program_reference.py +0 -0
  65. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/_remote.py +0 -0
  66. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/artifacts.py +0 -0
  67. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/cache.py +0 -0
  68. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/cli.py +0 -0
  69. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/client.py +0 -0
  70. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/compiler/__init__.py +0 -0
  71. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/compiler/dummy.py +0 -0
  72. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/config.py +0 -0
  73. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/convert_peft_to_paw.py +0 -0
  74. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/errors.py +0 -0
  75. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/local_program.py +0 -0
  76. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/paw_format.py +0 -0
  77. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/__init__.py +0 -0
  78. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/interpreter.py +0 -0
  79. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime/interpreter_onnx.py +0 -0
  80. {programasweights-0.4.7 → programasweights-0.4.9}/programasweights/runtime_llamacpp.py +0 -0
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.9 (2026-09-21)
4
+
5
+ - Lead quickstarts and examples with compiling your own functions, then
6
+ saving and reusing program IDs.
7
+ - Reuse loaded functions in the LangChain example and serialize calls to
8
+ each shared instance.
9
+
10
+ ## 0.4.8 (2026-09-20)
11
+
12
+ - Reduce the source distribution to the SDK and files needed to build and
13
+ document the package.
14
+
3
15
  ## 0.4.7 (2026-09-20)
4
16
 
5
17
  - Add `remote=True` to `paw.function` and `paw.compile_and_load`, plus
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: programasweights
3
- Version: 0.4.7
3
+ Version: 0.4.9
4
4
  Summary: Compile natural language specifications into neural programs that run locally via llama.cpp.
5
5
  Project-URL: Homepage, https://programasweights.com
6
6
  Project-URL: Repository, https://github.com/programasweights/programasweights-python
@@ -46,22 +46,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
46
46
  ```python
47
47
  import programasweights as paw
48
48
 
49
- # Use a pre-compiled function (downloads once, runs locally forever)
50
- fn = paw.function("email-triage")
49
+ # Compile and load your own function
50
+ fn = paw.compile_and_load(
51
+ "Classify if a message needs immediate attention or can wait. "
52
+ "Return only 'immediate' or 'wait'."
53
+ )
51
54
  fn("Urgent: the server is down!") # "immediate"
52
55
  fn("Newsletter: spring picnic") # "wait"
53
56
 
54
- # Compile your own from a description
57
+ # Compile once and save the program ID
55
58
  program = paw.compile(
56
- "Fix malformed JSON: repair missing quotes and trailing commas",
57
- slug="json-fixer" # optional: creates username/json-fixer handle
59
+ "Fix malformed JSON: repair missing quotes and trailing commas"
58
60
  )
59
- fn = paw.function(program.slug) # or paw.function(program.id)
61
+ print(program.id) # Save this ID for future runs
62
+ fn = paw.function(program.id)
60
63
  fn("{name: 'Alice',}") # '{"name":"Alice"}'
61
-
62
- # Or compile and load in one step
63
- fn = paw.compile_and_load("Classify sentiment as positive or negative")
64
- fn("I love this!") # "positive"
65
64
  ```
66
65
 
67
66
  If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
@@ -73,7 +72,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
73
72
  ```python
74
73
  import programasweights as paw
75
74
 
76
- with paw.function("email-triage", remote=True) as remote_fn:
75
+ with paw.compile_and_load(
76
+ "Classify if a message needs immediate attention or can wait. "
77
+ "Return only 'immediate' or 'wait'.",
78
+ remote=True,
79
+ ) as remote_fn:
77
80
  print(remote_fn("Urgent: the server is down!"))
78
81
  ```
79
82
 
@@ -15,22 +15,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
15
15
  ```python
16
16
  import programasweights as paw
17
17
 
18
- # Use a pre-compiled function (downloads once, runs locally forever)
19
- fn = paw.function("email-triage")
18
+ # Compile and load your own function
19
+ fn = paw.compile_and_load(
20
+ "Classify if a message needs immediate attention or can wait. "
21
+ "Return only 'immediate' or 'wait'."
22
+ )
20
23
  fn("Urgent: the server is down!") # "immediate"
21
24
  fn("Newsletter: spring picnic") # "wait"
22
25
 
23
- # Compile your own from a description
26
+ # Compile once and save the program ID
24
27
  program = paw.compile(
25
- "Fix malformed JSON: repair missing quotes and trailing commas",
26
- slug="json-fixer" # optional: creates username/json-fixer handle
28
+ "Fix malformed JSON: repair missing quotes and trailing commas"
27
29
  )
28
- fn = paw.function(program.slug) # or paw.function(program.id)
30
+ print(program.id) # Save this ID for future runs
31
+ fn = paw.function(program.id)
29
32
  fn("{name: 'Alice',}") # '{"name":"Alice"}'
30
-
31
- # Or compile and load in one step
32
- fn = paw.compile_and_load("Classify sentiment as positive or negative")
33
- fn("I love this!") # "positive"
34
33
  ```
35
34
 
36
35
  If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
@@ -42,7 +41,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
42
41
  ```python
43
42
  import programasweights as paw
44
43
 
45
- with paw.function("email-triage", remote=True) as remote_fn:
44
+ with paw.compile_and_load(
45
+ "Classify if a message needs immediate attention or can wait. "
46
+ "Return only 'immediate' or 'wait'.",
47
+ remote=True,
48
+ ) as remote_fn:
46
49
  print(remote_fn("Urgent: the server is down!"))
47
50
  ```
48
51
 
@@ -15,22 +15,21 @@ pip install programasweights --extra-index-url https://pypi.programasweights.com
15
15
  ```python
16
16
  import programasweights as paw
17
17
 
18
- # Use a pre-compiled function (downloads once, runs locally forever)
19
- fn = paw.function("email-triage")
18
+ # Compile and load your own function
19
+ fn = paw.compile_and_load(
20
+ "Classify if a message needs immediate attention or can wait. "
21
+ "Return only 'immediate' or 'wait'."
22
+ )
20
23
  fn("Urgent: the server is down!") # "immediate"
21
24
  fn("Newsletter: spring picnic") # "wait"
22
25
 
23
- # Compile your own from a description
26
+ # Compile once and save the program ID
24
27
  program = paw.compile(
25
- "Fix malformed JSON: repair missing quotes and trailing commas",
26
- slug="json-fixer" # optional: creates username/json-fixer handle
28
+ "Fix malformed JSON: repair missing quotes and trailing commas"
27
29
  )
28
- fn = paw.function(program.slug) # or paw.function(program.id)
30
+ print(program.id) # Save this ID for future runs
31
+ fn = paw.function(program.id)
29
32
  fn("{name: 'Alice',}") # '{"name":"Alice"}'
30
-
31
- # Or compile and load in one step
32
- fn = paw.compile_and_load("Classify sentiment as positive or negative")
33
- fn("I love this!") # "positive"
34
33
  ```
35
34
 
36
35
  If you specifically want the smaller browser-compatible runtime, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
@@ -42,7 +41,11 @@ Use the hosted API for fast inference in around 150 ms, without a local model do
42
41
  ```python
43
42
  import programasweights as paw
44
43
 
45
- with paw.function("email-triage", remote=True) as remote_fn:
44
+ with paw.compile_and_load(
45
+ "Classify if a message needs immediate attention or can wait. "
46
+ "Return only 'immediate' or 'wait'.",
47
+ remote=True,
48
+ ) as remote_fn:
46
49
  print(remote_fn("Urgent: the server is down!"))
47
50
  ```
48
51
 
@@ -5,12 +5,16 @@ functions that run locally.
5
5
  Quick start:
6
6
  import programasweights as paw
7
7
 
8
- # Use a pre-compiled function (downloads once, runs locally forever)
9
- fn = paw.function("email-triage")
8
+ # Compile and load your own function
9
+ fn = paw.compile_and_load(
10
+ "Classify if a message needs immediate attention or can wait. "
11
+ "Return only 'immediate' or 'wait'."
12
+ )
10
13
  fn("Urgent: server is down!") # "immediate"
11
14
 
12
- # Compile your own from a description
15
+ # Compile once and save the program ID
13
16
  program = paw.compile("Fix malformed JSON: repair missing quotes and trailing commas")
17
+ print(program.id) # Save this ID for future runs
14
18
  fn = paw.function(program.id)
15
19
  fn("{name: 'Alice',}") # '{"name":"Alice"}'
16
20
 
@@ -27,7 +31,7 @@ try:
27
31
  from importlib.metadata import version as _meta_version
28
32
  __version__ = _meta_version("programasweights")
29
33
  except Exception:
30
- __version__ = "0.4.7"
34
+ __version__ = "0.4.9"
31
35
 
32
36
  from ._output import ProgressCallback, ProgressEvent, report_progress
33
37
  from .cache import CachedProgram
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "programasweights"
7
- version = "0.4.7"
7
+ version = "0.4.9"
8
8
  description = "Compile natural language specifications into neural programs that run locally via llama.cpp."
9
9
  readme = "PYPI_README.md"
10
10
  requires-python = ">=3.9"
@@ -47,6 +47,16 @@ paw = "programasweights.cli:main"
47
47
  [tool.hatch.build.targets.wheel]
48
48
  packages = ["programasweights"]
49
49
 
50
+ [tool.hatch.build.targets.sdist]
51
+ only-include = [
52
+ "programasweights",
53
+ "README.md",
54
+ "PYPI_README.md",
55
+ "LICENSE",
56
+ "CHANGELOG.md",
57
+ "pyproject.toml",
58
+ ]
59
+
50
60
  [tool.pytest.ini_options]
51
61
  addopts = "-q"
52
62
  pythonpath = ["."]
@@ -1,17 +0,0 @@
1
- ---
2
- description: Publish and verify complete Python SDK releases
3
- alwaysApply: true
4
- ---
5
-
6
- # SDK releases
7
-
8
- For release or publication work, read `RELEASING.md` first.
9
-
10
- - A release is complete only when its annotated remote tag, PyPI wheel and
11
- source distribution, and published GitHub Release all exist and agree.
12
- - Build from the clean, tested release commit; push its annotated version tag
13
- before uploading the exact checked artifacts to PyPI.
14
- - Verify the `GitHub release` workflow succeeded and the latest GitHub Release
15
- agrees with PyPI. A tag alone is not a GitHub Release entry.
16
- - Repair missing entries using the documented workflow dispatch. Never move a
17
- published tag, rebuild an existing version, or bypass artifact verification.
@@ -1,72 +0,0 @@
1
- name: GitHub release
2
-
3
- on:
4
- push:
5
- tags: ['v*']
6
- workflow_dispatch:
7
- inputs:
8
- tag:
9
- description: 'Existing stable version tag, e.g. v0.4.6'
10
- required: true
11
- type: string
12
-
13
- permissions:
14
- contents: write
15
-
16
- concurrency:
17
- group: github-release-${{ inputs.tag || github.ref_name }}
18
- cancel-in-progress: false
19
-
20
- jobs:
21
- release:
22
- runs-on: ubuntu-latest
23
- timeout-minutes: 15
24
- env:
25
- RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
26
- GH_TOKEN: ${{ github.token }}
27
- GH_REPO: ${{ github.repository }}
28
- steps:
29
- - name: Set the verification output directory
30
- run: echo "RELEASE_DIR=$RUNNER_TEMP/verified-release" >> "$GITHUB_ENV"
31
- - uses: actions/checkout@v4
32
- with:
33
- fetch-depth: 0
34
- - uses: actions/setup-python@v5
35
- with:
36
- python-version: '3.12'
37
- - name: Verify the remote tag and both published PyPI artifacts
38
- # Tags are pushed before uploading. Wait for the wheel AND sdist;
39
- # never announce an unpublished version or rebuild release assets.
40
- run: python scripts/release_metadata.py --tag "$RELEASE_TAG" --output-dir "$RELEASE_DIR" --wait-seconds 600
41
- - name: Publish the missing GitHub release
42
- shell: bash
43
- run: |
44
- set -euo pipefail
45
- if gh release view "$RELEASE_TAG" --json tagName >/dev/null 2>&1; then
46
- echo "Release already exists; preserving its notes and assets."
47
- else
48
- latest=$(jq -r .latest "$RELEASE_DIR/verified.json")
49
- gh release create "$RELEASE_TAG" "$RELEASE_DIR"/artifacts/* \
50
- --verify-tag --title "$RELEASE_TAG" \
51
- --notes-file "$RELEASE_DIR/notes.md" --latest="$latest"
52
- fi
53
- gh release view "$RELEASE_TAG" --json tagName,isDraft,isPrerelease,url \
54
- | jq -e --arg tag "$RELEASE_TAG" '.tagName == $tag and .isDraft == false and .isPrerelease == false'
55
- - name: Verify the uploaded release assets and latest marker
56
- shell: bash
57
- run: |
58
- set -euo pipefail
59
- gh release download "$RELEASE_TAG" --pattern 'programasweights-*' \
60
- --dir "$RELEASE_DIR/github-assets"
61
- for artifact in "$RELEASE_DIR"/artifacts/*; do
62
- cmp "$artifact" "$RELEASE_DIR/github-assets/$(basename "$artifact")"
63
- done
64
- if [ "$(jq -r .latest "$RELEASE_DIR/verified.json")" = true ]; then
65
- gh api "repos/$GH_REPO/releases/latest" \
66
- | jq -e --arg tag "$RELEASE_TAG" '.tag_name == $tag'
67
- fi
68
- - name: Retain the verification record
69
- uses: actions/upload-artifact@v4
70
- with:
71
- name: release-verification-${{ inputs.tag || github.ref_name }}
72
- path: ${{ runner.temp }}/verified-release/verified.json
@@ -1,94 +0,0 @@
1
- name: tests
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
-
8
- jobs:
9
- release-metadata:
10
- runs-on: ubuntu-latest
11
- steps:
12
- - uses: actions/checkout@v4
13
- - uses: actions/setup-python@v5
14
- with:
15
- python-version: '3.12'
16
- - run: python -m pip install pytest
17
- - name: Test release verification without network or publishing
18
- run: python -m pytest tests/test_release_metadata.py
19
-
20
- test:
21
- runs-on: ubuntu-latest
22
- strategy:
23
- fail-fast: false
24
- matrix:
25
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
26
- steps:
27
- - uses: actions/checkout@v4
28
-
29
- - name: Set up Python ${{ matrix.python-version }}
30
- uses: actions/setup-python@v5
31
- with:
32
- python-version: ${{ matrix.python-version }}
33
-
34
- - name: Install (hermetic deps only)
35
- # Install httpx + pytest and the package itself without pulling the heavy
36
- # llama-cpp-python build. Runtime tests inject a fake llama_cpp module,
37
- # so CI needs neither the native extension nor a model download.
38
- run: |
39
- python -m pip install --upgrade pip
40
- python -m pip install httpx pytest
41
- python -m pip install -e . --no-deps
42
-
43
- - name: Run hermetic tests
44
- # Scoped to tests that need no network, no model download, and no
45
- # PAW_API_KEY. Auth tests (@needs_auth) auto-skip without a key; the
46
- # network/model-download tests in test_sdk.py are excluded here and can
47
- # be run separately against a live server.
48
- run: |
49
- pytest \
50
- tests/test_api_errors.py \
51
- tests/test_compile_timeouts.py \
52
- tests/test_local_program.py \
53
- tests/test_base_interpreter.py \
54
- tests/test_cli_auth.py \
55
- tests/test_remote_inference.py \
56
- tests/test_desktop_sdk.py \
57
- tests/test_runtime_registry_sdk.py \
58
- tests/test_sdk.py::TestInstallAndImport
59
-
60
- local-files-windows:
61
- runs-on: windows-latest
62
- strategy:
63
- fail-fast: false
64
- matrix:
65
- python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
66
- steps:
67
- - uses: actions/checkout@v4
68
- - uses: actions/setup-python@v5
69
- with:
70
- python-version: ${{ matrix.python-version }}
71
- - name: Install hermetic test dependencies
72
- run: |
73
- python -m pip install httpx pytest
74
- python -m pip install -e . --no-deps
75
- - name: Test Windows local paths, cache locks, and compile errors
76
- run: python -m pytest tests/test_api_errors.py tests/test_compile_timeouts.py tests/test_local_program.py tests/test_remote_inference.py --junitxml=test-results.xml
77
- - name: Annotate Windows test failures
78
- if: failure()
79
- shell: python
80
- run: |
81
- from pathlib import Path
82
- import xml.etree.ElementTree as ET
83
-
84
- report = Path("test-results.xml")
85
- if report.exists():
86
- for case in ET.parse(report).iter("testcase"):
87
- for result in case:
88
- if result.tag in {"failure", "error"}:
89
- # GitHub truncates annotations, so retain the actual
90
- # exception at the end of long pytest tracebacks.
91
- detail = result.text or result.get("message", "")
92
- message = f"{case.get('name')}: {detail[-3500:]}"
93
- message = message.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A")
94
- print(f"::error::{message}")
@@ -1,13 +0,0 @@
1
- version: 2
2
-
3
- build:
4
- os: ubuntu-24.04
5
- tools:
6
- python: "3.12"
7
-
8
- mkdocs:
9
- configuration: mkdocs.yml
10
-
11
- python:
12
- install:
13
- - requirements: docs/requirements.txt