├── .codecov.yml ├── .coveragerc ├── .dockerignore ├── .gitignore ├── .gitlab-ci.yml ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── PULL_REQUEST_TEMPLATE.md ├── README.rst ├── cauldron-app ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── jest.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.scss │ ├── App.vue │ ├── Variables.scss │ ├── assets │ │ └── logo.png │ ├── components │ │ ├── Notebook │ │ │ └── Notebook.vue │ │ ├── alertDialog │ │ │ └── AlertDialog.vue │ │ ├── browser │ │ │ ├── Browser.vue │ │ │ ├── File.vue │ │ │ ├── Folder.vue │ │ │ ├── ProjectFolder.vue │ │ │ └── StandardPathButton.vue │ │ ├── confirmDialog │ │ │ └── ConfirmDialog.vue │ │ ├── errorOverlay │ │ │ └── ErrorOverlay.vue │ │ ├── loader │ │ │ └── Loader.vue │ │ ├── lostConnectionOverlay │ │ │ └── LostConnectionOverlay.vue │ │ ├── modalScrim │ │ │ └── ModalScrim.vue │ │ ├── saver │ │ │ └── Saver.vue │ │ ├── spinner │ │ │ └── Spinner.vue │ │ └── warningOverlay │ │ │ └── WarningOverlay.vue │ ├── emitter.js │ ├── exceptions.js │ ├── http.js │ ├── loading.js │ ├── main.js │ ├── notebook.js │ ├── router.js │ ├── stepper.js │ ├── store.js │ ├── utils.js │ └── views │ │ ├── create │ │ └── Create.vue │ │ ├── home │ │ ├── Home.vue │ │ ├── RecentItem.vue │ │ ├── RemoteConnect.vue │ │ └── logo-128.png │ │ ├── open │ │ ├── Open.vue │ │ ├── ProjectItem.vue │ │ └── ProjectItemGroup.vue │ │ ├── project │ │ ├── MenuStrip │ │ │ ├── MenuButton.vue │ │ │ ├── MenuStrip.vue │ │ │ ├── MenuStripItem.vue │ │ │ ├── ProjectMenuOverlay.vue │ │ │ └── StepMenuOverlay.vue │ │ ├── Project.vue │ │ ├── RunStrip │ │ │ ├── FollowToggle.vue │ │ │ ├── RunStrip.vue │ │ │ ├── RunStripStep.vue │ │ │ └── stateStyles │ │ │ │ ├── clean.scss │ │ │ │ ├── dirty.scss │ │ │ │ ├── error.scss │ │ │ │ ├── queued.scss │ │ │ │ ├── running.scss │ │ │ │ ├── unknown.scss │ │ │ │ └── untouched.scss │ │ └── StepSettingsModal │ │ │ ├── DeleteConfirmation.vue │ │ │ └── StepSettingsModal.vue │ │ └── viewer │ │ ├── ViewMenuStrip │ │ └── ViewMenuStrip.vue │ │ └── Viewer.vue ├── tests │ └── unit │ │ ├── .eslintrc.js │ │ └── example.spec.js ├── vue.config.js └── webpack.config.js ├── cauldron-web ├── .eslintrc ├── .gitignore ├── deploy.py ├── package.json ├── src │ ├── js │ │ ├── app │ │ │ ├── header.js │ │ │ ├── interaction.js │ │ │ ├── loader.js │ │ │ ├── parser.js │ │ │ ├── resizer.js │ │ │ ├── updating │ │ │ │ ├── renaming.js │ │ │ │ └── updates.js │ │ │ └── utils.js │ │ └── initialize.js │ ├── project.html │ ├── project.js │ ├── project.scss │ └── style │ │ ├── app │ │ ├── body │ │ │ ├── Header.scss │ │ │ ├── Listing.scss │ │ │ ├── body.scss │ │ │ ├── body_pylab.scss │ │ │ ├── body_table.scss │ │ │ └── body_text.scss │ │ ├── code_box.scss │ │ ├── deprecated.scss │ │ ├── error.scss │ │ ├── general.scss │ │ ├── project_header.scss │ │ ├── project_step.scss │ │ ├── step_style.scss │ │ └── vars.scss │ │ ├── css │ │ ├── analysis.css │ │ └── shared.css │ │ ├── icons.scss │ │ ├── pygments.scss │ │ └── templates │ │ ├── ProjectStep.scss │ │ ├── StdErr.scss │ │ └── StepStop.scss └── webpack.config.js ├── cauldron ├── __init__.py ├── cli │ ├── __init__.py │ ├── batcher.py │ ├── commander.py │ ├── commands │ │ ├── __init__.py │ │ ├── alias.py │ │ ├── cd.py │ │ ├── clear.py │ │ ├── close.py │ │ ├── configure │ │ │ ├── __init__.py │ │ │ └── actions.py │ │ ├── connect.py │ │ ├── create │ │ │ ├── __init__.py │ │ │ └── actions.py │ │ ├── disconnect.py │ │ ├── exit.py │ │ ├── export.py │ │ ├── listing │ │ │ ├── __init__.py │ │ │ ├── _lister.py │ │ │ ├── _remover.py │ │ │ ├── _utils.py │ │ │ └── discovery.py │ │ ├── ls.py │ │ ├── open │ │ │ ├── __init__.py │ │ │ ├── actions.py │ │ │ ├── opener.py │ │ │ └── remote.py │ │ ├── purge.py │ │ ├── refresh.py │ │ ├── reload.py │ │ ├── run │ │ │ ├── __init__.py │ │ │ └── actions.py │ │ ├── save.py │ │ ├── show.py │ │ ├── status.py │ │ ├── steps │ │ │ ├── __init__.py │ │ │ ├── actions.py │ │ │ ├── removal.py │ │ │ ├── renaming.py │ │ │ └── selection.py │ │ ├── sync │ │ │ ├── __init__.py │ │ │ └── syncer.py │ │ ├── ui.py │ │ ├── version.py │ │ └── view.py │ ├── interaction │ │ ├── __init__.py │ │ ├── autocompletion.py │ │ └── query.py │ ├── parse.py │ ├── server │ │ ├── __init__.py │ │ ├── arguments.py │ │ ├── authorization.py │ │ ├── routes │ │ │ ├── __init__.py │ │ │ ├── display.py │ │ │ ├── execution.py │ │ │ ├── status.py │ │ │ ├── synchronize │ │ │ │ ├── __init__.py │ │ │ │ └── status.py │ │ │ └── ui_statuses.py │ │ └── run.py │ ├── shell.py │ ├── sync │ │ ├── __init__.py │ │ ├── comm.py │ │ ├── files.py │ │ ├── sync_io.py │ │ └── threads.py │ └── threads.py ├── docgen │ ├── __init__.py │ ├── conversions.py │ ├── function_returns.py │ ├── params.py │ └── parsing.py ├── environ │ ├── __init__.py │ ├── configuration.py │ ├── logger.py │ ├── modes.py │ ├── paths.py │ ├── response.py │ └── systems.py ├── invoke │ ├── __init__.py │ ├── containerized.py │ ├── invoker.py │ └── parser.py ├── plotting │ ├── __init__.py │ ├── _brewers.py │ ├── _categoricals.py │ ├── _colors.py │ ├── _definitions.py │ └── _helpers.py ├── render │ ├── __init__.py │ ├── encoding.py │ ├── inspection.py │ ├── plots.py │ ├── stack.py │ ├── syntax_highlighting.py │ ├── texts.py │ └── utils.py ├── resources │ ├── app │ │ ├── assets │ │ │ ├── css │ │ │ │ ├── app.098a576f.css │ │ │ │ ├── chunk-vendors.c518c4ef.css │ │ │ │ ├── create.019b4dfd.css │ │ │ │ ├── create~project.588b048f.css │ │ │ │ └── project.0beac151.css │ │ │ ├── fonts │ │ │ │ ├── MaterialIcons-Regular.0509ab09.woff2 │ │ │ │ ├── MaterialIcons-Regular.29b882f0.woff │ │ │ │ ├── MaterialIcons-Regular.96c47680.eot │ │ │ │ ├── MaterialIcons-Regular.d120c85b.ttf │ │ │ │ ├── SourceSansPro-Black.0ef9ee9f.otf │ │ │ │ ├── SourceSansPro-Black.4a31d5fa.ttf │ │ │ │ ├── SourceSansPro-Black.otf.2c99d731.woff │ │ │ │ ├── SourceSansPro-Black.ttf.1ec93fb0.woff2 │ │ │ │ ├── SourceSansPro-BlackIt.0bf3a60f.otf │ │ │ │ ├── SourceSansPro-BlackIt.88c36b15.ttf │ │ │ │ ├── SourceSansPro-BlackIt.otf.9330ab0d.woff │ │ │ │ ├── SourceSansPro-BlackIt.ttf.400e7325.woff2 │ │ │ │ ├── SourceSansPro-Bold.b23705a4.otf │ │ │ │ ├── SourceSansPro-Bold.cd9e6b79.ttf │ │ │ │ ├── SourceSansPro-Bold.otf.ac261598.woff │ │ │ │ ├── SourceSansPro-Bold.ttf.07a20717.woff2 │ │ │ │ ├── SourceSansPro-BoldIt.07ceebf1.otf │ │ │ │ ├── SourceSansPro-BoldIt.7e401b3e.ttf │ │ │ │ ├── SourceSansPro-BoldIt.otf.b81c2d8b.woff │ │ │ │ ├── SourceSansPro-BoldIt.ttf.433da739.woff2 │ │ │ │ ├── SourceSansPro-ExtraLight.8d0c3b1c.ttf │ │ │ │ ├── SourceSansPro-ExtraLight.c867d05d.otf │ │ │ │ ├── SourceSansPro-ExtraLight.otf.d577e2c5.woff │ │ │ │ ├── SourceSansPro-ExtraLight.ttf.d92614da.woff2 │ │ │ │ ├── SourceSansPro-ExtraLightIt.5f6c950a.ttf │ │ │ │ ├── SourceSansPro-ExtraLightIt.d6648c78.otf │ │ │ │ ├── SourceSansPro-ExtraLightIt.otf.9b9d35be.woff │ │ │ │ ├── SourceSansPro-ExtraLightIt.ttf.82097c26.woff2 │ │ │ │ ├── SourceSansPro-It.6c362e00.ttf │ │ │ │ ├── SourceSansPro-It.ad486cdf.otf │ │ │ │ ├── SourceSansPro-It.otf.5f31e7ec.woff │ │ │ │ ├── SourceSansPro-It.ttf.7ee03da8.woff2 │ │ │ │ ├── SourceSansPro-Light.420d839a.otf │ │ │ │ ├── SourceSansPro-Light.e7daa4ab.ttf │ │ │ │ ├── SourceSansPro-Light.otf.cd6456a8.woff │ │ │ │ ├── SourceSansPro-Light.ttf.7db69e93.woff2 │ │ │ │ ├── SourceSansPro-LightIt.0b4be0f9.otf │ │ │ │ ├── SourceSansPro-LightIt.cf7fa055.ttf │ │ │ │ ├── SourceSansPro-LightIt.otf.ed22e01b.woff │ │ │ │ ├── SourceSansPro-LightIt.ttf.9b26dad3.woff2 │ │ │ │ ├── SourceSansPro-Regular.906ba80a.ttf │ │ │ │ ├── SourceSansPro-Regular.da547242.otf │ │ │ │ ├── SourceSansPro-Regular.otf.344f4c8d.woff │ │ │ │ ├── SourceSansPro-Regular.ttf.8bb5b88b.woff2 │ │ │ │ ├── SourceSansPro-Semibold.d22df054.otf │ │ │ │ ├── SourceSansPro-Semibold.e8db8af2.ttf │ │ │ │ ├── SourceSansPro-Semibold.otf.90cd4925.woff │ │ │ │ ├── SourceSansPro-Semibold.ttf.b13c669d.woff2 │ │ │ │ ├── SourceSansPro-SemiboldIt.41995df8.ttf │ │ │ │ ├── SourceSansPro-SemiboldIt.6de08aa7.otf │ │ │ │ ├── SourceSansPro-SemiboldIt.otf.b27999d8.woff │ │ │ │ └── SourceSansPro-SemiboldIt.ttf.c474abd9.woff2 │ │ │ ├── img │ │ │ │ └── logo-128.a32de47b.png │ │ │ └── js │ │ │ │ ├── app.cf0a4552.js │ │ │ │ ├── app.cf0a4552.js.map │ │ │ │ ├── chunk-vendors.c932c0f7.js │ │ │ │ ├── chunk-vendors.c932c0f7.js.map │ │ │ │ ├── create.5f3503e1.js │ │ │ │ ├── create.5f3503e1.js.map │ │ │ │ ├── create~project.48b68943.js │ │ │ │ ├── create~project.48b68943.js.map │ │ │ │ ├── project.9b6477fc.js │ │ │ │ └── project.9b6477fc.js.map │ │ ├── favicon.ico │ │ └── index.html │ ├── examples │ │ ├── bokeh │ │ │ ├── cauldron.json │ │ │ ├── color_scatter.py │ │ │ └── with-figure.py │ │ ├── hello_cauldron │ │ │ ├── S01-create-data.py │ │ │ ├── S02-plot-data.py │ │ │ ├── cauldron.json │ │ │ └── step_tests │ │ │ │ ├── __init__.py │ │ │ │ └── test_hello_cauldron.py │ │ ├── hello_text │ │ │ ├── cauldron.json │ │ │ ├── code.py │ │ │ ├── equations.py │ │ │ ├── hello.py │ │ │ ├── lorem_ipsum.txt │ │ │ ├── portions.py │ │ │ └── variables.py │ │ ├── pyplot │ │ │ ├── cauldron.json │ │ │ └── histogram.py │ │ ├── seaborn │ │ │ ├── cauldron.json │ │ │ └── facets.py │ │ └── time-gender │ │ │ ├── S01-introduction.md │ │ │ ├── S02-load-data.py │ │ │ ├── S03-graph-raw-data.py │ │ │ ├── S04-smoothed-plot.py │ │ │ ├── S05-export-data.py │ │ │ ├── S06-activity.html │ │ │ ├── TIME_Gender_Ratio.csv │ │ │ ├── _styles.css │ │ │ ├── cauldron.json │ │ │ └── sp500.csv │ ├── templates │ │ ├── StdErr.html │ │ ├── bokeh_component.html │ │ ├── code-block.html │ │ ├── dependencies.html │ │ ├── elapsed_time.html │ │ ├── embedded-step.py.txt │ │ ├── first-step.py │ │ ├── image.html │ │ ├── import-error.html │ │ ├── json_include.html │ │ ├── katex.html │ │ ├── kernel_introduction.txt │ │ ├── list_grid.html │ │ ├── listing.html │ │ ├── markdown-block.html │ │ ├── markdown-error.html │ │ ├── notebook-script-header.html │ │ ├── plotly-component.html │ │ ├── project-dependency.html │ │ ├── report-top-bar.html │ │ ├── report.js.template │ │ ├── shell_introduction.txt │ │ ├── status-variable.template.html │ │ ├── step-body.html │ │ ├── step-status.html │ │ ├── step-stop.html │ │ ├── table.html │ │ ├── tree.html │ │ ├── unit_test.html │ │ ├── user-code-error.html │ │ └── user-code-error.txt │ └── web │ │ ├── assets │ │ ├── 32px.png │ │ ├── 40px.png │ │ ├── fonts │ │ │ ├── KaTeX_AMS-Regular.ttf │ │ │ ├── KaTeX_AMS-Regular.woff │ │ │ ├── KaTeX_AMS-Regular.woff2 │ │ │ ├── KaTeX_Caligraphic-Bold.ttf │ │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ │ ├── KaTeX_Caligraphic-Regular.ttf │ │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ │ ├── KaTeX_Fraktur-Bold.ttf │ │ │ ├── KaTeX_Fraktur-Bold.woff │ │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ │ ├── KaTeX_Fraktur-Regular.ttf │ │ │ ├── KaTeX_Fraktur-Regular.woff │ │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ │ ├── KaTeX_Main-Bold.ttf │ │ │ ├── KaTeX_Main-Bold.woff │ │ │ ├── KaTeX_Main-Bold.woff2 │ │ │ ├── KaTeX_Main-BoldItalic.ttf │ │ │ ├── KaTeX_Main-BoldItalic.woff │ │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ │ ├── KaTeX_Main-Italic.ttf │ │ │ ├── KaTeX_Main-Italic.woff │ │ │ ├── KaTeX_Main-Italic.woff2 │ │ │ ├── KaTeX_Main-Regular.ttf │ │ │ ├── KaTeX_Main-Regular.woff │ │ │ ├── KaTeX_Main-Regular.woff2 │ │ │ ├── KaTeX_Math-BoldItalic.ttf │ │ │ ├── KaTeX_Math-BoldItalic.woff │ │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ │ ├── KaTeX_Math-Italic.ttf │ │ │ ├── KaTeX_Math-Italic.woff │ │ │ ├── KaTeX_Math-Italic.woff2 │ │ │ ├── KaTeX_SansSerif-Bold.ttf │ │ │ ├── KaTeX_SansSerif-Bold.woff │ │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ │ ├── KaTeX_SansSerif-Italic.ttf │ │ │ ├── KaTeX_SansSerif-Italic.woff │ │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ │ ├── KaTeX_SansSerif-Regular.ttf │ │ │ ├── KaTeX_SansSerif-Regular.woff │ │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ │ ├── KaTeX_Script-Regular.ttf │ │ │ ├── KaTeX_Script-Regular.woff │ │ │ ├── KaTeX_Script-Regular.woff2 │ │ │ ├── KaTeX_Size1-Regular.ttf │ │ │ ├── KaTeX_Size1-Regular.woff │ │ │ ├── KaTeX_Size1-Regular.woff2 │ │ │ ├── KaTeX_Size2-Regular.ttf │ │ │ ├── KaTeX_Size2-Regular.woff │ │ │ ├── KaTeX_Size2-Regular.woff2 │ │ │ ├── KaTeX_Size3-Regular.ttf │ │ │ ├── KaTeX_Size3-Regular.woff │ │ │ ├── KaTeX_Size3-Regular.woff2 │ │ │ ├── KaTeX_Size4-Regular.ttf │ │ │ ├── KaTeX_Size4-Regular.woff │ │ │ ├── KaTeX_Size4-Regular.woff2 │ │ │ ├── KaTeX_Typewriter-Regular.ttf │ │ │ ├── KaTeX_Typewriter-Regular.woff │ │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ │ ├── MaterialIcons-Regular.eot │ │ │ ├── MaterialIcons-Regular.ttf │ │ │ ├── MaterialIcons-Regular.woff │ │ │ └── MaterialIcons-Regular.woff2 │ │ └── throbber.gif │ │ ├── project.css │ │ ├── project.html │ │ └── project.js ├── runner │ ├── __init__.py │ ├── html_file.py │ ├── markdown_file.py │ ├── python_file.py │ ├── redirection.py │ └── source.py ├── session │ ├── __init__.py │ ├── buffering.py │ ├── caching.py │ ├── definitions.py │ ├── display │ │ └── __init__.py │ ├── exposed.py │ ├── naming.py │ ├── projects │ │ ├── __init__.py │ │ ├── definitions.py │ │ ├── project.py │ │ ├── specio.py │ │ └── steps.py │ ├── reloading.py │ ├── report.py │ ├── spark │ │ └── __init__.py │ └── writing │ │ ├── __init__.py │ │ ├── components │ │ ├── __init__.py │ │ ├── bokeh_component.py │ │ ├── definitions.py │ │ ├── plotly_component.py │ │ └── project_component.py │ │ ├── file_io.py │ │ ├── html.py │ │ └── step.py ├── settings.json ├── steptest │ ├── __init__.py │ ├── functional.py │ ├── results.py │ └── support.py ├── templating.py ├── test │ ├── __init__.py │ ├── cli │ │ ├── __init__.py │ │ ├── commands │ │ │ ├── __init__.py │ │ │ ├── test_alias.py │ │ │ ├── test_cd.py │ │ │ ├── test_clear.py │ │ │ ├── test_close.py │ │ │ ├── test_configure.py │ │ │ ├── test_connect_command.py │ │ │ ├── test_create.py │ │ │ ├── test_disconnect_command.py │ │ │ ├── test_exit.py │ │ │ ├── test_export.py │ │ │ ├── test_listing.py │ │ │ ├── test_ls.py │ │ │ ├── test_open.py │ │ │ ├── test_open_actions.py │ │ │ ├── test_open_opener.py │ │ │ ├── test_purge.py │ │ │ ├── test_refresh.py │ │ │ ├── test_reload.py │ │ │ ├── test_run.py │ │ │ ├── test_save.py │ │ │ ├── test_show.py │ │ │ ├── test_status.py │ │ │ ├── test_step_actions.py │ │ │ ├── test_steps.py │ │ │ ├── test_steps_create_step.py │ │ │ ├── test_steps_insert.py │ │ │ ├── test_steps_modify_step.py │ │ │ ├── test_steps_selection.py │ │ │ ├── test_sync.py │ │ │ ├── test_ui.py │ │ │ ├── test_version.py │ │ │ └── test_view.py │ │ ├── interaction │ │ │ ├── __init__.py │ │ │ └── test_interaction_query.py │ │ ├── server │ │ │ ├── __init__.py │ │ │ ├── routes │ │ │ │ ├── __init__.py │ │ │ │ ├── synchronize │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── test_project_download.py │ │ │ │ │ ├── test_status.py │ │ │ │ │ ├── test_sync_create.py │ │ │ │ │ ├── test_sync_download.py │ │ │ │ │ ├── test_sync_file.py │ │ │ │ │ ├── test_sync_open.py │ │ │ │ │ ├── test_sync_status.py │ │ │ │ │ └── test_sync_touch.py │ │ │ │ └── test_ui_statuses.py │ │ │ ├── test_arguments.py │ │ │ ├── test_server.py │ │ │ ├── test_server_display.py │ │ │ ├── test_server_execution.py │ │ │ ├── test_server_run_status.py │ │ │ └── test_server_status.py │ │ ├── sync │ │ │ ├── __init__.py │ │ │ ├── test_sync_comm.py │ │ │ ├── test_sync_files.py │ │ │ ├── test_sync_io.py │ │ │ └── test_sync_threading.py │ │ ├── test_batcher.py │ │ ├── test_cli_commands.py │ │ ├── test_cli_shell.py │ │ └── test_commander.py │ ├── docgen │ │ ├── __init__.py │ │ └── test_docgen_parsing.py │ ├── environ │ │ ├── __init__.py │ │ ├── test_configuration.py │ │ ├── test_environ_paths.py │ │ ├── test_logger.py │ │ ├── test_modes.py │ │ ├── test_response.py │ │ └── test_systems.py │ ├── invoke │ │ ├── __init__.py │ │ ├── test_containerized.py │ │ ├── test_invoke.py │ │ ├── test_invoker.py │ │ └── utils.py │ ├── projects │ │ ├── __init__.py │ │ ├── test_Project.py │ │ ├── test_ProjectStep.py │ │ ├── test_exposed.py │ │ └── test_refresh.py │ ├── render │ │ ├── __init__.py │ │ ├── test_render.py │ │ ├── test_render_encoding.py │ │ ├── test_render_plots.py │ │ ├── test_render_texts.py │ │ └── test_syntax_highlighting.py │ ├── runner │ │ ├── __init__.py │ │ ├── test_error_display.py │ │ ├── test_printing.py │ │ ├── test_reload_libraries.py │ │ ├── test_runner.py │ │ ├── test_runner_markdown_file.py │ │ ├── test_runner_python_file.py │ │ ├── test_runner_redirection.py │ │ └── test_runner_source.py │ ├── session │ │ ├── __init__.py │ │ ├── projects │ │ │ ├── __init__.py │ │ │ └── test_specio_format_times.py │ │ ├── test_definitions.py │ │ ├── test_naming.py │ │ ├── test_session_buffer.py │ │ ├── test_session_display.py │ │ ├── test_session_reloading.py │ │ ├── test_session_spark.py │ │ └── writing │ │ │ ├── __init__.py │ │ │ ├── test_bokeh_component.py │ │ │ ├── test_components.py │ │ │ ├── test_file_io_move.py │ │ │ ├── test_plotly_component.py │ │ │ └── test_project_component.py │ ├── steptesting │ │ ├── S01-first.py │ │ ├── S02-errors.py │ │ ├── S03-lib-patching.py │ │ ├── __init__.py │ │ ├── cauldron.json │ │ ├── libs │ │ │ └── _testlib │ │ │ │ └── __init__.py │ │ ├── test_functional.py │ │ ├── test_steptest.py │ │ └── test_support.py │ ├── support │ │ ├── __init__.py │ │ ├── flask_scaffolds.py │ │ ├── functional.py │ │ ├── messages.py │ │ ├── mocking.py │ │ ├── scaffolds.py │ │ ├── server.py │ │ ├── test_messages.py │ │ └── test_mocking.py │ ├── test_init.py │ ├── test_plotting.py │ ├── test_templating.py │ ├── test_test_support.py │ ├── test_writer.py │ ├── ui │ │ ├── __init__.py │ │ ├── routes │ │ │ ├── __init__.py │ │ │ ├── apis │ │ │ │ ├── __init__.py │ │ │ │ ├── executions │ │ │ │ │ ├── __init__.py │ │ │ │ │ ├── test_endpoints.py │ │ │ │ │ ├── test_runner_abort.py │ │ │ │ │ ├── test_runner_execute.py │ │ │ │ │ └── test_runner_parsing.py │ │ │ │ └── statuses │ │ │ │ │ ├── __init__.py │ │ │ │ │ └── test_status.py │ │ │ ├── apps │ │ │ │ ├── __init__.py │ │ │ │ └── test_view.py │ │ │ ├── notebooks │ │ │ │ ├── __init__.py │ │ │ │ ├── test_get_remote_view.py │ │ │ │ └── test_notebook.py │ │ │ ├── test_hello.py │ │ │ └── viewers │ │ │ │ ├── __init__.py │ │ │ │ └── test_view.py │ │ ├── statuses │ │ │ ├── __init__.py │ │ │ ├── test_get_status.py │ │ │ └── test_merge_local_state.py │ │ ├── test_arguments.py │ │ ├── test_launcher.py │ │ └── test_ui_start.py │ └── writing │ │ ├── __init__.py │ │ └── test_writing.py ├── ui │ ├── __init__.py │ ├── arguments.py │ ├── configs.py │ ├── launcher.py │ ├── parsing.py │ ├── routes │ │ ├── __init__.py │ │ ├── apis │ │ │ ├── __init__.py │ │ │ ├── executions │ │ │ │ ├── __init__.py │ │ │ │ └── runner.py │ │ │ └── statuses │ │ │ │ └── __init__.py │ │ ├── apps │ │ │ └── __init__.py │ │ ├── notebooks │ │ │ └── __init__.py │ │ └── viewers │ │ │ └── __init__.py │ └── statuses │ │ ├── __init__.py │ │ ├── _reconciler.py │ │ └── _utils.py └── writer.py ├── conda-recipe ├── bld.bat ├── build.sh ├── conda-builder.py └── meta.yaml.template ├── deployment.md ├── development.dockerfile ├── docker-builder.py ├── docker-common.dockerfile ├── docker ├── build-configs │ ├── kernel-conda-3.yaml │ ├── kernel-miniconda-3.yaml │ ├── kernel-standard-py310.yaml │ ├── kernel-standard-py37.yaml │ ├── kernel-standard-py38.yaml │ ├── kernel-standard-py39.yaml │ ├── ui-conda-3.yaml │ ├── ui-miniconda-3.yaml │ ├── ui-standard-py310.yaml │ ├── ui-standard-py37.yaml │ ├── ui-standard-py38.yaml │ └── ui-standard-py39.yaml ├── kernel-description.txt ├── kernel-nginx.conf ├── kernel-run.py ├── kernel.py ├── run.sh ├── ui-description.txt ├── ui-nginx.conf ├── ui-run.py └── ui.py ├── release.py ├── requirements.txt ├── run.py ├── setup.cfg └── setup.py /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - setup.py 3 | - release.py 4 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | cauldron/scripts/*.py 4 | /setup.py 5 | /release.py 6 | /run.py 7 | /conda-recipe/*.py 8 | /docker-builder.py 9 | /launcher.py 10 | *.py.txt 11 | /docker/*.py 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2019 Scott Ernst 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | include cauldron/settings.json 4 | recursive-include cauldron/resources * 5 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Description 2 | Describe the goals of the PR. 3 | 4 | # Steps to Test or Reproduce 5 | Outline the steps to test or reproduce PR. 6 | -------------------------------------------------------------------------------- /cauldron-app/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /cauldron-app/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /cauldron-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | 4 | env: { 5 | node: true, 6 | }, 7 | 8 | extends: [ 9 | 'plugin:vue/recommended', 10 | '@vue/airbnb', 11 | ], 12 | 13 | rules: { 14 | 'no-console': 'off', 15 | 'no-debugger': 'off', 16 | }, 17 | 18 | parserOptions: { 19 | parser: 'babel-eslint', 20 | }, 21 | 22 | overrides: [ 23 | { 24 | files: [ 25 | '**/__tests__/*.{j,t}s?(x)', 26 | ], 27 | env: { 28 | jest: true, 29 | }, 30 | }, 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /cauldron-app/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /cauldron-app/README.md: -------------------------------------------------------------------------------- 1 | # cauldron-app 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your unit tests 19 | ``` 20 | npm run test:unit 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | 31 | -------------------------------------------------------------------------------- /cauldron-app/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /cauldron-app/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | moduleFileExtensions: [ 3 | 'js', 4 | 'jsx', 5 | 'json', 6 | 'vue', 7 | ], 8 | transform: { 9 | '^.+\\.vue$': 'vue-jest', 10 | '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub', 11 | '^.+\\.jsx?$': 'babel-jest', 12 | }, 13 | transformIgnorePatterns: [ 14 | '/node_modules/', 15 | ], 16 | moduleNameMapper: { 17 | '^@/(.*)$': '/src/$1', 18 | }, 19 | snapshotSerializers: [ 20 | 'jest-serializer-vue', 21 | ], 22 | testMatch: [ 23 | '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', 24 | ], 25 | testURL: 'http://localhost/', 26 | watchPlugins: [ 27 | 'jest-watch-typeahead/filename', 28 | 'jest-watch-typeahead/testname', 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /cauldron-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cauldron-app", 3 | "version": "0.2.0", 4 | "private": true, 5 | "scripts": { 6 | "build": "vue-cli-service build --dest=../cauldron/resources/app", 7 | "dev": "vue-cli-service build --mode=development --watch --dest=../cauldron/resources/app", 8 | "test:unit": "vue-cli-service test:unit", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "axios": "^0.21.1", 13 | "bulma": "^0.9.1", 14 | "bulma-extensions": "^6.2.7", 15 | "core-js": "^3.6.5", 16 | "material-icons": "^0.3.1", 17 | "source-sans-pro": "^3.6.0", 18 | "vue": "^2.6.12", 19 | "vue-router": "^3.4.7", 20 | "vue-tippy": "^4.7.1", 21 | "vuex": "^3.5.1" 22 | }, 23 | "devDependencies": { 24 | "@vue/cli-plugin-babel": "^4.5.8", 25 | "@vue/cli-plugin-eslint": "^4.5.8", 26 | "@vue/cli-plugin-unit-jest": "^4.5.8", 27 | "@vue/cli-service": "^4.5.8", 28 | "@vue/eslint-config-airbnb": "^5.1.0", 29 | "@vue/test-utils": "^1.1.0", 30 | "babel-core": "7.0.0-bridge.0", 31 | "babel-eslint": "^10.1.0", 32 | "babel-jest": "^26.6.1", 33 | "eslint": "^7.11.0", 34 | "eslint-plugin-vue": "^7.1.0", 35 | "node-sass": "^4.14.1", 36 | "sass-loader": "^10.0.4", 37 | "vue-cli-plugin-pug": "^1.0.7", 38 | "vue-template-compiler": "^2.6.12" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /cauldron-app/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /cauldron-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron-app/public/favicon.ico -------------------------------------------------------------------------------- /cauldron-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Cauldron 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /cauldron-app/src/App.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | width: 100%; 5 | height: 100%; 6 | overflow: hidden; 7 | } 8 | 9 | #app { 10 | position: fixed; 11 | top: 0; 12 | left: 0; 13 | padding: 0; 14 | margin: 0; 15 | width: 100%; 16 | height: 100%; 17 | overflow: hidden; 18 | } 19 | 20 | .App { 21 | &__routerView { 22 | position: fixed; 23 | top: 0; 24 | left: 0; 25 | padding: 0; 26 | margin: 0; 27 | width: 100%; 28 | height: 100%; 29 | } 30 | } 31 | 32 | /* Rules for sizing material icons. */ 33 | .material-icons.md-10 { font-size: 10px; } 34 | .material-icons.md-12 { font-size: 12px; } 35 | .material-icons.md-14 { font-size: 14px; } 36 | .material-icons.md-18 { font-size: 18px; } 37 | .material-icons.md-24 { font-size: 24px; } 38 | .material-icons.md-36 { font-size: 36px; } 39 | .material-icons.md-48 { font-size: 48px; } 40 | -------------------------------------------------------------------------------- /cauldron-app/src/Variables.scss: -------------------------------------------------------------------------------- 1 | $lost-connect-z-index: 250; 2 | $error-z-index: 200; 3 | $warning-z-index: 150; 4 | $loader-z-index: 100; 5 | $modal-z-index: 51; 6 | $modal-scrim-z-index: 50; 7 | $menu-z-index: 10; 8 | $overlay-z-index: 5; 9 | $over-z-index: 1; 10 | 11 | -------------------------------------------------------------------------------- /cauldron-app/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron-app/src/assets/logo.png -------------------------------------------------------------------------------- /cauldron-app/src/components/alertDialog/AlertDialog.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | 33 | 62 | -------------------------------------------------------------------------------- /cauldron-app/src/components/browser/File.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 37 | 38 | 61 | -------------------------------------------------------------------------------- /cauldron-app/src/components/browser/Folder.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 31 | 32 | 55 | -------------------------------------------------------------------------------- /cauldron-app/src/components/browser/ProjectFolder.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | 26 | 49 | -------------------------------------------------------------------------------- /cauldron-app/src/components/loader/Loader.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | 25 | 26 | 49 | -------------------------------------------------------------------------------- /cauldron-app/src/components/modalScrim/ModalScrim.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 29 | 30 | 48 | -------------------------------------------------------------------------------- /cauldron-app/src/emitter.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | const bus = new Vue(); 4 | 5 | function $on(event, callback) { 6 | return bus.$on(event, callback); 7 | } 8 | 9 | function $off(event, callback) { 10 | return bus.$off(event, callback); 11 | } 12 | 13 | function $emit(event, ...args) { 14 | return bus.$emit(event, ...args); 15 | } 16 | 17 | export default { $on, $off, $emit }; 18 | -------------------------------------------------------------------------------- /cauldron-app/src/loading.js: -------------------------------------------------------------------------------- 1 | import store from './store'; 2 | 3 | function show(id, message) { 4 | const current = store.getters.loadingMessages || []; 5 | store.commit('loadingMessages', current.concat([{ id, message }])); 6 | } 7 | 8 | function hide(id) { 9 | const keeps = (store.getters.loadingMessages || []) 10 | .filter((item) => id !== null && id !== item.id); 11 | store.commit('loadingMessages', keeps); 12 | } 13 | 14 | export default { show, hide }; 15 | -------------------------------------------------------------------------------- /cauldron-app/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueTippy, { TippyComponent } from 'vue-tippy'; 3 | 4 | import App from './App.vue'; 5 | import router from './router'; 6 | import store from './store'; 7 | 8 | Vue.use(VueTippy); 9 | Vue.component('tippy', TippyComponent); 10 | 11 | Vue.config.productionTip = false; 12 | 13 | new Vue({ 14 | router, 15 | store, 16 | render: (h) => h(App), 17 | }).$mount('#app'); 18 | -------------------------------------------------------------------------------- /cauldron-app/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from './views/home/Home.vue'; 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | mode: 'history', 9 | base: process.env.BASE_URL, 10 | routes: [ 11 | { 12 | path: '/', 13 | name: 'home', 14 | component: Home, 15 | }, 16 | { 17 | path: '/project', 18 | name: 'project', 19 | component: () => import(/* webpackChunkName: "project" */ './views/project/Project.vue'), 20 | }, 21 | { 22 | path: '/create', 23 | name: 'create', 24 | component: () => import(/* webpackChunkName: "create" */ './views/create/Create.vue'), 25 | }, 26 | { 27 | path: '/open', 28 | name: 'open', 29 | component: () => import(/* webpackChunkName: "create" */ './views/open/Open.vue'), 30 | }, 31 | { 32 | path: '/view', 33 | name: 'viewer', 34 | component: () => import(/* webpackChunkName: "create" */ './views/viewer/Viewer.vue'), 35 | }, 36 | ], 37 | }); 38 | -------------------------------------------------------------------------------- /cauldron-app/src/utils.js: -------------------------------------------------------------------------------- 1 | /** Exposes webpack DefinePlugin variables injected during build. */ 2 | function getBuildVar(key) { 3 | return process.env[key]; 4 | } 5 | 6 | function thenWait(elapsedMilliseconds, args) { 7 | return new Promise((resolve) => { 8 | setTimeout(() => { 9 | resolve(args); 10 | }, elapsedMilliseconds); 11 | }); 12 | } 13 | 14 | export default { thenWait, getBuildVar }; 15 | -------------------------------------------------------------------------------- /cauldron-app/src/views/home/logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron-app/src/views/home/logo-128.png -------------------------------------------------------------------------------- /cauldron-app/src/views/project/MenuStrip/MenuButton.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 29 | 30 | 56 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/clean.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: white; 3 | $color: #666; 4 | 5 | $background-selected: #4d4d4d; 6 | $color-selected: white; 7 | 8 | &--clean { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--clean { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/dirty.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: rgb(186, 220, 255); 3 | $color: #1b5d80; 4 | 5 | $background-selected: #42b7ee; 6 | $color-selected: white; 7 | 8 | &--dirty { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--dirty { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/error.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: rgb(255, 179, 187); 3 | $color: #790c13; 4 | 5 | $background-selected: #d65150; 6 | $color-selected: white; 7 | 8 | &--error { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--error { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/queued.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: #e0d8ff; 3 | $color: #7769bb; 4 | 5 | $background-selected: #7769bb; 6 | $color-selected: white; 7 | 8 | &--queued { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--queued { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/running.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: #a6e4a0; 3 | $color: #449959; 4 | 5 | $background-selected: #51b76a; 6 | $color-selected: white; 7 | 8 | &--running { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--running { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/unknown.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: rgb(255, 232, 205); 3 | $color: #795332; 4 | 5 | $background-selected: #d69c44; 6 | $color-selected: white; 7 | 8 | &--unknown { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--unknown { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid saturate(darken($background, 10%), 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid saturate(darken($background-selected, 10%), 10%) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/project/RunStrip/stateStyles/untouched.scss: -------------------------------------------------------------------------------- 1 | .RunStripStep { 2 | $background: #f1f1f1; 3 | $color: #717171; 4 | 5 | $background-selected: #717171; 6 | $color-selected: #f1f1f1; 7 | 8 | &--untouched { 9 | background-color: $background; 10 | color: $color; 11 | fill: $color; 12 | 13 | &Selected { 14 | background-color: $background-selected; 15 | color: $color-selected; 16 | fill: $color-selected; 17 | } 18 | } 19 | 20 | &__overlay--untouched { 21 | background-color: $background; 22 | color: $color; 23 | border: 1px solid darken($background, 10%); 24 | 25 | &Selected { 26 | background-color: $background-selected; 27 | color: $color-selected; 28 | border: 1px solid darken($background-selected, 10%); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /cauldron-app/src/views/viewer/ViewMenuStrip/ViewMenuStrip.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 39 | -------------------------------------------------------------------------------- /cauldron-app/tests/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /cauldron-app/tests/unit/example.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils'; 2 | import HelloWorld from '@/components/HelloWorld.vue'; 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message'; 7 | const wrapper = shallowMount(HelloWorld, { 8 | propsData: { msg }, 9 | }); 10 | expect(wrapper.text()).toMatch(msg); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /cauldron-app/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const packageSettings = require('./package'); 4 | 5 | module.exports = { 6 | runtimeCompiler: true, 7 | outputDir: '../cauldron/resources/app', 8 | assetsDir: 'assets', 9 | publicPath: '/v1/app/', 10 | chainWebpack: (config) => { 11 | config.resolve.alias.set('@', path.join(__dirname, 'src')); 12 | 13 | config.plugin('define').tap((definitions) => { 14 | const mode = (process.env.NODE_ENV === 'development') ? 'test' : 'prod'; 15 | const environmentVariables = { 16 | BUILD_MODE: JSON.stringify(mode), 17 | UI_VERSION: JSON.stringify(packageSettings.version), 18 | }; 19 | 20 | // Append custom environment variables to the ones that already exist 21 | // by default as part of the Vue webpack configuration. 22 | Object.assign(definitions[0]['process.env'], environmentVariables); 23 | return definitions; 24 | }); 25 | }, 26 | configureWebpack: { context: path.resolve(__dirname) }, 27 | }; 28 | -------------------------------------------------------------------------------- /cauldron-app/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | // === WARNING: STATIC DEVELOPMENT PURPOSES ONLY === 4 | // This file is not used for webpack compilation. Instead it is a static 5 | // representation of the webpack.config.js that is generated from the 6 | // vue.config.js that is needed to help support statically-determined 7 | // webpack behaviors within the code during development. For the moment, 8 | // this is the recommended way of handling this until dynamic webpack 9 | // configuration is more widely adopted within Vuejs projects. 10 | 11 | module.exports = { 12 | resolve: { 13 | alias: { 14 | '@': path.resolve(__dirname, 'src'), 15 | }, 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /cauldron-web/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb-base", 3 | "rules": { 4 | // Airbnb imposed rule for JSON compatibility 5 | "comma-dangle": 0, 6 | 7 | // Console output is allowed because of Node.js context, as 8 | // recommended by ESLint documentation 9 | "no-console": 0, 10 | 11 | // While they should be avoided in JS code, they do arise in data 12 | // structures from external sources. Reduce this to a warning to 13 | // restrict its use 14 | "no-underscore-dangle": "warn" 15 | }, 16 | 17 | "env": { 18 | "browser": true, 19 | "node": true, 20 | "jasmine": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cauldron-web/deploy.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | MY_DIRECTORY = os.path.realpath(os.path.dirname(__file__)) 5 | 6 | 7 | def main(): 8 | """Copies the current dist directory into the cauldron Python package.""" 9 | print('\n\n=== DEPLOYING ====\n') 10 | dist_path = os.path.join(MY_DIRECTORY, 'dist') 11 | deploy_path = os.path.realpath(os.path.join( 12 | MY_DIRECTORY, 13 | '..', 'cauldron', 'resources', 'web' 14 | )) 15 | print(f'DIST PATH: {dist_path}') 16 | print(f'DEPLOY PATH: {deploy_path}') 17 | 18 | print(f'[INFO]: Removing existing deployed files.') 19 | shutil.rmtree(deploy_path) 20 | 21 | print(f'[INFO]: Copying dist files to deployment path') 22 | shutil.copytree(dist_path, deploy_path) 23 | 24 | print('[SUCCESS]: Deployment operation complete.') 25 | 26 | 27 | if __name__ == '__main__': 28 | main() -------------------------------------------------------------------------------- /cauldron-web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cauldron-web", 3 | "version": "1.1.0", 4 | "author": "Scott Ernst", 5 | "repository": "github.com/sernst/cauldron", 6 | "description": "Web resources for Cauldron notebooks", 7 | "license": "MIT", 8 | "scripts": { 9 | "sync": "npm install && npm update", 10 | "pack": "webpack --mode production" 11 | }, 12 | "dependencies": { 13 | "d3": "^5.12.0", 14 | "jquery": "^3.4.1", 15 | "handsontable": "^6.2.2", 16 | "file-saver": "^2.0.2", 17 | "material-icons": "^0.3.1", 18 | "normalize.css": "^8.0.1", 19 | "jstree": "^3.3.8", 20 | "katex": "^0.11.1" 21 | }, 22 | "devDependencies": { 23 | "@babel/core": "^7.6.2", 24 | "@babel/preset-env": "^7.6.2", 25 | "babel-loader": "^8.0.6", 26 | "clean-webpack-plugin": "^3.0.0", 27 | "copy-webpack-plugin": "^5.0.4", 28 | "css-loader": "^3.2.0", 29 | "del": "^5.1.0", 30 | "eslint": "^6.1.0", 31 | "eslint-config-airbnb-base": "^14.0.0", 32 | "eslint-plugin-import": "^2.18.2", 33 | "file-loader": "^4.2.0", 34 | "mini-css-extract-plugin": "^0.8.0", 35 | "node-sass": "^4.12.0", 36 | "sass-loader": "^8.0.0", 37 | "style-loader": "^1.0.0", 38 | "webpack": "^4.41.0", 39 | "webpack-cli": "^3.3.9", 40 | "webpack-shell-plugin": "^0.5.0", 41 | "yargs": "^14.2.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /cauldron-web/src/js/app/header.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery'; 2 | 3 | import utils from './utils'; 4 | 5 | const headerDom = [ 6 | '
', 7 | '', 8 | '
', 9 | '
', 10 | '
', 11 | '
' 12 | ]; 13 | 14 | /** 15 | * 16 | */ 17 | function createHeader() { 18 | const cauldron = utils.getRoot(); 19 | const header = $(headerDom.join('')) 20 | .prependTo($('.body-wrapper')); 21 | 22 | if (cauldron.RESULTS.has_error) { 23 | header.addClass('project-error'); 24 | } 25 | } 26 | 27 | export default { createHeader }; 28 | -------------------------------------------------------------------------------- /cauldron-web/src/js/app/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | function getNoCacheString() { 5 | const d = new Date(); 6 | return [ 7 | d.getUTCMilliseconds(), 8 | d.getUTCSeconds(), 9 | d.getUTCMinutes(), 10 | d.getUTCHours(), 11 | d.getUTCDay(), 12 | d.getUTCMonth(), 13 | d.getUTCFullYear() 14 | ].join('-'); 15 | } 16 | 17 | 18 | /** 19 | * 20 | * @param lower 21 | * @returns {*|string|void} 22 | */ 23 | function capitalize(lower) { 24 | return lower.replace(/(?:^|\s)\S/g, (a) => a.toUpperCase()); 25 | } 26 | 27 | /** 28 | * 29 | * @param value 30 | * @param unc 31 | * @returns {string} 32 | */ 33 | function toDisplayNumber(value, unc) { 34 | function toDisplayValue(v) { 35 | return (0.01 * Math.round(100.0 * v)).toFixed(2); 36 | } 37 | 38 | return `${toDisplayValue(value)} ± ${toDisplayValue(unc)}`; 39 | } 40 | 41 | /** 42 | * 43 | * @returns {*|{}} 44 | */ 45 | function getRoot() { 46 | window.CAULDRON = window.CAULDRON || {}; 47 | return window.CAULDRON; 48 | } 49 | 50 | export default { 51 | getNoCacheString, 52 | toDisplayNumber, 53 | capitalize, 54 | getRoot 55 | }; 56 | -------------------------------------------------------------------------------- /cauldron-web/src/project.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Cauldron Project 10 | 11 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /cauldron-web/src/project.scss: -------------------------------------------------------------------------------- 1 | $material-icons-font-path: '~material-icons/iconfont/'; 2 | @import "style/app/vars"; 3 | 4 | @import '~material-icons/iconfont/material-icons.scss'; 5 | @import "~normalize.css/normalize.css"; 6 | @import "~handsontable/dist/handsontable.full.min.css"; 7 | @import "~jstree/dist/themes/default/style.min.css"; 8 | @import "~katex/dist/katex.min.css"; 9 | 10 | @import "style/css/analysis.css"; 11 | @import "style/css/shared.css"; 12 | 13 | @import "style/pygments"; 14 | @import "style/icons"; 15 | 16 | @import "style/app/general"; 17 | @import "style/app/error"; 18 | @import "style/app/project_header"; 19 | @import "style/app/project_step"; 20 | @import "style/app/step_style"; 21 | @import "style/app/deprecated"; 22 | @import "style/app/code_box"; 23 | 24 | @import "style/app/body/body"; 25 | @import "style/app/body/body_text"; 26 | @import "style/app/body/body_table"; 27 | @import "style/app/body/body_pylab"; 28 | @import "style/app/body/Header"; 29 | @import "style/app/body/Listing"; 30 | 31 | @import "style/templates/StdErr"; 32 | @import "style/templates/ProjectStep"; 33 | @import "style/templates/StepStop"; 34 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/Header.scss: -------------------------------------------------------------------------------- 1 | .cd-Header { 2 | margin: 0 auto; 3 | 4 | &--full { 5 | width: 100%; 6 | } 7 | 8 | &--limited { 9 | max-width: $max_page_width; 10 | min-width: 100px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/Listing.scss: -------------------------------------------------------------------------------- 1 | .cd-Listing { 2 | margin: 0 auto; 3 | 4 | &--full { 5 | width: 100%; 6 | } 7 | 8 | &--limited { 9 | max-width: $max_page_width; 10 | min-width: 100px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/body.scss: -------------------------------------------------------------------------------- 1 | .cd-project-step-body { 2 | margin: 0 0 1.0em 0; 3 | } 4 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/body_pylab.scss: -------------------------------------------------------------------------------- 1 | .cd-pylab-plot { 2 | width: 100%; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | 7 | 8 | .cd-pylab-svg { 9 | width: 100%; 10 | max-height: 80vh; 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/body_table.scss: -------------------------------------------------------------------------------- 1 | 2 | .cd-project-step-body .data-table { 3 | margin: 1.0em 2.0em 1.0em 2.0em; 4 | } 5 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/body/body_text.scss: -------------------------------------------------------------------------------- 1 | 2 | .cd-project-step-body .preformatted-textbox { 3 | margin: 0.2em 1.0em; 4 | padding: 0.5em 0; 5 | overflow-x: auto; 6 | } -------------------------------------------------------------------------------- /cauldron-web/src/style/app/code_box.scss: -------------------------------------------------------------------------------- 1 | .cd-project-step .code-box { 2 | padding: 0.5em; 3 | 4 | .code-toolbar { 5 | @extend .centered; 6 | margin: 0.5em 0; 7 | } 8 | } 9 | 10 | .cd-project-step .cd-dependencies-body { 11 | .code-toolbar { 12 | @extend .centered; 13 | margin: 0 0 0.5em 0; 14 | padding-top: 0.5em; 15 | } 16 | } 17 | 18 | .cd-project-step .code-box, .cd-project-step .cd-dependencies-body { 19 | background-color: #f4f4f4; 20 | 21 | .code-wrapper { 22 | line-height: 1.5; 23 | font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace; 24 | 25 | .linenos { 26 | opacity: 0.4; 27 | padding-right: 12px; 28 | } 29 | } 30 | 31 | .tool-button { 32 | @extend .clicker; 33 | 34 | background-color: #333; 35 | color: #FFF; 36 | font-size: 0.7em; 37 | border-radius: 0.5em; 38 | padding: 0.4em 1.2em 0.5em 1.2em; 39 | margin: 0 0.4em; 40 | 41 | &:hover { 42 | background-color: #AAA; 43 | color: black; 44 | } 45 | } 46 | 47 | .code-file-header { 48 | padding: 0.5em; 49 | background-color: #666666; 50 | color: #FFF; 51 | } 52 | 53 | .code-file-box { 54 | width: 100%; 55 | overflow-x: auto; 56 | } 57 | } -------------------------------------------------------------------------------- /cauldron-web/src/style/app/deprecated.scss: -------------------------------------------------------------------------------- 1 | .cd-plotly-box { 2 | /* 3 | This was replaced by `.cd-plotly-box-v2`, which has scoped inline styling 4 | for touch/non-touch support. This is preserved only to prevent rendering 5 | issues looking at notebooks generated prior to the update. 6 | */ 7 | margin: 0; 8 | padding: 0; 9 | min-height: 250px; 10 | } 11 | 12 | .cd-bokeh-plot { 13 | /* 14 | This has been replaced with inline styling and new bokeh components now 15 | use the `.cd-BokehPlot` base class. This is preserved for earlier rendering 16 | compatibility. 17 | */ 18 | width: 100%; 19 | 20 | &__inner { 21 | width: 100%; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/error.scss: -------------------------------------------------------------------------------- 1 | .cd-user-code-error { 2 | background-color: rgba(136, 0, 0, 0.1); 3 | 4 | .heading { 5 | background-color: #880000; 6 | padding: 0.5rem; 7 | 8 | .type { 9 | font-size: 1.2rem; 10 | color: rgba(255, 255, 255, 0.9); 11 | font-weight: 600; 12 | } 13 | 14 | .message { 15 | color: rgba(255, 255, 255, 0.6); 16 | } 17 | } 18 | 19 | .stack-box { 20 | padding:1.0rem; 21 | } 22 | 23 | .stack-entry { 24 | margin-bottom: 1.0rem; 25 | border-left: 5px solid #880000; 26 | padding-left: 0.5rem; 27 | 28 | .filename { 29 | font-size: 1.2rem; 30 | font-style: italic; 31 | color: #880000; 32 | margin-bottom: 0.5rem; 33 | } 34 | 35 | .item { 36 | color: rgba(0, 0, 0, 0.3); 37 | 38 | &.indented { 39 | padding-left: 1.0rem; 40 | } 41 | 42 | .value { 43 | font-style: italic; 44 | color: rgba(0, 0, 0, 0.6); 45 | } 46 | } 47 | 48 | .code-line { 49 | font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace; 50 | color: rgba(136, 0, 0, 0.8); 51 | /* color: rgb(175, 96, 112); */ 52 | padding: 0.75rem 0; 53 | } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /cauldron-web/src/style/app/general.scss: -------------------------------------------------------------------------------- 1 | 2 | .centered { 3 | display: flex; 4 | justify-content: center; 5 | align-content: center; 6 | align-items: center; 7 | } 8 | 9 | .clicker { 10 | cursor: pointer; 11 | 12 | &:hover { 13 | opacity: 0.8; 14 | } 15 | } 16 | 17 | .snapshot-bar { 18 | font-size: 0.7em; 19 | margin: 0; 20 | padding: 0.25em; 21 | background-color: #c88fbc; 22 | color: #463241; 23 | 24 | &.snapshot-bar-overlay { 25 | position: fixed; 26 | z-index: 100000; 27 | top:0; 28 | left:0; 29 | width: 100%; 30 | overflow: hidden; 31 | } 32 | } 33 | 34 | .body-wrapper { 35 | margin-bottom: 150px; 36 | } -------------------------------------------------------------------------------- /cauldron-web/src/style/app/project_header.scss: -------------------------------------------------------------------------------- 1 | 2 | .cd-body-header { 3 | @extend .centered; 4 | background-color: #333333; 5 | color: #FFF; 6 | padding: 0.5rem; 7 | } 8 | 9 | .cd-body-header.project-error { 10 | background-color: #880000; 11 | } -------------------------------------------------------------------------------- /cauldron-web/src/style/app/step_style.scss: -------------------------------------------------------------------------------- 1 | $PROGRESS_COLOR: #769bc7; 2 | 3 | .cd-step-status { 4 | background-color: #ddebff; 5 | margin: 20px; 6 | padding: 5px; 7 | 8 | &__header { 9 | color: $PROGRESS_COLOR; 10 | font-size: 12px; 11 | padding: 5px; 12 | } 13 | 14 | &__info { 15 | color: $PROGRESS_COLOR; 16 | padding: 10px; 17 | } 18 | 19 | &__progress { 20 | height: 15px; 21 | margin: 0; 22 | padding: 0; 23 | width: 100%; 24 | } 25 | 26 | &__progress-inner { 27 | height: 15px; 28 | background-color: $PROGRESS_COLOR; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cauldron-web/src/style/app/vars.scss: -------------------------------------------------------------------------------- 1 | $max_page_width: 1280px; 2 | -------------------------------------------------------------------------------- /cauldron-web/src/style/css/analysis.css: -------------------------------------------------------------------------------- 1 | .textbox, .plaintextbox { 2 | margin:auto; 3 | opacity: 0.9; 4 | padding: 0.25em 1.0em; 5 | max-width: 1280px; 6 | font-family: 'Open Sans', Helvetica, Arial, "Helvetica Neue", sans-serif; 7 | font-size: 1.1em; 8 | } 9 | 10 | .data-table { 11 | margin: 0 1.0rem; 12 | } 13 | 14 | .padded { 15 | margin: 0 1.0em; 16 | } 17 | 18 | pre { 19 | font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace; 20 | } 21 | 22 | p { 23 | margin: 0 0 0.75em 0; 24 | line-height: 1.6; 25 | } 26 | 27 | h1, h2, h3, h4, h5, h6 { 28 | padding-left: 0.5em; 29 | margin:0.5rem 0; 30 | } 31 | 32 | .box { 33 | padding: 0.25em 1.0em; 34 | } 35 | 36 | 37 | 38 | .status-variable .name { 39 | color: #996d90; 40 | font-weight: bold; 41 | } 42 | 43 | .status-variable .type { 44 | font-style: italic; 45 | opacity: 0.6; 46 | font-size: 0.9em; 47 | } 48 | 49 | .status-variable .value { 50 | margin-left: 2.0em; 51 | opacity: 0.5; 52 | font-size: 0.7em; 53 | line-height: 1.3; 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /cauldron-web/src/style/css/shared.css: -------------------------------------------------------------------------------- 1 | 2 | html, body { 3 | margin: 0; 4 | padding: 0; 5 | width: 100%; 6 | overflow-x: hidden; 7 | } 8 | 9 | .no-select { 10 | -webkit-touch-callout: none; 11 | -webkit-user-select: none; 12 | -khtml-user-select: none; 13 | -moz-user-select: none; 14 | -ms-user-select: none; 15 | user-select: none; 16 | } 17 | 18 | .spacer { 19 | flex-grow: 1; 20 | } 21 | 22 | .line-break { 23 | border-bottom: 1px dotted #999; 24 | margin: 0.5em 0; 25 | } 26 | 27 | .bottom-spacer { 28 | width: 100%; 29 | min-height: 10.0em; 30 | } 31 | -------------------------------------------------------------------------------- /cauldron-web/src/style/icons.scss: -------------------------------------------------------------------------------- 1 | /* Rules for sizing the icon. */ 2 | .material-icons.md-18 { font-size: 18px; } 3 | .material-icons.md-24 { font-size: 24px; } 4 | .material-icons.md-36 { font-size: 36px; } 5 | .material-icons.md-48 { font-size: 48px; } 6 | .material-icons.md-small { font-size: 18px; } 7 | .material-icons.md-medium { font-size: 24px; } 8 | .material-icons.md-large { font-size: 36px; } 9 | .material-icons.md-xlarge { font-size: 48px; } 10 | 11 | /* Rules for using icons as black on a light background. */ 12 | .material-icons.md-dark { color: rgba(0, 0, 0, 0.54); } 13 | .material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); } 14 | 15 | /* Rules for using icons as white on a dark background. */ 16 | .material-icons.md-light { color: rgba(255, 255, 255, 1); } 17 | .material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); } 18 | 19 | /* Rules for custom colors */ 20 | .material-icons.orange600 { color: #FB8C00; } 21 | -------------------------------------------------------------------------------- /cauldron-web/src/style/templates/ProjectStep.scss: -------------------------------------------------------------------------------- 1 | .ProjectStep { 2 | &__bodyInner { 3 | margin-top: 0.5em; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /cauldron-web/src/style/templates/StdErr.scss: -------------------------------------------------------------------------------- 1 | .cd-StdErr { 2 | background-color: #ffe7bf; 3 | color: #b67b00; 4 | border-top: 1px solid rgba(182, 123, 0, 0.2); 5 | 6 | &__bar { 7 | padding: 0.25em; 8 | align-items: center; 9 | display: flex; 10 | } 11 | 12 | &__titleBox { 13 | font-size: 0.8em; 14 | align-items: center; 15 | display: flex; 16 | } 17 | 18 | &__spacer { 19 | flex: 1; 20 | } 21 | 22 | &__body { 23 | padding: 1em; 24 | white-space: pre; 25 | overflow: auto; 26 | font-family: "Lucida Console", Monaco, "Courier New", Courier, monospace; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /cauldron-web/src/style/templates/StepStop.scss: -------------------------------------------------------------------------------- 1 | .cd-StepStop { 2 | display: flex; 3 | margin: 1em auto; 4 | padding: 0.5em; 5 | background-color: #ffc6ae; 6 | border: 1px solid #cd8e61; 7 | color: #815b35; 8 | max-width: 640px; 9 | 10 | &__left { 11 | padding-right: 0.5em; 12 | } 13 | 14 | &__header { 15 | font-size: 1.1em; 16 | font-weight: bold; 17 | } 18 | 19 | &__message { 20 | font-size: 1.2em; 21 | margin: 5px 0; 22 | } 23 | 24 | &__right { 25 | flex: 1; 26 | } 27 | 28 | &__frame { 29 | margin-top: 0.5em; 30 | padding-left: 2em; 31 | font-family: monospace; 32 | } 33 | 34 | &__value { 35 | font-weight: bolder; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /cauldron/cli/commands/__init__.py: -------------------------------------------------------------------------------- 1 | # All top-level modules are imported from within the commands module 2 | # as the commands module contains only valid commands. This makes it safe 3 | # against the all imports. 4 | 5 | from cauldron.cli.commands import configure # noqa 6 | from cauldron.cli.commands import open # noqa 7 | from cauldron.cli.commands import run # noqa 8 | from cauldron.cli.commands import steps # noqa 9 | from cauldron.cli.commands import alias # noqa 10 | from cauldron.cli.commands import cd # noqa 11 | from cauldron.cli.commands import clear # noqa 12 | from cauldron.cli.commands import close # noqa 13 | from cauldron.cli.commands import create # noqa 14 | from cauldron.cli.commands import exit # noqa 15 | from cauldron.cli.commands import export # noqa 16 | from cauldron.cli.commands import listing # noqa 17 | from cauldron.cli.commands import ls # noqa 18 | from cauldron.cli.commands import purge # noqa 19 | from cauldron.cli.commands import refresh # noqa 20 | from cauldron.cli.commands import reload # noqa 21 | from cauldron.cli.commands import save # noqa 22 | from cauldron.cli.commands import show # noqa 23 | from cauldron.cli.commands import status # noqa 24 | from cauldron.cli.commands import version # noqa 25 | from cauldron.cli.commands import connect # noqa 26 | from cauldron.cli.commands import disconnect # noqa 27 | from cauldron.cli.commands import sync # noqa 28 | from cauldron.cli.commands import ui # noqa 29 | from cauldron.cli.commands import view # noqa 30 | -------------------------------------------------------------------------------- /cauldron/cli/commands/clear.py: -------------------------------------------------------------------------------- 1 | import cauldron 2 | from cauldron import cli 3 | from cauldron.environ import Response 4 | from cauldron.cli import sync 5 | 6 | NAME = 'clear' 7 | DESCRIPTION = """ 8 | Clears all shared data in the cache and reloads all internal project 9 | libraries. 10 | """ 11 | 12 | 13 | def execute_remote(context: cli.CommandContext) -> Response: 14 | """...""" 15 | 16 | thread = sync.send_remote_command( 17 | command=context.name, 18 | raw_args=context.raw_args, 19 | asynchronous=False 20 | ) 21 | 22 | thread.join() 23 | 24 | response = thread.responses[0] 25 | return context.response.consume(response) 26 | 27 | 28 | def execute(context: cli.CommandContext) -> Response: 29 | """...""" 30 | project = cauldron.project.internal_project 31 | 32 | if not project: 33 | return context.response.fail( 34 | code='NO_OPEN_PROJECT', 35 | message='No open project on which to clear data' 36 | ).console( 37 | whitespace=1 38 | ).response 39 | 40 | project.shared.clear() 41 | 42 | for ps in project.steps: 43 | ps.mark_dirty(True, force=True) 44 | 45 | return context.response.update( 46 | project=project.kernel_serialize() 47 | ).notify( 48 | kind='SUCCESS', 49 | code='SHARED_CLEARED', 50 | message='Shared data has been cleared' 51 | ).console( 52 | whitespace=1 53 | ).response 54 | -------------------------------------------------------------------------------- /cauldron/cli/commands/close.py: -------------------------------------------------------------------------------- 1 | from cauldron import cli 2 | from cauldron import runner 3 | from cauldron.environ import Response 4 | from cauldron.cli import sync 5 | from cauldron import environ 6 | 7 | NAME = 'close' 8 | DESCRIPTION = """ 9 | Close the currently opened project. 10 | """ 11 | 12 | 13 | def execute_remote(context: cli.CommandContext) -> Response: 14 | """...""" 15 | thread = sync.send_remote_command( 16 | command=context.name, 17 | raw_args=context.raw_args, 18 | asynchronous=False 19 | ) 20 | 21 | thread.join() 22 | environ.remote_connection.local_project_directory = None 23 | environ.remote_connection.reset_sync_time() 24 | response = thread.responses[0] 25 | return context.response.consume(response) 26 | 27 | 28 | def execute(context: cli.CommandContext) -> Response: 29 | """...""" 30 | if runner.close(): 31 | return context.response.notify( 32 | kind='SUCCESS', 33 | code='PROJECT_CLOSED', 34 | message='Project has been closed' 35 | ).console(whitespace=1).response 36 | 37 | return context.response.notify( 38 | kind='ABORTED', 39 | code='NO_OPEN_PROJECT', 40 | message='There was no open project to close' 41 | ).console(whitespace=1).response 42 | -------------------------------------------------------------------------------- /cauldron/cli/commands/disconnect.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | from cauldron import cli 4 | from cauldron import environ 5 | from cauldron.environ import Response 6 | 7 | 8 | NAME = 'disconnect' 9 | DESCRIPTION = """ 10 | Disconnect from the remote cauldron server and restore shell to local 11 | control 12 | """ 13 | 14 | 15 | def execute(context: cli.CommandContext) -> Response: 16 | """...""" 17 | environ.remote_connection.active = False 18 | environ.remote_connection.url = None 19 | 20 | return context.response.notify( 21 | kind='SUCCESS', 22 | code='DISCONNECTED', 23 | message='Disconnected from remote cauldron' 24 | ).console(whitespace=1).response 25 | 26 | 27 | def autocomplete(segment: str, line: str, parts: typing.List[str]): 28 | """ 29 | 30 | :param segment: 31 | :param line: 32 | :param parts: 33 | :return: 34 | """ 35 | 36 | return [] 37 | -------------------------------------------------------------------------------- /cauldron/cli/commands/exit.py: -------------------------------------------------------------------------------- 1 | from cauldron import cli 2 | from cauldron import environ 3 | from cauldron.environ import Response 4 | 5 | NAME = 'exit' 6 | DESCRIPTION = 'Exit the cauldron shell' 7 | 8 | 9 | def execute(context: cli.CommandContext) -> Response: 10 | """...""" 11 | environ.configs.save() 12 | return context.response.end() 13 | -------------------------------------------------------------------------------- /cauldron/cli/commands/listing/_lister.py: -------------------------------------------------------------------------------- 1 | from cauldron import cli 2 | from cauldron import environ 3 | from cauldron.cli.commands.listing import _utils 4 | from cauldron.session.projects import specio 5 | 6 | 7 | def execute_list(context: cli.CommandContext) -> environ.Response: 8 | """ 9 | Executes the list action for the recent command according to the 10 | specified context object for the currently invoked command and 11 | returns a response object containing the listed projects. 12 | """ 13 | projects = _utils.get_recent_projects() 14 | if projects.specs: 15 | display = 'Recent Projects:\n\n{}'.format( 16 | specio.to_display_list(projects.specs) 17 | ) 18 | else: 19 | display = 'No recent projects found.' 20 | 21 | return ( 22 | context.response 23 | .update(projects=projects.specs) 24 | .notify( 25 | kind='RESULT', 26 | code='PROJECT_HISTORY', 27 | message=display 28 | ) 29 | .console(whitespace=1) 30 | .response 31 | ) 32 | -------------------------------------------------------------------------------- /cauldron/cli/commands/listing/_utils.py: -------------------------------------------------------------------------------- 1 | from cauldron import environ 2 | from cauldron.session.projects import specio 3 | 4 | 5 | def get_recent_projects() -> specio.ProjectSpecsReader: 6 | """ 7 | Loads contextual and configuration information for all projects 8 | in the recent project paths persistent environment setting. Each 9 | item in the returned list is a loaded ``cauldron.json`` file for 10 | an entry in that recent project path list that has been enriched 11 | with information about that project (e.g. modified timestamp) that 12 | can be used for the display of that project. Any paths that are 13 | found to no longer exist will be ignored and excluded from the 14 | returned list of results. 15 | """ 16 | paths = environ.configs.fetch('recent_paths', []) 17 | specs = specio.ProjectSpecsReader() 18 | 19 | for path in paths: 20 | specs.add(path) 21 | 22 | return specs 23 | -------------------------------------------------------------------------------- /cauldron/cli/commands/open/remote.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | from cauldron import cli 5 | from cauldron import environ 6 | from cauldron import runner 7 | from cauldron.cli import sync 8 | from cauldron.cli.commands.open import opener as local_opener 9 | from cauldron.environ.response import Response 10 | 11 | 12 | def sync_open( 13 | context: cli.CommandContext, 14 | path: str, 15 | forget: bool = False 16 | ) -> Response: 17 | """...""" 18 | source_directory = environ.paths.clean(path) 19 | environ.remote_connection.local_project_directory = source_directory 20 | source_path = os.path.join(source_directory, 'cauldron.json') 21 | 22 | with open(source_path, 'r') as f: 23 | definition = json.load(f) 24 | 25 | response = sync.comm.send_request( 26 | endpoint='/sync-open', 27 | method='POST', 28 | remote_connection=context.remote_connection, 29 | data=dict( 30 | definition=definition, 31 | source_directory=source_directory, 32 | ) 33 | ).response 34 | response.log_notifications() 35 | 36 | if not forget: # pragma: no cover 37 | local_opener.update_recent_paths(response, source_directory) 38 | 39 | runner.add_library_path(source_directory) 40 | 41 | return response 42 | -------------------------------------------------------------------------------- /cauldron/cli/commands/run/actions.py: -------------------------------------------------------------------------------- 1 | import cauldron 2 | from cauldron import session 3 | from cauldron.environ import Response 4 | from cauldron.session.projects import Project 5 | 6 | 7 | def get_project(response: Response): 8 | """ 9 | 10 | :return: 11 | """ 12 | 13 | project = cauldron.project.internal_project 14 | 15 | if not project: 16 | response.fail( 17 | code='NO_OPEN_PROJECT', 18 | message='No project opened' 19 | ).console( 20 | """ 21 | [ERROR]: No project has been opened. Use the "open" command to 22 | open a project, or the "create" command to create a new one. 23 | """, 24 | whitespace=1 25 | ) 26 | return None 27 | 28 | return project 29 | 30 | 31 | def preload_project(response: Response, project: Project): 32 | """...""" 33 | session.initialize_results_path(project.results_path) 34 | -------------------------------------------------------------------------------- /cauldron/cli/commands/steps/selection.py: -------------------------------------------------------------------------------- 1 | from cauldron.environ import Response 2 | from cauldron.session.projects import Project 3 | 4 | 5 | def select_step( 6 | response: Response, 7 | project: Project, 8 | step_name: str, 9 | ) -> Response: 10 | """...""" 11 | if project.select_step(step_name) is None: 12 | return ( 13 | response 14 | .update(project=project.kernel_serialize()) 15 | .fail( 16 | code='NO_SUCH_STEP', 17 | message='Step "{}" was not found to select.'.format(step_name) 18 | ) 19 | .console(whitespace=1) 20 | .response 21 | ) 22 | 23 | return ( 24 | response 25 | .update(project=project.kernel_serialize()) 26 | .notify( 27 | kind='SELECTED', 28 | code='SELECTED', 29 | message='Step "{}" has been selected.'.format(step_name) 30 | ) 31 | .console(whitespace=1) 32 | .response 33 | ) 34 | -------------------------------------------------------------------------------- /cauldron/cli/interaction/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cauldron/cli/server/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.cli.server.routes import display # noqa 2 | from cauldron.cli.server.routes import status # noqa 3 | from cauldron.cli.server.routes import execution # noqa 4 | from cauldron.cli.server.routes import synchronize # noqa 5 | from cauldron.cli.server.routes import ui_statuses # noqa 6 | from cauldron.cli.server import run as server_run # noqa 7 | from cauldron.cli.server.run import create_application # noqa 8 | -------------------------------------------------------------------------------- /cauldron/cli/server/arguments.py: -------------------------------------------------------------------------------- 1 | from flask import request as flask_request 2 | 3 | 4 | def from_request(request=None) -> dict: 5 | """ Fetches the arguments for the current Flask application request.""" 6 | 7 | request = request if request else flask_request 8 | 9 | try: 10 | json_args = request.get_json(silent=True) 11 | except Exception: 12 | json_args = None 13 | 14 | try: 15 | get_args = request.values 16 | except Exception: 17 | get_args = None 18 | 19 | arg_sources = list(filter( 20 | lambda arg: arg is not None, 21 | [json_args, get_args, {}] 22 | )) 23 | 24 | return arg_sources[0] 25 | -------------------------------------------------------------------------------- /cauldron/cli/server/authorization.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from flask import Response 4 | from flask import abort 5 | from flask import request 6 | 7 | from cauldron.cli.server import run as server_runner 8 | 9 | 10 | @server_runner.APPLICATION.errorhandler(401) 11 | def custom_401(*args, **kwargs): 12 | return Response('Invalid authorization', 401) 13 | 14 | 15 | def gatekeeper(func): 16 | """ 17 | This function is used to handle authorization code authentication of 18 | protected endpoints. This form of authentication is not recommended 19 | because it's not very secure, but can be used in places where SSH 20 | tunneling or similar strong connection security is not possible. 21 | 22 | The function looks for a special "Cauldron-Authentication-Code" header 23 | in the request and confirms that the specified value matches the code 24 | that was provided by arguments to the Cauldron kernel server. This function 25 | acts as a pass-through if no code is specified when the server starts. 26 | """ 27 | 28 | @wraps(func) 29 | def check_identity(*args, **kwargs): 30 | code = server_runner.authorization['code'] 31 | comparison = request.headers.get('Cauldron-Authentication-Code') 32 | 33 | return ( 34 | abort(401) 35 | if code and code != comparison else 36 | func(*args, **kwargs) 37 | ) 38 | 39 | return check_identity 40 | -------------------------------------------------------------------------------- /cauldron/cli/server/routes/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cauldron/cli/server/routes/display.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import os 3 | 4 | import cauldron 5 | import flask 6 | from cauldron.cli.server import run as server_run 7 | 8 | 9 | @server_run.APPLICATION.route('/view/', methods=['GET', 'POST']) 10 | def view(route: str): 11 | """ 12 | Retrieves the contents of the file specified by the view route if it 13 | exists. 14 | """ 15 | project = cauldron.project.get_internal_project() 16 | results_path = project.results_path if project else None 17 | if not project or not results_path: 18 | return '', 204 19 | 20 | path = os.path.join(results_path, route) 21 | if not os.path.exists(path): 22 | return '', 204 23 | 24 | return flask.send_file( 25 | path, 26 | mimetype=mimetypes.guess_type(path)[0], 27 | cache_timeout=-1 28 | ) 29 | -------------------------------------------------------------------------------- /cauldron/cli/server/routes/ui_statuses.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from cauldron.cli.server import run as server_runner 4 | from cauldron.ui import arguments 5 | from cauldron.ui import statuses 6 | 7 | 8 | @server_runner.APPLICATION.route('/ui-status', methods=['POST']) 9 | def ui_status(): 10 | args = arguments.from_request() 11 | last_timestamp = args.get('last_timestamp', 0) 12 | force = args.get('force', False) 13 | results = statuses.get_status(last_timestamp, force) 14 | return flask.jsonify(results) 15 | -------------------------------------------------------------------------------- /cauldron/cli/sync/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.cli.sync import sync_io as io # noqa 2 | from cauldron.cli.sync import files # noqa 3 | from cauldron.cli.sync import comm # noqa 4 | from cauldron.cli.sync.threads import send_remote_command # noqa 5 | -------------------------------------------------------------------------------- /cauldron/docgen/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.docgen.parsing import parse_function as parse_function 2 | -------------------------------------------------------------------------------- /cauldron/docgen/conversions.py: -------------------------------------------------------------------------------- 1 | def arg_type_to_string(arg_type) -> str: 2 | """ 3 | Converts the argument type to a string 4 | 5 | :param arg_type: 6 | :return: 7 | String representation of the argument type. Multiple return types are 8 | turned into a comma delimited list of type names 9 | """ 10 | 11 | union_params = ( 12 | getattr(arg_type, '__union_params__', None) or 13 | getattr(arg_type, '__args__', None) 14 | ) 15 | 16 | if union_params and isinstance(union_params, (list, tuple)): 17 | return ', '.join([arg_type_to_string(item) for item in union_params]) 18 | 19 | try: 20 | return arg_type.__name__ 21 | except AttributeError: 22 | return '{}'.format(arg_type) 23 | -------------------------------------------------------------------------------- /cauldron/docgen/function_returns.py: -------------------------------------------------------------------------------- 1 | import typing 2 | from cauldron.docgen import conversions 3 | 4 | 5 | def parse(target, lines: typing.List[str]) -> typing.Union[None, dict]: 6 | """ 7 | 8 | :param target: 9 | :param lines: 10 | :return: 11 | """ 12 | 13 | annotations = getattr(target, '__annotations__') 14 | annotations = annotations if annotations is not None else {} 15 | arg_type = annotations.get('return') 16 | return_type = ( 17 | None 18 | if arg_type is None else 19 | conversions.arg_type_to_string(arg_type) 20 | ) 21 | 22 | description = ' '.join([ 23 | line[1:].split(':', 1)[-1].strip() 24 | for line in filter(lambda line: line.startswith(':return'), lines) 25 | ]).strip() 26 | 27 | return dict( 28 | type=return_type, 29 | description=description 30 | ) 31 | -------------------------------------------------------------------------------- /cauldron/plotting/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.plotting._colors import Palettes # noqa 2 | from cauldron.plotting._colors import get_color # noqa 3 | from cauldron.plotting._colors import get_gray_color # noqa 4 | from cauldron.plotting._definitions import ColorPalette # noqa 5 | from cauldron.plotting._helpers import create_layout # noqa 6 | from cauldron.plotting._helpers import make_line_data # noqa 7 | 8 | #: This exists for backward compatibility when there was only 9 | #: one color palette available (<= v1.0.0). For newer use-cases 10 | #: the Palettes enumeration class should be used instead. 11 | PLOT_COLOR_PALETTE = Palettes.categorical_10.value.colors 12 | -------------------------------------------------------------------------------- /cauldron/plotting/_definitions.py: -------------------------------------------------------------------------------- 1 | import typing 2 | 3 | ColorPalette = typing.NamedTuple('ColorPalette', [ 4 | ('name', str), 5 | ('colors', typing.Tuple[typing.Tuple[int, ...], ...]) 6 | ]) 7 | -------------------------------------------------------------------------------- /cauldron/render/utils.py: -------------------------------------------------------------------------------- 1 | html_escapes = [ 2 | ("&", "&"), 3 | ('"', """), 4 | ("'", "'"), 5 | (">", ">"), 6 | ("<", "<"), 7 | ] 8 | 9 | 10 | def html_escape(text: str) -> str: 11 | """ 12 | 13 | :param text: 14 | :return: 15 | """ 16 | 17 | for k, v in html_escapes: 18 | text = text.replace(k, v) 19 | 20 | return text 21 | 22 | 23 | def format_latex(source: str) -> str: 24 | """ 25 | 26 | :param source: 27 | :return: 28 | """ 29 | 30 | source = [line.strip() for line in source.strip().split('\n')] 31 | return ' '.join(source).replace('\\', '\\\\') 32 | -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/MaterialIcons-Regular.0509ab09.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/MaterialIcons-Regular.0509ab09.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/MaterialIcons-Regular.29b882f0.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/MaterialIcons-Regular.29b882f0.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/MaterialIcons-Regular.96c47680.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/MaterialIcons-Regular.96c47680.eot -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/MaterialIcons-Regular.d120c85b.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/MaterialIcons-Regular.d120c85b.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Black.0ef9ee9f.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Black.0ef9ee9f.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Black.4a31d5fa.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Black.4a31d5fa.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Black.otf.2c99d731.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Black.otf.2c99d731.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Black.ttf.1ec93fb0.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Black.ttf.1ec93fb0.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.0bf3a60f.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.0bf3a60f.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.88c36b15.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.88c36b15.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.otf.9330ab0d.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.otf.9330ab0d.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.ttf.400e7325.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BlackIt.ttf.400e7325.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Bold.b23705a4.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Bold.b23705a4.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Bold.cd9e6b79.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Bold.cd9e6b79.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Bold.otf.ac261598.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Bold.otf.ac261598.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Bold.ttf.07a20717.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Bold.ttf.07a20717.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.07ceebf1.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.07ceebf1.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.7e401b3e.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.7e401b3e.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.otf.b81c2d8b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.otf.b81c2d8b.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.ttf.433da739.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-BoldIt.ttf.433da739.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.8d0c3b1c.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.8d0c3b1c.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.c867d05d.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.c867d05d.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.otf.d577e2c5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.otf.d577e2c5.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.ttf.d92614da.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLight.ttf.d92614da.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.5f6c950a.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.5f6c950a.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.d6648c78.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.d6648c78.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.otf.9b9d35be.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.otf.9b9d35be.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.82097c26.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.82097c26.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-It.6c362e00.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-It.6c362e00.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-It.ad486cdf.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-It.ad486cdf.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-It.otf.5f31e7ec.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-It.otf.5f31e7ec.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-It.ttf.7ee03da8.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-It.ttf.7ee03da8.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Light.420d839a.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Light.420d839a.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Light.e7daa4ab.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Light.e7daa4ab.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Light.otf.cd6456a8.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Light.otf.cd6456a8.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Light.ttf.7db69e93.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Light.ttf.7db69e93.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.0b4be0f9.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.0b4be0f9.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.cf7fa055.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.cf7fa055.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.otf.ed22e01b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.otf.ed22e01b.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.ttf.9b26dad3.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-LightIt.ttf.9b26dad3.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Regular.906ba80a.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Regular.906ba80a.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Regular.da547242.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Regular.da547242.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Regular.otf.344f4c8d.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Regular.otf.344f4c8d.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Regular.ttf.8bb5b88b.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Regular.ttf.8bb5b88b.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.d22df054.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.d22df054.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.e8db8af2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.e8db8af2.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.otf.90cd4925.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.otf.90cd4925.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.ttf.b13c669d.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-Semibold.ttf.b13c669d.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.41995df8.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.41995df8.ttf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.6de08aa7.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.6de08aa7.otf -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.otf.b27999d8.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.otf.b27999d8.woff -------------------------------------------------------------------------------- /cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.c474abd9.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.c474abd9.woff2 -------------------------------------------------------------------------------- /cauldron/resources/app/assets/img/logo-128.a32de47b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/assets/img/logo-128.a32de47b.png -------------------------------------------------------------------------------- /cauldron/resources/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/app/favicon.ico -------------------------------------------------------------------------------- /cauldron/resources/app/index.html: -------------------------------------------------------------------------------- 1 | Cauldron
-------------------------------------------------------------------------------- /cauldron/resources/examples/bokeh/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "bokeh", 3 | "name": "bokeh", 4 | "steps": [ 5 | "color_scatter.py", 6 | "with-figure.py" 7 | ] 8 | } -------------------------------------------------------------------------------- /cauldron/resources/examples/bokeh/color_scatter.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | from bokeh.plotting import figure 3 | 4 | # prepare some data 5 | x = [1, 2, 3, 4, 5] 6 | y = [6, 7, 2, 4, 5] 7 | 8 | # create a new plot with a title and axis labels 9 | p = figure( 10 | title="simple line example", 11 | x_axis_label='x', 12 | y_axis_label='y' 13 | ) 14 | 15 | # add a line renderer with legend and line thickness 16 | p.line(x, y, legend="Temp.", line_width=2) 17 | 18 | cd.display.bokeh(p) 19 | -------------------------------------------------------------------------------- /cauldron/resources/examples/bokeh/with-figure.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | from bokeh.plotting import figure 3 | 4 | 5 | plot = figure() 6 | plot.line(x=[1, 2, 3], y=[3, 4, 5]) 7 | plot.scatter(x=[1, 2, 3], y=[3, 4, 5]) 8 | 9 | cd.display.bokeh(plot) 10 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_cauldron/S01-create-data.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | import cauldron as cd 4 | 5 | df = pd.DataFrame( 6 | np.random.randn(10, 5), 7 | columns=['a', 'b', 'c', 'd', 'e'] 8 | ) 9 | 10 | cd.display.header('Random Data Frame:') 11 | cd.display.markdown( 12 | """ 13 | We've created a random data frame with 14 | 15 | * Shape: [{{ x }}, {{ y}}] 16 | * Column Names: {{ columns }} 17 | 18 | It looks like: 19 | """, 20 | x=df.shape[0], 21 | y=df.shape[1], 22 | columns=', '.join(df.columns.tolist()) 23 | ) 24 | 25 | cd.display.table(df) 26 | 27 | print('We store the DataFrame in shared variables for use by other steps.') 28 | cd.shared.df = df 29 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_cauldron/S02-plot-data.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import cauldron as cd 3 | 4 | df = cd.shared.df 5 | 6 | for column_name in df.columns: 7 | plt.plot(df[column_name]) 8 | 9 | plt.title('Random Plot') 10 | plt.xlabel('Indexes') 11 | plt.ylabel('Values') 12 | 13 | cd.display.pyplot() 14 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_cauldron/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_cauldron", 3 | "steps":[ 4 | "S01-create-data.py", 5 | "S02-plot-data.py" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_cauldron/step_tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/examples/hello_cauldron/step_tests/__init__.py -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_cauldron/step_tests/test_hello_cauldron.py: -------------------------------------------------------------------------------- 1 | from cauldron.steptest import StepTestCase 2 | 3 | 4 | class TestNotebook(StepTestCase): 5 | 6 | def test_first_attempt(self): 7 | """Should run the step without error.""" 8 | self.run_step('S01-create-data.py') 9 | 10 | def test_second_attempt(self): 11 | """Should run the same step a second time without error.""" 12 | self.run_step('S01-create-data.py') 13 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello_text", 3 | "steps": [ 4 | "hello.py", 5 | "portions.py", 6 | "variables.py", 7 | "equations.py", 8 | "code.py" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/code.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | 3 | cd.display.markdown( 4 | """ 5 | # Syntax Highlight Code Blocks 6 | 7 | Code can also be added to the notebook with syntax highlighting like so: 8 | """ 9 | ) 10 | 11 | cd.display.code_block( 12 | """ 13 | import cauldron as cd 14 | cd.display.code_block( 15 | code='print("Hello World!")', 16 | language='py3' 17 | ) 18 | """, 19 | language_id='py3', 20 | ) 21 | 22 | cd.display.markdown( 23 | """ 24 | Code can also be included from a file using the same display command, 25 | but specifying a path instead of the code as a string: 26 | """ 27 | ) 28 | 29 | cd.display.code_block( 30 | """ 31 | import cauldron as cd 32 | cd.display.code_block(path='cauldron.json') 33 | """, 34 | language_id='py3', 35 | ) 36 | 37 | cd.display.markdown( 38 | """ 39 | which would produce the following result: 40 | """ 41 | ) 42 | 43 | cd.display.code_block(path='cauldron.json') 44 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/equations.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | 3 | cd.display.header('Latex Equation Support') 4 | cd.display.latex('e = m * c^2') 5 | 6 | cd.display.markdown( 7 | """ 8 | Latex equations can also be included within markdown blocks. The equations 9 | can be inline, $$ 2^2 = 4 $$, by wrapping the equation in double $, or 10 | they can be separate lines with triple $ like: 11 | 12 | $$$ 13 | test = @frac { @sqrt{ x_1^2 + x_2^2 } } { N } 14 | $$$ 15 | 16 | Most of latex math mode is supported. However, the latex backslash 17 | character has been replaced by the ampersand, @, character because 18 | backslashes are escape characters in Markdown and Python strings. 19 | """ 20 | ) 21 | 22 | 23 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/hello.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | 3 | cd.display.text('You can add text') 4 | 5 | cd.display.text( 6 | """ 7 | You can also 8 | add text that 9 | preserves formatting 10 | by setting the 11 | 12 | "preformatted" 13 | 14 | argument to true 15 | """, 16 | preformatted=True 17 | ) 18 | 19 | print( 20 | """ 21 | The print() function works just like it normally does, and adds 22 | preformatted text. However, you can add more than just text: 23 | """, 24 | 21 * 2, 25 | cd 26 | ) 27 | 28 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/portions.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | 3 | with open('lorem_ipsum.txt', 'r') as f: 4 | text = f.read() 5 | 6 | cd.display.header('HTML Headers with different levels') 7 | 8 | cd.display.header('First 5 Lines with head()', 2) 9 | cd.display.head(text) 10 | 11 | cd.display.header('Last 5 Lines with tail()', 2) 12 | cd.display.tail(text) 13 | 14 | cd.shared.lorem_ipsum = text 15 | -------------------------------------------------------------------------------- /cauldron/resources/examples/hello_text/variables.py: -------------------------------------------------------------------------------- 1 | import json 2 | import cauldron as cd 3 | 4 | with open('cauldron.json', 'r') as f: 5 | data = json.load(f) 6 | 7 | 8 | cd.display.markdown( 9 | """ 10 | {{ greeting }} 11 | 12 | _Markdown syntax_ is also supported. It comes with __Jinja2__ templating, 13 | which allows for more advanced templating than Python's built-in string 14 | formatting. 15 | 16 | {% for key, value in dictionary | dictsort %} 17 | * {{ key }}: {{ value }} 18 | {% endfor %} 19 | """, 20 | greeting='More Advanced Text', 21 | dictionary=data 22 | ) 23 | 24 | -------------------------------------------------------------------------------- /cauldron/resources/examples/pyplot/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pyplot", 3 | "steps":[ 4 | "histogram.py" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /cauldron/resources/examples/pyplot/histogram.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | import cauldron as cd 5 | 6 | # Create data to plot 7 | mu = 100 8 | sigma = 15 9 | x = mu + sigma * np.random.randn(10000) 10 | 11 | cd.display.markdown( 12 | """ 13 | # Plotting with PyPlot 14 | 15 | We created a normally-randomized data set centered at $$ @mu = {{ mu }} $$ 16 | and with a standard deviation of $$ @sigma = {{ sigma }} $$. 17 | """, 18 | mu=mu, 19 | sigma=sigma 20 | ) 21 | 22 | # Histogram of the data 23 | n, bins, patches = plt.hist( 24 | x=x, 25 | bins=50, 26 | facecolor='green', 27 | alpha=0.75, 28 | density=1, 29 | ) 30 | 31 | plt.xlabel('Smarts') 32 | plt.ylabel('Probability') 33 | plt.title(r'$\mathrm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') 34 | plt.axis([40, 160, 0, 0.03]) 35 | plt.grid(True) 36 | 37 | cd.display.pyplot() 38 | -------------------------------------------------------------------------------- /cauldron/resources/examples/seaborn/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seaborn", 3 | "steps": [ 4 | "facets.py" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /cauldron/resources/examples/seaborn/facets.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | import pandas as pd 4 | import seaborn as sns 5 | import cauldron as cd 6 | 7 | sns.set() 8 | 9 | # Generate an example radial datast 10 | r = np.linspace(0, 10, num=100) 11 | df = pd.DataFrame({'r': r, 'slow': r, 'medium': 2 * r, 'fast': 4 * r}) 12 | 13 | # Convert the dataframe to long-form or "tidy" format 14 | df = pd.melt(df, id_vars=['r'], var_name='speed', value_name='theta') 15 | 16 | # Set up a grid of axes with a polar projection 17 | g = sns.FacetGrid(df, col="speed", hue="speed", 18 | subplot_kws=dict(projection='polar'), size=4.5, 19 | sharex=False, sharey=False, despine=False) 20 | 21 | # Draw a scatterplot onto each axes in the grid 22 | g.map(plt.scatter, "theta", "r") 23 | 24 | cd.display.pyplot() 25 | -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/S01-introduction.md: -------------------------------------------------------------------------------- 1 | Time Cover Genders 2 | ================== 3 | 4 | This example uses data from 5 | [CrowdFlower's "Data For Everyone"](http://www.crowdflower.com/data-for-everyone/) 6 | data set on the yearly breakdown of the number of men and women appearing on 7 | Time Magazine covers from the year 1923. 8 | -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/S02-load-data.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | import pandas as pd 3 | 4 | cd.display.markdown( 5 | """ 6 | ## Load CSV Data 7 | 8 | In this step we load the time gender CSV data 9 | and display it using the table display function 10 | as follows: 11 | 12 | ``` 13 | cd.display.table(df) 14 | ``` 15 | 16 | We're passing in the Pandas DataFrame that was 17 | returned from the *read_csv* function. 18 | """ 19 | ) 20 | 21 | df = pd.read_csv('TIME_Gender_Ratio.csv') 22 | 23 | cd.display.table(df, scale=0.5) 24 | 25 | cd.shared.df = df 26 | -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/S03-graph-raw-data.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | from cauldron import plotting 3 | 4 | import plotly.graph_objs as go 5 | 6 | 7 | df = cd.shared.df 8 | 9 | cd.display.markdown( 10 | """ 11 | ## Plot Data 12 | 13 | Now we're going to plot the loaded data to get an 14 | idea for what it looks like. For this notebook, 15 | we're going to use the Plotly plotting library. 16 | """ 17 | ) 18 | 19 | cd.display.plotly( 20 | data=go.Scatter( 21 | x=df['Year'], 22 | y=100.0 * df['Female'] / df['Total'], 23 | mode='lines+markers' 24 | ), 25 | layout=plotting.create_layout( 26 | title='Female Time Covers', 27 | y_label='Percentage each Year (%)', 28 | x_label='Year' 29 | ) 30 | ) 31 | 32 | cd.display.markdown( 33 | """ 34 | Immediately apparent from this plot is that the 35 | data has high-frequency variations. We want to get 36 | a better sense of the trend. To do that we'll use 37 | a running-window smoothing operator that looks like: 38 | 39 | $$$ 40 | X_i = @frac{1}{2N + 1} @sum_{@delta=-N}^N x_{@delta} 41 | $$$ 42 | 43 | where $$N$$ is the window size. 44 | """ 45 | ) 46 | -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/S05-export-data.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | 3 | df = cd.shared.df 4 | 5 | percentages = df['Female'] / df['Total'] 6 | smoothed = cd.shared.smooth_data(percentages, 4) 7 | 8 | normalized = [s - min(smoothed) for s in smoothed] 9 | normalized = [n / max(normalized) for n in normalized] 10 | 11 | cd.display.json(percentages=normalized) 12 | 13 | cd.display.markdown( 14 | """ 15 | ## HTML & JavaScript 16 | 17 | Cauldron is capable of working directly with HTML and JavaScript. 18 | This is useful if you want to create custom displays. In this example 19 | we'll create a custom graphic for the data above using D3 directly 20 | from JavaScript. 21 | 22 | First we need to save some data from Python into our notebook page so 23 | that JavaScript has access to it. To do that we use the JSON display 24 | function: 25 | 26 | `` 27 | cd.display.json(data=my_data) 28 | `` 29 | 30 | where we set a key and a value. In this case we map the key "data" to the 31 | the variable "my_data". It is important to understand that this data 32 | is going to be serialized in JavaScript, which requires mapping only 33 | data types that JSON serialization supports. 34 | """ 35 | ) -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/S06-activity.html: -------------------------------------------------------------------------------- 1 |
2 | 20 | -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/_styles.css: -------------------------------------------------------------------------------- 1 | #activityDisplayChart div { 2 | display: inline-block; 3 | width: 10px; 4 | height: 15px; 5 | margin-right: 3px; 6 | } -------------------------------------------------------------------------------- /cauldron/resources/examples/time-gender/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "time-gender", 3 | "name": "time-gender", 4 | "web_includes": ["_styles.css"], 5 | "naming_scheme": "S{{##}}-{{name}}.{{ext}}", 6 | "steps": [ 7 | "S01-introduction.md", 8 | "S02-load-data.py", 9 | "S03-graph-raw-data.py", 10 | "S04-smoothed-plot.py", 11 | "S05-export-data.py", 12 | "S06-activity.html" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /cauldron/resources/templates/StdErr.html: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 |
10 |
17 | keyboard_arrow_down 18 | keyboard_arrow_up 19 |
Console Error Log
20 |
21 |
22 |
23 |
24 | 33 |
34 | -------------------------------------------------------------------------------- /cauldron/resources/templates/bokeh_component.html: -------------------------------------------------------------------------------- 1 | 13 | 14 |
18 |
19 | {{ dom }} 20 |
21 | 27 |
28 | -------------------------------------------------------------------------------- /cauldron/resources/templates/code-block.html: -------------------------------------------------------------------------------- 1 |
5 | {% if title %} 6 |
{{ title }}
7 | {% endif %} 8 | 9 |
{{ code }}
10 | 11 | {% if caption %} 12 |
{{ caption }}
13 | {% endif %} 14 |
15 | -------------------------------------------------------------------------------- /cauldron/resources/templates/dependencies.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
9 | keyboard_arrow_down 10 | keyboard_arrow_up 11 |
Project Definitions
12 |
13 | 14 |
15 |
16 | 17 | 41 |
42 | -------------------------------------------------------------------------------- /cauldron/resources/templates/embedded-step.py.txt: -------------------------------------------------------------------------------- 1 | {{ source_contents }} 2 | 3 | import cauldron as __cauldron__ 4 | __cauldron__.display.whitespace(0) 5 | __cauldron__.step.breathe() 6 | -------------------------------------------------------------------------------- /cauldron/resources/templates/first-step.py: -------------------------------------------------------------------------------- 1 | """ 2 | # {{ project_name }} 3 | """ 4 | import cauldron as cd 5 | 6 | cd.display.markdown(__doc__) 7 | -------------------------------------------------------------------------------- /cauldron/resources/templates/image.html: -------------------------------------------------------------------------------- 1 | 17 | 18 |
22 | 33 |
34 | -------------------------------------------------------------------------------- /cauldron/resources/templates/import-error.html: -------------------------------------------------------------------------------- 1 |
2 |
Import Error: {{ library_name }}
3 |
4 | Please confirm that this library is properly installed in the active 5 | python environment in which Cauldron is running. 6 | {{ additional_info }} 7 |
8 |
9 | -------------------------------------------------------------------------------- /cauldron/resources/templates/json_include.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /cauldron/resources/templates/katex.html: -------------------------------------------------------------------------------- 1 | {%- if inline -%} 2 | 3 | {%- else -%} 4 |
5 | {%- endif -%} 6 | 18 | -------------------------------------------------------------------------------- /cauldron/resources/templates/kernel_introduction.txt: -------------------------------------------------------------------------------- 1 | ___ _ _ 2 | / __\__ _ _ _| | __| |_ __ ___ _ __ 3 | / / / _` | | | | |/ _` | '__/ _ \| '_ \ 4 | / /__| (_| | |_| | | (_| | | | (_) | | | | 5 | \____/\__,_|\__,_|_|\__,_|_| \___/|_| |_| 6 | 7 | "The Un-Notebook" 8 | Interactive Data Environment 9 | 10 | Version: {{ version }} 11 | -------------------------------------------------------------------------------- /cauldron/resources/templates/list_grid.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /cauldron/resources/templates/listing.html: -------------------------------------------------------------------------------- 1 | <{{ type }} class="cd-Listing cd-Listing--{{ css_modifier }}"> 2 | {% for item in items %} 3 |
  • {{ item }}
  • 4 | {% endfor %} 5 | 6 | -------------------------------------------------------------------------------- /cauldron/resources/templates/markdown-block.html: -------------------------------------------------------------------------------- 1 |
    5 | {{ text }} 6 |
    7 | -------------------------------------------------------------------------------- /cauldron/resources/templates/markdown-error.html: -------------------------------------------------------------------------------- 1 |
    2 |
    Markdown Rendering Error
    3 |
    {{ error.message }}
    4 |
    5 | -------------------------------------------------------------------------------- /cauldron/resources/templates/notebook-script-header.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /cauldron/resources/templates/plotly-component.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 |
    22 | {{ dom }} 23 | 28 |
    29 |
    30 | -------------------------------------------------------------------------------- /cauldron/resources/templates/project-dependency.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    8 |
    {{ filename }}
    9 |
    10 | {{ code }} 11 |
    12 |
    13 | 14 |
    15 |
    16 | -------------------------------------------------------------------------------- /cauldron/resources/templates/report-top-bar.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 |
    {{ title }}
    5 |
    6 | 7 |
    8 |
    9 | -------------------------------------------------------------------------------- /cauldron/resources/templates/report.js.template: -------------------------------------------------------------------------------- 1 | (function () { 2 | 3 | window.RESULTS = {{ DATA }}; 4 | 5 | }()); 6 | -------------------------------------------------------------------------------- /cauldron/resources/templates/shell_introduction.txt: -------------------------------------------------------------------------------- 1 | ___ _ _ 2 | / __\__ _ _ _| | __| |_ __ ___ _ __ 3 | / / / _` | | | | |/ _` | '__/ _ \| '_ \ 4 | / /__| (_| | |_| | | (_| | | | (_) | | | | 5 | \____/\__,_|\__,_|_|\__,_|_| \___/|_| |_| 6 | 7 | "The Un-Notebook" 8 | Data Analysis Environment 9 | 10 | Version: {{ version }} 11 | 12 | --- HELP --- 13 | For help, type "help" or "?" in the command prompt 14 | to get information on the available commands and 15 | how to get started. 16 | -------------------------------------------------------------------------------- /cauldron/resources/templates/status-variable.template.html: -------------------------------------------------------------------------------- 1 |
    2 |
    5 | {{ name }}: 6 | {% if types %} 7 | {{ type }} 8 | {% endif %} 9 |
    10 | {% if values %} 11 | 17 | {% endif %} 18 |
    19 | 20 | -------------------------------------------------------------------------------- /cauldron/resources/templates/step-status.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 |
    Current Run Status:
    5 | 6 | {% if progress_message %} 7 |
    8 | {{ progress_message }} 9 |
    10 | {% endif %} 11 | 12 | {% if progress > 0 %} 13 |
    14 |
    18 |
    19 | {% endif %} 20 | 21 | {% if sub_progress_message %} 22 |
    23 | {{ sub_progress_message }} 24 |
    25 | {% endif %} 26 | 27 | {% if sub_progress > 0 %} 28 |
    29 |
    33 |
    34 | {% endif %} 35 | 36 |
    37 | -------------------------------------------------------------------------------- /cauldron/resources/templates/step-stop.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | error_outline 4 |
    5 | 6 |
    7 |
    Step Stopped
    8 |
    {{ message }}
    9 | 10 | {% if frame %} 11 |
    12 |
    13 | file: {{ frame.filename | e }} 14 |
    15 | 16 | {% if frame.location %} 17 |
    18 |   in: {{ frame.location | e }} 19 |
    20 | {% endif %} 21 | 22 |
    23 | line: {{ frame.line_number | e }} 24 |
    25 |
    26 | {% endif %} 27 |
    28 |
    29 | -------------------------------------------------------------------------------- /cauldron/resources/templates/table.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 | 37 | -------------------------------------------------------------------------------- /cauldron/resources/templates/tree.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 15 |
    16 | -------------------------------------------------------------------------------- /cauldron/resources/templates/unit_test.html: -------------------------------------------------------------------------------- 1 | {{ value }} 2 | -------------------------------------------------------------------------------- /cauldron/resources/templates/user-code-error.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    {{ type | e }}
    4 |
    {{ message | e }}
    5 |
    6 | 7 |
    8 | {% for s in stack %} 9 |
    10 |
    {{ s.filename | e }}
    11 | {% if s.location %} 12 |
    13 | in: {{ s.location | e }} 14 |
    15 | {% endif %} 16 |
    17 | line: {{ s.line_number | e }} 18 |
    19 |
    {{ s.line | e }}
    20 |
    21 | {% endfor %} 22 |
    23 | 24 |
    25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /cauldron/resources/templates/user-code-error.txt: -------------------------------------------------------------------------------- 1 | 2 | ___ _ __ _ __ ___ _ __ 3 | / _ \ '__| '__/ _ \| '__| 4 | | __/ | | | | (_) | | 5 | \___|_| |_| \___/|_| 6 | 7 | [{{ type }}]: {{ message }} 8 | {% for s in stack %} 9 | ## "{{ s.filename }}" 10 | {% if s.location -%} 11 | ## * IN: {{ s.location }} 12 | {% endif -%} 13 | ## * LINE: {{ s.line_number }} 14 | ## 15 | ## {{ s.line }} 16 | ## 17 | {% endfor %} 18 | -------------------------------------------------------------------------------- /cauldron/resources/web/assets/32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/32px.png -------------------------------------------------------------------------------- /cauldron/resources/web/assets/40px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/40px.png -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/MaterialIcons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/MaterialIcons-Regular.eot -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /cauldron/resources/web/assets/fonts/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/fonts/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /cauldron/resources/web/assets/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/resources/web/assets/throbber.gif -------------------------------------------------------------------------------- /cauldron/resources/web/project.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Cauldron Project 10 | 11 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
    38 | 39 | 40 | -------------------------------------------------------------------------------- /cauldron/runner/html_file.py: -------------------------------------------------------------------------------- 1 | from cauldron import render 2 | from cauldron import templating 3 | from cauldron.session import projects 4 | 5 | 6 | def run( 7 | project: 'projects.Project', 8 | step: 'projects.ProjectStep' 9 | ) -> dict: 10 | """ 11 | 12 | :param project: 13 | :param step: 14 | :return: 15 | """ 16 | 17 | with open(step.source_path, 'r') as f: 18 | code = f.read() 19 | 20 | step.report.append_body(render.html(templating.render( 21 | template=code, 22 | **project.shared.fetch(None) 23 | ))) 24 | 25 | return {'success': True} 26 | -------------------------------------------------------------------------------- /cauldron/runner/markdown_file.py: -------------------------------------------------------------------------------- 1 | import cauldron 2 | from cauldron import templating 3 | from cauldron.session import projects 4 | 5 | 6 | def run( 7 | project: 'projects.Project', 8 | step: 'projects.ProjectStep' 9 | ) -> dict: 10 | """ 11 | Runs the markdown file and renders the contents to the notebook display 12 | 13 | :param project: 14 | :param step: 15 | :return: 16 | A run response dictionary containing 17 | """ 18 | 19 | with open(step.source_path, 'r') as f: 20 | code = f.read() 21 | 22 | try: 23 | cauldron.display.markdown(code, **project.shared.fetch(None)) 24 | return {'success': True} 25 | except Exception as err: 26 | return dict( 27 | success=False, 28 | html_message=templating.render_template( 29 | 'markdown-error.html', 30 | error=err 31 | ) 32 | ) 33 | -------------------------------------------------------------------------------- /cauldron/session/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from cauldron import environ 4 | from cauldron.environ import systems 5 | from cauldron.session.exposed import ExposedProject 6 | from cauldron.session.exposed import ExposedStep 7 | from cauldron.session.writing import file_io 8 | 9 | project = ExposedProject() 10 | step = ExposedStep() 11 | 12 | 13 | def initialize_results_path(results_path: str): 14 | """...""" 15 | dest_path = environ.paths.clean(results_path) 16 | if not os.path.exists(dest_path): 17 | os.makedirs(dest_path) 18 | 19 | web_src_path = environ.paths.resources('web') 20 | for item in os.listdir(web_src_path): 21 | item_path = os.path.join(web_src_path, item) 22 | out_path = os.path.join(dest_path, item) 23 | 24 | systems.remove(out_path, max_retries=10) 25 | file_io.copy(file_io.FILE_COPY_ENTRY( 26 | source=item_path, 27 | destination=out_path 28 | )) 29 | -------------------------------------------------------------------------------- /cauldron/session/projects/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.session.projects.project import DEFAULT_SCHEME # noqa 2 | from cauldron.session.projects.project import Project # noqa 3 | from cauldron.session.projects.project import StopCondition # noqa 4 | from cauldron.session.projects.steps import ProjectStep # noqa 5 | -------------------------------------------------------------------------------- /cauldron/session/writing/components/__init__.py: -------------------------------------------------------------------------------- 1 | from cauldron.session import projects 2 | from cauldron.session.writing.components import bokeh_component 3 | from cauldron.session.writing.components import definitions 4 | from cauldron.session.writing.components import plotly_component 5 | from cauldron.session.writing.components import project_component 6 | from cauldron.session.writing.components.definitions import COMPONENT 7 | from cauldron.session.writing.components.definitions import WEB_INCLUDE 8 | 9 | 10 | def _get_components(lib_name: str, project: 'projects.Project') -> COMPONENT: 11 | if lib_name == 'bokeh': 12 | return bokeh_component.create(project) 13 | 14 | if lib_name == 'plotly': 15 | return plotly_component.create(project) 16 | 17 | # Unknown components will just return as empty components. There used 18 | # to be a shared component type that was removed in 1.0.0, but hadn't 19 | # been used for a long time before that. If that becomes interesting 20 | # again old code can be reviewed to see how shared components once 21 | # worked. 22 | return COMPONENT([], []) 23 | 24 | 25 | def get(step: 'projects.ProjectStep') -> COMPONENT: 26 | """...""" 27 | return definitions.merge_components( 28 | project_component.create_many(step.project, step.web_includes), 29 | *[ 30 | _get_components(name, step.project) 31 | for name in step.report.library_includes 32 | ], 33 | ) 34 | -------------------------------------------------------------------------------- /cauldron/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.9", 3 | "notebookVersion": "v1" 4 | } 5 | -------------------------------------------------------------------------------- /cauldron/test/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /cauldron/test/cli/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/commands/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/commands/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_cd.py: -------------------------------------------------------------------------------- 1 | import os 2 | from unittest.mock import MagicMock 3 | from unittest.mock import patch 4 | 5 | from cauldron import environ 6 | from cauldron.test import support 7 | 8 | MY_DIRECTORY = environ.paths.clean(os.path.dirname(__file__)) 9 | 10 | 11 | @patch('cauldron.cli.commands.cd.os.chdir') 12 | def test_cd(os_chdir: MagicMock): 13 | """Should change to the specified directory.""" 14 | response = support.run_command('cd "{}"'.format(MY_DIRECTORY)) 15 | assert response.success, 'Expect cd to succeed.' 16 | assert MY_DIRECTORY == os_chdir.call_args[0][0], """ 17 | Expect to change to the specified directory, removing the 18 | wrapped quotation marks along the way. 19 | """ 20 | 21 | 22 | @patch('cauldron.cli.commands.cd.os.chdir') 23 | def test_cd_no_such_directory(os_chdir: MagicMock): 24 | """Should fail to change to non-existent directory.""" 25 | os_chdir.side_effect = FileNotFoundError 26 | response = support.run_command('cd "{}"'.format(MY_DIRECTORY)) 27 | assert support.has_error_code(response, 'NO_SUCH_DIRECTORY') 28 | 29 | 30 | @patch('cauldron.cli.commands.cd.os.chdir') 31 | def test_cd_permission_error(os_chdir: MagicMock): 32 | """Should fail to change to directory one cannot access.""" 33 | os_chdir.side_effect = PermissionError 34 | response = support.run_command('cd "{}"'.format(MY_DIRECTORY)) 35 | assert support.has_error_code(response, 'PERMISSION_DENIED') 36 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_clear.py: -------------------------------------------------------------------------------- 1 | from cauldron.test import support 2 | from cauldron.test.support import scaffolds 3 | 4 | 5 | class TestClear(scaffolds.ResultsTest): 6 | """...""" 7 | 8 | def test_clear(self): 9 | """Should clear variables successfully.""" 10 | support.run_command('open @examples:hello_cauldron --forget') 11 | response = support.run_command('clear') 12 | self.assertFalse(response.failed, 'should not have failed') 13 | 14 | def test_no_project(self): 15 | """Should error when no project is open.""" 16 | response = support.run_command('clear') 17 | self.assertTrue(response.failed, 'should not have failed') 18 | self.assert_has_error_code(response, 'NO_OPEN_PROJECT') 19 | 20 | def test_remote(self): 21 | """Should error when no remote project is open.""" 22 | response = support.run_remote_command('clear') 23 | self.assert_has_error_code(response, 'NO_OPEN_PROJECT') 24 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_close.py: -------------------------------------------------------------------------------- 1 | import cauldron 2 | from cauldron.test import support 3 | from cauldron.test.support import scaffolds 4 | 5 | 6 | class TestClose(scaffolds.ResultsTest): 7 | """Test suite for the close CLI command""" 8 | 9 | def test_close_open_project(self): 10 | """Should close open project.""" 11 | support.run_command('open @examples:hello_cauldron --forget') 12 | response = support.run_command('close') 13 | self.assertTrue(response.success, 'should not have failed') 14 | self.assertIsNone(cauldron.project.get_internal_project()) 15 | 16 | def test_no_open_project(self): 17 | """Should not close when no project is open""" 18 | response = support.run_command('close') 19 | self.assert_has_success_code(response, 'NO_OPEN_PROJECT') 20 | 21 | def test_remote(self): 22 | """Should not close remotely when no project is open""" 23 | response = support.run_remote_command('close') 24 | self.assert_has_success_code(response, 'NO_OPEN_PROJECT') 25 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_disconnect_command.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | from unittest.mock import MagicMock 3 | from requests import exceptions as request_exceptions 4 | 5 | from cauldron.test import support 6 | from cauldron.test.support import scaffolds 7 | 8 | 9 | class TestDisconnectCommand(scaffolds.ResultsTest): 10 | """...""" 11 | 12 | def test_disconnected(self): 13 | """Should fail if no url is provided in the command.""" 14 | 15 | r = support.run_command('disconnect') 16 | self.assertFalse(r.failed) 17 | 18 | def test_autocomplete(self): 19 | """Should return empty options for autocomplete.""" 20 | 21 | result = support.autocomplete('disconnect') 22 | self.assertEqual(len(result), 0) -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_exit.py: -------------------------------------------------------------------------------- 1 | from cauldron.test import support 2 | from cauldron.test.support import scaffolds 3 | 4 | 5 | class TestExit(scaffolds.ResultsTest): 6 | """...""" 7 | 8 | def test_exit(self): 9 | """...""" 10 | 11 | r = support.run_command('exit') 12 | self.assertTrue(r.ended, 'should have ended') 13 | self.assertFalse(r.failed, 'should not have failed') 14 | 15 | 16 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_steps_selection.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | from cauldron import environ 4 | from cauldron.cli.commands.steps import selection 5 | from cauldron.test import support 6 | 7 | 8 | def test_select_step(): 9 | """Should select the specified step.""" 10 | project = MagicMock() 11 | response = selection.select_step(environ.Response(), project, 'foo.py') 12 | assert support.has_success_code(response, 'SELECTED') 13 | 14 | 15 | def test_select_step_failed(): 16 | """Should fail to select the specified step if it does not exist.""" 17 | project = MagicMock() 18 | project.select_step.return_value = None 19 | response = selection.select_step(environ.Response(), project, 'foo.py') 20 | assert support.has_error_code(response, 'NO_SUCH_STEP') 21 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_ui.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | from unittest.mock import patch 3 | 4 | from pytest import mark 5 | 6 | from cauldron.test import support 7 | 8 | 9 | @patch('cauldron.cli.commands.ui.ui.start') 10 | def test_ui(ui_start: MagicMock): 11 | """Should retrieve version info.""" 12 | response = support.run_command('ui') 13 | assert response.success, 'Expect command to succeed.' 14 | assert 1 == ui_start.call_count, 'Expect ui to be started.' 15 | 16 | 17 | AUTOCOMPLETE_SCENARIOS = [ 18 | ('ui --p', {'port', 'public'}), 19 | ('ui foo', set()), 20 | ('ui -', {'p', 'n', '-'}), 21 | ] 22 | 23 | 24 | @mark.parametrize('command, expected', AUTOCOMPLETE_SCENARIOS) 25 | def test_ui_autocomplete(command: str, expected: set): 26 | """Should return the expected autocomplete options.""" 27 | results = support.autocomplete(command) 28 | assert expected == set(results) 29 | -------------------------------------------------------------------------------- /cauldron/test/cli/commands/test_version.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | from cauldron.test import support 3 | from cauldron.test.support import scaffolds 4 | from cauldron.cli.commands import version 5 | 6 | 7 | class TestVersion(scaffolds.ResultsTest): 8 | """...""" 9 | 10 | def test_version(self): 11 | """Should retrieve version info.""" 12 | r = support.run_command('version') 13 | self.assertFalse(r.failed, 'should not have failed') 14 | 15 | def test_version_args(self): 16 | """Should retrieve version info with additional args.""" 17 | r = support.run_command('version --verbose --json') 18 | self.assertFalse(r.failed, 'should not have failed') 19 | 20 | def test_pretty_print(self): 21 | """Should pretty print the source dictionary.""" 22 | data = dict( 23 | a=[False, 1, 'two', 3.000001, dict(a=1, b='tester')], 24 | b=OrderedDict(a=12, b='hello'), 25 | c=dict(a=1, b=2, c=3) 26 | ) 27 | 28 | result = version.pretty_print(data) 29 | self.assertTrue(len(result)) 30 | self.assertGreater(result.find('hello'), 0) 31 | self.assertGreater(result.find('two'), 0) 32 | self.assertGreater(result.find('tester'), 0) 33 | 34 | def test_version_remote(self): 35 | """Should retrieve version info.""" 36 | r = support.run_remote_command('version') 37 | self.assertFalse(r.failed, 'should not have failed') 38 | -------------------------------------------------------------------------------- /cauldron/test/cli/interaction/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/interaction/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/server/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/server/routes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/server/routes/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/server/routes/synchronize/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/server/routes/synchronize/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/server/routes/synchronize/test_sync_status.py: -------------------------------------------------------------------------------- 1 | from cauldron.test import support 2 | from cauldron.test.support import flask_scaffolds 3 | 4 | 5 | class TestSyncStatus(flask_scaffolds.FlaskResultsTest): 6 | """...""" 7 | 8 | def test_sync_status_no_project(self): 9 | """...""" 10 | 11 | sync_status = self.get('/sync-status') 12 | self.assertEqual(sync_status.flask.status_code, 200) 13 | 14 | response = sync_status.response 15 | self.assert_has_error_code(response, 'NO_PROJECT') 16 | 17 | def test_sync_status_valid(self): 18 | """...""" 19 | 20 | support.create_project(self, 'angelica') 21 | 22 | sync_status = self.get('/sync-status') 23 | self.assertEqual(sync_status.flask.status_code, 200) 24 | 25 | response = sync_status.response 26 | self.assertEqual(len(response.errors), 0) 27 | 28 | status = response.data.get('status') 29 | self.assertIsNotNone(status) 30 | self.assertTrue('project' in status) 31 | -------------------------------------------------------------------------------- /cauldron/test/cli/server/routes/synchronize/test_sync_touch.py: -------------------------------------------------------------------------------- 1 | from cauldron.test import support 2 | from cauldron.test.support import flask_scaffolds 3 | 4 | 5 | class TestSyncTouch(flask_scaffolds.FlaskResultsTest): 6 | """...""" 7 | 8 | def test_no_project(self): 9 | """Should fail if no project is open.""" 10 | 11 | touch_response = self.get('/sync-touch') 12 | self.assertEqual(touch_response.flask.status_code, 200) 13 | 14 | response = touch_response.response 15 | self.assert_has_error_code(response, 'NO_PROJECT') 16 | 17 | def test_valid(self): 18 | """Should refresh the project.""" 19 | 20 | support.create_project(self, 'hammer') 21 | 22 | touched = self.get('/sync-touch') 23 | self.assertEqual(touched.flask.status_code, 200) 24 | 25 | response = touched.response 26 | self.assertEqual(len(response.errors), 0) 27 | -------------------------------------------------------------------------------- /cauldron/test/cli/server/routes/test_ui_statuses.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | from unittest.mock import patch 3 | 4 | from cauldron.test.support.flask_scaffolds import FlaskResultsTest 5 | 6 | 7 | class TestUiStatuses(FlaskResultsTest): 8 | """Test suite for the ui_statuses module.""" 9 | 10 | @patch('cauldron.cli.server.routes.ui_statuses.statuses.get_status') 11 | def test_get_status(self, get_status: MagicMock): 12 | """Should return the expected JSON status data.""" 13 | get_status.return_value = {'foo': 'bar'} 14 | result = self.post('/ui-status', {}) 15 | assert {'foo': 'bar'} == result.flask.get_json() 16 | -------------------------------------------------------------------------------- /cauldron/test/cli/server/test_arguments.py: -------------------------------------------------------------------------------- 1 | from cauldron.cli.server import arguments 2 | from cauldron.test.support.flask_scaffolds import FlaskResultsTest 3 | 4 | 5 | class TestArguments(FlaskResultsTest): 6 | """...""" 7 | 8 | def test_mocked_request(self): 9 | """...""" 10 | 11 | result = arguments.from_request('invalid-request-value') 12 | self.assertIsInstance(result, dict) 13 | -------------------------------------------------------------------------------- /cauldron/test/cli/server/test_server_display.py: -------------------------------------------------------------------------------- 1 | from cauldron.test import support 2 | from cauldron.test.support import flask_scaffolds 3 | 4 | 5 | class TestServerDisplay(flask_scaffolds.FlaskResultsTest): 6 | """...""" 7 | 8 | def test_view_no_project(self): 9 | """Should fail if no project is open for viewing """ 10 | 11 | viewed = self.get('/view/fake-file.html') 12 | self.assertEqual(viewed.flask.status_code, 204) 13 | 14 | def test_view(self): 15 | """Should return file data if file exists.""" 16 | 17 | support.create_project(self, 'renee') 18 | 19 | viewed = self.get('/view/project.html') 20 | self.assertEqual(viewed.flask.status_code, 200) 21 | 22 | def test_view_no_file(self): 23 | """Should fail if the file does not exist.""" 24 | 25 | support.create_project(self, 'reginald') 26 | 27 | viewed = self.get('/view/fake-file.html') 28 | self.assertEqual(viewed.flask.status_code, 204) 29 | -------------------------------------------------------------------------------- /cauldron/test/cli/sync/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/cli/sync/__init__.py -------------------------------------------------------------------------------- /cauldron/test/cli/sync/test_sync_io.py: -------------------------------------------------------------------------------- 1 | import os 2 | from cauldron.test.support import scaffolds 3 | from cauldron.cli import sync 4 | 5 | 6 | class TestSyncIo(scaffolds.ResultsTest): 7 | """ Tests for the cauldron.cli.sync.sync_io module.""" 8 | 9 | def test_packing(self): 10 | """Should pack and then unpack a string successfully.""" 11 | 12 | source = b'abcdefg' 13 | packed = sync.io.pack_chunk(source) 14 | unpacked = sync.io.unpack_chunk(packed) 15 | self.assertEqual(source, unpacked) 16 | 17 | def test_reading_chunks(self): 18 | """Should read this file and write an identical file.""" 19 | 20 | path = os.path.realpath(__file__) 21 | out = self.get_temp_path('test_reading_chunks', 'test.py') 22 | for chunk, length in sync.io.read_file_chunks(path, 100): 23 | sync.io.write_file_chunk(out, chunk) 24 | 25 | with open(path) as f: 26 | me = f.read() 27 | with open(out) as f: 28 | compare = f.read() 29 | 30 | self.assertEqual(me, compare) 31 | 32 | def test_reading_no_such_file(self): 33 | """Should abort reading chunks if no such file exists.""" 34 | 35 | fake_path = '{}.fake-file'.format(__file__) 36 | chunks = [c for c, length in sync.io.read_file_chunks(fake_path)] 37 | self.assertEqual(0, len(chunks)) 38 | -------------------------------------------------------------------------------- /cauldron/test/cli/test_cli_commands.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from cauldron.cli import parse 4 | 5 | 6 | class TestCliCommands(unittest.TestCase): 7 | 8 | def test_explode_line(self): 9 | """...""" 10 | 11 | src = 'run "my name" --force --help --test 1' 12 | parts = parse.explode_line(src) 13 | 14 | self.assertEqual(len(parts), 6) 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /cauldron/test/docgen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/docgen/__init__.py -------------------------------------------------------------------------------- /cauldron/test/environ/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/environ/__init__.py -------------------------------------------------------------------------------- /cauldron/test/environ/test_configuration.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from unittest.mock import patch 3 | from unittest.mock import mock_open 4 | 5 | from cauldron.environ.configuration import Configuration 6 | 7 | 8 | class TestConfiguration(unittest.TestCase): 9 | 10 | def test_no_such_path(self): 11 | """Should assign empty dictionary if path does not exist.""" 12 | c = Configuration() 13 | c.load('~/fake_path') 14 | self.assertIsInstance(c._persistent, dict) 15 | self.assertEqual(len(list(c._persistent.keys())), 0) 16 | 17 | def test_invalid_config_file(self): 18 | c = Configuration() 19 | 20 | invalid = '{ a: "hello" }' 21 | with patch('__main__.open', mock_open(read_data=invalid)) as m: 22 | c.load(__file__) 23 | 24 | self.assertEqual(c._persistent, c.NO_VALUE) 25 | -------------------------------------------------------------------------------- /cauldron/test/environ/test_environ_paths.py: -------------------------------------------------------------------------------- 1 | import typing 2 | import os 3 | from os.path import realpath 4 | from pytest import mark 5 | 6 | from cauldron.environ import paths 7 | from cauldron.test import support 8 | from cauldron.test.support import scaffolds 9 | 10 | PATH_SCENARIOS = [ 11 | (None, lambda: realpath(os.curdir)), 12 | ('.', lambda: realpath(os.curdir)), 13 | (__file__, realpath(__file__)), 14 | ('~/bob', realpath(os.path.expanduser('~/bob'))), 15 | ('"~/bob"', realpath(os.path.expanduser('~/bob'))), 16 | ] 17 | 18 | 19 | @mark.parametrize('value, expected', PATH_SCENARIOS) 20 | def test_clean_path( 21 | value: str, 22 | expected: typing.Union[str, typing.Callable[[], str]] 23 | ): 24 | """Should clean path to be current directory.""" 25 | observed = paths.clean(value) 26 | expected = expected if isinstance(expected, str) else expected() 27 | assert expected == observed 28 | -------------------------------------------------------------------------------- /cauldron/test/environ/test_modes.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | import typing 3 | from unittest.mock import patch 4 | 5 | from cauldron.environ import modes 6 | from pytest import mark 7 | 8 | POSSIBILITIES = { 9 | 'is_ui': modes.UI, 10 | 'is_test': modes.TESTING, 11 | 'is_interactive': modes.INTERACTIVE, 12 | 'is_single_run': modes.SINGLE_RUN, 13 | 'is_server': modes.SERVER, 14 | } 15 | 16 | SCENARIOS = [ 17 | dict(combination) 18 | for combination 19 | in itertools.combinations_with_replacement(POSSIBILITIES.items(), 2) 20 | ] 21 | 22 | 23 | @mark.parametrize('scenario', SCENARIOS) 24 | def test_modes(scenario: typing.Dict[str, str]): 25 | """Should identify according to the expected results.""" 26 | em = modes.ExposedModes 27 | patch_path = 'cauldron.environ.modes._current_modes' 28 | with patch(patch_path, new=[]): 29 | for m in scenario.values(): 30 | modes.add(m) 31 | 32 | assert em.is_interactive() == ('is_interactive' in scenario) 33 | assert em.is_server() == ('is_server' in scenario) 34 | assert em.is_single_run() == ('is_single_run' in scenario) 35 | assert em.is_test() == ('is_test' in scenario) 36 | assert em.is_ui() == ('is_ui' in scenario) 37 | 38 | for m in scenario.values(): 39 | modes.remove(m) 40 | assert not modes._current_modes 41 | -------------------------------------------------------------------------------- /cauldron/test/invoke/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/invoke/__init__.py -------------------------------------------------------------------------------- /cauldron/test/invoke/utils.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | 3 | from cauldron.invoke import invoker 4 | from cauldron.invoke import parser 5 | 6 | 7 | def run_command(command: str) -> int: 8 | """Executes the specified command by parsing the args and running them.""" 9 | args = parser.parse(command.split(' ')) 10 | 11 | with patch('cauldron.invoke.invoker._pre_run_updater'): 12 | return invoker.run(args.get('command'), args) 13 | -------------------------------------------------------------------------------- /cauldron/test/projects/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/projects/__init__.py -------------------------------------------------------------------------------- /cauldron/test/render/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/render/__init__.py -------------------------------------------------------------------------------- /cauldron/test/render/test_render_plots.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | from cauldron.test import support 4 | from cauldron.render import plots 5 | 6 | 7 | def test_pyplot_bs4_error(): 8 | """Should render import error if bs4 is not installed.""" 9 | with support.ImportPatcher() as mocked_importer: 10 | mocked_importer.error_on = ['bs4'] 11 | result = plots.pyplot() 12 | 13 | assert 'The beatifulsoup4 library is needed' in result 14 | 15 | 16 | def test_pyplot_pyplot_error(): 17 | """Should render import error if matplotlib is not installed.""" 18 | with support.ImportPatcher() as mocked_importer: 19 | mocked_importer.error_on = ['matplotlib'] 20 | result = plots.pyplot() 21 | 22 | assert 'matplotlib' in result 23 | 24 | 25 | def test_pyplot_no_figure(): 26 | """Should create default render if no figure is specified.""" 27 | result = plots.pyplot(aspect_ratio=[4, 3]) 28 | assert result is not None 29 | 30 | 31 | def test_bokeh_plot_import_error(): 32 | """Should render bokeh import error if library not installed.""" 33 | with support.ImportPatcher() as mocked_importer: 34 | mocked_importer.error_on = ['bokeh'] 35 | result = plots.bokeh_plot(MagicMock()) 36 | 37 | assert 'bokeh' in result 38 | -------------------------------------------------------------------------------- /cauldron/test/runner/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/runner/__init__.py -------------------------------------------------------------------------------- /cauldron/test/runner/test_runner_markdown_file.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | from cauldron.test import support 3 | from cauldron.test.support import scaffolds 4 | 5 | 6 | class TestRunnerMarkdownFile(scaffolds.ResultsTest): 7 | """Test suite for the runner.markdown_file module""" 8 | 9 | def test_run_markdown(self): 10 | """Should render markdown.""" 11 | 12 | support.create_project(self, 'salem') 13 | support.add_step(self, 'test.md', contents='This is markdown') 14 | response = support.run_command('run -f') 15 | self.assertFalse(response.failed, 'should have failed') 16 | 17 | step = cd.project.get_internal_project().steps[0] 18 | self.assertFalse(step.is_dirty()) 19 | 20 | def test_invalid_markdown(self): 21 | """Should fail with a jinja error.""" 22 | 23 | support.create_project(self, 'des-moines') 24 | support.add_step( 25 | self, 26 | 'test.md', 27 | contents='# Hello {{ missing_variable + "12" }}' 28 | ) 29 | response = support.run_command('run -f') 30 | self.assertTrue(response.failed) 31 | -------------------------------------------------------------------------------- /cauldron/test/runner/test_runner_python_file.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | from unittest.mock import patch 3 | 4 | from cauldron.runner import python_file 5 | from cauldron.test.support import scaffolds 6 | 7 | 8 | @patch('cauldron.runner.python_file.functools') 9 | def test_get_file_contents_failed(functools: MagicMock): 10 | """Should return code that raises IOError if unable to open file""" 11 | func = MagicMock() 12 | func.side_effect = IOError 13 | functools.partial.return_value = func 14 | result = python_file.get_file_contents('FAKE') 15 | assert result.startswith('raise IOError(') 16 | -------------------------------------------------------------------------------- /cauldron/test/session/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/session/__init__.py -------------------------------------------------------------------------------- /cauldron/test/session/projects/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/session/projects/__init__.py -------------------------------------------------------------------------------- /cauldron/test/session/projects/test_specio_format_times.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | from pytest import mark 4 | 5 | from cauldron.session.projects import specio 6 | 7 | SCENARIOS = [ 8 | (20, 'just now'), 9 | (3 * 60, '3 minutes ago'), 10 | (3 * 3600, '3 hours ago'), 11 | (4 * 86400, '4 days ago'), 12 | (6 * 7 * 86400, '6 weeks ago'), 13 | (367 * 86400, '1 year ago'), 14 | (3 * 365 * 86400, '3 years ago'), 15 | ] 16 | 17 | 18 | @mark.parametrize('offset, expected', SCENARIOS) 19 | def test_format_times(offset: float, expected: str): 20 | """Should return formatted time according to scenario expectation.""" 21 | timestamp = time.time() - offset 22 | assert expected == specio.format_times(timestamp)['elapsed'] 23 | -------------------------------------------------------------------------------- /cauldron/test/session/test_session_buffer.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from cauldron.session import buffering 4 | from cauldron.test.support import scaffolds 5 | 6 | 7 | class TestSessionBuffer(scaffolds.ResultsTest): 8 | 9 | def test_buffer_write(self): 10 | value = 'This is a test' 11 | b = buffering.RedirectBuffer(sys.stdout) 12 | b.active = True 13 | sys.stdout = b 14 | 15 | # This print statement is needed for this test 16 | print(value) 17 | 18 | sys.stdout = b.redirection_source 19 | 20 | contents = b.flush_all().strip() 21 | self.assertEqual(contents, value) 22 | -------------------------------------------------------------------------------- /cauldron/test/session/writing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/session/writing/__init__.py -------------------------------------------------------------------------------- /cauldron/test/session/writing/test_bokeh_component.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | from cauldron.session.writing.components import bokeh_component 4 | from cauldron.test import support 5 | 6 | 7 | def test_bokeh_component_import_error(): 8 | """Should return empty component if bokeh is not install.""" 9 | with support.ImportPatcher() as mocked_importer: 10 | mocked_importer.error_on = ['bokeh.resources'] 11 | result = bokeh_component.create(MagicMock()) 12 | 13 | assert bokeh_component.COMPONENT([], []) == result 14 | -------------------------------------------------------------------------------- /cauldron/test/session/writing/test_components.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | 3 | from cauldron.session.writing import components 4 | 5 | 6 | def test_get_components_unknown(): 7 | """Should return an empty component for unknown component name.""" 8 | result = components._get_components('foo', MagicMock()) 9 | assert not result.files 10 | assert not result.includes 11 | -------------------------------------------------------------------------------- /cauldron/test/session/writing/test_project_component.py: -------------------------------------------------------------------------------- 1 | import os 2 | from unittest.mock import MagicMock 3 | 4 | from cauldron.session.writing.components import project_component 5 | 6 | 7 | def test_project_component_does_not_exist(): 8 | """Should return empty component when source does not exist.""" 9 | project = MagicMock() 10 | project.source_directory = os.path.realpath(os.path.dirname(__file__)) 11 | result = project_component.create(project, 'fake-include-path') 12 | assert project_component.COMPONENT([], []) == result 13 | -------------------------------------------------------------------------------- /cauldron/test/steptesting/S01-first.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | import pandas as pd 3 | 4 | is_testing = cd.mode.is_test() 5 | is_interactive = cd.mode.is_interactive() 6 | is_single_run = cd.mode.is_single_run() 7 | 8 | 9 | df = pd.DataFrame({ 10 | 'a': [1, 2, 3], 11 | 'b': [True, False, True], 12 | 'c': ['Hello', 'World', 'Foo'], 13 | 'd': [3, None, 5] 14 | }) 15 | 16 | df = df.fillna(4) 17 | 18 | 19 | def to_strings(values): 20 | return ['{}'.format(value) for value in values] 21 | 22 | 23 | def create_unified_column(data_frame: pd.DataFrame) -> pd.Series: 24 | unified = [ 25 | '-'.join(to_strings(row.to_dict().values())) 26 | for _, row in data_frame.iterrows() 27 | ] 28 | 29 | return pd.Series(unified) 30 | 31 | 32 | df['d'] = create_unified_column(df) 33 | 34 | cd.shared.df = df 35 | 36 | -------------------------------------------------------------------------------- /cauldron/test/steptesting/S02-errors.py: -------------------------------------------------------------------------------- 1 | raise RuntimeError('I HAVE AN ERROR!') 2 | -------------------------------------------------------------------------------- /cauldron/test/steptesting/S03-lib-patching.py: -------------------------------------------------------------------------------- 1 | import cauldron as cd 2 | import _testlib 3 | 4 | value = cd.shared.value 5 | result_value = _testlib.patching_test(value) 6 | cd.shared.result = result_value 7 | -------------------------------------------------------------------------------- /cauldron/test/steptesting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/steptesting/__init__.py -------------------------------------------------------------------------------- /cauldron/test/steptesting/cauldron.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "step-testing", 3 | "naming_scheme": "S{{##}}-{{name}}.{{ext}}", 4 | "steps": [ 5 | "S01-first.py", 6 | "S02-errors.py", 7 | "S03-lib-patching.py" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /cauldron/test/steptesting/libs/_testlib/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def patching_test(value): 4 | """ 5 | A test function for patching values during step tests. By default this 6 | function returns the value it was passed. Patching this should change its 7 | behavior in step tests. 8 | """ 9 | return value 10 | -------------------------------------------------------------------------------- /cauldron/test/support/flask_scaffolds.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from flask import Response as FlaskResponse 4 | 5 | from cauldron.test.support import server 6 | from cauldron.test.support.scaffolds import ResultsTest 7 | 8 | 9 | class FlaskResultsTest(ResultsTest): 10 | """Parent class for Flask application related testing.""" 11 | 12 | def setUp(self): 13 | super(FlaskResultsTest, self).setUp() 14 | self.app = server.create_test_app() 15 | 16 | def get(self, endpoint: str, **kwargs) -> server.Responses: 17 | """ send get request to the test flask application.""" 18 | return server.get(self.app, endpoint, **kwargs) 19 | 20 | def post(self, endpoint: str, data = None, **kwargs) -> server.Responses: 21 | """ send post request to the test flask application.""" 22 | return server.post(self.app, endpoint, data, **kwargs) 23 | -------------------------------------------------------------------------------- /cauldron/test/support/test_messages.py: -------------------------------------------------------------------------------- 1 | from cauldron.environ.response import Response 2 | from cauldron.test.support import messages 3 | 4 | 5 | def test_message(): 6 | """Should echo message when printed.""" 7 | r = Response() 8 | m = messages.Message( 9 | 'MESSAGE', 10 | 'Test message', 11 | 'with multiple args', 12 | data={'a': [1, 2, 3], 'b': True}, 13 | response=r 14 | ) 15 | 16 | assert str(m) == m.echo() 17 | -------------------------------------------------------------------------------- /cauldron/test/support/test_mocking.py: -------------------------------------------------------------------------------- 1 | from cauldron.test.support import mocking 2 | import pytest 3 | 4 | 5 | def test_patched_import(): 6 | """Should successfully import the specified package.""" 7 | with mocking.ImportPatcher() as mocked_importer: 8 | import sys 9 | assert hasattr(sys, 'path') 10 | 11 | 12 | def test_patched_import_error(): 13 | """Should raise import error.""" 14 | 15 | with mocking.ImportPatcher() as mocked_importer: 16 | mocked_importer.error_on = ['sys'] 17 | with pytest.raises(ImportError): 18 | import sys 19 | -------------------------------------------------------------------------------- /cauldron/test/test_init.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import patch 2 | 3 | import cauldron 4 | from cauldron.cli.server import run as server_runner 5 | from cauldron.cli.shell import CauldronShell 6 | from cauldron.test.support import scaffolds 7 | 8 | 9 | class TestInit(scaffolds.ResultsTest): 10 | """...""" 11 | 12 | def test_get_env_info(self): 13 | """...""" 14 | 15 | result = cauldron.get_environment_info() 16 | self.assertIsInstance(result, dict) 17 | self.assertTrue('cauldron' in result) 18 | 19 | def test_run_shell(self): 20 | """...""" 21 | 22 | with patch.object(CauldronShell, 'cmdloop') as cmd_loop: 23 | cauldron.run_shell() 24 | self.assertTrue(cmd_loop.call_count == 1) 25 | 26 | def test_run_server(self): 27 | """...""" 28 | 29 | with patch.object(server_runner, 'execute') as server_execute: 30 | cauldron.run_server() 31 | server_execute.assert_called_once_with(port=5010, debug=False) 32 | 33 | def test_run_server_custom_args(self): 34 | """...""" 35 | 36 | kwargs = dict(port=8000, debug=True, host='www.some-host-name.com') 37 | 38 | with patch.object(server_runner, 'execute') as server_execute: 39 | cauldron.run_server(**kwargs) 40 | server_execute.assert_called_once_with(**kwargs) 41 | -------------------------------------------------------------------------------- /cauldron/test/test_templating.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from cauldron import templating 4 | from cauldron import environ 5 | 6 | 7 | class TestTemplating(unittest.TestCase): 8 | 9 | def test_id_filter(self): 10 | """...""" 11 | 12 | result = templating.render('{{ "test" | id }}') 13 | parts = result.split('-', 2) 14 | self.assertEqual( 15 | parts[0], 'cdi', 16 | msg='"{}" should start with "cdi"'.format(result) 17 | ) 18 | self.assertEqual( 19 | parts[1], 'test', 20 | msg='"{}" should match the prefix'.format(result) 21 | ) 22 | 23 | def test_latex_filter(self): 24 | """...""" 25 | 26 | result = templating.render('{{ "e = mc^2" | latex }}') 27 | self.assertNotEqual(result.find('katex'), -1, 'where is katex?') 28 | 29 | def test_render_template(self): 30 | """ 31 | 32 | :return: 33 | """ 34 | 35 | result = templating.render_template('unit_test.html', value='hello') 36 | self.assertEqual(result, 'hello') 37 | 38 | def test_render_file(self): 39 | """ 40 | 41 | :return: 42 | """ 43 | 44 | result = templating.render_file( 45 | environ.paths.package('resources', 'templates', 'unit_test.html'), 46 | value='hello' 47 | ) 48 | self.assertEqual(result, 'hello') 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /cauldron/test/test_test_support.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from cauldron.environ import Response 4 | from cauldron.test.support import messages 5 | 6 | 7 | class TestTestSupport(unittest.TestCase): 8 | 9 | def test_explode_line(self): 10 | """...""" 11 | 12 | r = Response('TEST').update( 13 | test_info='More test information' 14 | ) 15 | 16 | m = messages.Message( 17 | 'Some-Message', 18 | 'This is a test', 19 | 'Message that will be turned into a string', 20 | response=r 21 | ) 22 | 23 | m = str(m) 24 | self.assertGreater(len(m), 0, messages.Message( 25 | 'Message to String', 26 | 'Unable to convert message to string' 27 | )) 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /cauldron/test/ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/apis/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/apis/executions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/apis/executions/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/apis/executions/test_runner_abort.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | from unittest.mock import patch 3 | 4 | from cauldron.ui.routes.apis.executions import runner 5 | 6 | 7 | @patch('cauldron.ui.routes.apis.executions.runner.ui_configs') 8 | @patch('cauldron.ui.routes.apis.executions.runner.redirection') 9 | @patch('cauldron.project.get_internal_project') 10 | def test_abort( 11 | get_internal_project: MagicMock, 12 | redirection: MagicMock, 13 | ui_configs: MagicMock, 14 | ): 15 | """Should carry out an abort process on the active response thread.""" 16 | active_response = MagicMock() 17 | active_response.thread.abort_running.side_effect = ValueError 18 | ui_configs.ACTIVE_EXECUTION_RESPONSE = active_response 19 | 20 | step = MagicMock() 21 | step.is_running = True 22 | project = MagicMock() 23 | project.current_step = step 24 | get_internal_project.return_value = project 25 | 26 | response = runner.abort() 27 | 28 | assert response.success 29 | assert redirection.disable.called 30 | assert redirection.restore_default_configuration.called 31 | assert not step.is_running, """ 32 | Expect the current step to be stopped given that 33 | it was running. 34 | """ 35 | -------------------------------------------------------------------------------- /cauldron/test/ui/routes/apis/statuses/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/apis/statuses/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/apps/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/notebooks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/notebooks/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/routes/notebooks/test_get_remote_view.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | from unittest.mock import patch 3 | 4 | from cauldron.ui.routes import notebooks 5 | 6 | 7 | @patch('cauldron.ui.routes.notebooks.flask') 8 | @patch('cauldron.ui.routes.notebooks.requests.request') 9 | def test_get_remote_view( 10 | requests_request: MagicMock, 11 | mock_flask: MagicMock, 12 | ): 13 | """Should retrieve remote view via request.""" 14 | remote_response = MagicMock() 15 | remote_response.raw.headers = {'foo': 'bar'} 16 | remote_response.content = 'hello' 17 | remote_response.status_code = 200 18 | requests_request.return_value = remote_response 19 | 20 | response = notebooks._get_remote_view('foo.js') 21 | assert response is not None 22 | 23 | args = mock_flask.Response.call_args[0] 24 | assert 'hello' == args[0] 25 | assert 200 == args[1] 26 | assert ('foo', 'bar') in list(args[2]) 27 | -------------------------------------------------------------------------------- /cauldron/test/ui/routes/test_hello.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | from cauldron.ui import routes 4 | from cauldron.ui import configs 5 | 6 | test_app = flask.Flask(__name__) 7 | test_app.register_blueprint(routes.blueprint) 8 | 9 | 10 | def test_hello(): 11 | """Should return a redirect.""" 12 | client = test_app.test_client() 13 | response = client.get('/') 14 | assert 302 == response.status_code 15 | 16 | expected = '{}/app'.format(configs.ROOT_PREFIX) 17 | assert expected == response.location 18 | -------------------------------------------------------------------------------- /cauldron/test/ui/routes/viewers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/routes/viewers/__init__.py -------------------------------------------------------------------------------- /cauldron/test/ui/statuses/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/ui/statuses/__init__.py -------------------------------------------------------------------------------- /cauldron/test/writing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/test/writing/__init__.py -------------------------------------------------------------------------------- /cauldron/ui/arguments.py: -------------------------------------------------------------------------------- 1 | import flask 2 | 3 | 4 | def from_request(request=None) -> dict: 5 | """ Fetches the arguments for the current Flask application request.""" 6 | request = request if request else flask.request 7 | 8 | try: 9 | json_args = request.get_json(silent=True) 10 | except Exception: 11 | json_args = None 12 | 13 | try: 14 | get_args = request.values 15 | except Exception: 16 | get_args = None 17 | 18 | return next(a for a in [json_args, get_args, {}] if a is not None) 19 | -------------------------------------------------------------------------------- /cauldron/ui/configs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import typing 3 | from cauldron import environ 4 | 5 | DEFAULT_PORT = 8899 6 | 7 | LAUNCH_THREAD = None 8 | 9 | ACTIVE_EXECUTION_RESPONSE = None # type: typing.Optional[environ.Response] 10 | 11 | #: The root URL prefix for the UI 12 | ROOT_PREFIX = '/v1' 13 | 14 | #: UI Version 15 | UI_VERSION = [0, 0, 1, 1] 16 | 17 | UI_APP_DATA = dict( 18 | version=UI_VERSION, 19 | user=os.environ.get('USER'), 20 | test=1, 21 | pid=os.getpid() 22 | ) 23 | 24 | # Count of the number of consecutive UI get status failures. 25 | # Will reset to zero once a successful status response has 26 | # been returned. See cauldron/environ/response.py for details. 27 | status_failures = 0 28 | 29 | 30 | def is_active_async() -> bool: 31 | """ 32 | Determines whether or not an async command execution is currently 33 | underway within the UI execution environment. 34 | """ 35 | r = ACTIVE_EXECUTION_RESPONSE 36 | return r is not None and r.thread and r.thread.is_alive() 37 | -------------------------------------------------------------------------------- /cauldron/ui/routes/__init__.py: -------------------------------------------------------------------------------- 1 | import flask 2 | from cauldron.ui import configs as ui_configs 3 | 4 | blueprint = flask.Blueprint( 5 | name='roots', 6 | import_name=__name__, 7 | ) 8 | 9 | 10 | @blueprint.route('/') 11 | def hello(): 12 | return flask.redirect( 13 | '{}/app'.format(ui_configs.ROOT_PREFIX), 14 | code=302 15 | ) 16 | -------------------------------------------------------------------------------- /cauldron/ui/routes/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sernst/cauldron/7cf455c521ab9a323950fed094ffddd762f022d0/cauldron/ui/routes/apis/__init__.py -------------------------------------------------------------------------------- /cauldron/ui/routes/apps/__init__.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import os 3 | 4 | import cauldron 5 | import flask 6 | from cauldron.ui import configs as ui_configs 7 | 8 | blueprint = flask.Blueprint( 9 | name='app', 10 | import_name=__name__, 11 | url_prefix='{}/app'.format(ui_configs.ROOT_PREFIX) 12 | ) 13 | 14 | 15 | def _get_app_path(route: str) -> str: 16 | """Returns application resource path.""" 17 | return os.path.realpath(os.path.join( 18 | os.path.dirname(cauldron.__file__), 19 | 'resources', 'app', *route.split('/') 20 | )) 21 | 22 | 23 | @blueprint.route('/', defaults={'route': 'index.html'}, methods=['GET']) 24 | @blueprint.route('/', methods=['GET']) 25 | def view(route: str): 26 | """ 27 | Retrieves the contents of the file specified by the view route if it 28 | exists. 29 | """ 30 | path = _get_app_path(route) 31 | if not os.path.exists(path): 32 | return '', 204 33 | 34 | return flask.send_file( 35 | path, 36 | mimetype=mimetypes.guess_type(path)[0], 37 | cache_timeout=-1 38 | ) 39 | -------------------------------------------------------------------------------- /cauldron/ui/routes/viewers/__init__.py: -------------------------------------------------------------------------------- 1 | import mimetypes 2 | import os 3 | 4 | import flask 5 | from cauldron import environ 6 | from cauldron.ui import configs as ui_configs 7 | 8 | blueprint = flask.Blueprint( 9 | name='viewers', 10 | import_name=__name__, 11 | url_prefix='{}/view'.format(ui_configs.ROOT_PREFIX) 12 | ) 13 | 14 | 15 | @blueprint.route('/notebook/', methods=['GET', 'POST']) 16 | def view(route: str): 17 | """ 18 | Retrieves the contents of the file specified by the view route if it 19 | exists. 20 | """ 21 | path = environ.paths.resources('web', route) 22 | if not os.path.exists(path): 23 | return '', 204 24 | 25 | return flask.send_file( 26 | path, 27 | mimetype=mimetypes.guess_type(path)[0], 28 | cache_timeout=-1 29 | ) 30 | 31 | 32 | @blueprint.route('/cache/', methods=['GET', 'POST']) 33 | def cache(route: str): 34 | """ 35 | Retrieves the contents of the file specified by the cache route if it 36 | exists. 37 | """ 38 | path = environ.paths.user('reader', 'cache', route) 39 | if not os.path.exists(path): 40 | return '', 204 41 | 42 | return flask.send_file( 43 | path, 44 | mimetype=mimetypes.guess_type(path)[0], 45 | cache_timeout=-1 46 | ) 47 | -------------------------------------------------------------------------------- /conda-recipe/bld.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | %PYTHON% setup.py install 3 | -------------------------------------------------------------------------------- /conda-recipe/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | $PYTHON setup.py install 3 | -------------------------------------------------------------------------------- /conda-recipe/meta.yaml.template: -------------------------------------------------------------------------------- 1 | package: 2 | name: cauldron 3 | version: "{{ VERSION }}" 4 | 5 | build: 6 | number: 1 7 | noarch: python 8 | 9 | source: 10 | path: {{ PATH }} 11 | 12 | requirements: 13 | build: 14 | - python 15 | - pandas 16 | - numpy>=1.16.0 17 | - jinja2 18 | - markdown 19 | - pygments 20 | - beautifulsoup4 21 | - flask 22 | - requests 23 | - pytest 24 | - pytest-runner 25 | - waitress 26 | 27 | run: 28 | - python 29 | - numpy 30 | - pandas 31 | - jinja2 32 | - markdown 33 | - pygments 34 | - beautifulsoup4 35 | - flask 36 | - requests 37 | - pytest 38 | - pytest-runner 39 | 40 | test: 41 | imports: 42 | - cauldron 43 | 44 | about: 45 | home: https://github.com/sernst/cauldron 46 | license: MIT 47 | license_file: LICENSE 48 | -------------------------------------------------------------------------------- /deployment.md: -------------------------------------------------------------------------------- 1 | # Deployment 2 | 3 | The following are the steps required to release a new version of 4 | Cauldron. Prior to release make sure that production builds of the 5 | web application and web notebook have been built into the Cauldron 6 | library. 7 | 8 | ## 1. Release the package 9 | 10 | ### Mac OS/Linux 11 | 12 | ```bash 13 | $ rm -rf ./dist 14 | $ python3 setup.py sdist bdist_wheel 15 | $ twine upload dist/cauldron* 16 | $ docker run --rm -it -v $(pwd):/cauldron continuumio/anaconda3 /bin/bash 17 | $ cd /cauldron 18 | $ conda config --set anaconda_upload yes 19 | $ python3 conda-recipe/conda-builder.py 20 | ``` 21 | 22 | ### WINDOWS 23 | 24 | ```powershell 25 | CMD> rmdir dist /s /q 26 | PS> rm dist -r -fo 27 | 28 | > python setup.py sdist bdist_wheel 29 | > twine upload dist/cauldron* 30 | > docker run --rm -it -v ${pwd}:/cauldron continuumio/anaconda3 /bin/bash 31 | > cd /cauldron 32 | > conda config --set anaconda_upload yes 33 | > python conda-recipe/conda-builder.py 34 | ``` 35 | 36 | ## 2. Push new container images 37 | 38 | ```bash 39 | $ python docker-builder.py --publish 40 | ``` 41 | 42 | ## 3. Update release information 43 | 44 | ```bash 45 | $ python release.py 46 | ``` 47 | -------------------------------------------------------------------------------- /development.dockerfile: -------------------------------------------------------------------------------- 1 | ARG PYTHON 2 | 3 | FROM python:$PYTHON 4 | 5 | COPY requirements.txt /build-data/requirements.txt 6 | 7 | RUN pip install -r /build-data/requirements.txt --upgrade 8 | -------------------------------------------------------------------------------- /docker-common.dockerfile: -------------------------------------------------------------------------------- 1 | ARG PARENT 2 | 3 | FROM $PARENT 4 | 5 | LABEL maintainer="swernst@gmail.com" 6 | 7 | WORKDIR /cauldron_local 8 | 9 | COPY requirements.txt /cauldron_local/ 10 | 11 | RUN apt-get -y --no-install-recommends update \ 12 | && apt-get -y --no-install-recommends install \ 13 | nginx \ 14 | && apt-get clean \ 15 | && pip install gunicorn \ 16 | && pip install -r /cauldron_local/requirements.txt 17 | 18 | COPY cauldron /cauldron_local/cauldron 19 | COPY README.rst /cauldron_local/ 20 | COPY setup.cfg /cauldron_local/ 21 | COPY setup.py /cauldron_local/ 22 | 23 | RUN python setup.py develop \ 24 | && chmod -R 775 /cauldron_local 25 | 26 | ARG TYPE 27 | 28 | ENV PYTHONUNBUFFERED=1 29 | ENV CAULDRON_CONTAINER_TYPE=$TYPE 30 | 31 | COPY docker /launch 32 | 33 | WORKDIR /notebooks 34 | 35 | ENTRYPOINT ["/bin/bash", "/launch/run.sh"] 36 | CMD [] 37 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-conda-3.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - conda 3 | - kernel-conda 4 | build_args: 5 | PARENT: continuumio/anaconda3:latest 6 | TYPE: kernel 7 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-miniconda-3.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - miniconda 3 | - kernel-miniconda 4 | build_args: 5 | PARENT: continuumio/miniconda3:latest 6 | TYPE: kernel 7 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-standard-py310.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - standard 3 | - kernel-standard 4 | - standard310 5 | - kernel-standard310 6 | build_args: 7 | PARENT: python:3.10 8 | TYPE: kernel 9 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-standard-py37.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - standard37 3 | - kernel-standard37 4 | build_args: 5 | PARENT: python:3.7 6 | TYPE: kernel 7 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-standard-py38.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - standard38 3 | - kernel-standard38 4 | build_args: 5 | PARENT: python:3.8 6 | TYPE: kernel 7 | -------------------------------------------------------------------------------- /docker/build-configs/kernel-standard-py39.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - standard39 3 | - kernel-standard39 4 | build_args: 5 | PARENT: python:3.9 6 | TYPE: kernel 7 | -------------------------------------------------------------------------------- /docker/build-configs/ui-conda-3.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-conda 3 | build_args: 4 | PARENT: continuumio/anaconda3:latest 5 | TYPE: ui 6 | -------------------------------------------------------------------------------- /docker/build-configs/ui-miniconda-3.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-miniconda 3 | build_args: 4 | PARENT: continuumio/miniconda3:latest 5 | TYPE: ui 6 | -------------------------------------------------------------------------------- /docker/build-configs/ui-standard-py310.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-standard 3 | - ui-standard310 4 | build_args: 5 | PARENT: python:3.10 6 | TYPE: ui 7 | -------------------------------------------------------------------------------- /docker/build-configs/ui-standard-py37.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-standard37 3 | build_args: 4 | PARENT: python:3.7 5 | TYPE: ui 6 | -------------------------------------------------------------------------------- /docker/build-configs/ui-standard-py38.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-standard38 3 | build_args: 4 | PARENT: python:3.8 5 | TYPE: ui 6 | -------------------------------------------------------------------------------- /docker/build-configs/ui-standard-py39.yaml: -------------------------------------------------------------------------------- 1 | ids: 2 | - ui-standard39 3 | build_args: 4 | PARENT: python:3.9 5 | TYPE: ui 6 | -------------------------------------------------------------------------------- /docker/kernel-description.txt: -------------------------------------------------------------------------------- 1 | Cauldron Kernel 2 | 3 | The Cauldron kernel container serves as remote kernel execution environment, 4 | creating a separation from the Cauldron UI. This makes it possible to work on 5 | one host while running the notebook code on another. Running the container 6 | looks like: 7 | 8 | $ docker run -p 5010:5010 swernst/cauldron:current-standard 9 | 10 | The key is publishing the 5010 container port to the host environment in 11 | some fashion so that the kernel is accessible from outside of the container. 12 | -------------------------------------------------------------------------------- /docker/kernel.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file serves as the package entrypoint for kernel execution via 3 | gunicorn. The environment variables are set in the paired kernel-run.py 4 | file where the gunicorn application is called. 5 | """ 6 | import os 7 | 8 | from cauldron.cli import server 9 | 10 | # Allow for changing the directory as part of the application launch 11 | # action so that this application directory isn't where users start 12 | # when browsing in the user-interface. 13 | os.chdir(os.environ.get('CAULDRON_INITIAL_DIRECTORY') or '.') 14 | 15 | kernel_data = server.create_application( 16 | port=int(os.environ.get('CAULDRON_SERVER_PORT', '8000')), 17 | debug=False, 18 | public=True, 19 | quiet=True 20 | ) 21 | 22 | # Assign to the application to expose it for gunicorn access 23 | application = kernel_data['application'] 24 | -------------------------------------------------------------------------------- /docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Run either the ui or kernel depending on the value specified 4 | # in the CAULDRON_CONTAINER_TYPE environment variables, which 5 | # is set in the container image at build time via a build arg. 6 | python "/launch/${CAULDRON_CONTAINER_TYPE}-run.py" "$@" 7 | -------------------------------------------------------------------------------- /docker/ui.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file serves as the package entrypoint for UI execution via 3 | gunicorn. The environment variables are set in the paired ui-run.py 4 | file where the gunicorn application is called. 5 | """ 6 | import os 7 | from cauldron import ui 8 | 9 | # Allow for changing the directory as part of the application launch 10 | # action so that this application directory isn't where users start 11 | # when browsing in the user-interface. 12 | os.chdir(os.environ.get('CAULDRON_INITIAL_DIRECTORY') or '.') 13 | 14 | app_data = ui.create_application( 15 | port=int(os.environ.get('CAULDRON_SERVER_PORT', '8000')), 16 | debug=False, 17 | public=True, 18 | quiet=True, 19 | connection_url=os.environ.get('CAULDRON_REMOTE_CONNECTION', None), 20 | ) 21 | 22 | # Assign to the application to expose it for gunicorn access 23 | application = app_data['application'] 24 | -------------------------------------------------------------------------------- /release.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import time 5 | 6 | import boto3 7 | import cauldron 8 | 9 | configs_path = os.path.join( 10 | os.path.dirname(os.path.relpath(__file__)), 11 | 'release-settings.json' 12 | ) 13 | 14 | settings_path = os.path.join( 15 | os.path.dirname(os.path.realpath(cauldron.__file__)), 16 | 'settings.json' 17 | ) 18 | 19 | if not os.path.exists(configs_path): 20 | print('MISSING SETTINGS FILE:\n{}'.format(configs_path)) 21 | sys.exit(1) 22 | 23 | 24 | with open(configs_path, 'r') as f: 25 | configs = json.load(f) 26 | 27 | session = boto3.Session(profile_name=configs.get('profile', 'default')) 28 | 29 | s3_client = session.client('s3') 30 | args = {'ACL': 'public-read'} 31 | s3_client.upload_file( 32 | Filename=settings_path, 33 | Bucket=configs['bucket'], 34 | Key=configs['key'], 35 | ExtraArgs=args 36 | ) 37 | 38 | cloudfront_client = session.client('cloudfront') 39 | cloudfront_client.create_invalidation( 40 | DistributionId=configs['distributionId'], 41 | InvalidationBatch=dict( 42 | Paths={'Quantity': 1, 'Items': ['/{}'.format(configs['key'])]}, 43 | CallerReference='{}'.format(time.time()) 44 | ) 45 | ) 46 | 47 | 48 | print('Operation Complete') 49 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pandas 2 | numpy 3 | jinja2 4 | markdown 5 | pygments 6 | beautifulsoup4 7 | flask 8 | plotly 9 | matplotlib 10 | bokeh 11 | seaborn 12 | requests 13 | pytest 14 | pytest-runner 15 | pytest-cov 16 | waitress 17 | pyyaml 18 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from cauldron import invoke 3 | 4 | if __name__ == '__main__': 5 | invoke.run(sys.argv[1:]) 6 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | test=pytest 3 | 4 | [bdist_wheel] 5 | universal=1 6 | --------------------------------------------------------------------------------