whybook 0.1.0__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.
Files changed (168) hide show
  1. epi/__init__.py +15 -0
  2. whybook/__init__.py +65 -0
  3. whybook/_display.py +49 -0
  4. whybook/_progress.py +34 -0
  5. whybook/_version.py +4 -0
  6. whybook/explore.py +838 -0
  7. whybook/kernels/__init__.py +5 -0
  8. whybook/kernels/sas.py +74 -0
  9. whybook/plots.py +347 -0
  10. whybook/sandbox/__init__.py +15 -0
  11. whybook/sandbox/__main__.py +7 -0
  12. whybook/sandbox/bwrap.py +164 -0
  13. whybook/sandbox/codex/LICENSE +201 -0
  14. whybook/sandbox/codex/NOTICE +6 -0
  15. whybook/sandbox/codex/seatbelt_base_policy.sbpl +121 -0
  16. whybook/sandbox/codex/seatbelt_read_only_platform_defaults.sbpl +193 -0
  17. whybook/sandbox/kernelspec.py +198 -0
  18. whybook/sandbox/policy.py +131 -0
  19. whybook/sandbox/provisioner.py +495 -0
  20. whybook/sandbox/seatbelt.py +165 -0
  21. whybook/server/__init__.py +34 -0
  22. whybook/server/agent.py +1011 -0
  23. whybook/server/cell_titles.py +128 -0
  24. whybook/server/claude.py +384 -0
  25. whybook/server/codegen.py +694 -0
  26. whybook/server/config.py +231 -0
  27. whybook/server/connection.py +418 -0
  28. whybook/server/databases.py +119 -0
  29. whybook/server/dependencies.py +335 -0
  30. whybook/server/frame_notes.py +105 -0
  31. whybook/server/kernel_code/analyze_cells.py +763 -0
  32. whybook/server/kernel_code/inspect_variables.py +507 -0
  33. whybook/server/kernel_code/kernel_facts.py +57 -0
  34. whybook/server/kernel_code/plot_hooks.py +675 -0
  35. whybook/server/kernel_code/r/analyze_cells.R +1102 -0
  36. whybook/server/kernel_code/r/inspect_variables.R +240 -0
  37. whybook/server/kernel_code/r/kernel_facts.R +17 -0
  38. whybook/server/kernel_code/r/write_frames.R +61 -0
  39. whybook/server/kernel_code/region_summary.py +112 -0
  40. whybook/server/kernel_code/table_rows.py +605 -0
  41. whybook/server/kernel_code/write_frames.py +123 -0
  42. whybook/server/keystore.py +126 -0
  43. whybook/server/library_defaults.py +349 -0
  44. whybook/server/local_models.py +1209 -0
  45. whybook/server/model_client.py +650 -0
  46. whybook/server/privacy.py +323 -0
  47. whybook/server/providers.py +442 -0
  48. whybook/server/questions/__init__.py +1 -0
  49. whybook/server/questions/cells.py +1063 -0
  50. whybook/server/questions/claude_questions.py +681 -0
  51. whybook/server/questions/drops.py +849 -0
  52. whybook/server/questions/files.py +307 -0
  53. whybook/server/questions/learned_ranker.json +74 -0
  54. whybook/server/questions/models.py +370 -0
  55. whybook/server/questions/rankers.py +206 -0
  56. whybook/server/questions/ranking.py +202 -0
  57. whybook/server/questions/reshape.py +144 -0
  58. whybook/server/questions/review.py +267 -0
  59. whybook/server/questions/starts.py +329 -0
  60. whybook/server/questions/tables.py +202 -0
  61. whybook/server/questions/templates.py +224 -0
  62. whybook/server/questions/values.py +754 -0
  63. whybook/server/routes.py +994 -0
  64. whybook/server/signin.py +287 -0
  65. whybook/server/solve.py +408 -0
  66. whybook/server/sorting.py +143 -0
  67. whybook/server/speech.py +292 -0
  68. whybook/server/table_facts.py +611 -0
  69. whybook/server/table_notes.py +113 -0
  70. whybook/server/tests/__init__.py +1 -0
  71. whybook/server/tests/data/secret_names.json +311 -0
  72. whybook/server/tests/demo_state.py +120 -0
  73. whybook/server/tests/test_agent.py +398 -0
  74. whybook/server/tests/test_agent_answers.py +194 -0
  75. whybook/server/tests/test_agent_prompt.py +102 -0
  76. whybook/server/tests/test_cell_titles.py +96 -0
  77. whybook/server/tests/test_chip_rules.py +127 -0
  78. whybook/server/tests/test_claude.py +232 -0
  79. whybook/server/tests/test_claude_code_login.py +27 -0
  80. whybook/server/tests/test_codegen.py +176 -0
  81. whybook/server/tests/test_connection.py +266 -0
  82. whybook/server/tests/test_constant_kinds.py +265 -0
  83. whybook/server/tests/test_cross_kernel.py +345 -0
  84. whybook/server/tests/test_databases.py +76 -0
  85. whybook/server/tests/test_decisions.py +248 -0
  86. whybook/server/tests/test_demo_templates.py +153 -0
  87. whybook/server/tests/test_dependencies.py +81 -0
  88. whybook/server/tests/test_dogfood2_templates.py +477 -0
  89. whybook/server/tests/test_dogfood2_view.py +32 -0
  90. whybook/server/tests/test_dogfood_templates.py +386 -0
  91. whybook/server/tests/test_drop_templates.py +115 -0
  92. whybook/server/tests/test_files.py +60 -0
  93. whybook/server/tests/test_first_drops.py +249 -0
  94. whybook/server/tests/test_frame_notes.py +78 -0
  95. whybook/server/tests/test_home_energy.py +81 -0
  96. whybook/server/tests/test_image_solve.py +116 -0
  97. whybook/server/tests/test_kernel_code.py +301 -0
  98. whybook/server/tests/test_key_check.py +302 -0
  99. whybook/server/tests/test_later_demo.py +67 -0
  100. whybook/server/tests/test_learned_order.py +54 -0
  101. whybook/server/tests/test_library_defaults.py +295 -0
  102. whybook/server/tests/test_list_prices.py +133 -0
  103. whybook/server/tests/test_local_models.py +800 -0
  104. whybook/server/tests/test_model_client.py +345 -0
  105. whybook/server/tests/test_model_questions.py +265 -0
  106. whybook/server/tests/test_no_template.py +93 -0
  107. whybook/server/tests/test_notebook_helpers.py +291 -0
  108. whybook/server/tests/test_notes.py +70 -0
  109. whybook/server/tests/test_plot_hooks.py +649 -0
  110. whybook/server/tests/test_privacy.py +187 -0
  111. whybook/server/tests/test_providers.py +313 -0
  112. whybook/server/tests/test_question_timing.py +110 -0
  113. whybook/server/tests/test_questions.py +157 -0
  114. whybook/server/tests/test_r_analysis.py +520 -0
  115. whybook/server/tests/test_ranking.py +123 -0
  116. whybook/server/tests/test_refusals.py +96 -0
  117. whybook/server/tests/test_review_questions.py +163 -0
  118. whybook/server/tests/test_routes.py +167 -0
  119. whybook/server/tests/test_sandbox.py +902 -0
  120. whybook/server/tests/test_sas_demo.py +363 -0
  121. whybook/server/tests/test_sas_kernel.py +104 -0
  122. whybook/server/tests/test_secret_names.py +62 -0
  123. whybook/server/tests/test_settings.py +31 -0
  124. whybook/server/tests/test_signatures.py +164 -0
  125. whybook/server/tests/test_signin.py +327 -0
  126. whybook/server/tests/test_solve.py +139 -0
  127. whybook/server/tests/test_sorting.py +254 -0
  128. whybook/server/tests/test_speech.py +317 -0
  129. whybook/server/tests/test_start_questions.py +341 -0
  130. whybook/server/tests/test_table_notes.py +91 -0
  131. whybook/server/tests/test_table_rows.py +296 -0
  132. whybook/server/tests/test_task_models.py +123 -0
  133. whybook/server/tests/test_template_names.py +155 -0
  134. whybook/server/tests/test_template_values.py +35 -0
  135. whybook/server/tests/test_temporaries.py +214 -0
  136. whybook/server/tests/test_zero_data_retention.py +140 -0
  137. whybook/server/tiers.py +110 -0
  138. whybook-0.1.0.data/data/etc/jupyter/jupyter_server_config.d/whybook.json +7 -0
  139. whybook-0.1.0.data/data/share/jupyter/kernels/python3-sandboxed/kernel.json +11 -0
  140. whybook-0.1.0.data/data/share/jupyter/kernels/python3-sandboxed/logo-32x32.png +0 -0
  141. whybook-0.1.0.data/data/share/jupyter/kernels/python3-sandboxed/logo-64x64.png +0 -0
  142. whybook-0.1.0.data/data/share/jupyter/kernels/python3-sandboxed/logo-svg.svg +1 -0
  143. whybook-0.1.0.data/data/share/jupyter/kernels/sas-licence-needed/kernel.json +6 -0
  144. whybook-0.1.0.data/data/share/jupyter/kernels/sas-licence-needed/logo-32x32.png +0 -0
  145. whybook-0.1.0.data/data/share/jupyter/kernels/sas-licence-needed/logo-64x64.png +0 -0
  146. whybook-0.1.0.data/data/share/jupyter/kernels/sas-licence-needed/logo-svg.svg +1 -0
  147. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/build_log.json +731 -0
  148. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/install.json +5 -0
  149. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/package.json +190 -0
  150. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/schemas/whybook/agent-runs.json +16 -0
  151. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/schemas/whybook/checkup.json +39 -0
  152. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/schemas/whybook/package.json.orig +185 -0
  153. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/schemas/whybook/plugin.json +437 -0
  154. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/schemas/whybook/reproduce.json +28 -0
  155. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/lib_index_js.2e1a92730036e254.js +38961 -0
  156. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/lib_index_js.2e1a92730036e254.js.map +1 -0
  157. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/remoteEntry.7d8f48217cb3932b.js +1008 -0
  158. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/remoteEntry.7d8f48217cb3932b.js.map +1 -0
  159. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/style.js +4 -0
  160. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/style_index_js.050953e2cb74c362.js +7434 -0
  161. whybook-0.1.0.data/data/share/jupyter/labextensions/whybook/static/style_index_js.050953e2cb74c362.js.map +1 -0
  162. whybook-0.1.0.dist-info/METADATA +109 -0
  163. whybook-0.1.0.dist-info/RECORD +168 -0
  164. whybook-0.1.0.dist-info/WHEEL +4 -0
  165. whybook-0.1.0.dist-info/entry_points.txt +2 -0
  166. whybook-0.1.0.dist-info/licenses/LICENSE +29 -0
  167. whybook-0.1.0.dist-info/licenses/whybook/sandbox/codex/LICENSE +201 -0
  168. whybook-0.1.0.dist-info/licenses/whybook/sandbox/codex/NOTICE +6 -0
