research-panel 3.1.1__py3-none-any.whl
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.
- research/__init__.py +253 -0
- research/_vendor/__init__.py +0 -0
- research/_vendor/yaml/LICENSE +20 -0
- research/_vendor/yaml/__init__.py +390 -0
- research/_vendor/yaml/composer.py +139 -0
- research/_vendor/yaml/constructor.py +748 -0
- research/_vendor/yaml/dumper.py +62 -0
- research/_vendor/yaml/emitter.py +1137 -0
- research/_vendor/yaml/error.py +75 -0
- research/_vendor/yaml/events.py +86 -0
- research/_vendor/yaml/loader.py +63 -0
- research/_vendor/yaml/nodes.py +49 -0
- research/_vendor/yaml/parser.py +589 -0
- research/_vendor/yaml/reader.py +185 -0
- research/_vendor/yaml/representer.py +389 -0
- research/_vendor/yaml/resolver.py +227 -0
- research/_vendor/yaml/scanner.py +1435 -0
- research/_vendor/yaml/serializer.py +111 -0
- research/_vendor/yaml/tokens.py +104 -0
- research/agents.py +459 -0
- research/agentsmd.py +176 -0
- research/api/__init__.py +157 -0
- research/api/agent_tools.py +183 -0
- research/api/agents.py +219 -0
- research/api/chat.py +357 -0
- research/api/decisions.py +45 -0
- research/api/guide.py +110 -0
- research/api/hpc.py +137 -0
- research/api/plans.py +364 -0
- research/api/records.py +289 -0
- research/api/runs.py +43 -0
- research/api/settings.py +142 -0
- research/approval.py +331 -0
- research/autopromote.py +432 -0
- research/backends/__init__.py +18 -0
- research/backends/base.py +44 -0
- research/backends/local.py +61 -0
- research/backends/slurm.py +136 -0
- research/bootstrap.py +224 -0
- research/chat/__init__.py +119 -0
- research/chat/actions.py +63 -0
- research/chat/alerts.py +117 -0
- research/chat/commands.py +353 -0
- research/chat/digest.py +22 -0
- research/chat/discord_bot.py +728 -0
- research/chat/gateway.py +402 -0
- research/chat/manage.py +91 -0
- research/chat/pairing.py +141 -0
- research/chat/telegram.py +297 -0
- research/checks.py +319 -0
- research/compare.py +69 -0
- research/configfile.py +577 -0
- research/context.py +613 -0
- research/control.py +144 -0
- research/daemonlib.py +67 -0
- research/decisions.py +351 -0
- research/doctor.py +342 -0
- research/durability.py +203 -0
- research/envcheck.py +115 -0
- research/evidence.py +488 -0
- research/execution.py +235 -0
- research/expcheck.py +79 -0
- research/fullreport.py +1044 -0
- research/gitinfo.py +91 -0
- research/governance.py +94 -0
- research/guide.py +530 -0
- research/guide_quarto.py +770 -0
- research/guide_review.py +159 -0
- research/harness.py +53 -0
- research/hooks.py +294 -0
- research/hpc/__init__.py +0 -0
- research/hpc/bundle.py +708 -0
- research/hpc/config.py +267 -0
- research/hpc/datasets.py +470 -0
- research/hpc/remote.py +806 -0
- research/hpc/results.py +382 -0
- research/hpc/transport.py +225 -0
- research/initproject.py +403 -0
- research/intervene.py +503 -0
- research/investigator.py +203 -0
- research/isolation.py +504 -0
- research/localbin.py +173 -0
- research/machine.py +53 -0
- research/mcp.py +326 -0
- research/mirrors.py +121 -0
- research/notify.py +340 -0
- research/orchestrate.py +672 -0
- research/packs.py +317 -0
- research/plans.py +554 -0
- research/planspec.py +732 -0
- research/processes.py +49 -0
- research/promotion.py +441 -0
- research/provenance.py +713 -0
- research/providers/__init__.py +228 -0
- research/providers/agy.py +92 -0
- research/providers/base.py +97 -0
- research/providers/claude.py +87 -0
- research/providers/codex.py +108 -0
- research/providers/custom.py +28 -0
- research/providers/limits.py +199 -0
- research/providers/opencode.py +267 -0
- research/registry.py +879 -0
- research/report.py +409 -0
- research/rpc.py +107 -0
- research/runner.py +194 -0
- research/runs.py +822 -0
- research/sandbox.py +178 -0
- research/schema.py +374 -0
- research/search.py +77 -0
- research/selfupdate.py +144 -0
- research/services.py +692 -0
- research/setup_agents.py +202 -0
- research/skills.py +532 -0
- research/store.py +911 -0
- research/strategy.py +377 -0
- research/supervisor.py +2053 -0
- research/supervisord.py +10 -0
- research/task_spec.py +73 -0
- research/taskprompt.py +145 -0
- research/templates/AGENTS.block.md +111 -0
- research/templates/catalog/cirq/LICENSE +21 -0
- research/templates/catalog/cirq/SKILL.md +378 -0
- research/templates/catalog/cirq/SOURCE.yaml +9 -0
- research/templates/catalog/cirq/references/building.md +333 -0
- research/templates/catalog/cirq/references/experiments.md +215 -0
- research/templates/catalog/cirq/references/hardware.md +272 -0
- research/templates/catalog/cirq/references/noise.md +234 -0
- research/templates/catalog/cirq/references/review.md +61 -0
- research/templates/catalog/cirq/references/simulation.md +176 -0
- research/templates/catalog/cirq/references/transformation.md +150 -0
- research/templates/catalog/citation-management/LICENSE +21 -0
- research/templates/catalog/citation-management/SKILL.md +359 -0
- research/templates/catalog/citation-management/SOURCE.yaml +9 -0
- research/templates/catalog/dask/LICENSE +21 -0
- research/templates/catalog/dask/SKILL.md +493 -0
- research/templates/catalog/dask/SOURCE.yaml +9 -0
- research/templates/catalog/experimental-design/LICENSE +21 -0
- research/templates/catalog/experimental-design/SKILL.md +286 -0
- research/templates/catalog/experimental-design/SOURCE.yaml +9 -0
- research/templates/catalog/experimental-design/references/design_types.md +137 -0
- research/templates/catalog/experimental-design/references/factorial_and_doe.md +156 -0
- research/templates/catalog/experimental-design/references/randomization_and_blocking.md +133 -0
- research/templates/catalog/experimental-design/references/sequential_and_adaptive.md +109 -0
- research/templates/catalog/experimental-design/scripts/doe_designs.py +227 -0
- research/templates/catalog/experimental-design/scripts/randomization.py +228 -0
- research/templates/catalog/exploratory-data-analysis/LICENSE +21 -0
- research/templates/catalog/exploratory-data-analysis/SKILL.md +311 -0
- research/templates/catalog/exploratory-data-analysis/SOURCE.yaml +9 -0
- research/templates/catalog/frontend-design/LICENSE +177 -0
- research/templates/catalog/frontend-design/LICENSE.txt +177 -0
- research/templates/catalog/frontend-design/SKILL.md +71 -0
- research/templates/catalog/frontend-design/SOURCE.yaml +9 -0
- research/templates/catalog/hypothesis-generation/LICENSE +21 -0
- research/templates/catalog/hypothesis-generation/SKILL.md +290 -0
- research/templates/catalog/hypothesis-generation/SOURCE.yaml +9 -0
- research/templates/catalog/literature-review/LICENSE +21 -0
- research/templates/catalog/literature-review/SKILL.md +229 -0
- research/templates/catalog/literature-review/SOURCE.yaml +9 -0
- research/templates/catalog/matplotlib/LICENSE +21 -0
- research/templates/catalog/matplotlib/SKILL.md +435 -0
- research/templates/catalog/matplotlib/SOURCE.yaml +9 -0
- research/templates/catalog/peer-review/LICENSE +21 -0
- research/templates/catalog/peer-review/SKILL.md +317 -0
- research/templates/catalog/peer-review/SOURCE.yaml +9 -0
- research/templates/catalog/pennylane/LICENSE +21 -0
- research/templates/catalog/pennylane/SKILL.md +141 -0
- research/templates/catalog/pennylane/SOURCE.yaml +9 -0
- research/templates/catalog/pennylane/references/advanced_features.md +187 -0
- research/templates/catalog/pennylane/references/devices_backends.md +172 -0
- research/templates/catalog/pennylane/references/getting_started.md +112 -0
- research/templates/catalog/pennylane/references/optimization.md +165 -0
- research/templates/catalog/pennylane/references/quantum_chemistry.md +154 -0
- research/templates/catalog/pennylane/references/quantum_circuits.md +135 -0
- research/templates/catalog/pennylane/references/quantum_ml.md +147 -0
- research/templates/catalog/ponytail/LICENSE +21 -0
- research/templates/catalog/ponytail/SKILL.md +52 -0
- research/templates/catalog/ponytail/SOURCE.yaml +9 -0
- research/templates/catalog/ponytail-review/LICENSE +21 -0
- research/templates/catalog/ponytail-review/SKILL.md +101 -0
- research/templates/catalog/ponytail-review/SOURCE.yaml +9 -0
- research/templates/catalog/pydicom/LICENSE +21 -0
- research/templates/catalog/pydicom/SKILL.md +428 -0
- research/templates/catalog/pydicom/SOURCE.yaml +9 -0
- research/templates/catalog/pytorch-lightning/LICENSE +21 -0
- research/templates/catalog/pytorch-lightning/SKILL.md +208 -0
- research/templates/catalog/pytorch-lightning/SOURCE.yaml +9 -0
- research/templates/catalog/pytorch-lightning/references/best_practices.md +87 -0
- research/templates/catalog/pytorch-lightning/references/callbacks.md +117 -0
- research/templates/catalog/pytorch-lightning/references/data_module.md +98 -0
- research/templates/catalog/pytorch-lightning/references/distributed_training.md +148 -0
- research/templates/catalog/pytorch-lightning/references/lightning_module.md +126 -0
- research/templates/catalog/pytorch-lightning/references/logging.md +144 -0
- research/templates/catalog/pytorch-lightning/references/trainer.md +90 -0
- research/templates/catalog/pytorch-lightning/scripts/quick_trainer_setup.py +483 -0
- research/templates/catalog/pytorch-lightning/scripts/template_datamodule.py +170 -0
- research/templates/catalog/pytorch-lightning/scripts/template_lightning_module.py +220 -0
- research/templates/catalog/qiskit/LICENSE +21 -0
- research/templates/catalog/qiskit/SKILL.md +283 -0
- research/templates/catalog/qiskit/SOURCE.yaml +9 -0
- research/templates/catalog/receiving-code-review/LICENSE +21 -0
- research/templates/catalog/receiving-code-review/SKILL.md +205 -0
- research/templates/catalog/receiving-code-review/SOURCE.yaml +9 -0
- research/templates/catalog/reproducibility-statement/LICENSE +24 -0
- research/templates/catalog/reproducibility-statement/SKILL.md +97 -0
- research/templates/catalog/reproducibility-statement/SOURCE.yaml +9 -0
- research/templates/catalog/requesting-code-review/LICENSE +21 -0
- research/templates/catalog/requesting-code-review/SKILL.md +95 -0
- research/templates/catalog/requesting-code-review/SOURCE.yaml +9 -0
- research/templates/catalog/requesting-code-review/code-reviewer.md +198 -0
- research/templates/catalog/scientific-critical-thinking/LICENSE +21 -0
- research/templates/catalog/scientific-critical-thinking/SKILL.md +235 -0
- research/templates/catalog/scientific-critical-thinking/SOURCE.yaml +9 -0
- research/templates/catalog/scientific-visualization-kdense/LICENSE +21 -0
- research/templates/catalog/scientific-visualization-kdense/SKILL.md +307 -0
- research/templates/catalog/scientific-visualization-kdense/SOURCE.yaml +9 -0
- research/templates/catalog/scientific-writing/LICENSE +21 -0
- research/templates/catalog/scientific-writing/SKILL.md +381 -0
- research/templates/catalog/scientific-writing/SOURCE.yaml +9 -0
- research/templates/catalog/scikit-learn/LICENSE +21 -0
- research/templates/catalog/scikit-learn/SKILL.md +346 -0
- research/templates/catalog/scikit-learn/SOURCE.yaml +9 -0
- research/templates/catalog/shap/LICENSE +21 -0
- research/templates/catalog/shap/SKILL.md +315 -0
- research/templates/catalog/shap/SOURCE.yaml +9 -0
- research/templates/catalog/simpy/LICENSE +21 -0
- research/templates/catalog/simpy/SKILL.md +314 -0
- research/templates/catalog/simpy/SOURCE.yaml +9 -0
- research/templates/catalog/statistical-analysis/LICENSE +21 -0
- research/templates/catalog/statistical-analysis/SKILL.md +453 -0
- research/templates/catalog/statistical-analysis/SOURCE.yaml +9 -0
- research/templates/catalog/statistical-power/LICENSE +21 -0
- research/templates/catalog/statistical-power/SKILL.md +225 -0
- research/templates/catalog/statistical-power/SOURCE.yaml +9 -0
- research/templates/catalog/statistical-power/references/closed_form_recipes.md +200 -0
- research/templates/catalog/statistical-power/references/effect_sizes.md +134 -0
- research/templates/catalog/statistical-power/references/simulation_based_power.md +144 -0
- research/templates/catalog/statistical-power/scripts/power.py +453 -0
- research/templates/catalog/statistical-power/scripts/simulate_power.py +314 -0
- research/templates/catalog/sympy/LICENSE +21 -0
- research/templates/catalog/sympy/SKILL.md +408 -0
- research/templates/catalog/sympy/SOURCE.yaml +9 -0
- research/templates/catalog/sympy/references/advanced-topics.md +651 -0
- research/templates/catalog/sympy/references/code-generation-printing.md +632 -0
- research/templates/catalog/sympy/references/core-capabilities.md +376 -0
- research/templates/catalog/sympy/references/core_capabilities.md +195 -0
- research/templates/catalog/sympy/references/matrices-linear-algebra.md +531 -0
- research/templates/catalog/sympy/references/physics-mechanics.md +630 -0
- research/templates/catalog/sympy/references/review.md +88 -0
- research/templates/catalog/systematic-debugging/CREATION-LOG.md +119 -0
- research/templates/catalog/systematic-debugging/LICENSE +21 -0
- research/templates/catalog/systematic-debugging/SKILL.md +283 -0
- research/templates/catalog/systematic-debugging/SOURCE.yaml +9 -0
- research/templates/catalog/systematic-debugging/condition-based-waiting-example.ts +158 -0
- research/templates/catalog/systematic-debugging/condition-based-waiting.md +115 -0
- research/templates/catalog/systematic-debugging/defense-in-depth.md +122 -0
- research/templates/catalog/systematic-debugging/find-polluter.sh +72 -0
- research/templates/catalog/systematic-debugging/root-cause-tracing.md +169 -0
- research/templates/catalog/systematic-debugging/test-academic.md +14 -0
- research/templates/catalog/systematic-debugging/test-pressure-1.md +58 -0
- research/templates/catalog/systematic-debugging/test-pressure-2.md +68 -0
- research/templates/catalog/systematic-debugging/test-pressure-3.md +69 -0
- research/templates/catalog/verification-before-completion/LICENSE +21 -0
- research/templates/catalog/verification-before-completion/SKILL.md +120 -0
- research/templates/catalog/verification-before-completion/SOURCE.yaml +9 -0
- research/templates/catalog/webapp-testing/LICENSE +202 -0
- research/templates/catalog/webapp-testing/LICENSE.txt +202 -0
- research/templates/catalog/webapp-testing/SKILL.md +96 -0
- research/templates/catalog/webapp-testing/SOURCE.yaml +9 -0
- research/templates/catalog/webapp-testing/examples/console_logging.py +35 -0
- research/templates/catalog/webapp-testing/examples/element_discovery.py +40 -0
- research/templates/catalog/webapp-testing/examples/static_html_automation.py +33 -0
- research/templates/catalog/webapp-testing/scripts/with_server.py +106 -0
- research/templates/catalog.yaml +853 -0
- research/templates/claude-agents/research-haiku.md +8 -0
- research/templates/claude-agents/research-opus.md +8 -0
- research/templates/claude-agents/research-sonnet.md +8 -0
- research/templates/packs.yaml +122 -0
- research/templates/prompts/resume-session.md +3 -0
- research/templates/prompts/synthesize.md +3 -0
- research/templates/skills/clean-dataset/SKILL.md +13 -0
- research/templates/skills/engineering-loop/SKILL.md +31 -0
- research/templates/skills/failure-triage/SKILL.md +30 -0
- research/templates/skills/hpc-setup/SKILL.md +147 -0
- research/templates/skills/hypothesis-design/SKILL.md +24 -0
- research/templates/skills/independent-review/SKILL.md +23 -0
- research/templates/skills/literature-evidence/SKILL.md +19 -0
- research/templates/skills/parameter-tuning/SKILL.md +18 -0
- research/templates/skills/promote-validated-work/SKILL.md +19 -0
- research/templates/skills/reproduce-paper/SKILL.md +30 -0
- research/templates/skills/reproducibility-audit/SKILL.md +19 -0
- research/templates/skills/research-context/SKILL.md +20 -0
- research/templates/skills/run-experiment/SKILL.md +24 -0
- research/templates/skills/scientific-briefing/SKILL.md +47 -0
- research/templates/skills/scientific-handoff/SKILL.md +24 -0
- research/templates/skills/scientific-visualization/SKILL.md +22 -0
- research/templates/skills/synthesize-experiment/SKILL.md +29 -0
- research/templates/skills/uncertainty-analysis/SKILL.md +20 -0
- research/templates/skills/validation-oracles/SKILL.md +24 -0
- research/templates/templates/experiment-brief.md +10 -0
- research/templates/templates/note.md +6 -0
- research/totp.py +51 -0
- research/usage.py +134 -0
- research/util.py +215 -0
- research/verification.py +314 -0
- research/views.py +407 -0
- research/workspace.py +616 -0
- research/yamlio.py +72 -0
- research_cli/__init__.py +1 -0
- research_cli/__main__.py +5 -0
- research_cli/commands/__init__.py +8 -0
- research_cli/commands/agents.py +684 -0
- research_cli/commands/chat.py +157 -0
- research_cli/commands/decide.py +77 -0
- research_cli/commands/guide.py +588 -0
- research_cli/commands/hpc.py +564 -0
- research_cli/commands/plans.py +377 -0
- research_cli/commands/project.py +589 -0
- research_cli/commands/records.py +982 -0
- research_cli/commands/skills.py +294 -0
- research_cli/commands/supervisor.py +581 -0
- research_cli/main.py +143 -0
- research_cli/output.py +237 -0
- research_cli/tui/__init__.py +8 -0
- research_cli/tui/app.py +508 -0
- research_cli/tui/views.py +256 -0
- research_cli/tui/widgets.py +183 -0
- research_panel-3.1.1.dist-info/METADATA +507 -0
- research_panel-3.1.1.dist-info/RECORD +332 -0
- research_panel-3.1.1.dist-info/WHEEL +5 -0
- research_panel-3.1.1.dist-info/entry_points.txt +2 -0
- research_panel-3.1.1.dist-info/licenses/LICENSE +21 -0
- research_panel-3.1.1.dist-info/top_level.txt +2 -0
research/__init__.py
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""research — project-local research memory: questions → experiments → runs → findings → decisions → checkpoints.
|
|
2
|
+
|
|
3
|
+
Python API (all functions operate on the project containing the current directory,
|
|
4
|
+
or $RESEARCH_ROOT, unless you pass `project=Project(...)`):
|
|
5
|
+
|
|
6
|
+
import research
|
|
7
|
+
research.get_resume_context()
|
|
8
|
+
q = research.create_question("Does alpha affect error?")
|
|
9
|
+
e = research.create_experiment("alpha sweep", question=q["id"], hypothesis="…", parameters={"alpha": [0.1, 0.5]})
|
|
10
|
+
run = research.create_run(e["id"], command="python sweep.py --alpha 0.1", parameters={"alpha": 0.1})
|
|
11
|
+
research.log_metric("rmse", 0.12, run=run["id"]) # inside a `research run exec` job: run is implicit
|
|
12
|
+
research.register_artifact("outputs/plot.png", run=run["id"], description="error vs alpha")
|
|
13
|
+
research.create_finding("alpha=0.5 best tradeoff", supports=[e["id"], run["id"]], confidence="medium")
|
|
14
|
+
research.create_decision("Use alpha=0.5 as baseline", supporting_findings=["F-001"])
|
|
15
|
+
research.create_checkpoint()
|
|
16
|
+
|
|
17
|
+
# Plans and Tasks (Phase 0)
|
|
18
|
+
plan = research.create_plan("Reproduce paper X", objective="Reproduce Table 1")
|
|
19
|
+
t1 = research.create_task(plan["id"], "Implement baseline model", goal="...")
|
|
20
|
+
t2 = research.create_task(plan["id"], "Run experiments", depends_on=[t1["id"]])
|
|
21
|
+
research.start_task(t1["id"])
|
|
22
|
+
research.complete_task(t1["id"], result="baseline implemented in model.py")
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import functools
|
|
27
|
+
from typing import Any, Dict, List, Optional
|
|
28
|
+
|
|
29
|
+
from . import context as _context
|
|
30
|
+
from . import plans as _plans
|
|
31
|
+
from . import runs as _runs
|
|
32
|
+
from . import services as _services
|
|
33
|
+
from . import views as _views
|
|
34
|
+
from .store import Project, find_root
|
|
35
|
+
from .util import BudgetExceeded, NotFound, NotInitialized, ResearchError
|
|
36
|
+
|
|
37
|
+
__version__ = "3.1.1"
|
|
38
|
+
|
|
39
|
+
__all__ = [
|
|
40
|
+
"Project", "ResearchError", "BudgetExceeded", "NotFound", "NotInitialized", "init", "open_project",
|
|
41
|
+
"get_project_context", "get_resume_context", "list_questions", "create_question", "update_question",
|
|
42
|
+
"create_experiment", "create_variant", "get_experiment", "list_experiments", "update_experiment",
|
|
43
|
+
"set_status", "synthesize", "set_baseline",
|
|
44
|
+
"create_run", "attach_run", "update_run", "get_run", "list_runs", "exec_run", "submit_run", "cancel_run",
|
|
45
|
+
"register_artifact", "list_artifacts", "log_metric",
|
|
46
|
+
"create_finding", "update_finding", "list_findings", "supersede_finding",
|
|
47
|
+
"create_decision", "list_decisions", "create_checkpoint", "checkpoint_draft", "list_checkpoints",
|
|
48
|
+
"create_note", "list_notes", "list_skills", "show", "regenerate_context",
|
|
49
|
+
# Phase 0: Plans and Tasks
|
|
50
|
+
"create_plan", "update_plan", "list_plans", "get_plan",
|
|
51
|
+
"create_task", "update_task", "list_tasks", "get_task", "get_next_ready_task",
|
|
52
|
+
"start_task", "complete_task", "block_task", "task_context",
|
|
53
|
+
"release_task", "add_task_note", "verify_task", "review_finding", "search", "compare_runs", "sweep_run",
|
|
54
|
+
"write_report", "dispatch", "list_skills_full", "add_skills", "remove_skill", "update_skills", "link_skills",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def init(root: str = ".", name: Optional[str] = None, goal: Optional[str] = None) -> Project:
|
|
59
|
+
return Project.init(root, name=name, goal=goal)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def open_project(root: Optional[str] = None) -> Project:
|
|
63
|
+
return Project(root) if root else Project.find()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _with_project(fn):
|
|
67
|
+
@functools.wraps(fn)
|
|
68
|
+
def wrapper(*args, project: Optional[Project] = None, **kwargs):
|
|
69
|
+
if project is not None:
|
|
70
|
+
return fn(project, *args, **kwargs)
|
|
71
|
+
p = Project.find()
|
|
72
|
+
try:
|
|
73
|
+
return fn(p, *args, **kwargs)
|
|
74
|
+
finally:
|
|
75
|
+
p.close()
|
|
76
|
+
return wrapper
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# ------------------------------------------------------------------------------------ context
|
|
80
|
+
@_with_project
|
|
81
|
+
def get_resume_context(p: Project) -> Dict[str, Any]:
|
|
82
|
+
return _context.resume_context(p)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
get_project_context = get_resume_context
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@_with_project
|
|
89
|
+
def regenerate_context(p: Project) -> str:
|
|
90
|
+
return _context.write_current_md(p)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@_with_project
|
|
94
|
+
def show(p: Project, id_: str) -> Dict[str, Any]:
|
|
95
|
+
return _views.show(p, id_)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# ------------------------------------------------------------------------------------ questions
|
|
99
|
+
@_with_project
|
|
100
|
+
def list_questions(p: Project, status: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
101
|
+
return p.list("question", "status=?" if status else "", (status,) if status else ())
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
create_question = _with_project(_services.create_question)
|
|
105
|
+
update_question = _with_project(_services.update_question)
|
|
106
|
+
|
|
107
|
+
# ------------------------------------------------------------------------------------ experiments
|
|
108
|
+
create_experiment = _with_project(_services.create_experiment)
|
|
109
|
+
create_variant = _with_project(_services.create_variant)
|
|
110
|
+
update_experiment = _with_project(_services.update_experiment)
|
|
111
|
+
set_status = _with_project(_services.set_status)
|
|
112
|
+
synthesize = _with_project(_services.synthesize)
|
|
113
|
+
set_baseline = _with_project(_services.set_baseline)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@_with_project
|
|
117
|
+
def get_experiment(p: Project, exp_id: str) -> Dict[str, Any]:
|
|
118
|
+
return _views.experiment_detail(p, exp_id)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@_with_project
|
|
122
|
+
def list_experiments(p: Project, status: Optional[str] = None, question: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
123
|
+
where, args = [], []
|
|
124
|
+
if status:
|
|
125
|
+
where.append("status=?")
|
|
126
|
+
args.append(status)
|
|
127
|
+
if question:
|
|
128
|
+
from .schema import normalize_id
|
|
129
|
+
where.append("question_id=?")
|
|
130
|
+
args.append(normalize_id(question, "Q"))
|
|
131
|
+
return p.list("experiment", " AND ".join(where), tuple(args))
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------------------------ runs
|
|
135
|
+
create_run = _with_project(_runs.create_run)
|
|
136
|
+
attach_run = _with_project(_runs.attach_run)
|
|
137
|
+
update_run = _with_project(_runs.update_run)
|
|
138
|
+
get_run = _with_project(_runs.get_run)
|
|
139
|
+
list_runs = _with_project(_runs.list_runs)
|
|
140
|
+
exec_run = _with_project(_runs.exec_run)
|
|
141
|
+
submit_run = _with_project(_runs.submit_run)
|
|
142
|
+
cancel_run = _with_project(_runs.cancel_run)
|
|
143
|
+
list_artifacts = _with_project(_runs.list_artifacts)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def log_metric(name: str, value: Any, step: Optional[int] = None, unit: Optional[str] = None,
|
|
147
|
+
run: Optional[str] = None, experiment: Optional[str] = None,
|
|
148
|
+
project: Optional[Project] = None) -> Dict[str, Any]:
|
|
149
|
+
"""Log a metric. Inside a `research run` job (RESEARCH_RUN_DIR set) this only appends to the
|
|
150
|
+
run directory — safe on SLURM compute nodes, no database access."""
|
|
151
|
+
if run is None and experiment is None and project is None and _runs.in_job_run_dir():
|
|
152
|
+
return _runs.job_log_metric(name, value, step, unit)
|
|
153
|
+
return _with_project(_runs.log_metric)(name, value, step, unit, run, experiment, project=project)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def register_artifact(path: str, run: Optional[str] = None, experiment: Optional[str] = None,
|
|
157
|
+
name: Optional[str] = None, type: Optional[str] = None,
|
|
158
|
+
description: Optional[str] = None, tags: Any = None,
|
|
159
|
+
project: Optional[Project] = None, **kw: Any) -> Dict[str, Any]:
|
|
160
|
+
"""Register a file/dir by reference. Inside a running job this is recorded in the run dir
|
|
161
|
+
and ingested (assigned an A-id) the next time the project is synced."""
|
|
162
|
+
if run is None and experiment is None and project is None and _runs.in_job_run_dir():
|
|
163
|
+
return _runs.job_register_artifact(path, name, description, type, tags)
|
|
164
|
+
return _with_project(_runs.register_artifact)(path, run, experiment, name, type, description, tags,
|
|
165
|
+
project=project, **kw)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ------------------------------------------------------------------------------------ findings/decisions
|
|
169
|
+
create_finding = _with_project(_services.create_finding)
|
|
170
|
+
update_finding = _with_project(_services.update_finding)
|
|
171
|
+
supersede_finding = _with_project(_services.supersede_finding)
|
|
172
|
+
create_decision = _with_project(_services.create_decision)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@_with_project
|
|
176
|
+
def list_findings(p: Project, status: Optional[str] = None, kind: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
177
|
+
where, args = [], []
|
|
178
|
+
if status:
|
|
179
|
+
where.append("status=?")
|
|
180
|
+
args.append(status)
|
|
181
|
+
if kind:
|
|
182
|
+
where.append("kind=?")
|
|
183
|
+
args.append(kind)
|
|
184
|
+
return p.list("finding", " AND ".join(where), tuple(args))
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@_with_project
|
|
188
|
+
def list_decisions(p: Project, status: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
189
|
+
return p.list("decision", "status=?" if status else "", (status,) if status else ())
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# ------------------------------------------------------------------------------------ checkpoints/notes/skills
|
|
193
|
+
create_checkpoint = _with_project(_context.create_checkpoint)
|
|
194
|
+
checkpoint_draft = _with_project(_context.checkpoint_draft)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@_with_project
|
|
198
|
+
def list_checkpoints(p: Project) -> List[Dict[str, Any]]:
|
|
199
|
+
return p.list("checkpoint", order="created_at DESC, id DESC")
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
create_note = _with_project(_services.create_note)
|
|
203
|
+
list_notes = _with_project(_services.list_notes)
|
|
204
|
+
list_skills = _with_project(_services.list_skills)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# ------------------------------------------------------------------------------------ plans/tasks (Phase 0)
|
|
208
|
+
create_plan = _with_project(_plans.create_plan)
|
|
209
|
+
update_plan = _with_project(_plans.update_plan)
|
|
210
|
+
list_plans = _with_project(_plans.list_plans)
|
|
211
|
+
create_task = _with_project(_plans.create_task)
|
|
212
|
+
update_task = _with_project(_plans.update_task)
|
|
213
|
+
list_tasks = _with_project(_plans.list_tasks)
|
|
214
|
+
start_task = _with_project(_plans.start_task)
|
|
215
|
+
complete_task = _with_project(_plans.complete_task)
|
|
216
|
+
block_task = _with_project(_plans.block_task)
|
|
217
|
+
get_next_ready_task = _with_project(_plans.get_next_ready_task)
|
|
218
|
+
task_context = _with_project(_plans.task_context)
|
|
219
|
+
release_task = _with_project(_plans.release_task)
|
|
220
|
+
add_task_note = _with_project(_plans.add_task_note)
|
|
221
|
+
|
|
222
|
+
# ------------------------------------------------------------------------------------ verification, retrieval, agents
|
|
223
|
+
from . import agents as _agents # noqa: E402
|
|
224
|
+
from . import compare as _compare # noqa: E402
|
|
225
|
+
from . import report as _report # noqa: E402
|
|
226
|
+
from . import search as _search # noqa: E402
|
|
227
|
+
from . import skills as _skills # noqa: E402
|
|
228
|
+
from . import verification as _verification # noqa: E402
|
|
229
|
+
|
|
230
|
+
verify_task = _with_project(_verification.verify_task)
|
|
231
|
+
review_finding = _with_project(_verification.review_finding)
|
|
232
|
+
search = _with_project(_search.search)
|
|
233
|
+
compare_runs = _with_project(_compare.compare_runs)
|
|
234
|
+
sweep_run = _with_project(_runs.sweep_run)
|
|
235
|
+
write_report = _with_project(_report.write_report)
|
|
236
|
+
dispatch = _with_project(_agents.dispatch)
|
|
237
|
+
list_skills_full = _with_project(_skills.list_skills)
|
|
238
|
+
add_skills = _with_project(_skills.add_skills)
|
|
239
|
+
remove_skill = _with_project(_skills.remove_skill)
|
|
240
|
+
update_skills = _with_project(_skills.update_skills)
|
|
241
|
+
link_skills = _with_project(_skills.link_skills)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@_with_project
|
|
245
|
+
def get_plan(p: Project, plan_id: str) -> Dict[str, Any]:
|
|
246
|
+
"""Get plan with all its tasks and summary statistics."""
|
|
247
|
+
return _plans.get_plan_with_tasks(p, plan_id)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@_with_project
|
|
251
|
+
def get_task(p: Project, task_id: str) -> Dict[str, Any]:
|
|
252
|
+
"""Get task with resolved dependencies and readiness status."""
|
|
253
|
+
return _plans.get_task_with_deps(p, task_id)
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2017-2021 Ingy döt Net
|
|
2
|
+
Copyright (c) 2006-2016 Kirill Simonov
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
the Software without restriction, including without limitation the rights to
|
|
7
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
8
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
|
9
|
+
so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
|
|
2
|
+
from .error import *
|
|
3
|
+
|
|
4
|
+
from .tokens import *
|
|
5
|
+
from .events import *
|
|
6
|
+
from .nodes import *
|
|
7
|
+
|
|
8
|
+
from .loader import *
|
|
9
|
+
from .dumper import *
|
|
10
|
+
|
|
11
|
+
__version__ = '6.0.3'
|
|
12
|
+
try:
|
|
13
|
+
from .cyaml import *
|
|
14
|
+
__with_libyaml__ = True
|
|
15
|
+
except ImportError:
|
|
16
|
+
__with_libyaml__ = False
|
|
17
|
+
|
|
18
|
+
import io
|
|
19
|
+
|
|
20
|
+
#------------------------------------------------------------------------------
|
|
21
|
+
# XXX "Warnings control" is now deprecated. Leaving in the API function to not
|
|
22
|
+
# break code that uses it.
|
|
23
|
+
#------------------------------------------------------------------------------
|
|
24
|
+
def warnings(settings=None):
|
|
25
|
+
if settings is None:
|
|
26
|
+
return {}
|
|
27
|
+
|
|
28
|
+
#------------------------------------------------------------------------------
|
|
29
|
+
def scan(stream, Loader=Loader):
|
|
30
|
+
"""
|
|
31
|
+
Scan a YAML stream and produce scanning tokens.
|
|
32
|
+
"""
|
|
33
|
+
loader = Loader(stream)
|
|
34
|
+
try:
|
|
35
|
+
while loader.check_token():
|
|
36
|
+
yield loader.get_token()
|
|
37
|
+
finally:
|
|
38
|
+
loader.dispose()
|
|
39
|
+
|
|
40
|
+
def parse(stream, Loader=Loader):
|
|
41
|
+
"""
|
|
42
|
+
Parse a YAML stream and produce parsing events.
|
|
43
|
+
"""
|
|
44
|
+
loader = Loader(stream)
|
|
45
|
+
try:
|
|
46
|
+
while loader.check_event():
|
|
47
|
+
yield loader.get_event()
|
|
48
|
+
finally:
|
|
49
|
+
loader.dispose()
|
|
50
|
+
|
|
51
|
+
def compose(stream, Loader=Loader):
|
|
52
|
+
"""
|
|
53
|
+
Parse the first YAML document in a stream
|
|
54
|
+
and produce the corresponding representation tree.
|
|
55
|
+
"""
|
|
56
|
+
loader = Loader(stream)
|
|
57
|
+
try:
|
|
58
|
+
return loader.get_single_node()
|
|
59
|
+
finally:
|
|
60
|
+
loader.dispose()
|
|
61
|
+
|
|
62
|
+
def compose_all(stream, Loader=Loader):
|
|
63
|
+
"""
|
|
64
|
+
Parse all YAML documents in a stream
|
|
65
|
+
and produce corresponding representation trees.
|
|
66
|
+
"""
|
|
67
|
+
loader = Loader(stream)
|
|
68
|
+
try:
|
|
69
|
+
while loader.check_node():
|
|
70
|
+
yield loader.get_node()
|
|
71
|
+
finally:
|
|
72
|
+
loader.dispose()
|
|
73
|
+
|
|
74
|
+
def load(stream, Loader):
|
|
75
|
+
"""
|
|
76
|
+
Parse the first YAML document in a stream
|
|
77
|
+
and produce the corresponding Python object.
|
|
78
|
+
"""
|
|
79
|
+
loader = Loader(stream)
|
|
80
|
+
try:
|
|
81
|
+
return loader.get_single_data()
|
|
82
|
+
finally:
|
|
83
|
+
loader.dispose()
|
|
84
|
+
|
|
85
|
+
def load_all(stream, Loader):
|
|
86
|
+
"""
|
|
87
|
+
Parse all YAML documents in a stream
|
|
88
|
+
and produce corresponding Python objects.
|
|
89
|
+
"""
|
|
90
|
+
loader = Loader(stream)
|
|
91
|
+
try:
|
|
92
|
+
while loader.check_data():
|
|
93
|
+
yield loader.get_data()
|
|
94
|
+
finally:
|
|
95
|
+
loader.dispose()
|
|
96
|
+
|
|
97
|
+
def full_load(stream):
|
|
98
|
+
"""
|
|
99
|
+
Parse the first YAML document in a stream
|
|
100
|
+
and produce the corresponding Python object.
|
|
101
|
+
|
|
102
|
+
Resolve all tags except those known to be
|
|
103
|
+
unsafe on untrusted input.
|
|
104
|
+
"""
|
|
105
|
+
return load(stream, FullLoader)
|
|
106
|
+
|
|
107
|
+
def full_load_all(stream):
|
|
108
|
+
"""
|
|
109
|
+
Parse all YAML documents in a stream
|
|
110
|
+
and produce corresponding Python objects.
|
|
111
|
+
|
|
112
|
+
Resolve all tags except those known to be
|
|
113
|
+
unsafe on untrusted input.
|
|
114
|
+
"""
|
|
115
|
+
return load_all(stream, FullLoader)
|
|
116
|
+
|
|
117
|
+
def safe_load(stream):
|
|
118
|
+
"""
|
|
119
|
+
Parse the first YAML document in a stream
|
|
120
|
+
and produce the corresponding Python object.
|
|
121
|
+
|
|
122
|
+
Resolve only basic YAML tags. This is known
|
|
123
|
+
to be safe for untrusted input.
|
|
124
|
+
"""
|
|
125
|
+
return load(stream, SafeLoader)
|
|
126
|
+
|
|
127
|
+
def safe_load_all(stream):
|
|
128
|
+
"""
|
|
129
|
+
Parse all YAML documents in a stream
|
|
130
|
+
and produce corresponding Python objects.
|
|
131
|
+
|
|
132
|
+
Resolve only basic YAML tags. This is known
|
|
133
|
+
to be safe for untrusted input.
|
|
134
|
+
"""
|
|
135
|
+
return load_all(stream, SafeLoader)
|
|
136
|
+
|
|
137
|
+
def unsafe_load(stream):
|
|
138
|
+
"""
|
|
139
|
+
Parse the first YAML document in a stream
|
|
140
|
+
and produce the corresponding Python object.
|
|
141
|
+
|
|
142
|
+
Resolve all tags, even those known to be
|
|
143
|
+
unsafe on untrusted input.
|
|
144
|
+
"""
|
|
145
|
+
return load(stream, UnsafeLoader)
|
|
146
|
+
|
|
147
|
+
def unsafe_load_all(stream):
|
|
148
|
+
"""
|
|
149
|
+
Parse all YAML documents in a stream
|
|
150
|
+
and produce corresponding Python objects.
|
|
151
|
+
|
|
152
|
+
Resolve all tags, even those known to be
|
|
153
|
+
unsafe on untrusted input.
|
|
154
|
+
"""
|
|
155
|
+
return load_all(stream, UnsafeLoader)
|
|
156
|
+
|
|
157
|
+
def emit(events, stream=None, Dumper=Dumper,
|
|
158
|
+
canonical=None, indent=None, width=None,
|
|
159
|
+
allow_unicode=None, line_break=None):
|
|
160
|
+
"""
|
|
161
|
+
Emit YAML parsing events into a stream.
|
|
162
|
+
If stream is None, return the produced string instead.
|
|
163
|
+
"""
|
|
164
|
+
getvalue = None
|
|
165
|
+
if stream is None:
|
|
166
|
+
stream = io.StringIO()
|
|
167
|
+
getvalue = stream.getvalue
|
|
168
|
+
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
|
169
|
+
allow_unicode=allow_unicode, line_break=line_break)
|
|
170
|
+
try:
|
|
171
|
+
for event in events:
|
|
172
|
+
dumper.emit(event)
|
|
173
|
+
finally:
|
|
174
|
+
dumper.dispose()
|
|
175
|
+
if getvalue:
|
|
176
|
+
return getvalue()
|
|
177
|
+
|
|
178
|
+
def serialize_all(nodes, stream=None, Dumper=Dumper,
|
|
179
|
+
canonical=None, indent=None, width=None,
|
|
180
|
+
allow_unicode=None, line_break=None,
|
|
181
|
+
encoding=None, explicit_start=None, explicit_end=None,
|
|
182
|
+
version=None, tags=None):
|
|
183
|
+
"""
|
|
184
|
+
Serialize a sequence of representation trees into a YAML stream.
|
|
185
|
+
If stream is None, return the produced string instead.
|
|
186
|
+
"""
|
|
187
|
+
getvalue = None
|
|
188
|
+
if stream is None:
|
|
189
|
+
if encoding is None:
|
|
190
|
+
stream = io.StringIO()
|
|
191
|
+
else:
|
|
192
|
+
stream = io.BytesIO()
|
|
193
|
+
getvalue = stream.getvalue
|
|
194
|
+
dumper = Dumper(stream, canonical=canonical, indent=indent, width=width,
|
|
195
|
+
allow_unicode=allow_unicode, line_break=line_break,
|
|
196
|
+
encoding=encoding, version=version, tags=tags,
|
|
197
|
+
explicit_start=explicit_start, explicit_end=explicit_end)
|
|
198
|
+
try:
|
|
199
|
+
dumper.open()
|
|
200
|
+
for node in nodes:
|
|
201
|
+
dumper.serialize(node)
|
|
202
|
+
dumper.close()
|
|
203
|
+
finally:
|
|
204
|
+
dumper.dispose()
|
|
205
|
+
if getvalue:
|
|
206
|
+
return getvalue()
|
|
207
|
+
|
|
208
|
+
def serialize(node, stream=None, Dumper=Dumper, **kwds):
|
|
209
|
+
"""
|
|
210
|
+
Serialize a representation tree into a YAML stream.
|
|
211
|
+
If stream is None, return the produced string instead.
|
|
212
|
+
"""
|
|
213
|
+
return serialize_all([node], stream, Dumper=Dumper, **kwds)
|
|
214
|
+
|
|
215
|
+
def dump_all(documents, stream=None, Dumper=Dumper,
|
|
216
|
+
default_style=None, default_flow_style=False,
|
|
217
|
+
canonical=None, indent=None, width=None,
|
|
218
|
+
allow_unicode=None, line_break=None,
|
|
219
|
+
encoding=None, explicit_start=None, explicit_end=None,
|
|
220
|
+
version=None, tags=None, sort_keys=True):
|
|
221
|
+
"""
|
|
222
|
+
Serialize a sequence of Python objects into a YAML stream.
|
|
223
|
+
If stream is None, return the produced string instead.
|
|
224
|
+
"""
|
|
225
|
+
getvalue = None
|
|
226
|
+
if stream is None:
|
|
227
|
+
if encoding is None:
|
|
228
|
+
stream = io.StringIO()
|
|
229
|
+
else:
|
|
230
|
+
stream = io.BytesIO()
|
|
231
|
+
getvalue = stream.getvalue
|
|
232
|
+
dumper = Dumper(stream, default_style=default_style,
|
|
233
|
+
default_flow_style=default_flow_style,
|
|
234
|
+
canonical=canonical, indent=indent, width=width,
|
|
235
|
+
allow_unicode=allow_unicode, line_break=line_break,
|
|
236
|
+
encoding=encoding, version=version, tags=tags,
|
|
237
|
+
explicit_start=explicit_start, explicit_end=explicit_end, sort_keys=sort_keys)
|
|
238
|
+
try:
|
|
239
|
+
dumper.open()
|
|
240
|
+
for data in documents:
|
|
241
|
+
dumper.represent(data)
|
|
242
|
+
dumper.close()
|
|
243
|
+
finally:
|
|
244
|
+
dumper.dispose()
|
|
245
|
+
if getvalue:
|
|
246
|
+
return getvalue()
|
|
247
|
+
|
|
248
|
+
def dump(data, stream=None, Dumper=Dumper, **kwds):
|
|
249
|
+
"""
|
|
250
|
+
Serialize a Python object into a YAML stream.
|
|
251
|
+
If stream is None, return the produced string instead.
|
|
252
|
+
"""
|
|
253
|
+
return dump_all([data], stream, Dumper=Dumper, **kwds)
|
|
254
|
+
|
|
255
|
+
def safe_dump_all(documents, stream=None, **kwds):
|
|
256
|
+
"""
|
|
257
|
+
Serialize a sequence of Python objects into a YAML stream.
|
|
258
|
+
Produce only basic YAML tags.
|
|
259
|
+
If stream is None, return the produced string instead.
|
|
260
|
+
"""
|
|
261
|
+
return dump_all(documents, stream, Dumper=SafeDumper, **kwds)
|
|
262
|
+
|
|
263
|
+
def safe_dump(data, stream=None, **kwds):
|
|
264
|
+
"""
|
|
265
|
+
Serialize a Python object into a YAML stream.
|
|
266
|
+
Produce only basic YAML tags.
|
|
267
|
+
If stream is None, return the produced string instead.
|
|
268
|
+
"""
|
|
269
|
+
return dump_all([data], stream, Dumper=SafeDumper, **kwds)
|
|
270
|
+
|
|
271
|
+
def add_implicit_resolver(tag, regexp, first=None,
|
|
272
|
+
Loader=None, Dumper=Dumper):
|
|
273
|
+
"""
|
|
274
|
+
Add an implicit scalar detector.
|
|
275
|
+
If an implicit scalar value matches the given regexp,
|
|
276
|
+
the corresponding tag is assigned to the scalar.
|
|
277
|
+
first is a sequence of possible initial characters or None.
|
|
278
|
+
"""
|
|
279
|
+
if Loader is None:
|
|
280
|
+
loader.Loader.add_implicit_resolver(tag, regexp, first)
|
|
281
|
+
loader.FullLoader.add_implicit_resolver(tag, regexp, first)
|
|
282
|
+
loader.UnsafeLoader.add_implicit_resolver(tag, regexp, first)
|
|
283
|
+
else:
|
|
284
|
+
Loader.add_implicit_resolver(tag, regexp, first)
|
|
285
|
+
Dumper.add_implicit_resolver(tag, regexp, first)
|
|
286
|
+
|
|
287
|
+
def add_path_resolver(tag, path, kind=None, Loader=None, Dumper=Dumper):
|
|
288
|
+
"""
|
|
289
|
+
Add a path based resolver for the given tag.
|
|
290
|
+
A path is a list of keys that forms a path
|
|
291
|
+
to a node in the representation tree.
|
|
292
|
+
Keys can be string values, integers, or None.
|
|
293
|
+
"""
|
|
294
|
+
if Loader is None:
|
|
295
|
+
loader.Loader.add_path_resolver(tag, path, kind)
|
|
296
|
+
loader.FullLoader.add_path_resolver(tag, path, kind)
|
|
297
|
+
loader.UnsafeLoader.add_path_resolver(tag, path, kind)
|
|
298
|
+
else:
|
|
299
|
+
Loader.add_path_resolver(tag, path, kind)
|
|
300
|
+
Dumper.add_path_resolver(tag, path, kind)
|
|
301
|
+
|
|
302
|
+
def add_constructor(tag, constructor, Loader=None):
|
|
303
|
+
"""
|
|
304
|
+
Add a constructor for the given tag.
|
|
305
|
+
Constructor is a function that accepts a Loader instance
|
|
306
|
+
and a node object and produces the corresponding Python object.
|
|
307
|
+
"""
|
|
308
|
+
if Loader is None:
|
|
309
|
+
loader.Loader.add_constructor(tag, constructor)
|
|
310
|
+
loader.FullLoader.add_constructor(tag, constructor)
|
|
311
|
+
loader.UnsafeLoader.add_constructor(tag, constructor)
|
|
312
|
+
else:
|
|
313
|
+
Loader.add_constructor(tag, constructor)
|
|
314
|
+
|
|
315
|
+
def add_multi_constructor(tag_prefix, multi_constructor, Loader=None):
|
|
316
|
+
"""
|
|
317
|
+
Add a multi-constructor for the given tag prefix.
|
|
318
|
+
Multi-constructor is called for a node if its tag starts with tag_prefix.
|
|
319
|
+
Multi-constructor accepts a Loader instance, a tag suffix,
|
|
320
|
+
and a node object and produces the corresponding Python object.
|
|
321
|
+
"""
|
|
322
|
+
if Loader is None:
|
|
323
|
+
loader.Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
324
|
+
loader.FullLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
325
|
+
loader.UnsafeLoader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
326
|
+
else:
|
|
327
|
+
Loader.add_multi_constructor(tag_prefix, multi_constructor)
|
|
328
|
+
|
|
329
|
+
def add_representer(data_type, representer, Dumper=Dumper):
|
|
330
|
+
"""
|
|
331
|
+
Add a representer for the given type.
|
|
332
|
+
Representer is a function accepting a Dumper instance
|
|
333
|
+
and an instance of the given data type
|
|
334
|
+
and producing the corresponding representation node.
|
|
335
|
+
"""
|
|
336
|
+
Dumper.add_representer(data_type, representer)
|
|
337
|
+
|
|
338
|
+
def add_multi_representer(data_type, multi_representer, Dumper=Dumper):
|
|
339
|
+
"""
|
|
340
|
+
Add a representer for the given type.
|
|
341
|
+
Multi-representer is a function accepting a Dumper instance
|
|
342
|
+
and an instance of the given data type or subtype
|
|
343
|
+
and producing the corresponding representation node.
|
|
344
|
+
"""
|
|
345
|
+
Dumper.add_multi_representer(data_type, multi_representer)
|
|
346
|
+
|
|
347
|
+
class YAMLObjectMetaclass(type):
|
|
348
|
+
"""
|
|
349
|
+
The metaclass for YAMLObject.
|
|
350
|
+
"""
|
|
351
|
+
def __init__(cls, name, bases, kwds):
|
|
352
|
+
super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
|
|
353
|
+
if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
|
|
354
|
+
if isinstance(cls.yaml_loader, list):
|
|
355
|
+
for loader in cls.yaml_loader:
|
|
356
|
+
loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
|
357
|
+
else:
|
|
358
|
+
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
|
|
359
|
+
|
|
360
|
+
cls.yaml_dumper.add_representer(cls, cls.to_yaml)
|
|
361
|
+
|
|
362
|
+
class YAMLObject(metaclass=YAMLObjectMetaclass):
|
|
363
|
+
"""
|
|
364
|
+
An object that can dump itself to a YAML stream
|
|
365
|
+
and load itself from a YAML stream.
|
|
366
|
+
"""
|
|
367
|
+
|
|
368
|
+
__slots__ = () # no direct instantiation, so allow immutable subclasses
|
|
369
|
+
|
|
370
|
+
yaml_loader = [Loader, FullLoader, UnsafeLoader]
|
|
371
|
+
yaml_dumper = Dumper
|
|
372
|
+
|
|
373
|
+
yaml_tag = None
|
|
374
|
+
yaml_flow_style = None
|
|
375
|
+
|
|
376
|
+
@classmethod
|
|
377
|
+
def from_yaml(cls, loader, node):
|
|
378
|
+
"""
|
|
379
|
+
Convert a representation node to a Python object.
|
|
380
|
+
"""
|
|
381
|
+
return loader.construct_yaml_object(node, cls)
|
|
382
|
+
|
|
383
|
+
@classmethod
|
|
384
|
+
def to_yaml(cls, dumper, data):
|
|
385
|
+
"""
|
|
386
|
+
Convert a Python object to a representation node.
|
|
387
|
+
"""
|
|
388
|
+
return dumper.represent_yaml_object(cls.yaml_tag, data, cls,
|
|
389
|
+
flow_style=cls.yaml_flow_style)
|
|
390
|
+
|