epi/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """The former name of the helpers in ``whybook``, kept so that saved notebooks run.
2
+
3
+ ``import epi`` warns and gives the same helpers; new code uses ``import whybook``.
4
+ """
5
+
6
+ import warnings
7
+
8
+ import whybook
9
+ from whybook import __all__ # noqa: F401
10
+
11
+ warnings.warn("epi is now whybook: use `import whybook`", DeprecationWarning, stacklevel=2)
12
+
13
+
14
+ def __getattr__(name):
15
+ return getattr(whybook, name)
whybook/__init__.py ADDED
@@ -0,0 +1,65 @@
1
+ """Whybook: a question-driven view of Jupyter notebooks.
2
+
3
+ In a notebook, ``import whybook`` gives the helpers that the view reads:
4
+ plots whose marks keep the rows behind them, so that the view can ask about
5
+ the rows in a region of a plot, and ``progress``, which shows as a progress
6
+ bar on the cell that calls it, also in a branch that runs in a subshell.
7
+ They load on first use, so that the Jupyter server, which imports this
8
+ package to find its extension, loads no plotting code.
9
+
10
+ The Jupyter server extension is ``whybook.server``.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import importlib
16
+ from typing import Any
17
+
18
+ # Each helper, and the module that defines it.
19
+ _HELPERS = {
20
+ "bars": "plots",
21
+ "hist": "plots",
22
+ "ribbon": "plots",
23
+ "scatter": "plots",
24
+ "progress": "_progress",
25
+ "by_group": "explore",
26
+ "compare_frames": "explore",
27
+ "compare_levels": "explore",
28
+ "cross_table": "explore",
29
+ "icc": "explore",
30
+ "line_up": "explore",
31
+ "profile": "explore",
32
+ "rows_per_unit": "explore",
33
+ "screen": "explore",
34
+ "summary": "explore",
35
+ "time_profile": "explore",
36
+ "who_is_in": "explore",
37
+ "within_between": "explore",
38
+ }
39
+
40
+ __all__ = sorted(_HELPERS)
41
+
42
+
43
+ def __getattr__(name: str) -> Any:
44
+ module = _HELPERS.get(name)
45
+ if module is None:
46
+ raise AttributeError(f"module 'whybook' has no attribute {name!r}")
47
+ return getattr(importlib.import_module(f".{module}", __name__), name)
48
+
49
+
50
+ def __dir__() -> list[str]:
51
+ return sorted(set(globals()) | set(_HELPERS))
52
+
53
+
54
+ try:
55
+ from ._version import __version__
56
+ except ImportError: # a checkout that pip has not installed
57
+ __version__ = "dev"
58
+
59
+
60
+ def _jupyter_labextension_paths():
61
+ return [{"src": "labextension", "dest": "whybook"}]
62
+
63
+
64
+ def _jupyter_server_extension_points():
65
+ return [{"module": "whybook.server"}]
whybook/_display.py ADDED
@@ -0,0 +1,49 @@
1
+ """Display helpers shared by the plotting and progress functions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+ PLOT_MIME = "application/vnd.whybook.plot+json"
8
+ PROGRESS_MIME = "application/vnd.whybook.progress+json"
9
+
10
+
11
+ def shell() -> Any:
12
+ try:
13
+ from IPython import get_ipython
14
+ except ImportError:
15
+ return None
16
+ return get_ipython()
17
+
18
+
19
+ def name_of(value: Any) -> str | None:
20
+ """The name of a user variable that holds ``value``, if there is one."""
21
+ ip = shell()
22
+ if ip is None:
23
+ return None
24
+ for name, candidate in list(ip.user_ns.items()):
25
+ if candidate is value and not name.startswith("_"):
26
+ return name
27
+ return None
28
+
29
+
30
+ def current_request() -> str | None:
31
+ """The id of the execute request that is running in this thread.
32
+
33
+ ipykernel 7 keeps the parent message in a context variable, so this is
34
+ also right inside a kernel subshell.
35
+ """
36
+ ip = shell()
37
+ kernel = getattr(ip, "kernel", None)
38
+ if kernel is None:
39
+ return None
40
+ try:
41
+ return kernel.get_parent()["header"]["msg_id"]
42
+ except (KeyError, TypeError, AttributeError):
43
+ return None
44
+
45
+
46
+ def show(bundle: dict[str, Any], **kwargs: Any) -> None:
47
+ from IPython.display import display
48
+
49
+ display(bundle, raw=True, **kwargs)
whybook/_progress.py ADDED
@@ -0,0 +1,34 @@
1
+ """Progress bars for long cells, including branches that run in subshells."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+
7
+ from ._display import PROGRESS_MIME, current_request, show
8
+
9
+ # One display per execute request: a new run of the cell starts a new bar.
10
+ _displays: dict[str | None, str] = {}
11
+
12
+
13
+ def progress(fraction: float, stage: str | None = None) -> None:
14
+ """Report how far the running cell is, from 0 to 1.
15
+
16
+ The Whybook view draws a progress bar on the cell. A classic notebook
17
+ shows the same report as one line of text that updates in place.
18
+ """
19
+ fraction = min(max(float(fraction), 0.0), 1.0)
20
+ request = current_request()
21
+ bundle = {
22
+ PROGRESS_MIME: {"fraction": fraction, "stage": stage},
23
+ "text/plain": f"[{fraction:4.0%}] {stage or ''}".rstrip(),
24
+ }
25
+ display_id = _displays.get(request)
26
+ if display_id is None:
27
+ display_id = _displays[request] = uuid.uuid4().hex
28
+ show(bundle, display_id=display_id)
29
+ else:
30
+ from IPython.display import update_display
31
+
32
+ update_display(bundle, raw=True, display_id=display_id)
33
+ if fraction >= 1.0:
34
+ _displays.pop(request, None)
whybook/_version.py ADDED
@@ -0,0 +1,4 @@
1
+ # This file is auto-generated by Hatchling. As such, do not:
2
+ # - modify
3
+ # - track in version control e.g. be sure to add to .gitignore
4
+ __version__ = VERSION = '0.1.0'