├── docs
├── .nojekyll
├── _static
│ ├── versions.json
│ └── media
│ │ ├── favicon.ico
│ │ ├── main-page.png
│ │ ├── other-tab.png
│ │ ├── change-tab.png
│ │ ├── delete-tab.png
│ │ ├── foliage-icon.png
│ │ ├── authentication.png
│ │ ├── caltech-round.png
│ │ ├── list-uuids-tab.png
│ │ ├── lookup-barcode.png
│ │ ├── macos-keychain.png
│ │ ├── clean-records-tab.png
│ │ ├── foliage-icon-white.png
│ │ ├── list-uuids-example.png
│ │ ├── foliage-icon-white-sm.png
│ │ ├── foliage-macos-systray.png
│ │ ├── change-tab-select-field.png
│ │ ├── foliage-windows-taskbar.png
│ │ ├── macos-accept-connections.png
│ │ ├── change-tab-selected-field.png
│ │ ├── change-tab-value-selector.png
│ │ ├── foliage-change-case-1.graffle
│ │ ├── foliage-change-case-2.graffle
│ │ ├── foliage-change-case-3.graffle
│ │ ├── foliage-change-case-4.graffle
│ │ ├── omnigraffle-export-options.png
│ │ ├── windows-accept-connections.png
│ │ └── README.md
├── index.md
├── README.md
├── colophon.md
├── Makefile
└── glossary.md
├── vendor
└── github.com
│ └── mhucka
│ └── PyWebIO
│ ├── test
│ ├── assets
│ │ ├── helloworld.txt
│ │ └── img.png
│ ├── .percy.yml
│ ├── run_all.sh
│ ├── Readme.md
│ ├── output_diff.py
│ ├── 3.django_backend.py
│ ├── 9.aiohttp_backend.py
│ ├── 4.flask_backend.py
│ ├── 5.coroutine_based_session.py
│ ├── 6.flask_coroutine.py
│ ├── 2.script_mode.py
│ ├── 1.basic.py
│ ├── 10.aiohttp_multiple_session_impliment.py
│ ├── 7.multiple_session_impliment.py
│ ├── 8.flask_multiple_session_impliment.py
│ └── util.py
│ ├── Procfile
│ ├── MANIFEST.in
│ ├── docs
│ ├── assets
│ │ ├── demo.gif
│ │ ├── demo.png
│ │ ├── layout.png
│ │ ├── input_1.png
│ │ ├── input_2.png
│ │ ├── input_demo.gif
│ │ ├── output_demo.gif
│ │ ├── put_table.png
│ │ ├── architecture.png
│ │ ├── table_onclick.gif
│ │ ├── table_onclick.png
│ │ └── codemirror_textarea.png
│ ├── output.rst
│ ├── session.rst
│ ├── platform.rst
│ ├── input.rst
│ ├── exceptions.rst
│ ├── releases.rst
│ ├── demos.rst
│ ├── releases
│ │ ├── v0.3.0.rst
│ │ ├── v0.2.0.rst
│ │ ├── v1.1.0.rst
│ │ └── v1.0.0.rst
│ ├── Makefile
│ ├── _ext
│ │ ├── README.md
│ │ └── codeblock.py
│ ├── make.bat
│ ├── static
│ │ ├── pywebio.css
│ │ └── pywebio.js
│ ├── FAQ.rst
│ ├── misc.rst
│ └── libraries_support.rst
│ ├── pywebio
│ ├── html
│ │ ├── image
│ │ │ ├── favicon_open_16.png
│ │ │ ├── favicon_open_32.png
│ │ │ ├── favicon_closed_16.png
│ │ │ └── favicon_closed_32.png
│ │ ├── css
│ │ │ └── toastify.min.css
│ │ ├── codemirror
│ │ │ ├── base16-light.min.css
│ │ │ ├── loadmode.js
│ │ │ └── active-line.js
│ │ └── js
│ │ │ ├── bs-custom-file-input.min.js
│ │ │ └── FileSaver.min.js
│ ├── __version__.py
│ ├── exceptions.py
│ ├── platform
│ │ └── __init__.py
│ └── __init__.py
│ ├── demos
│ ├── __init__.py
│ ├── config.py
│ ├── bmi.py
│ ├── set_env_demo.py
│ ├── bokeh_app.py
│ └── chat_room.py
│ ├── webiojs
│ ├── tsconfig.json
│ ├── README.md
│ ├── src
│ │ ├── vendor.d.ts
│ │ ├── models
│ │ │ └── input
│ │ │ │ ├── index.ts
│ │ │ │ ├── select.ts
│ │ │ │ ├── actions.ts
│ │ │ │ └── base.ts
│ │ ├── handlers
│ │ │ ├── download.ts
│ │ │ ├── script.ts
│ │ │ ├── env.ts
│ │ │ ├── base.ts
│ │ │ └── toast.ts
│ │ ├── state.ts
│ │ └── i18n.ts
│ ├── package.json
│ ├── gulpfile.js
│ └── .gitignore
│ ├── .gitattributes
│ ├── requirements.txt
│ ├── .gitignore
│ ├── .github
│ ├── ISSUE_TEMPLATE
│ │ └── bug_report.md
│ └── workflows
│ │ ├── lint.yml
│ │ ├── test.yml
│ │ ├── sync_repo.yml
│ │ └── release.yml
│ ├── lgtm.yml
│ ├── tools
│ └── build_dev_version.py
│ ├── .readthedocs.yml
│ ├── .drone.yml
│ └── LICENSE
├── dev
├── icon
│ ├── foliage-icon.ico
│ ├── foliage-icon.png
│ ├── foliage-icon.icns
│ ├── foliage-icon-white.png
│ ├── foliage-icon-white-sm.png
│ └── README.md
├── one-page-docs
│ ├── read-me-first-windows
│ │ ├── see-more.png
│ │ ├── google-keep.png
│ │ ├── keep-anyway.png
│ │ ├── trust-foliage.png
│ │ ├── browser-download.png
│ │ ├── download-anyway.png
│ │ ├── google-warning.png
│ │ ├── hover-over-downloads.png
│ │ └── read-me-first.md
│ ├── read-me-first-macos
│ │ ├── control-click.png
│ │ ├── file-dialog.png
│ │ ├── macos-malicious-warning.png
│ │ └── read-me-first.md
│ ├── sakura-css
│ │ └── README.md
│ └── pandoc-template
│ │ ├── README.md
│ │ └── template.html5
├── dev-docs
│ ├── windows-installer.md
│ ├── installing-pyqt5-on-macos.md
│ ├── README.md
│ └── making-a-new-release.md
├── misc
│ ├── folio-data-samples
│ │ ├── README.md
│ │ └── sample-2-holdings-3-items
│ │ │ ├── holdings-storage-holdings-795b4843-2736-4ccc-ade6-c928f8628831.json
│ │ │ └── holdings-storage-holdings-c0b6d0cf-38d0-43f7-b476-7debbba52bc5.json
│ ├── experiments
│ │ ├── settings.ini
│ │ └── macos-widget.py
│ └── t.py
├── installers
│ └── windows
│ │ ├── create-innosetup-script.py
│ │ ├── create-version.py
│ │ ├── version.py.tmpl
│ │ └── create-zip.py
└── splash-screen
│ ├── create-splash-screen.py
│ └── README.md
├── .graphics
├── caltech-round.png
├── foliage-icon.png
├── foliage-screenshot.png
├── example-splash-screen.png
├── status-warning.svg
└── caltech-round.svg
├── foliage
├── data
│ ├── foliage-icon.ico
│ ├── foliage-icon.png
│ ├── foliage-icon-r.png
│ ├── foliage-icon-32x32.png
│ ├── foliage-icon-64x64.png
│ ├── foliage-icon-128x128.png
│ ├── foliage-icon-256x256.png
│ └── macos-systray-widget
│ │ ├── icon
│ │ ├── icon-64.png
│ │ ├── make_icon.sh
│ │ └── README.md
│ │ ├── macos-systray-widget.go
│ │ ├── go.mod
│ │ ├── README.md
│ │ └── go.sum
├── exceptions.py
├── base_tab.py
├── enum_utils.py
└── __init__.py
├── requirements-windows.txt
├── tests
├── settings.ini
├── test_init.py
├── test_credentials.py
└── test_folio.py
├── .jsonlintrc.json
├── bin
├── README.md
└── foliage
├── .yamllint.yml
├── SUPPORT.md
├── .markdownlint.json
├── entitlements.plist
├── CITATION.cff
├── .github
├── workflows
│ ├── archive-github-pages.yml
│ ├── iga.yml
│ └── build-sphinx.yml
└── rename_project.sh
├── .editorconfig
├── requirements-dev.txt
├── .gitattributes
├── CONTRIBUTING.md
├── codemeta.json
├── requirements.txt
├── make.bat
├── LICENSE
├── setup.cfg
├── .flake8
├── setup.py
└── .gitignore
/docs/.nojekyll:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/_static/versions.json:
--------------------------------------------------------------------------------
1 | {"release": "", "development": "devel"}
2 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/assets/helloworld.txt:
--------------------------------------------------------------------------------
1 | hello world
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/Procfile:
--------------------------------------------------------------------------------
1 | web: python -m demos --port=$PORT
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/.percy.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | snapshot:
3 | widths: [1000]
--------------------------------------------------------------------------------
/dev/icon/foliage-icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/icon/foliage-icon.ico
--------------------------------------------------------------------------------
/dev/icon/foliage-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/icon/foliage-icon.png
--------------------------------------------------------------------------------
/.graphics/caltech-round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/.graphics/caltech-round.png
--------------------------------------------------------------------------------
/.graphics/foliage-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/.graphics/foliage-icon.png
--------------------------------------------------------------------------------
/dev/icon/foliage-icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/icon/foliage-icon.icns
--------------------------------------------------------------------------------
/docs/_static/media/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/favicon.ico
--------------------------------------------------------------------------------
/foliage/data/foliage-icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon.ico
--------------------------------------------------------------------------------
/foliage/data/foliage-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon.png
--------------------------------------------------------------------------------
/requirements-windows.txt:
--------------------------------------------------------------------------------
1 | # Summary: requirements when using Windows.
2 |
3 | -r requirements.txt
4 |
5 | pywin32
6 |
--------------------------------------------------------------------------------
/.graphics/foliage-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/.graphics/foliage-screenshot.png
--------------------------------------------------------------------------------
/dev/icon/foliage-icon-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/icon/foliage-icon-white.png
--------------------------------------------------------------------------------
/docs/_static/media/main-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/main-page.png
--------------------------------------------------------------------------------
/docs/_static/media/other-tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/other-tab.png
--------------------------------------------------------------------------------
/foliage/data/foliage-icon-r.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon-r.png
--------------------------------------------------------------------------------
/.graphics/example-splash-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/.graphics/example-splash-screen.png
--------------------------------------------------------------------------------
/dev/icon/foliage-icon-white-sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/icon/foliage-icon-white-sm.png
--------------------------------------------------------------------------------
/docs/_static/media/change-tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/change-tab.png
--------------------------------------------------------------------------------
/docs/_static/media/delete-tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/delete-tab.png
--------------------------------------------------------------------------------
/docs/_static/media/foliage-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-icon.png
--------------------------------------------------------------------------------
/foliage/data/foliage-icon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon-32x32.png
--------------------------------------------------------------------------------
/foliage/data/foliage-icon-64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon-64x64.png
--------------------------------------------------------------------------------
/docs/_static/media/authentication.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/authentication.png
--------------------------------------------------------------------------------
/docs/_static/media/caltech-round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/caltech-round.png
--------------------------------------------------------------------------------
/docs/_static/media/list-uuids-tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/list-uuids-tab.png
--------------------------------------------------------------------------------
/docs/_static/media/lookup-barcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/lookup-barcode.png
--------------------------------------------------------------------------------
/docs/_static/media/macos-keychain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/macos-keychain.png
--------------------------------------------------------------------------------
/foliage/data/foliage-icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon-128x128.png
--------------------------------------------------------------------------------
/foliage/data/foliage-icon-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/foliage-icon-256x256.png
--------------------------------------------------------------------------------
/docs/_static/media/clean-records-tab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/clean-records-tab.png
--------------------------------------------------------------------------------
/docs/_static/media/foliage-icon-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-icon-white.png
--------------------------------------------------------------------------------
/docs/_static/media/list-uuids-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/list-uuids-example.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include demos *.py
2 | prune docs
3 | graft pywebio/html
4 | graft pywebio/platform/tpl
--------------------------------------------------------------------------------
/docs/_static/media/foliage-icon-white-sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-icon-white-sm.png
--------------------------------------------------------------------------------
/docs/_static/media/foliage-macos-systray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-macos-systray.png
--------------------------------------------------------------------------------
/docs/_static/media/change-tab-select-field.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/change-tab-select-field.png
--------------------------------------------------------------------------------
/docs/_static/media/foliage-windows-taskbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-windows-taskbar.png
--------------------------------------------------------------------------------
/docs/_static/media/macos-accept-connections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/macos-accept-connections.png
--------------------------------------------------------------------------------
/docs/_static/media/change-tab-selected-field.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/change-tab-selected-field.png
--------------------------------------------------------------------------------
/docs/_static/media/change-tab-value-selector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/change-tab-value-selector.png
--------------------------------------------------------------------------------
/docs/_static/media/foliage-change-case-1.graffle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-change-case-1.graffle
--------------------------------------------------------------------------------
/docs/_static/media/foliage-change-case-2.graffle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-change-case-2.graffle
--------------------------------------------------------------------------------
/docs/_static/media/foliage-change-case-3.graffle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-change-case-3.graffle
--------------------------------------------------------------------------------
/docs/_static/media/foliage-change-case-4.graffle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/foliage-change-case-4.graffle
--------------------------------------------------------------------------------
/docs/_static/media/omnigraffle-export-options.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/omnigraffle-export-options.png
--------------------------------------------------------------------------------
/docs/_static/media/windows-accept-connections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/docs/_static/media/windows-accept-connections.png
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/icon/icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/foliage/data/macos-systray-widget/icon/icon-64.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/see-more.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/see-more.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/assets/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/test/assets/img.png
--------------------------------------------------------------------------------
/dev/dev-docs/windows-installer.md:
--------------------------------------------------------------------------------
1 | # Windows installer for Foliage
2 |
3 | about.html needs to be built on mac first
4 | https://www.npmjs.com/package/inliner
5 |
6 |
--------------------------------------------------------------------------------
/dev/misc/folio-data-samples/README.md:
--------------------------------------------------------------------------------
1 | # Folio data samples
2 |
3 | This directory contains samples of records from Caltech's FOLIO server obtained in late 2021.
4 |
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-macos/control-click.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-macos/control-click.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-macos/file-dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-macos/file-dialog.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/google-keep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/google-keep.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/keep-anyway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/keep-anyway.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/demo.gif
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/demo.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/layout.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/trust-foliage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/trust-foliage.png
--------------------------------------------------------------------------------
/tests/settings.ini:
--------------------------------------------------------------------------------
1 | # This settings file is read by the code in folio.py
2 |
3 | [settings]
4 | FOLIO_OKAPI_URL =
5 | FOLIO_OKAPI_TENANT_ID =
6 | FOLIO_OKAPI_TOKEN =
7 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/input_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/input_1.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/input_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/input_2.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/browser-download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/browser-download.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/download-anyway.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/download-anyway.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/google-warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/google-warning.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/input_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/input_demo.gif
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/output_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/output_demo.gif
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/put_table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/put_table.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/output.rst:
--------------------------------------------------------------------------------
1 | ``pywebio.output`` --- 输出模块
2 | ====================================================
3 |
4 | .. automodule:: pywebio.output
5 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/architecture.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/table_onclick.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/table_onclick.gif
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/table_onclick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/table_onclick.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/session.rst:
--------------------------------------------------------------------------------
1 | ``pywebio.session`` --- 会话相关
2 | ====================================================
3 |
4 | .. automodule:: pywebio.session
5 |
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-macos/macos-malicious-warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-macos/macos-malicious-warning.png
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-windows/hover-over-downloads.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/dev/one-page-docs/read-me-first-windows/hover-over-downloads.png
--------------------------------------------------------------------------------
/dev/misc/experiments/settings.ini:
--------------------------------------------------------------------------------
1 | # This settings file is read by the code in isbn_checker.py
2 |
3 | [settings]
4 | FOLIO_OKAPI_URL =
5 | FOLIO_OKAPI_TENANT_ID =
6 | FOLIO_OKAPI_TOKEN =
7 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/assets/codemirror_textarea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/docs/assets/codemirror_textarea.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/platform.rst:
--------------------------------------------------------------------------------
1 | ``pywebio.platform`` --- Web框架支持
2 | ===============================================================
3 |
4 | .. automodule:: pywebio.platform
5 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/input.rst:
--------------------------------------------------------------------------------
1 | ``pywebio.input`` --- 输入模块
2 | ====================================================
3 |
4 | .. automodule:: pywebio.input
5 | :members:
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_open_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_open_16.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_open_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_open_32.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/demos/__init__.py:
--------------------------------------------------------------------------------
1 | r"""
2 | .. automodule:: demos.bmi
3 | .. automodule:: demos.input_usage
4 | .. automodule:: demos.output_usage
5 | .. automodule:: demos.chat_room
6 | """
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/exceptions.rst:
--------------------------------------------------------------------------------
1 | ``pywebio.exceptions``
2 | ====================================================
3 |
4 | .. automodule:: pywebio.exceptions
5 | :members:
6 |
7 |
8 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_closed_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_closed_16.png
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_closed_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/caltechlibrary/foliage/HEAD/vendor/github.com/mhucka/PyWebIO/pywebio/html/image/favicon_closed_32.png
--------------------------------------------------------------------------------
/.jsonlintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "comments": false,
3 | "trailing-commas": false,
4 | "duplicate-keys": false,
5 | "log-files": false,
6 | "compact": true,
7 | "continue": true,
8 | "patterns": ["**/*.json"]
9 | }
10 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/releases.rst:
--------------------------------------------------------------------------------
1 | Release notes
2 | =============
3 |
4 | .. toctree::
5 | :maxdepth: 2
6 |
7 | releases/v1.1.0
8 | releases/v1.0.0
9 | releases/v0.3.0
10 | releases/v0.2.0
11 |
--------------------------------------------------------------------------------
/dev/one-page-docs/sakura-css/README.md:
--------------------------------------------------------------------------------
1 | # Sakura CSS theme
2 |
3 | The CSS file in this directory originally came from (sakura)[https://github.com/oxalorg/sakura] by Mitesh Shah, downloaded on 2022-01-28 (at the time, sakura version 1.3.0).
4 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "src/**/*.ts"
4 | ],
5 | "compilerOptions": {
6 | "noImplicitAny": true,
7 | "target": "es2015",
8 | "module": "commonjs"
9 | }
10 | }
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/README.md:
--------------------------------------------------------------------------------
1 | # PyWebIO JS library
2 |
3 | ## Build
4 |
5 | ```bash
6 | npm install
7 | DEV=1 gulp
8 | ```
9 |
10 | ## Use built js
11 |
12 | ```bash
13 | cp dist/pywebio.min.* ../pywebio/html/js
14 | ```
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/demos/config.py:
--------------------------------------------------------------------------------
1 | # demos 模块的部署地址
2 | demo_host = 'http://pywebio-demos.demo.wangweimin.site'
3 |
4 | # https://github.com/wang0618/pywebio-chart-gallery 的部署地址
5 | charts_demo_host = 'http://pywebio-charts.demo.wangweimin.site'
6 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/demos.rst:
--------------------------------------------------------------------------------
1 | 示例Demos
2 | ==========
3 |
4 | 基本demo
5 | ------------
6 | 使用PyWebIO编写的示例应用
7 |
8 | .. automodule:: demos
9 |
10 | 数据可视化demo
11 | -----------------
12 | PyWebIO支持使用第三方库进行数据可视化,详情见 :ref:`使用PyWebIO进行数据可视化 `
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/run_all.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -o xtrace
4 |
5 | mkdir output
6 |
7 | exit_code=0
8 |
9 | for file in ./[0-9]*.*.py
10 | do
11 | python3 "$file" auto || exit_code=1
12 | done
13 |
14 | python3 output_diff.py && exit "$exit_code"
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/vendor.d.ts:
--------------------------------------------------------------------------------
1 | // declare var $: any;
2 | declare let Mustache: any;
3 | declare let saveAs: any;
4 | declare let CodeMirror: any;
5 | declare let bsCustomFileInput: any;
6 | declare let Toastify: any;
7 | declare let Prism: any; // Prism.js
8 | declare let DOMPurify: any; // DOMPurify.js
--------------------------------------------------------------------------------
/tests/test_init.py:
--------------------------------------------------------------------------------
1 | def test_version():
2 | """Test version import."""
3 | from foliage import __version__
4 | assert __version__
5 |
6 |
7 | def test_print_version(capsys):
8 | from foliage import print_version
9 | print_version()
10 | captured = capsys.readouterr()
11 | assert 'URL' in captured.out
12 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/__version__.py:
--------------------------------------------------------------------------------
1 | __package__ = 'pywebio'
2 | __description__ = 'Write interactive web app in script way.'
3 | __url__ = 'https://pywebio.readthedocs.io'
4 | __version__ = "1.1.0"
5 | __version_info__ = (1, 1, 0, 0)
6 | __author__ = 'WangWeimin'
7 | __author_email__ = 'wang0.618@qq.com'
8 | __license__ = 'MIT'
--------------------------------------------------------------------------------
/dev/one-page-docs/pandoc-template/README.md:
--------------------------------------------------------------------------------
1 | # Pandoc Markdown CSS theme
2 |
3 | The original pandoc HTML5 template file in this directory came from [pandoc-markdown-css-theme](https://github.com/jez/pandoc-markdown-css-theme) by Jake Zimmerman, downloaded on 2022-01-28 (at the time, latest commit 019a482 from Jun 29, 2021). I modified it from the original.
4 |
5 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.gitattributes:
--------------------------------------------------------------------------------
1 | # https://github.com/github/linguist#overrides
2 |
3 | pywebio/html/js/* linguist-vendored
4 | pywebio/html/css/* linguist-vendored
5 | pywebio/html/codemirror/* linguist-vendored
6 |
7 | pywebio/html/css/app.css -linguist-vendored
8 |
9 | docs/* linguist-documentation
10 |
11 | webiojs/package* linguist-generated
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/requirements.txt:
--------------------------------------------------------------------------------
1 | tornado>=5.0
2 | user-agents
3 |
4 | # extra support
5 | flask
6 | django
7 | aiohttp
8 | bokeh
9 | pandas
10 | cutecharts
11 | pyecharts
12 | plotly
13 | Pillow
14 |
15 | # test requirements
16 | selenium==3.*
17 | percy-python-selenium
18 | coverage
19 |
20 | # doc building requirements
21 | sphinx
22 | sphinx-tabs
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/models/input/index.ts:
--------------------------------------------------------------------------------
1 | import {Input} from "./input"
2 | import {Actions} from "./actions"
3 | import {CheckboxRadio} from "./checkbox_radio"
4 | import {Textarea} from "./textarea"
5 | import {File} from "./file"
6 | import {Select} from "./select"
7 |
8 |
9 | export const all_input_items = [Input, Actions, CheckboxRadio, Textarea, File, Select];
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.py[cod]
3 | *$py.class
4 | *.db
5 | *.sqlite3
6 |
7 | .idea/
8 |
9 | # 2022-05-09 I'm checking in the JS files so that I
10 | # can use my fork of PyWebIO for installations (for use with Foliage).
11 | # pywebio/html/js/pywebio.min.*
12 | /no_git
13 | /build
14 | /dist
15 | /*.egg-info
16 | /docs/_build
17 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/Readme.md:
--------------------------------------------------------------------------------
1 | ## Test
2 | 使用 selenium 进行 + percy 进行测试。
3 |
4 | 测试的原理为使用selenium打开编写的PyWebIO测试服务,在页面上进行模拟操作,
5 | 将一些时刻的网页快照使用percy进行保存,percy可以比较不同提交之间的相同页面的区别。
6 |
7 | ### 编写测试用例
8 | // todo
9 |
10 | ### 运行测试用例
11 |
12 | ```bash
13 | pip3 install -e ".[dev]"
14 | npm install -D @percy/agent
15 | export PERCY_TOKEN=[projects-token]
16 |
17 | npx percy exec -- python3 1.basic_output.py auto
18 | ```
19 |
20 |
21 |
--------------------------------------------------------------------------------
/bin/README.md:
--------------------------------------------------------------------------------
1 | # About the shell script in this directory
2 |
3 | The shell script in this directory is mainly for testing and development. During development, I run Foliage from a terminal emulator by starting it simply like this:
4 |
5 | ```sh
6 | ./foliage
7 | ```
8 |
9 | When Foliage is installed on a computer using `pip` or `pipx`, a different wrapper script is installed, not the one that is in this directory. The one here is merely a convenience.
10 |
--------------------------------------------------------------------------------
/dev/icon/README.md:
--------------------------------------------------------------------------------
1 | The [vector artwork](https://thenounproject.com/term/branch/1047074/) used as a starting point for the logo for this repository was created by [Alice Noir](https://thenounproject.com/AliceNoir/) for the [Noun Project](https://thenounproject.com). It is licensed under the Creative Commons [Attribution 3.0 Unported](https://creativecommons.org/licenses/by/3.0/deed.en) license. The vector graphics was modified by Mike Hucka to change the color.
2 |
--------------------------------------------------------------------------------
/.yamllint.yml:
--------------------------------------------------------------------------------
1 | # Summary: configuration file for .github/workflows/yaml-linter.yml.
2 | #
3 | # Copyright 2024 California Institute of Technology.
4 | # License: Modified BSD 3-clause – see file "LICENSE" in the project website.
5 | # Website: https://github.com/caltechlibrary/baler
6 |
7 | rules:
8 | colons:
9 | max-spaces-after: -1
10 | quoted-strings:
11 | required: only-when-needed
12 | document-start:
13 | present: false
14 | document-end:
15 | present: false
16 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/exceptions.py:
--------------------------------------------------------------------------------
1 | """
2 | pywebio.exceptions
3 | ~~~~~~~~~~~~~~~~~~~
4 |
5 | This module contains the set of PyWebIO's exceptions.
6 | """
7 |
8 |
9 | class SessionException(Exception):
10 | """PyWebIO会话相关异常的基类"""
11 |
12 |
13 | class SessionClosedException(SessionException):
14 | """会话已经关闭异常"""
15 |
16 |
17 | class SessionNotFoundException(SessionException):
18 | """会话未找到异常"""
19 |
20 |
21 | class PyWebIOWarning(UserWarning):
22 | pass
23 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/handlers/download.ts:
--------------------------------------------------------------------------------
1 | import {Command} from "../session";
2 | import {CommandHandler} from "./base";
3 | import {b64toBlob} from "../utils";
4 |
5 | export class DownloadHandler implements CommandHandler {
6 | accept_command: string[] = ['download'];
7 |
8 | constructor() {
9 | }
10 |
11 | handle_message(msg: Command) {
12 | let blob = b64toBlob(msg.spec.content);
13 | saveAs(blob, msg.spec.name, {}, false);
14 | }
15 | }
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/macos-systray-widget.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/getlantern/systray"
5 | "macos-systray-widget/icon"
6 | )
7 |
8 | func main() {
9 | onExit := func() { }
10 | systray.Run(onReady, onExit)
11 | }
12 |
13 | func onReady() {
14 | systray.SetTemplateIcon(icon.Data, icon.Data)
15 | systray.SetTooltip("Foliage")
16 | mQuit := systray.AddMenuItem("Quit", "Quit Foliage")
17 | go func() {
18 | <-mQuit.ClickedCh
19 | systray.Quit()
20 | }()
21 | }
22 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | Support
2 | =======
3 |
4 | Thank you for your interest in this project. If you are experiencing problems or have questions, the following are the preferred methods of reaching someone:
5 |
6 | 1. Report a new issue using the [issue tracker](https://github.com/caltechlibrary/foliage/issues).
7 | 2. Send email to the Caltech Library: [helpdesk@library.caltech.edu](mailto:helpdesk@library.caltech.edu).
8 | 3. Send email to an individual involved in the project. People's names appear in the top-level `README.md` file in the source code repository.
9 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 | 注:
10 |
11 | 对于PyWebIO使用咨询或对于其他人也可能有帮助的问题,请考虑移至 [Discussions](https://github.com/wang0618/PyWebIO/discussions) 进行发帖。
12 |
13 | **BUG描述**
14 | 描述BUG表现以及复现方式。
15 | 如果浏览器控制台有报错以及脚本抛出异常也请将报错信息附上
16 |
17 | **环境信息**
18 | - 操作系统:
19 | - 浏览器及版本:
20 | - Python版本: 使用 `python3 --version` 查看
21 | - PyWebIO版本: 使用 `python3 -c "import pywebio;print(pywebio.__version__)"` 查看
22 |
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/icon/make_icon.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # To install 2goarray:
4 | #
5 | # setenv GOPATH /usr/local/go
6 | # go install github.com/cratonica/2goarray@latest
7 |
8 | if [ -z "$1" ]; then
9 | echo Please specify a PNG file
10 | exit
11 | fi
12 |
13 | if [ ! -f "$1" ]; then
14 | echo $1 is not a valid file
15 | exit
16 | fi
17 |
18 | OUTPUT=iconunix.go
19 | echo Generating $OUTPUT
20 | echo "//+build linux darwin" > $OUTPUT
21 | echo >> $OUTPUT
22 | cat "$1" | 2goarray Data icon >> $OUTPUT
23 | if [ $? -ne 0 ]; then
24 | echo Failure generating $OUTPUT
25 | exit
26 | fi
27 | echo Finished
28 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/lgtm.yml:
--------------------------------------------------------------------------------
1 | ##########################################################################################
2 | # Use the `path_classifiers` block to define changes to the default classification of #
3 | # files. #
4 | ##########################################################################################
5 |
6 | path_classifiers:
7 | test:
8 | - exclude: /
9 | - test
10 | - exclude: test/util.py
11 |
12 | library:
13 | - pywebio/html
14 | - exclude: pywebio/html/css/app.css
15 | - exclude: pywebio/html/index.html
16 |
--------------------------------------------------------------------------------
/.markdownlint.json:
--------------------------------------------------------------------------------
1 | {
2 | "blank_lines": {
3 | "maximum": 2
4 | },
5 | "html": {
6 | "allowed_elements": [
7 | "a",
8 | "b",
9 | "br",
10 | "code",
11 | "details",
12 | "div",
13 | "em",
14 | "figure",
15 | "figcaption",
16 | "i",
17 | "img",
18 | "ins",
19 | "kbd",
20 | "p",
21 | "picture",
22 | "source",
23 | "span",
24 | "sup",
25 | "summary"
26 | ]
27 | },
28 | "line-length": {
29 | "line_length": 10000
30 | },
31 | "no-alt-text": true,
32 | "no-duplicate-heading": {
33 | "allow_different_nesting": true
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 | com.apple.security.cs.allow-jit
10 |
11 | com.apple.security.cs.allow-unsigned-executable-memory
12 |
13 | com.apple.security.cs.disable-library-validation
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2
2 | message: "If you use this software, please cite it using these metadata."
3 | title: "Foliage"
4 | authors:
5 | -
6 | affiliation: "Caltech Library"
7 | given-names: Mike
8 | family-names: Hucka
9 | orcid: "0000-0001-9105-5960"
10 | version: "1.8.0"
11 | abstract: "Foliage (FOLIo chAnGe Editor): a tool to do bulk changes in FOLIO using the OKAPI API"
12 | repository-code: "https://github.com/caltechlibrary/foliage"
13 | type: software
14 | license-url: "https://github.com/caltechlibrary/foliage/blob/main/LICENSE"
15 | keywords:
16 | - FOLIO
17 | - batch operations
18 | - desktop software
19 | date-released: 2024-06-07
20 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/tools/build_dev_version.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import os
3 | import re
4 |
5 | proj_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 |
7 | version = datetime.datetime.now().strftime('.dev%y%m%d%H%M')
8 | version_path = os.path.join(proj_dir, 'pywebio', '__version__.py')
9 |
10 | content = open(version_path).read()
11 | new_content = re.sub(r'__version__ = "(.*)?"', r'__version__ = "\g<1>%s"' % version, content)
12 | new_content += '\n__commit_hash__ = %r' % os.environ.get('GITHUB_SHA', '')[:8]
13 | open(version_path, 'w').write(new_content)
14 |
15 | about = {}
16 | exec(new_content, about)
17 | print(about['__version__'])
18 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/state.ts:
--------------------------------------------------------------------------------
1 | import {Session} from "./session";
2 |
3 | // 运行时状态
4 | export let state = {
5 | AutoScrollBottom: false, // 是否有新内容时自动滚动到底部
6 | CurrentSession: null as Session, // 当前正在活跃的会话
7 | ShowDuration: 200, // ms, 显示表单的过渡动画时长
8 | };
9 |
10 | // 应用配置
11 | export let config = {
12 | codeMirrorModeURL: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/mode/%N/%N.min.js",
13 | codeMirrorThemeURL: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.52.2/theme/%N.min.css",
14 | outputAnimation: true, // 启用内容输出动画
15 | httpPullInterval: 1000, // HttpSession 拉取消息的周期(ms)
16 | debug: false, // 调试模式, 打印所有交互的消息
17 | };
18 |
--------------------------------------------------------------------------------
/dev/dev-docs/installing-pyqt5-on-macos.md:
--------------------------------------------------------------------------------
1 | # Notes about install PyQt5 on macOS systems
2 |
3 | As of 2023-04-27, getting PyQt5 installed in Python seems much harder for Python versions 3.10 and later. I ended up using Python 3.9 for this reason for Foliage development.
4 |
5 | On macOS Ventura, When I tried `pip install pyqt5`, it produced errors that implied it couldn't find `qmake`.
6 |
7 | I got a copy of `qmake` by doing
8 | ```
9 | brew install qt5
10 | ```
11 |
12 | This put `qmake` in `/opt/homebrew/opt/qt5/bin`. I put that path on my shell `$PATH`, and verified `qmake` existed, then ran
13 | ```
14 | pip3 install pyqt5 --config-settings --confirm-license= --verbose
15 | ```
16 | again, and it worked that time.
17 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/releases/v0.3.0.rst:
--------------------------------------------------------------------------------
1 | What's new in PyWebIO 0.3
2 | ==========================
3 |
4 | 2020 5/13
5 | ----------
6 |
7 | Highlights
8 | ^^^^^^^^^^
9 |
10 | * 支持输出 bokeh 数据可视化图表, :ref:`文档 `
11 | * 添加 :func:`session.get_info() ` 获取会话相关信息
12 | * 前端js代码迁移typescript
13 | * `output.put_table() ` 支持跨行/列单元格, 单元格内容支持使用 ``put_xxx`` 类输出函数
14 |
15 | Detailed changes by module
16 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
17 |
18 | UI
19 | ~~~~~~~~~~~~~~
20 |
21 | * 当与服务器连接断开时,点击前端的交互式按钮会报错提示。
22 |
23 |
24 | `pywebio.output`
25 | ~~~~~~~~~~~~~~~~
26 |
27 | * 锚点名字支持使用空格
28 | * 弃用 `table_cell_buttons() `
29 |
30 |
31 |
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/icon/README.md:
--------------------------------------------------------------------------------
1 | # Systray icon for Foliage macOS systray widget
2 |
3 | The files [make_icon.bat](make_icon.bat) and [make_icon.sh](make_icon.sh) originally came from the repository [systray](https://github.com/getlantern/systray) by [Latern](https://github.com/getlantern).
4 |
5 | Install Go, then install [2goarray](https://github.com/cratonica/2goarray) like this:
6 |
7 | ```sh
8 | setenv GOPATH /usr/local/go
9 | go install github.com/cratonica/2goarray@latest
10 | ```
11 |
12 | The icon file is the 64x64 Foliage icon from the foliage/data directory. Generate the icon here like this:
13 |
14 | ```sh
15 | ./make_icon.sh icon-64.png
16 | ```
17 |
18 | That will produce the file [iconunix.go](iconunix.go).
19 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.readthedocs.yml:
--------------------------------------------------------------------------------
1 | # .readthedocs.yml
2 | # Read the Docs configuration file
3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4 |
5 | # Required
6 | version: 2
7 |
8 | # Build documentation in the docs/ directory with Sphinx
9 | sphinx:
10 | configuration: docs/conf.py
11 |
12 | # Build documentation with MkDocs
13 | #mkdocs:
14 | # configuration: mkdocs.yml
15 |
16 | # Optionally build your docs in additional formats such as PDF and ePub
17 | formats: all
18 |
19 | # Optionally set the version of Python and requirements required to build your docs
20 | python:
21 | version: 3.7
22 | install:
23 | - requirements: requirements.txt
24 | - method: pip
25 | path: .
26 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/output_diff.py:
--------------------------------------------------------------------------------
1 | import os, sys
2 |
3 |
4 | def diff_file(file_a, file_b):
5 | if open(file_a).read() != open(file_b).read():
6 | cmd = 'diff %s %s' % (file_a, file_b)
7 | print('#' * 4, cmd, '#' * 4)
8 | os.system(cmd)
9 | return True
10 | return False
11 |
12 |
13 | def diff_dir(dir):
14 | files = [os.path.join(dir, f) for f in os.listdir(dir) if os.path.isfile(os.path.join(dir, f))]
15 | has_diff = any(diff_file(files[idx - 1], files[idx]) for idx in range(1, len(files)))
16 | if has_diff:
17 | sys.exit(1)
18 |
19 |
20 | if __name__ == '__main__':
21 | here_dir = os.path.dirname(os.path.abspath(__file__))
22 | diff_dir(os.path.join(here_dir, 'output'))
23 |
--------------------------------------------------------------------------------
/docs/_static/media/README.md:
--------------------------------------------------------------------------------
1 | # Foliage diagrams
2 |
3 | The diagrams used in the Foliage documentation were created by Michael Hucka in 2022, using OmniGraffle Pro 7.18.5 on a macOS 10.4.6 computer. The SVG versions were produced using the following steps:
4 |
5 |
6 |
7 | 1. Export from OmniGraffle to SVG format, using the options "transparent background" and `0`inch margin. (See screen image at the right.)
8 | 2. Run [svg-buddy](https://github.com/phauer/svg-buddy) on the SVG file produced from step #1. This will embed the fonts used in the SVG file, overcoming a limitation of OmniGraffle's SVG output. The following is an example of the command used:
9 | ```sh
10 | java -jar svg-buddy.jar foliage-change-case-1.svg
11 | ```
12 |
--------------------------------------------------------------------------------
/.github/workflows/archive-github-pages.yml:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file archive-github-pages.yml
3 | # @brief Save the Github pages in the Internet Archive
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the repository
6 | # @repo https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | name: Archive latest GitHub Pages in IA
10 | on:
11 | release:
12 | types: [published]
13 | jobs:
14 | Workflow:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: caltechlibrary/waystation@main
18 | with:
19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 | dry_run: false
21 | debug: false
22 |
--------------------------------------------------------------------------------
/dev/misc/experiments/macos-widget.py:
--------------------------------------------------------------------------------
1 | from os.path import dirname, join
2 | from PyQt5.QtGui import *
3 | from PyQt5.QtWidgets import *
4 |
5 | # Code originally based on example found on 2021-12-10 at
6 | # https://www.pythonguis.com/tutorials/system-tray-mac-menu-bar-applications-pyqt/
7 |
8 | app = QApplication([])
9 | app.setQuitOnLastWindowClosed(False)
10 |
11 | # Create the icon
12 | icon = QIcon(join(dirname(__file__), 'foliage-icon.png'))
13 |
14 | # Create the tray
15 | tray = QSystemTrayIcon()
16 | tray.setIcon(icon)
17 | tray.setVisible(True)
18 |
19 | # Create the menu
20 | menu = QMenu()
21 |
22 | # Add a Quit option to the menu.
23 | quit = QAction("Quit")
24 | quit.triggered.connect(app.quit)
25 | menu.addAction(quit)
26 |
27 | # Add the menu to the tray
28 | tray.setContextMenu(menu)
29 |
30 | app.exec_()
31 |
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/go.mod:
--------------------------------------------------------------------------------
1 | module macos-systray-widget
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect
7 | github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect
8 | github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect
9 | github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect
10 | github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect
11 | github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect
12 | github.com/getlantern/systray v1.1.0 // indirect
13 | github.com/go-stack/stack v1.8.0 // indirect
14 | github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect
15 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
16 | )
17 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/handlers/script.ts:
--------------------------------------------------------------------------------
1 | import {Command, Session} from "../session";
2 | import {CommandHandler} from "./base";
3 |
4 |
5 | export class ScriptHandler implements CommandHandler {
6 | session: Session;
7 |
8 | accept_command = ['run_script'];
9 |
10 | constructor(session: Session) {
11 | this.session = session;
12 | }
13 |
14 | handle_message(msg: Command) {
15 | let script = msg.spec.code as string;
16 | let args = msg.spec.args as { [i: string]: any };
17 | let arg_names:string[] = ['WebIOCurrentTaskID'], arg_vals:any[] = [msg.task_id];
18 | for(let key in args){
19 | arg_names.push(key);
20 | arg_vals.push(args[key]);
21 | }
22 | const script_func = new Function(...arg_names, script);
23 | script_func(...arg_vals);
24 | }
25 | }
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/_ext/README.md:
--------------------------------------------------------------------------------
1 | ## sphinx示例代码添加在线Demo链接
2 |
3 | ### 自定义sphinx `exportable-codeblock` directive
4 |
5 | 代码实现:`PyWebIO/docs/_ext/codeblock.py`
6 |
7 | `exportable-codeblock` 指令可以像 `codeblock` 指令一样使用,用于展示代码:
8 |
9 | ```rest
10 | ..exportable-codeblock::
11 | :name: test
12 | :summary: 描述
13 |
14 | put_text('hello world')
15 |
16 | ```
17 |
18 | 当设置环境变量 `CODE_EXPORT_PATH` 后进行文档构建时,使用`exportable-codeblock`指令展示的示例代码会被导出到环境变量 `CODE_EXPORT_PATH`指定的目录中。
19 |
20 | 比如:
21 | ```bash
22 | CODE_EXPORT_PATH=/Users/wangweimin/repos/PyWebIO/demos/doc_domes make clean html
23 | ```
24 |
25 | 使用`exportable-codeblock`指令展示的示例代码被导出后,可以使用 `PyWebIO/demos/doc_demo.py` 来运行。
26 |
27 | 为了在运行示例代码时,可以有更多选项,定义了一些特殊注释,这些特殊不会出现在生成的文档中,但会被导出并在运行示例代码时被特殊处理。
28 |
29 | 特殊注释如下:
30 |
31 | - `## ----` : 表示分割示例代码,将示例代码分割成不同的部分来分别运行。该注释主要放到行首
32 | - `# ..demo-only` : 表示该行代码仅在Demo页面中显示
33 | - `# ..doc-only` : 表示该行代码仅在文档中显示
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Summary: EditorConfig file for this project. -*- conf -*-
2 | #
3 | # For more information, see https://EditorConfig.org
4 | #
5 | # Copyright 2024 California Institute of Technology.
6 | # License: Modified BSD 3-clause – see file "LICENSE" in the project website.
7 | # Website: https://github.com/caltechlibrary/baler
8 |
9 | root = true
10 |
11 | [*]
12 | charset = utf-8
13 | end_of_line = lf
14 | indent_size = 4
15 | indent_style = space
16 | insert_final_newline = true
17 | max_line_length = 90
18 | tab_width = 4
19 | trim_trailing_whitespace = true
20 |
21 | [*.cfg]
22 | indent_size = 2
23 |
24 | [*.json]
25 | indent_size = 2
26 |
27 | [*.{yml, yaml}]
28 | indent_size = 2
29 |
30 | # Shell scripts on Windows.
31 | [*.{cmd, bat}]
32 | end_of_line = crlf
33 |
34 | [Makefile, makefile]
35 | indent_size = 4
36 | indent_style = tab
37 | tab_width = 8
38 |
39 | [.applescript]
40 | indent_size = 4
41 | indent_style = tab
42 | tab_width = 4
43 |
--------------------------------------------------------------------------------
/.graphics/status-warning.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webiojs",
3 | "version": "0.2.0",
4 | "description": "",
5 | "main": "src/main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "@types/jquery": "^3.3.38",
13 | "@types/marked": "^1.2.2",
14 | "babel-core": "^6.26.3",
15 | "babel-preset-es2015": "^6.24.1",
16 | "babelify": "^8.0.0",
17 | "browserify": "^16.5.1",
18 | "fancy-log": "^1.3.3",
19 | "gulp": "^4.0.0",
20 | "gulp-sourcemaps": "^2.6.5",
21 | "gulp-typescript": "^6.0.0-alpha.1",
22 | "gulp-uglify": "^3.0.2",
23 | "gulp-uglify-es": "^2.0.0",
24 | "highlight.js": "^10.5.0",
25 | "marked": "^1.2.8",
26 | "tsify": "^4.0.1",
27 | "typescript": "^3.8.3",
28 | "vinyl-buffer": "^1.0.1",
29 | "vinyl-source-stream": "^2.0.0",
30 | "watchify": "^3.11.1"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Foliage
2 |
3 | Foliage (_**Foli**o ch**a**n**g**e **E**ditor_) is a desktop computer application that can perform operations in [FOLIO](https://www.folio.org), a library services platform ([LSP](https://journals.ala.org/index.php/ltr/article/view/5686/7063)) used by Caltech and other institutions. Foliage allows a user to look up records of various kinds, perform bulk changes in the values of record fields, delete records, and more. It communicates with a FOLIO server using the [OKAPI network API](https://github.com/folio-org/okapi/blob/master/doc/guide.md). The program is cross-platform compatible and currently in use on Windows and macOS computers at the Caltech Library.
4 |
5 | ## Sections
6 |
7 | ```{toctree}
8 | ---
9 | maxdepth: 2
10 | ---
11 | installation.md
12 | first-time-usage.md
13 | foliage-interface.md
14 | nitty.md
15 | glossary.md
16 | colophon.md
17 | ```
18 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/static/pywebio.css:
--------------------------------------------------------------------------------
1 | /* Tabs */
2 |
3 | .ui.menu {
4 | font-family: Helvetica;
5 | min-height: 0;
6 | }
7 |
8 | .ui.tabular.menu .item {
9 | padding: 9px 1em;
10 | }
11 |
12 | .ui.menu .item {
13 | padding: 0;
14 | }
15 |
16 | .sphinx-tabs {
17 | margin-bottom: 1em;
18 | }
19 |
20 | /* Table cell */
21 | td .line-block {
22 | margin-bottom: 0 !important;
23 | }
24 |
25 | .rst-content img {
26 | box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, .35);
27 | -moz-box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, .35);
28 | -webkit-box-shadow: 0px 4px 20px 0px rgba(0, 0, 0, .35);
29 | }
30 |
31 | #hello-world img {
32 | box-shadow: none;
33 | -moz-box-shadow: none;
34 | -webkit-box-shadow: none;
35 | }
36 |
37 | .demo-cb .highlight{
38 | position: relative;
39 | }
40 |
41 | .demo-cb .viewcode-back{
42 | position: absolute;
43 | right: 10px;
44 | top: 4px;
45 | padding-left: 0px;
46 | background-color: #f8f8f8;
47 | }
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var browserify = require('browserify');
3 | var source = require('vinyl-source-stream');
4 | var tsify = require('tsify');
5 | var sourcemaps = require('gulp-sourcemaps');
6 | var buffer = require('vinyl-buffer');
7 | var uglify = require('gulp-uglify-es').default;
8 |
9 |
10 | gulp.task('default', function () {
11 | return browserify({
12 | basedir: '.',
13 | debug: true,
14 | entries: ['src/main.ts'],
15 | cache: {},
16 | packageCache: {}
17 | })
18 | .plugin(tsify)
19 | .transform('babelify', {
20 | presets: ['es2015'],
21 | extensions: ['.ts']
22 | })
23 | .bundle()
24 | .pipe(source('pywebio.min.js'))
25 | .pipe(buffer())
26 | .pipe(sourcemaps.init({loadMaps: true}))
27 | .pipe(uglify())
28 | .pipe(sourcemaps.write('./',{addComment: !!process.env.DEV}))
29 | .pipe(gulp.dest('dist'));
30 | });
--------------------------------------------------------------------------------
/bin/foliage:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # =============================================================================
3 | # @file foliage
4 | # @brief Simple interface to run foliage, for testing and exploration
5 | # @author Michael Hucka
6 | # @license Please see the file named LICENSE in the project directory
7 | # @website https://github.com/caltechlibrary/foliage
8 | # =============================================================================
9 |
10 | # Allow this program to be executed directly from the 'bin' directory.
11 | import os
12 | import sys
13 | import plac
14 |
15 | # Allow this program to be executed directly from the 'bin' directory.
16 | try:
17 | thisdir = os.path.dirname(os.path.abspath(__file__))
18 | sys.path.append(os.path.join(thisdir, '..'))
19 | except:
20 | sys.path.append('..')
21 |
22 | # Hand over to the command line interface.
23 | import foliage
24 | from foliage.__main__ import main as main
25 |
26 | if __name__ == "__main__":
27 | plac.call(main)
28 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file requirements-dev.txt
3 | # @brief Python dependencies for Foliage for development
4 | # @created 2021-10-16
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | -r requirements.txt
10 |
11 | pytest >= 6.2.5
12 | pytest-cov >= 3.0.0
13 | pytest-mock >= 3.7.0
14 |
15 | flake8 >= 4.0.1
16 | flake8-bugbear >= 22.4.25
17 | flake8-builtins >= 1.5.3
18 | flake8-comprehensions >= 3.8.0
19 | flake8-executable >= 2.1.1
20 | flake8_implicit_str_concat >= 0.3.0
21 | flake8-pie >= 0.15.0
22 | flake8-simplify >= 0.19.2
23 |
24 | pyinstaller
25 |
26 | linkify-it-py
27 | myst-parser
28 | sphinx-autobuild
29 | sphinx-material
30 | sphinxcontrib-mermaid
31 | twine
32 | wheel
33 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/handlers/env.ts:
--------------------------------------------------------------------------------
1 | import {Command, HttpSession} from "../session";
2 | import {CommandHandler} from "./base";
3 | import {config, state} from "../state";
4 |
5 | export class EnvSettingHandler implements CommandHandler {
6 | accept_command: string[] = ['set_env'];
7 |
8 | constructor() {
9 | }
10 |
11 | handle_message(msg: Command) {
12 | let spec = msg.spec;
13 | if (spec.title !== undefined) {
14 | document.title = spec.title;
15 | }
16 |
17 | if (spec.auto_scroll_bottom !== undefined)
18 | state.AutoScrollBottom = spec.auto_scroll_bottom;
19 |
20 | if (spec.output_animation !== undefined) {
21 | config.outputAnimation = spec.output_animation;
22 | }
23 |
24 | if (spec.http_pull_interval !== undefined) {
25 | if (state.CurrentSession instanceof HttpSession)
26 | state.CurrentSession.change_pull_interval(spec.http_pull_interval);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/dev/dev-docs/README.md:
--------------------------------------------------------------------------------
1 | # Foliage developer documentation
2 |
3 | This directory constains my attempt at describing everything about how the Foliage application is built.
4 |
5 | To build Foliage for Windows, I use a Windows 10 virtual machine running in [Parallels](https://www.parallels.com) on a Mac. For the command shell where I execute all commands, I use [Cmder](https://cmder.net) instead of the default Windows `cmd.exe`. The Windows environment has a shared file system with the Mac environment, so that any file changes made in one are visible immediately in the other. (All of the build and installation instructions here assume a shared file system between operating environments.)
6 |
7 | Explanations about the software architecture:
8 |
9 | * [How the Foliage splash screen works](creating-a-splash-screen.md)
10 | * [How the taskbar/system tray widget works](system-widget.md)
11 |
12 | Explanations about building the software:
13 |
14 | * [Using PyInstaller](using-pyinstaller.md)
15 | * [Making a new release of Foliage](making-a-new-release.md)
16 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/platform/__init__.py:
--------------------------------------------------------------------------------
1 | r"""
2 | ``platform`` 模块为PyWebIO提供了对不同Web框架的支持。
3 |
4 | 具体用法参见用户手册 :ref:`与Web框架集成 ` 小节
5 |
6 | Tornado相关
7 | --------------
8 | .. autofunction:: pywebio.platform.tornado.start_server
9 | .. autofunction:: pywebio.platform.tornado.webio_handler
10 |
11 | Flask相关
12 | --------------
13 | .. autofunction:: pywebio.platform.flask.webio_view
14 | .. autofunction:: pywebio.platform.flask.start_server
15 |
16 | Django相关
17 | --------------
18 | .. autofunction:: pywebio.platform.django.webio_view
19 | .. autofunction:: pywebio.platform.django.start_server
20 |
21 | aiohttp相关
22 | --------------
23 | .. autofunction:: pywebio.platform.aiohttp.webio_handler
24 | .. autofunction:: pywebio.platform.aiohttp.start_server
25 |
26 | 其他
27 | --------------
28 | .. autofunction:: pywebio.platform.seo
29 | .. autofunction:: pywebio.platform.run_event_loop
30 |
31 | """
32 |
33 | from .httpbased import run_event_loop
34 | from .tornado import start_server
35 | from .utils import seo
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/3.django_backend.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from selenium.webdriver import Chrome
5 |
6 | import pywebio
7 | import template
8 | import util
9 | from pywebio.input import *
10 | from pywebio.platform.django import start_server
11 | from pywebio.utils import run_as_function
12 |
13 |
14 | def target():
15 | template.basic_output()
16 | template.background_output()
17 |
18 | run_as_function(template.basic_input())
19 | actions(buttons=['Continue'])
20 | template.background_input()
21 |
22 |
23 | def test(server_proc: subprocess.Popen, browser: Chrome):
24 | template.test_output(browser)
25 |
26 | time.sleep(1)
27 |
28 | template.test_input(browser)
29 |
30 | time.sleep(1)
31 | template.save_output(browser, '3.django_backend.html')
32 |
33 |
34 | def start_test_server():
35 | pywebio.enable_debug()
36 |
37 | start_server(target, port=8080, host='127.0.0.1', cdn=False)
38 |
39 |
40 | if __name__ == '__main__':
41 | util.run_test(start_test_server, test)
42 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/9.aiohttp_backend.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from selenium.webdriver import Chrome
5 |
6 | import pywebio
7 | import template
8 | import util
9 | from pywebio.input import *
10 | from pywebio.platform.aiohttp import start_server
11 | from pywebio.utils import run_as_function
12 |
13 |
14 | def target():
15 | template.basic_output()
16 | template.background_output()
17 |
18 | run_as_function(template.basic_input())
19 | actions(buttons=['Continue'])
20 | template.background_input()
21 |
22 |
23 | def test(server_proc: subprocess.Popen, browser: Chrome):
24 | template.test_output(browser)
25 |
26 | time.sleep(1)
27 |
28 | template.test_input(browser)
29 |
30 | time.sleep(1)
31 | template.save_output(browser, '9.aiohttp_backend.html')
32 |
33 |
34 | def start_test_server():
35 | pywebio.enable_debug()
36 |
37 | start_server(target, port=8080, host='127.0.0.1', cdn=False)
38 |
39 |
40 | if __name__ == '__main__':
41 | util.run_test(start_test_server, test)
42 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.drone.yml:
--------------------------------------------------------------------------------
1 | kind: pipeline
2 | type: exec
3 | name: default
4 |
5 | clone:
6 | disable: true
7 |
8 | trigger:
9 | branch:
10 | - dev
11 | event:
12 | - push
13 |
14 | steps:
15 | - name: clone
16 | commands:
17 | - sleep 300 # wait aliyun repo to sync
18 | - git init
19 | - git remote add aliyun "https://code.aliyun.com/wang0618/pywebio.git"
20 | - git fetch --no-tags --prune --progress --no-recurse-submodules --depth=1 aliyun $DRONE_BRANCH
21 | - git checkout --progress --force -B $DRONE_BRANCH aliyun/$DRONE_BRANCH
22 | - git log -1
23 | - name: deploy demos
24 | commands:
25 | - docker rm -f pywebio-demos || true
26 | - >
27 | docker run --restart=always --name=pywebio-demos -v $PWD:/app_tmp
28 | --label="traefik.http.services.pywebiodemos.loadbalancer.server.port=80"
29 | -d python:3 bash -c "cp -r /app_tmp /app && cd /app && pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple . && python3 -m demos --port=80"
30 | - sleep 5 # wait container start
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # -*- mode: sh; -*-
2 |
3 | # Set the default behavior, in case people don't have core.autocrlf set.
4 | # .............................................................................
5 |
6 | * text=auto
7 |
8 | # Specify what's text and should be normalized.
9 | # .............................................................................
10 |
11 | *.py text
12 | *.in text
13 | *.rst text
14 | *.cfg text
15 | *.ini text
16 | *.yml text
17 | *.json text
18 | *.bat text
19 | *.sh text
20 | LICENSE text
21 | CONTRIBUTING text
22 |
23 | # Denote all files that are truly binary and should not be modified.
24 | # .............................................................................
25 |
26 | *.png binary
27 | *.jpg binary
28 | *.xls binary
29 | *.doc binary
30 |
31 | # This next one is because in other projects, we've had problems with git
32 | # getting confused about line endings when people using Windows and Mac edit
33 | # the same files.
34 | # .............................................................................
35 |
36 | *.csv binary diff=csv
37 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Guidelines for contributing to this project
2 |
3 | Any constructive contributions – bug reports, pull requests (code or documentation), suggestions for improvements, and more – are welcome.
4 |
5 | ## Conduct
6 |
7 | Everyone is asked to read and respect the [code of conduct](CODE_OF_CONDUCT.md) before participating in this project.
8 |
9 | ## Coordinating work
10 |
11 | A quick way to find out what is currently in the near-term plans for this project is to look at the [GitHub issue tracker](https://github.com/caltechlibrary/foliage/issues), but the possibilities are not limited to what you see there – if you have ideas for new features and enhancements, please feel free to write them up as a new issue or contact the developers directly!
12 |
13 | ## Submitting contributions
14 |
15 | Please feel free to contact the author directly, or even better, jump right in and use the standard GitHub approach of forking the repo and creating a pull request. When committing code changes and submitting pull requests, please write a clear log message for your commits.
16 |
--------------------------------------------------------------------------------
/dev/installers/windows/create-innosetup-script.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file create-innosetup-script.py
3 | # @brief Replace version string in foliage_innosetup_script.iss.in
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | import os
10 | from os.path import abspath, dirname, join
11 | from string import Template
12 |
13 | here = abspath(dirname(__file__))
14 | with open(join(here, '../../../setup.cfg')) as setup_file:
15 | for line in setup_file.readlines():
16 | if line.startswith('version'):
17 | version = line.split('=')[1].strip()
18 | break
19 |
20 | with open(join(here, 'foliage_innosetup_script.iss.tmpl')) as template_file:
21 | with open(join(here, 'foliage_innosetup_script.iss'), 'w') as output_file:
22 | output_file.write(template_file.read().replace('@@VERSION@@', version))
23 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/4.flask_backend.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from selenium.webdriver import Chrome
5 |
6 | import pywebio
7 | import template
8 | import util
9 | from pywebio.input import *
10 | from pywebio.platform.flask import start_server
11 | from pywebio.utils import run_as_function
12 |
13 |
14 | def target():
15 | template.basic_output()
16 | template.background_output()
17 |
18 | run_as_function(template.basic_input())
19 | actions(buttons=['Continue'])
20 | template.background_input()
21 |
22 |
23 | def test(server_proc: subprocess.Popen, browser: Chrome):
24 | template.test_output(browser)
25 |
26 | time.sleep(1)
27 |
28 | template.test_input(browser)
29 |
30 | time.sleep(1)
31 | template.save_output(browser, '4.flask_backend.html')
32 |
33 |
34 | def start_test_server():
35 | pywebio.enable_debug()
36 | start_server(target, port=8080, host='127.0.0.1', cdn=False)
37 |
38 |
39 | if __name__ == '__main__':
40 | util.run_test(start_test_server, test, address='http://localhost:8080?_pywebio_debug=1&_pywebio_http_pull_interval=400')
41 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/static/pywebio.js:
--------------------------------------------------------------------------------
1 | let DEMO_URL;
2 | if (localStorage.getItem('pywebio_doc_demo_url'))
3 | DEMO_URL = localStorage.getItem('pywebio_doc_demo_url');
4 | else
5 | DEMO_URL = 'http://pywebio-demos.demo.wangweimin.site/doc_demo';
6 |
7 | var parseHTML = function (str) {
8 | let tmp = document.implementation.createHTMLDocument();
9 | tmp.body.innerHTML = str;
10 | return tmp.body.children;
11 | };
12 |
13 | function ready(fn) {
14 | if (document.readyState != 'loading') {
15 | fn();
16 | } else {
17 | document.addEventListener('DOMContentLoaded', fn);
18 | }
19 | }
20 |
21 | let demo_url = new URL(DEMO_URL);
22 |
23 | ready(function () {
24 | let codes = document.querySelectorAll('.demo-cb');
25 | for (let c of codes) {
26 | let id = c.getAttribute('id');
27 | let ele = c.querySelector('.highlight');
28 | demo_url.searchParams.set("app", id);
29 | let node = parseHTML(`[Demo]`)[0];
30 | ele.insertBefore(node, ele.firstChild);
31 | }
32 | });
33 |
--------------------------------------------------------------------------------
/foliage/exceptions.py:
--------------------------------------------------------------------------------
1 | '''
2 | exceptions.py: exceptions defined by Foliage
3 |
4 | Authors
5 | -------
6 |
7 | Michael Hucka -- Caltech Library
8 |
9 | Copyright
10 | ---------
11 |
12 | Copyright (c) 2021-2022 by the California Institute of Technology. This code is
13 | open-source software released under a 3-clause BSD license. Please see the
14 | file "LICENSE" for more information.
15 | '''
16 |
17 |
18 | # Base class.
19 | # .............................................................................
20 | # The base class makes it possible to use a single test to distinguish between
21 | # exceptions generated by Foliage and exceptions generated by something else.
22 |
23 | class FoliageException(Exception):
24 | '''Base class for Foliage exceptions.'''
25 |
26 |
27 | # Exception classes.
28 | # .............................................................................
29 |
30 | class FolioOpFailed(FoliageException):
31 | '''Requested operation was unsuccessful.'''
32 |
33 |
34 | class FolioError(FoliageException):
35 | '''Unrecoverable problem involving interactions with the FOLIO server.'''
36 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/5.coroutine_based_session.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from percy import percySnapshot
5 | from selenium.webdriver import Chrome
6 |
7 | import pywebio
8 | import template
9 | import util
10 | from pywebio.input import *
11 | from pywebio.output import *
12 | from pywebio.utils import to_coroutine
13 | from pywebio import start_server
14 |
15 |
16 | async def target():
17 | template.basic_output()
18 | await template.coro_background_output()
19 |
20 | await to_coroutine(template.basic_input())
21 | await actions(buttons=['Continue'])
22 | await template.coro_background_input()
23 |
24 |
25 | def test(server_proc: subprocess.Popen, browser: Chrome):
26 | template.test_output(browser)
27 |
28 | time.sleep(1)
29 |
30 | template.test_input(browser)
31 |
32 | time.sleep(1)
33 | template.save_output(browser, '5.coroutine_based_session.html')
34 |
35 |
36 | def start_test_server():
37 | pywebio.enable_debug()
38 | start_server(target, port=8080, host='127.0.0.1', cdn=False)
39 |
40 |
41 | if __name__ == '__main__':
42 | util.run_test(start_test_server, test)
43 |
--------------------------------------------------------------------------------
/foliage/base_tab.py:
--------------------------------------------------------------------------------
1 | '''
2 | base_tab.py: base class for tabs
3 |
4 | The tabs in Foliage are conceptually pretty simple: there's a function to
5 | create the tab contents, and another function to set up optional watchers
6 | for detecting and acting on designated PyWebIO "pin" objects. The class
7 | FoliageTab is a base class used by all the Foliage tab classes. This common
8 | base class makes it possible to implement tab creation and pin watching in
9 | __main__.py's foliage_page() as a loop over a list of objects, rather than
10 | by hardcoding calls to every tab directly.
11 |
12 | Copyright
13 | ---------
14 |
15 | Copyright (c) 2021-2022 by the California Institute of Technology. This code
16 | is open-source software released under a 3-clause BSD license. Please see the
17 | file "LICENSE" for more information.
18 | '''
19 |
20 |
21 | class FoliageTab():
22 | def contents(self):
23 | '''Return a dict of elements {'title': '...', 'content': [objects]}.'''
24 | raise NotImplementedError()
25 |
26 | def pin_watchers(self):
27 | '''Return a dict of elements {'pin_name': callback_function}.'''
28 | raise NotImplementedError()
29 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 WangWeimin
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.
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies and lint with a variety of Python versions
2 |
3 | name: Python lint
4 |
5 | on: [push, pull_request]
6 |
7 | jobs:
8 | lint:
9 | runs-on: ubuntu-latest
10 | strategy:
11 | matrix:
12 | python-version: [3.5, 3.6, 3.7, 3.8]
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 | - name: Set up Python ${{ matrix.python-version }}
17 | uses: actions/setup-python@v1
18 | with:
19 | python-version: ${{ matrix.python-version }}
20 | - name: Install dependencies
21 | run: |
22 | python -m pip install --upgrade pip
23 | pip install -r requirements.txt
24 | - name: Lint with flake8
25 | run: |
26 | pip install flake8
27 | # stop the build if there are Python syntax errors or undefined names
28 | flake8 pywebio --count --select=E9,F63,F7,F82 --show-source --statistics
29 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
30 | flake8 pywebio --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/FAQ.rst:
--------------------------------------------------------------------------------
1 | 常见问题
2 | ==========================
3 |
4 | .. contents::
5 | :local:
6 |
7 | 如何让输入框在提交后不消失,并可以持续性地输入
8 | ----------------------------------------------------------
9 | PyWebIO 的设计就是输入表单在成功提交后就销毁,因为 PyWebIO 的输入是阻塞式的,一旦提交表单,输入函数就返回了,此时表单还留在界面上是没有意义的。如果想实现持续性的输入,可以将接收输入以及后续操作放到一个 ``while`` 循环中。
10 |
11 |
12 | 如何输出一个诸如搜索栏的输入框
13 | ----------------------------------------------------------
14 | 很遗憾,PyWebIO并不支持将输入框作为一般性的内容输出到页面。因为这样就相当于又回到了基于回调获取输入的方式了,会导致应用开发的复杂性提高,PyWebIO不太推荐过多依赖回调机制,所以对此仅提供了非常少的支持。
15 | 不过也可以使用另一种方式实现近似的效果:只需要在需要显示输入框的地方放置一个button( `put_buttons() ` ),然后在button的回调函数中调用输入函数来获取输入并进行后续操作。
16 |
17 |
18 | 为什么 ``put_buttons()`` 的回调不起作用
19 | ----------------------------------------------------------
20 | 一般情况下,在Server模式下,任务函数一旦返回(或在Script模式下,脚本运行结束),会话就结束了,此时事件回调也将不起作用,可以在任务函数(或脚本)末尾处使用 `pywebio.session.hold()` 函数来将会话保持,这样在用户关闭浏览器页面前,事件回调将一直可用。 参见 :ref:`Server模式与Script模式 `
21 |
22 |
23 | 为什么 ``put_file()`` 无法下载文件
24 | ----------------------------------------------------------
25 | 原因同上。 ``put_file()`` 的文件链接被点击后,也是需要和服务端通信获取文件数据的,所以会话关闭后下载链接会不可用。可以在任务函数末尾处使用 `pywebio.session.hold()` 函数来将会话保持。
--------------------------------------------------------------------------------
/codemeta.json:
--------------------------------------------------------------------------------
1 | {
2 | "@context": "https://doi.org/10.5063/schema/codemeta-2.0",
3 | "@type": "SoftwareSourceCode",
4 | "description": "Foliage: a tool to do bulk changes in FOLIO using the OKAPI API",
5 | "name": "foliage",
6 | "codeRepository": "https://github.com/caltechlibrary/foliage",
7 | "issueTracker": "https://github.com/caltechlibrary/foliage/issues",
8 | "license": "https://github.com/caltechlibrary/foliage/blob/main/LICENSE",
9 | "version": "1.8.0",
10 | "author": [
11 | {
12 | "@type": "Person",
13 | "givenName": "Mike",
14 | "familyName": "Hucka",
15 | "affiliation": "California Institute of Technology Library",
16 | "email": "mhucka@library.caltech.edu",
17 | "@id": "https://orcid.org/0000-0001-9105-5960"
18 | }],
19 | "developmentStatus": "active",
20 | "downloadUrl": "https://github.com/caltechlibrary/foliage/archive/main.zip",
21 | "keywords": [
22 | "software",
23 | "science"
24 | ],
25 | "maintainer": "https://orcid.org/0000-0001-9105-5960",
26 | "funder": {
27 | "@id": "https://doi.org/10.13039/100006961",
28 | "@type": "Organization",
29 | "name": "Caltech Library"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/dev/misc/folio-data-samples/sample-2-holdings-3-items/holdings-storage-holdings-795b4843-2736-4ccc-ade6-c928f8628831.json:
--------------------------------------------------------------------------------
1 | { '_version': 1,
2 | 'bareHoldingsItems': [],
3 | 'callNumber': 'QC806 .F625 2005',
4 | 'callNumberPrefix': '',
5 | 'callNumberSuffix': '',
6 | 'callNumberTypeId': '95467209-6d7b-468b-94df-0f5d7ad2747d',
7 | 'discoverySuppress': False,
8 | 'electronicAccess': [],
9 | 'formerIds': [],
10 | 'holdingsItems': [],
11 | 'holdingsStatements': [],
12 | 'holdingsStatementsForIndexes': [],
13 | 'holdingsStatementsForSupplements': [],
14 | 'holdingsTypeId': '03c9c400-b9e3-4a07-ac0e-05ab470233ed',
15 | 'hrid': 'ho00000517710',
16 | 'id': '795b4843-2736-4ccc-ade6-c928f8628831',
17 | 'instanceId': '848d5d4b-6e49-49d9-b02b-c9eb19d8b07d',
18 | 'metadata': { 'createdByUserId': '25148b30-565b-4012-8300-451fb5cbe124',
19 | 'createdDate': '2021-09-15T20:22:30.786+00:00',
20 | 'updatedByUserId': '25148b30-565b-4012-8300-451fb5cbe124',
21 | 'updatedDate': '2021-09-15T20:22:30.786+00:00'},
22 | 'notes': [],
23 | 'permanentLocationId': 'e418607a-70b6-482c-9a94-b2e56ec12110',
24 | 'shelvingTitle': '',
25 | 'statisticalCodeIds': []}
26 |
--------------------------------------------------------------------------------
/dev/misc/folio-data-samples/sample-2-holdings-3-items/holdings-storage-holdings-c0b6d0cf-38d0-43f7-b476-7debbba52bc5.json:
--------------------------------------------------------------------------------
1 | { '_version': 1,
2 | 'bareHoldingsItems': [],
3 | 'callNumber': 'QC806 .F625 2005',
4 | 'callNumberPrefix': '',
5 | 'callNumberSuffix': '',
6 | 'callNumberTypeId': '95467209-6d7b-468b-94df-0f5d7ad2747d',
7 | 'discoverySuppress': False,
8 | 'electronicAccess': [],
9 | 'formerIds': [],
10 | 'holdingsItems': [],
11 | 'holdingsStatements': [],
12 | 'holdingsStatementsForIndexes': [],
13 | 'holdingsStatementsForSupplements': [],
14 | 'holdingsTypeId': '03c9c400-b9e3-4a07-ac0e-05ab470233ed',
15 | 'hrid': 'ho00000438575',
16 | 'id': 'c0b6d0cf-38d0-43f7-b476-7debbba52bc5',
17 | 'instanceId': '848d5d4b-6e49-49d9-b02b-c9eb19d8b07d',
18 | 'metadata': { 'createdByUserId': '25148b30-565b-4012-8300-451fb5cbe124',
19 | 'createdDate': '2021-09-15T20:20:33.431+00:00',
20 | 'updatedByUserId': '25148b30-565b-4012-8300-451fb5cbe124',
21 | 'updatedDate': '2021-09-15T20:20:33.431+00:00'},
22 | 'notes': [],
23 | 'permanentLocationId': '817af180-8807-413a-861e-d483b2b97025',
24 | 'shelvingTitle': '',
25 | 'statisticalCodeIds': []}
26 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/6.flask_coroutine.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from selenium.webdriver import Chrome
5 |
6 | import pywebio
7 | import template
8 | import util
9 | from pywebio.input import *
10 | from pywebio.output import *
11 | from pywebio.platform.flask import start_server
12 | from pywebio.utils import to_coroutine
13 |
14 |
15 | async def target():
16 | template.basic_output()
17 | await template.coro_background_output()
18 |
19 | await to_coroutine(template.basic_input())
20 | await actions(buttons=['Continue'])
21 | await template.flask_coro_background_input()
22 |
23 |
24 | def test(server_proc: subprocess.Popen, browser: Chrome):
25 | template.test_output(browser)
26 |
27 | time.sleep(1)
28 |
29 | template.test_input(browser)
30 |
31 | time.sleep(1)
32 | template.save_output(browser, '6.flask_coroutine.html')
33 |
34 |
35 | def start_test_server():
36 | pywebio.enable_debug()
37 | start_server(target, port=8080, host='127.0.0.1', cdn=False)
38 |
39 |
40 | if __name__ == '__main__':
41 | util.run_test(start_test_server, test, address='http://localhost:8080?_pywebio_debug=1&_pywebio_http_pull_interval=400')
42 |
--------------------------------------------------------------------------------
/foliage/enum_utils.py:
--------------------------------------------------------------------------------
1 | '''
2 | enum_utils.py: extensions and utilities for working with enums
3 |
4 | Copyright
5 | ---------
6 |
7 | Copyright (c) 2021-2022 by the California Institute of Technology. This code
8 | is open-source software released under a 3-clause BSD license. Please see the
9 | file "LICENSE" for more information.
10 | '''
11 |
12 | from enum import Enum, EnumMeta
13 |
14 |
15 | # The following class was based in part on the posting by user "Pierre D" at
16 | # https://stackoverflow.com/a/65225753/743730 made on 2020-12-09.
17 |
18 | class MetaEnum(EnumMeta):
19 | '''Meta class for enums that implements "contain" test ability.'''
20 | def __contains__(cls, item):
21 | try:
22 | cls(item)
23 | except ValueError:
24 | return False
25 | return True
26 |
27 |
28 | # Inheriting from str solves the problem that PyWebIO otherwise complains about
29 | # the type values not being json serializable. This brilliant approach is due
30 | # to a posting by "Justin Carter" @ https://stackoverflow.com/a/51976841/743730
31 |
32 | class ExtendedEnum(str, Enum, metaclass = MetaEnum):
33 | '''Extend Enum class with a function allowing a test for containment.'''
34 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/2.script_mode.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 |
4 | import time
5 | from percy import percySnapshot
6 | from selenium.webdriver import Chrome
7 |
8 | import template
9 | import util
10 | from pywebio.input import *
11 | from pywebio.output import *
12 | from pywebio.utils import run_as_function
13 |
14 |
15 | def target():
16 | template.basic_output()
17 | template.background_output()
18 |
19 | run_as_function(template.basic_input())
20 | actions(buttons=['Continue'])
21 | template.background_input()
22 |
23 |
24 | def test(server_proc: subprocess.Popen, browser: Chrome):
25 | template.test_output(browser)
26 |
27 | time.sleep(1)
28 |
29 | template.test_input(browser)
30 |
31 | # script mode 下,此时 server 应停止
32 | server_proc.wait(timeout=8)
33 |
34 | time.sleep(1)
35 | template.save_output(browser, '2.script_mode.html',
36 | process_func=lambda i: i.replace('::1', '127.0.0.1')) # because tornado default bind ipv4 and ipv6 in script mode
37 |
38 |
39 | if __name__ == '__main__':
40 | # 设置监听端口,并关闭自动打开浏览器
41 | os.environ["PYWEBIO_SCRIPT_MODE_PORT"] = "8080"
42 |
43 | util.run_test(target, test)
44 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/__init__.py:
--------------------------------------------------------------------------------
1 | from . import input
2 | from . import output
3 | from .__version__ import __author__, __author_email__, __license__
4 | from .__version__ import __description__, __url__, __version__
5 | from .exceptions import SessionException, SessionClosedException, SessionNotFoundException
6 | from .platform import start_server
7 | from .platform.bokeh import try_install_bokeh_hook
8 | from .session import *
9 | from .utils import STATIC_PATH
10 |
11 | try_install_bokeh_hook()
12 | del try_install_bokeh_hook
13 |
14 | # Set default logging handler to avoid "No handler found" warnings.
15 | import logging
16 |
17 | logging.getLogger(__name__).addHandler(logging.NullHandler())
18 |
19 |
20 | def enable_debug(level=logging.DEBUG):
21 | """Output PyWebIO logging message to sys.stderr"""
22 | ch = logging.StreamHandler()
23 | ch.setLevel(level)
24 | formatter = logging.Formatter('[%(levelname)s %(asctime)s %(module)s:%(lineno)d %(funcName)s] %(message)s',
25 | datefmt='%y%m%d %H:%M:%S')
26 | ch.setFormatter(formatter)
27 | logger = logging.getLogger(__name__)
28 | logger.handlers = [ch]
29 | logger.setLevel(level)
30 | logger.propagate = False
31 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/1.basic.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from selenium.webdriver import Chrome
5 |
6 | import pywebio
7 | import template
8 | import util
9 | from pywebio import start_server
10 | from pywebio.input import *
11 | from pywebio.output import *
12 | from pywebio.session import set_env
13 | from pywebio.utils import run_as_function
14 |
15 |
16 | def target():
17 | set_env(auto_scroll_bottom=True)
18 | template.set_defer_call()
19 |
20 | template.basic_output()
21 | template.background_output()
22 |
23 | run_as_function(template.basic_input())
24 | actions(buttons=['Continue'])
25 | template.background_input()
26 |
27 |
28 | def test(server_proc: subprocess.Popen, browser: Chrome):
29 | template.test_output(browser, enable_percy=True)
30 |
31 | template.test_input(browser, enable_percy=True)
32 |
33 | time.sleep(1)
34 | template.save_output(browser, '1.basic.html')
35 |
36 | template.test_defer_call()
37 |
38 |
39 | def start_test_server():
40 | pywebio.enable_debug()
41 | start_server(target, port=8080, host='127.0.0.1', auto_open_webbrowser=False, cdn=False)
42 |
43 |
44 | if __name__ == '__main__':
45 | util.run_test(start_test_server, test)
46 |
--------------------------------------------------------------------------------
/dev/installers/windows/create-version.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file create_version.py
3 | # @brief Replace version numbers and create version.py file for Foliage
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # This expects to be in the same directory as version.py.tmpl.
9 | # =============================================================================
10 |
11 | import os
12 | from os.path import abspath, dirname, join
13 | from string import Template
14 |
15 | here = abspath(dirname(__file__))
16 | with open(join(here, '../../../setup.cfg')) as setup_file:
17 | for line in setup_file.readlines():
18 | if line.startswith('version'):
19 | version = line.split('=')[1].strip()
20 | break
21 |
22 | major, minor, patch = version.split('.')
23 |
24 | with open(join(here, 'version.py.tmpl'), 'r') as template_file:
25 | with open(join(here, 'version.py'), 'w') as output_file:
26 | tmpl = Template(template_file.read())
27 | text = tmpl.substitute(major = major, minor = minor, patch = patch)
28 | output_file.write(text)
29 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file requirements.txt
3 | # @brief Python dependencies for Foliage
4 | # @created 2021-10-16
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | appdirs == 1.4.4
10 | boltons == 21.0.0
11 | commonpy == 1.13.0
12 | fastnumbers == 3.1.0
13 | keyring == 23.2.1
14 | openpyxl == 3.0.7
15 | plac == 1.3.4
16 | pyperclip == 1.8.2
17 | PyQt5 == 5.15.9
18 | python-decouple == 3.5
19 | python_dateutil == 2.8.2
20 | rich >= 13.3.5
21 | setuptools
22 | sidetrack >= 2.0.1
23 | tornado == 6.1
24 | python-slugify == 8.0.1
25 | validators == 0.20.0
26 | wand == 0.6.11
27 |
28 | # The following is a fork of PyWebIo with a couple of minor but crucial
29 | # modifications. It cannot be put as a requirement in this file because PyPI
30 | # will not accept a distribution with a dependency in this form. I have to
31 | # install it by hand when I create a python environment to run Foliage.
32 | #pywebio @ git+https://github.com/mhucka/PyWebIO.git@2af53fc
33 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/handlers/base.ts:
--------------------------------------------------------------------------------
1 | import {Command, Session} from "../session";
2 |
3 |
4 | export interface CommandHandler {
5 | accept_command: string[],
6 |
7 | handle_message(msg: Command): void
8 | }
9 |
10 | export class CloseHandler implements CommandHandler {
11 | accept_command: string[] = ['close_session'];
12 |
13 | constructor(readonly session: Session) {
14 | }
15 |
16 | handle_message(msg: Command) {
17 | this.session.close_session();
18 | }
19 | }
20 |
21 | export class CommandDispatcher {
22 | command2handler: { [cmd: string]: CommandHandler } = {};
23 |
24 | constructor(...handlers: CommandHandler[]) {
25 | for (let h of handlers) {
26 | for (let cmd of h.accept_command) {
27 | if (cmd in this.command2handler)
28 | throw new Error(`Conflict command handler: both ${this.command2handler[cmd]} and ${h} accepts '${cmd}' command`);
29 | this.command2handler[cmd] = h;
30 | }
31 | }
32 | }
33 |
34 | dispatch_message(msg: Command): boolean {
35 | if (msg.command in this.command2handler) {
36 | this.command2handler[msg.command].handle_message(msg);
37 | return true;
38 | }
39 | return false
40 | }
41 | }
--------------------------------------------------------------------------------
/foliage/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | __init__.py for foliage
3 |
4 | Copyright
5 | ---------
6 |
7 | Copyright (c) 2021-2022 by the California Institute of Technology. This code
8 | is open-source software released under a 3-clause BSD license. Please see the
9 | file "LICENSE" for more information.
10 | '''
11 |
12 | # Package metadata
13 | # .............................................................................
14 | #
15 | # ╭────────────────────── Notice ── Notice ── Notice ─────────────────────╮
16 | # | The following values are automatically updated at every release |
17 | # | by the Makefile. Manual changes to these values will be lost. |
18 | # ╰────────────────────── Notice ── Notice ── Notice ─────────────────────╯
19 |
20 | __version__ = '1.8.0'
21 | __description__ = 'Foliage: a tool to do bulk changes in FOLIO using the OKAPI API'
22 | __url__ = 'https://github.com/caltechlibrary/foliage'
23 | __author__ = 'Mike Hucka'
24 | __email__ = 'helpdesk@library.caltech.edu'
25 | __license__ = 'BSD 3-clause license'
26 |
27 |
28 | # Miscellaneous utilities.
29 | # .............................................................................
30 |
31 | def print_version():
32 | print(f'{__name__} version {__version__}')
33 | print(f'Authors: {__author__}')
34 | print(f'URL: {__url__}')
35 | print(f'License: {__license__}')
36 |
--------------------------------------------------------------------------------
/dev/splash-screen/create-splash-screen.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file create-splash-screen.py
3 | # @brief Replace version number in splash screen SVG and generate a PNG file
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # This expects to be in the same directory as foliage-splash-screen.svg.tmpl.
9 | # =============================================================================
10 |
11 | import os
12 | from os.path import abspath, dirname, join
13 | from string import Template
14 | from wand.image import Image
15 |
16 | here = abspath(dirname(__file__))
17 | with open(join(here, '../../setup.cfg')) as setup_file:
18 | for line in setup_file.readlines():
19 | if line.startswith('version'):
20 | version = line.split('=')[1].strip()
21 | break
22 |
23 | major, minor, patch = version.split('.')
24 |
25 | with open(join(here, 'foliage-splash-screen.svg.tmpl'), 'r') as template_file:
26 | tmpl = Template(template_file.read())
27 | svg = tmpl.substitute(major = major, minor = minor, patch = patch)
28 | with Image(blob = svg.encode(), format = "svg") as image:
29 | image.format = 'png'
30 | image.save(filename = join(here, 'foliage-splash-screen.png'))
31 |
--------------------------------------------------------------------------------
/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO off
2 | REM ===========================================================================
3 | REM @file make.bat
4 | REM @brief Build a .exe using PyInstaller
5 | REM @author Michael Hucka
6 | REM @license Please see the file named LICENSE in the project directory
7 | REM @website https://github.com/caltechlibrary/holdit
8 | REM
9 | REM Usage:
10 | REM 1. start a terminal shell (e.g., cmd.exe)
11 | REM 2. cd into this directory
12 | REM 3. run "make"
13 | REM ===========================================================================
14 |
15 | ECHO Removing "dist/win" and "build/win" subdirectories.
16 |
17 | IF EXIST dist\win RD /S /Q dist\win
18 | IF EXIST build\win RD /S /Q build\win
19 |
20 | ECHO Making sure all Python packages are the right version
21 |
22 | python -m pip install -r requirements.txt
23 |
24 | ECHO Generating version.py ...
25 |
26 | python dev/installers/windows/create-version.py
27 |
28 | ECHO Generating InnoSetup script.
29 |
30 | python dev/installers/windows/create-innosetup-script.py
31 |
32 | ECHO Generating splash screen file ...
33 |
34 | python dev/splash-screen/create-splash-screen.py
35 |
36 | ECHO Running PyInstaller ...
37 |
38 | python -m PyInstaller --distpath dist/win --clean --noconfirm pyinstaller-win32.spec
39 |
40 | ECHO "make.bat" finished.
41 | ECHO The .exe will be in the "dist" subdirectory.
42 | ECHO Now run Innosetup to create an installer.
43 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/releases/v0.2.0.rst:
--------------------------------------------------------------------------------
1 | What's new in PyWebIO 0.2
2 | ==========================
3 |
4 | 2020 4/30
5 | ----------
6 |
7 | Highlights
8 | ^^^^^^^^^^
9 |
10 | * 支持与Django、aiohttp Web框架整合
11 | * 支持使用 plotly、pyecharts 等第三方库进行数据可视化
12 | * 与Web框架整合时支持同时使用基于线程和协程的会话实现
13 | * 添加 `defer_call() ` 、 `hold() ` 会话控制函数
14 | * 添加 `put_image() ` 输出图像、 `remove(anchor) ` 移除内容
15 | * 加入动画提升UI体验
16 | * 添加测试用例,构建CI工作流
17 |
18 | Detailed changes by module
19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^
20 |
21 | UI
22 | ~~~~~~~~~~~~~~
23 |
24 | * 添加元素显示动画
25 | * 页面底部添加footer
26 |
27 | `pywebio.input`
28 | ~~~~~~~~~~~~~~~~
29 |
30 | * `input_group() ` 添加 ``cancelable`` 参数来允许用户取消输入
31 | * `actions() ` 函数 ``button`` 参数支持 ``reset`` 和 ``cancel`` 按钮类型
32 |
33 | `pywebio.output`
34 | ~~~~~~~~~~~~~~~~
35 |
36 | * 输出函数使用 ``anchor`` 参数指定输出锚点时,若锚点已经存在,则将锚点处的内容替换为当前内容。
37 | * `clear_range() ` 添加添加锚点存在检查
38 | * `scroll_to(anchor, position) ` 添加 ``position`` 参数精细化控制滚动位置
39 |
40 | `pywebio.platform`
41 | ~~~~~~~~~~~~~~~~~~~
42 |
43 | * `start_server` 和 `webio_view` 、 `webio_handle` 添加跨域支持
44 |
45 | `pywebio.session`
46 | ~~~~~~~~~~~~~~~~~~~
47 |
48 | * Session 关闭时,清理更彻底:任何还在进行的PyWebIO调用都会抛出 ``SessionClosedException`` 异常
49 | * fix: Session 对象构造函数无法识别 ``functools.partial`` 处理的任务函数
50 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/handlers/toast.ts:
--------------------------------------------------------------------------------
1 | import {Command} from "../session";
2 | import {CommandHandler} from "./base";
3 | import {state} from "../state";
4 |
5 | export class ToastHandler implements CommandHandler {
6 | accept_command: string[] = ['toast'];
7 |
8 | constructor() {
9 | }
10 |
11 | handle_message(msg: Command) {
12 | let spec = msg.spec;
13 | let toast = Toastify({
14 | text: Mustache.escape(spec.content),
15 | duration: spec.duration === 0 ? -1 : spec.duration, // -1 for permanent toast
16 | close: spec.duration === 0,//To show the close icon or not
17 | gravity: "top", // `top` or `bottom`
18 | position: spec.position, // `left`, `center` or `right`
19 | backgroundColor: spec.color,
20 | stopOnFocus: true, // Prevents dismissing of toast on hover
21 | onClick: function () {
22 | if (!spec.callback_id)
23 | return;
24 |
25 | if (state.CurrentSession === null)
26 | return console.error("Error: WebIOController is not instantiated");
27 | state.CurrentSession.send_message({
28 | event: "callback",
29 | task_id: spec.callback_id,
30 | data: null
31 | });
32 | toast.hideToast();
33 | }
34 | });
35 | toast.showToast();
36 | }
37 | }
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/css/toastify.min.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Minified by jsDelivr using clean-css v4.2.3.
3 | * Original file: /npm/toastify-js@1.9.3/src/toastify.css
4 | *
5 | * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
6 | */
7 | /*!
8 | * Toastify js 1.9.3
9 | * https://github.com/apvarun/toastify-js
10 | * @license MIT licensed
11 | *
12 | * Copyright (C) 2018 Varun A P
13 | */
14 | .toastify{padding:12px 20px;color:#fff;display:inline-block;box-shadow:0 3px 6px -1px rgba(0,0,0,.12),0 10px 36px -4px rgba(77,96,232,.3);background:-webkit-linear-gradient(315deg,#73a5ff,#5477f5);background:linear-gradient(135deg,#73a5ff,#5477f5);position:fixed;opacity:0;transition:all .4s cubic-bezier(.215,.61,.355,1);border-radius:2px;cursor:pointer;text-decoration:none;max-width:calc(50% - 20px);z-index:2147483647}.toastify.on{opacity:1}.toast-close{opacity:.4;padding:0 5px}.toastify-right{right:15px}.toastify-left{left:15px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{width:1.5em;height:1.5em;margin:-7px 5px;border-radius:2px}.toastify-center{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content;max-width:-moz-fit-content}@media only screen and (max-width:360px){.toastify-left,.toastify-right{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content}}
15 | /*# sourceMappingURL=/sm/40f738e33ed5dbe7907b48c3be4b63e977eab6cb49c8df4f76f3edc3f1f2fb0d.map */
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/misc.rst:
--------------------------------------------------------------------------------
1 | 其他
2 | ============
3 |
4 | .. _codemirror_options:
5 |
6 | 常用的Codemirror选项
7 | --------------------
8 |
9 | * ``mode`` (str): 代码语言。支持的语言有:https://codemirror.net/mode/index.html
10 | * ``theme`` (str): 编辑器主题。可使用的主题:https://codemirror.net/demo/theme.html
11 | * ``lineNumbers`` (bool): 是否显示行号
12 | * ``indentUnit`` (int): 缩进使用的空格数
13 | * ``tabSize`` (int): 制表符宽度
14 | * ``lineWrapping`` (bool): 是否换行以显示长行
15 |
16 | 完整的Codemirror选项请见 https://codemirror.net/doc/manual.html#config
17 |
18 | .. _nginx_ws_config:
19 |
20 | Nginx WebSocket配置示例
21 | -----------------------
22 |
23 | 假设后端服务器运行在 ``localhost:5000`` 地址,并将PyWebIO的后端接口绑定到 ``/tool`` 路径上,则通过Nginx访问PyWebIO服务的配置如下::
24 |
25 | map $http_upgrade $connection_upgrade {
26 | default upgrade;
27 | '' close;
28 | }
29 |
30 | server {
31 | listen 80;
32 |
33 | location / {
34 | alias /path/to/pywebio/static/dir/;
35 | }
36 | location /tool {
37 | proxy_read_timeout 300s;
38 | proxy_send_timeout 300s;
39 | proxy_http_version 1.1;
40 | proxy_set_header Upgrade $http_upgrade;
41 | proxy_set_header Connection $connection_upgrade;
42 | proxy_pass http://localhost:5000;
43 | }
44 | }
45 |
46 | 以上配置文件将PyWebIO的静态文件托管到 ``/`` 目录下, 并将 ``/tool`` 反向代理到 ``localhost:5000``
47 |
48 | PyWebIO的静态文件的路径可使用命令 ``python3 -c "import pywebio; print(pywebio.STATIC_PATH)"`` 获得,你也可以将静态文件复制到其他目录下::
49 |
50 | cp -r `python3 -c "import pywebio; print(pywebio.STATIC_PATH)"` ~/web
51 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 | on: [push, pull_request]
3 | jobs:
4 | test:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Checkout
8 | uses: actions/checkout@master
9 | - name: Set up Python 3.7
10 | uses: actions/setup-python@v1
11 | with:
12 | python-version: 3.7
13 | - name: Set up Node.js v13.5
14 | uses: actions/setup-node@v1
15 | with:
16 | node-version: 13.5
17 | - name: Build frontend
18 | working-directory: ./webiojs
19 | run: |
20 | npm install
21 | gulp
22 | cp dist/pywebio.min.* ../pywebio/html/js
23 | - name: Install Test JS deps
24 | run: npm install -D @percy/agent
25 | - name: Install package
26 | run: pip3 install ".[all]"
27 | - name: Install dev dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | - name: Install env
32 | run: echo "PERCY_TOKEN=${{ secrets.PERCY_TOKEN }}" >> $GITHUB_ENV
33 | - name: Percy Test
34 | uses: percy/exec-action@v0.3.1
35 | with:
36 | working-directory: ./test
37 | command: "./run_all.sh"
38 | - name: Upload test output
39 | uses: actions/upload-artifact@v1
40 | if: failure()
41 | with:
42 | name: test output
43 | path: test/output
44 | - name: Upload Codecov Report
45 | working-directory: ./test
46 | run: bash <(curl -s https://codecov.io/bash)
47 |
--------------------------------------------------------------------------------
/tests/test_credentials.py:
--------------------------------------------------------------------------------
1 | def test_encoding():
2 | from foliage.credentials import _encoded, _decoded
3 | assert _decoded(_encoded('a', '1', 'c')) == ('a', '1', 'c')
4 |
5 |
6 | def test_current_credentials(monkeypatch):
7 | from foliage.credentials import Credentials, current_credentials
8 | monkeypatch.setenv('FOLIO_OKAPI_URL', 'https://foo')
9 | monkeypatch.setenv('FOLIO_OKAPI_TENANT_ID', '1')
10 | monkeypatch.setenv('FOLIO_OKAPI_TOKEN', 'abc')
11 | assert current_credentials() == Credentials('https://foo', '1', 'abc')
12 |
13 |
14 | def test_credentials_complete():
15 | from foliage.credentials import Credentials, credentials_complete
16 | assert credentials_complete(Credentials('https://foo', '1', 'abc'))
17 |
18 |
19 | def test_credentials_from_file(monkeypatch, tmp_path):
20 | from foliage.credentials import Credentials, credentials_from_file
21 | d = tmp_path / 'sub'
22 | d.mkdir()
23 | p = d / 'settings.ini'
24 | p.write_text('''
25 | [settings]
26 | FOLIO_OKAPI_URL = https://foo
27 | FOLIO_OKAPI_TENANT_ID = 1
28 | FOLIO_OKAPI_TOKEN = abc
29 | ''')
30 | monkeypatch.chdir(d)
31 | assert credentials_from_file(str(p)) == Credentials('https://foo', '1', 'abc')
32 |
33 |
34 | def test_credentials_from_env(monkeypatch):
35 | from foliage.credentials import Credentials, credentials_from_env
36 | monkeypatch.setenv('FOLIO_OKAPI_URL', 'https://foo')
37 | monkeypatch.setenv('FOLIO_OKAPI_TENANT_ID', '1')
38 | monkeypatch.setenv('FOLIO_OKAPI_TOKEN', 'abc')
39 | assert credentials_from_env() == Credentials('https://foo', '1', 'abc')
40 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021-2023, Caltech.
2 | All rights not granted herein are expressly reserved by Caltech.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | 1. Redistributions of source code must retain the above copyright notice,
8 | this list of conditions and the following disclaimer.
9 |
10 | 2. Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | 3. Neither the name of the copyright holder nor the names of its contributors
15 | may be used to endorse or promote products derived from this software without
16 | specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 | POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/releases/v1.1.0.rst:
--------------------------------------------------------------------------------
1 | What's new in PyWebIO 1.1
2 | ==========================
3 |
4 | 2021 2/7
5 | ----------
6 |
7 | 距离写下PyWebIO的第一行代码过去已经整整一年了🎂 ,2020年发生了太多的事情,但对我来说又多了一份特殊的意义。新的一年继续努力💪 ,将PyWebIO做得越来越好。
8 |
9 | Highlights
10 | ^^^^^^^^^^^
11 | * 添加安全性支持: `put_html() `, `put_markdown() ` 中支持使用 ``sanitize`` 参数开启防 XSS 攻击
12 | * UI国际化支持
13 | * 添加SEO支持: 通过任务函数的注释或 `pywebio.platform.seo()` 来设置SEO信息
14 | * CDN支持,Web框架整合更加方便,仅需引入一条路由即可
15 | * 应用访问速度提升,不再使用探测请求的方式确定通信协议
16 |
17 | Backwards-incompatible changes
18 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19 | * 移除使用 django 和 flask 框架 `start_server()` 中的 `disable_asyncio` 参数
20 | * 废弃 `pywebio.session.data()` ,使用 `pywebio.session.local` 作为会话本地状态存储对象
21 | * 整合到Web框架的应用,访问地址发生变化,参见 :ref:`Web框架整合文档 `
22 | * `put_scrollable() ` 废弃 `max_height` 参数,使用 `height` 替代
23 |
24 | Detailed changes
25 | ^^^^^^^^^^^^^^^^^
26 | * `put_code() ` 支持使用 `rows` 参数限制最大显示行数
27 | * `put_scrollable() ` 支持使用 `keep_bottom` 参数设定自动滚动到底部
28 | * `put_markdown() ` 支持配置Markdown解析参数
29 | * 为 `put_code() `, `put_image() `, `put_link() `, `put_row() `, `put_grid() ` 中的参数添加转义
30 | * `output() ` 的 ``reset()``, ``append()``, ``insert()`` 方法接受字符串作为输出内容
31 | * 修复: `file_upload() ` 的 `max_size` and `max_total_size` 参数解析错误
32 | * 修复: py3.6自动打开浏览器失败
33 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Foliage user documentation
2 |
3 | This directory contains the **user** documentation for Foliage. The **developer** documentation is in a separate directory, [`../dev/dev-docs`](../dev/dev-docs). The rest of this page describes how to (re)create the formatted Foliage user documentation.
4 |
5 | ## Building the docs locally
6 |
7 | First, install [MyST](https://myst-parser.readthedocs.io/en/latest/index.html) and [Sphinx](https://www.sphinx-doc.org):
8 |
9 | ```sh
10 | python3 -m pip install "myst-parser[linkify]"
11 | python3 -m pip install sphinx-material
12 | python3 -m pip install sphinx-autobuild
13 | ```
14 |
15 | After that, rebuilding the docs should be simply a matter of running `make html` in the current directory:
16 |
17 | ```sh
18 | make html
19 | ```
20 |
21 | The output will be put in [`_build/html`](_build/html). Instead of running `make` deliberately, you can also get auto-rebuilds and live preview using `sphinx-autobuild` by running the following command in the current directory (preferably in a new terminal window, because it will generate continuous output):
22 |
23 | ```sh
24 | make auto
25 | ```
26 |
27 |
28 | ## Writing documentation
29 |
30 | This documentation is written in [MyST-flavored Markdown](https://myst-parser.readthedocs.io/en/latest/) and the [Napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html) extension to Sphinx. What this means is that the documentation is written in Markdown (not reStructuredText), with essentially all the features of Sphinx and reStructuredText having MyST equivalents and some additional features – things like [pandoc](https://pandoc.org)-style footnotes, LaTeX math, and more.
31 |
--------------------------------------------------------------------------------
/dev/one-page-docs/read-me-first-macos/read-me-first.md:
--------------------------------------------------------------------------------
1 | # Important macOS info about Foliage
2 |
3 | There are two issues on macOS that may cause confusion the first time you try to use Foliage: a macOS security error, and slow startup times.
4 |
5 | ## macOS security error
6 |
7 | After you download the Foliage disk image and open it, if you first try to run the application by double-clicking the icon in the Finder, you will get a macOS error dialog:
8 |
9 |
10 |
11 |
12 |
13 | To get around the warning, instead of double-clicking the Foliage app, **control-click on the Foliage icon in the Finder to get the following pop-up menu**:
14 |
15 |
16 |
17 |
18 |
19 | Next, select "Open" from the menu. MacOS will show a similar warning as before, but this time, the warning dialog will have an additional button named "Open":
20 |
21 |
22 |
23 |
24 |
25 | **Click the "Open" button**, and now it will start Foliage.
26 |
27 | After you do these steps, macOS will **not** ask you again, and you will be able to double-click the icon to start it as usual.
28 |
29 |
30 | ## Slow startup time
31 |
32 | You may experience very long startup times on macOS. This is currently a known issue. During the startup, there will unfortunately be no feedback – it will look like nothing is happening. Please be patient and give it a significant time, as much as half a minute depending on your hardware. It should eventually start up.
33 |
34 |
--------------------------------------------------------------------------------
/dev/splash-screen/README.md:
--------------------------------------------------------------------------------
1 | # Splash screen creator for Foliage
2 |
3 | A limitation of PyInstaller's splash screen feature is that it can only show an image. For Foliage, I wanted to show a version number in the splash screen so that the user knows which version they're getting, but doing so meant finding a way to generate a new splash screen image every time a new version of Foliage was produced.
4 |
5 |
6 |
7 |
8 |
9 | I automated this process using code in this subdirectory. The artwork is in SVG format. Since an SVG file is written in plain text, it's possible to put placeholders in the SVG file itself and then substitute the values when needed. The scheme for Foliage works like this:
10 |
11 | 1. The file `foliage-splash-screen.svg.tmpl` contains placeholders.
12 | 2. The small program [`create-splash-screen.py`](create-splash-screen.py) is run by the top level `make.bat` file before PyInstaller is run, and performs two steps:
13 | 1. substitute values for the placeholders and produce a new file, `foliage-splash-screen.svg`
14 | 2. convert `foliage-splash-screen.svg` to a PNG file (`foliage-splash-screen.png`) written in the same directory
15 | 3. The PyInstaller [specification file](../../pyinstaller-win32.spec) points to the `.png` file in the splash screen configuration, so that PyInstaller reads an image with an up-to-date version number.
16 |
17 | The splash screen image for a given Foliage release is static. The small program is run at application build time, not at run-time. The image is embedded in the self-contained Foliage application created by PyInstaller.
18 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/codemirror/base16-light.min.css:
--------------------------------------------------------------------------------
1 | .cm-s-base16-light.CodeMirror{background:#f5f5f5;color:#202020}.cm-s-base16-light div.CodeMirror-selected{background:#e0e0e0}.cm-s-base16-light .CodeMirror-line::selection,.cm-s-base16-light .CodeMirror-line>span::selection,.cm-s-base16-light .CodeMirror-line>span>span::selection{background:#e0e0e0}.cm-s-base16-light .CodeMirror-line::-moz-selection,.cm-s-base16-light .CodeMirror-line>span::-moz-selection,.cm-s-base16-light .CodeMirror-line>span>span::-moz-selection{background:#e0e0e0}.cm-s-base16-light .CodeMirror-gutters{background:#f5f5f5;border-right:0}.cm-s-base16-light .CodeMirror-guttermarker{color:#ac4142}.cm-s-base16-light .CodeMirror-guttermarker-subtle{color:#b0b0b0}.cm-s-base16-light .CodeMirror-linenumber{color:#b0b0b0}.cm-s-base16-light .CodeMirror-cursor{border-left:1px solid #505050}.cm-s-base16-light span.cm-comment{color:#8f5536}.cm-s-base16-light span.cm-atom{color:#aa759f}.cm-s-base16-light span.cm-number{color:#aa759f}.cm-s-base16-light span.cm-attribute,.cm-s-base16-light span.cm-property{color:#90a959}.cm-s-base16-light span.cm-keyword{color:#ac4142}.cm-s-base16-light span.cm-string{color:#f4bf75}.cm-s-base16-light span.cm-variable{color:#90a959}.cm-s-base16-light span.cm-variable-2{color:#6a9fb5}.cm-s-base16-light span.cm-def{color:#d28445}.cm-s-base16-light span.cm-bracket{color:#202020}.cm-s-base16-light span.cm-tag{color:#ac4142}.cm-s-base16-light span.cm-link{color:#aa759f}.cm-s-base16-light span.cm-error{background:#ac4142;color:#505050}.cm-s-base16-light .CodeMirror-activeline-background{background:#dddcdc}.cm-s-base16-light .CodeMirror-matchingbracket{color:#f5f5f5!important;background-color:#6a9fb5!important}
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file setup.cfg
3 | # @brief Package metadata and PyPI configuration
4 | # @created 2021-10-16
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | [metadata]
10 | name = foliage
11 | version = 1.8.0
12 | description = Foliage: a tool to do bulk changes in FOLIO using the OKAPI API
13 | author = Mike Hucka
14 | author_email = helpdesk@library.caltech.edu
15 | license = BSD 3-clause license
16 | license_files = LICENSE
17 | url = https://github.com/caltechlibrary/foliage
18 | # The remaining items below are used by PyPI.
19 | project_urls =
20 | Source Code = https://github.com/caltechlibrary/foliage
21 | Bug Tracker = https://github.com/caltechlibrary/foliage/issues
22 | keywords = Python, applications
23 | classifiers =
24 | Development Status :: 5 - Production/Stable
25 | Environment :: Console
26 | License :: OSI Approved :: BSD License
27 | Intended Audience :: Science/Research
28 | Operating System :: MacOS :: MacOS X
29 | Operating System :: POSIX
30 | Operating System :: POSIX :: Linux
31 | Operating System :: Unix
32 | Programming Language :: Python
33 | Programming Language :: Python :: 3.9
34 | long_description = file:README.md
35 | long_description_content_type = text/markdown
36 |
37 | [options]
38 | packages = find:
39 | zip_safe = False
40 | python_requires = >= 3.9
41 |
42 | [options.entry_points]
43 | console_scripts =
44 | foliage = foliage.__main__:console_scripts_main
45 |
46 | [tool:pytest]
47 | pythonpath = .
48 |
49 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | # =========================================================== -*- conf-toml -*-
2 | # @file .flake8
3 | # @brief Project-wide Flake8 configuration
4 | # @created 2022-05-10
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # Note: as of version 4.0, flake8 does NOT read global configuration files
9 | # from ~/.flake8 or ~/.config/flake8. If you had such a config file of your
10 | # own, and you're looking at this config file and wondering how the two will
11 | # interaction, the answer is simple: they won't. Only this file matters.
12 | #
13 | # The following flake8 plugins are assumed to be installed:
14 | # flake8-bugbear
15 | # flake8-builtins
16 | # flake8-comprehensions
17 | # flake8-executable
18 | # flake8-implicit-str-concat
19 | # flake8-pie
20 | # flake8_simplify
21 | # =============================================================================
22 |
23 | [flake8]
24 | # I try to stick to 80 chars, but sometimes it's more readable to go longer.
25 | max-line-length = 120
26 |
27 | ignore =
28 | # We prefer to put spaces around the = in keyword arg lists.
29 | E251,
30 | # We prefer two lines between methods of a class.
31 | E303,
32 | # Sometimes we want to align keywords, and these rules run counter to it.
33 | E271,
34 | E221,
35 | # In some situations, it's more readable to omit spaces around operators
36 | # and colons.
37 | E203,
38 | E226,
39 | # According to Flake8 docs at https://www.flake8rules.com/rules/W503.html
40 | # line breaks *should* come before a binary operator, but as of version 4,
41 | # Flake8 still flags the breaks as bad. So:
42 | W503
43 | # I disagree wit this one.
44 | B005
45 |
--------------------------------------------------------------------------------
/dev/installers/windows/version.py.tmpl:
--------------------------------------------------------------------------------
1 | # ======================================================== -*- mode: python -*-
2 | # @file version.py.tmpl
3 | # @brief Version file template for Windows application
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # See https://stackoverflow.com/a/14626175/743730 for more info about this
9 | # file format.
10 | # =============================================================================
11 |
12 | VSVersionInfo(
13 | ffi=FixedFileInfo(
14 | filevers=($major, $minor, $patch, 0),
15 | prodvers=($major, $minor, $patch, 0),
16 | mask=0x3f,
17 | flags=0x0,
18 | OS=0x40004,
19 | fileType=0x1,
20 | subtype=0x0,
21 | date=(0, 0)
22 | ),
23 | kids=[
24 | StringFileInfo(
25 | [
26 | StringTable(
27 | u'040904B0',
28 | [StringStruct(u'CompanyName', u'California Institute of Technology Library'),
29 | StringStruct(u'FileDescription', u'Foliage'),
30 | StringStruct(u'FileVersion', u'$major.$minor.$patch'),
31 | StringStruct(u'ProductVersion', u'$major.$minor.$patch'),
32 | StringStruct(u'InternalName', u'Foliage'),
33 | StringStruct(u'LegalCopyright', u'\xa9 Caltech. All rights reserved.'),
34 | StringStruct(u'OriginalFilename', u'Foliage.Exe'),
35 | StringStruct(u'ProductName', u'Foliage')])
36 | ]),
37 | VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
38 | ]
39 | )
40 |
--------------------------------------------------------------------------------
/docs/colophon.md:
--------------------------------------------------------------------------------
1 | # Colophon
2 |
3 | The Foliage documentation has been written by [Michael Hucka](https://www.cds.caltech.edu/~mhucka/) using the [Sphinx](https://www.sphinx-doc.org) document generator together with [MyST-flavored Markdown](https://myst-parser.readthedocs.io/en/latest/). The theme is the [Material theme for Sphinx](https://bashtage.github.io/sphinx-material/), with light customizations such as the use of Google's [Atkinson Hyperlegible](https://fonts.google.com/specimen/Atkinson+Hyperlegible) font. A [GitHub Action](https://github.com/caltechlibrary/foliage/blob/main/.github/workflows/build-sphinx.yml) takes care of creating the formatted version of the documentation and hosting it on GitHub.io at https://caltechlibrary.github.io/foliage. The formatted output can also be produced manually using commands implemented in the `Makefile` located in the [`docs/`](https://github.com/caltechlibrary/foliage/tree/main/docs) subdirectory of the Foliage source code repository.
4 |
5 | The [vector artwork](https://thenounproject.com/term/branch/1047074/) used as a starting point for the logo and icon for Foliage was created by [Alice Noir](https://thenounproject.com/AliceNoir/) for the [Noun Project](https://thenounproject.com). The artwork is licensed under the Creative Commons [Attribution 3.0 Unported](https://creativecommons.org/licenses/by/3.0/deed.en) license. The vector graphics was modified by Michael Hucka to change the color.
6 |
7 | Unless indicated otherwise, all other artwork in this documentation was created using [OmniGraffle Pro](https://www.omnigroup.com/omnigraffle) on a macOS computer. SVG versions of the diagrams were produced with the help of [svg-buddy](https://github.com/phauer/svg-buddy) to embed fonts into the SVG files and overcome a limitation of OmniGraffle's SVG output.
8 |
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/README.md:
--------------------------------------------------------------------------------
1 | # Systray widget for macOS
2 |
3 | This directory contains a widget for putting an icon in the macOS system tray (the row of icons in the upper right of the screen on macOS, in the system menubar). The widget has only one function: offer a _Quit_ menu option. It is started when Foliage first starts up, and while Foliage runs, the widget will stay in the system tray. Its purpose is to make it possible for the user to quit Foliage if they have lost track of Foliage's web page.
4 |
5 | The widget is written in [go](https://go.dev) rather than Python so that it is possible to create a self-contained executable that can be bundled inside the Foliage application created using PyInstaller. It is not possible to use a Python script for this purpose because PyInstaller [does not bundle a Python interpreter](https://github.com/pyinstaller/pyinstaller/wiki/FAQ) in the application it creates, and we can't assume that the user's environment has a Python interpreter (or where it might be installed). Give this constraint, I searched for a solution that would allow a self-contained binary to be bundled inside the application we create using PyInstaller, so that Foliage could run this application as a subprocess. Go is well suited to this purpose because the binaries it creates are statically-linked.
6 |
7 | This widget code is based on the example widget with [systray](https://github.com/getlantern/systray), a cross-platform Go library to create system tray widgets. I simply copied the example's [main.go](https://github.com/getlantern/systray/blob/master/example/main.go) file and the icon code, and adapted them to create what's in this directory.
8 |
9 | The [systray](https://github.com/getlantern/systray) code by [Lantern](https://github.com/getlantern) is licensed under the Apache 2.0 open-source license.
10 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # =============================================================================
3 | # @file setup.py
4 | # @brief Installation setup file
5 | # @created 2021-10-16
6 | # @license Please see the file named LICENSE in the project directory
7 | # @website https://github.com/caltechlibrary/foliage
8 | #
9 | # Note: configuration metadata is maintained in setup.cfg. This file exists
10 | # primarily to hook in setup.cfg and requirements.txt.
11 | # =============================================================================
12 |
13 | from setuptools import setup
14 |
15 |
16 | def requirements(file):
17 | from os import path
18 | required = []
19 | requirements_file = path.join(path.abspath(path.dirname(__file__)), file)
20 | if path.exists(requirements_file):
21 | with open(requirements_file, encoding='utf-8') as f:
22 | required = [ln for ln in filter(str.strip, f.read().splitlines())
23 | if not ln.startswith('#')]
24 | if any(item.startswith(('-', '.', '/')) for item in required):
25 | # The requirements.txt uses pip features. Try to use pip's parser.
26 | try:
27 | from pip._internal.req import parse_requirements
28 | from pip._internal.network.session import PipSession
29 | parsed = parse_requirements(requirements_file, PipSession())
30 | required = [item.requirement for item in parsed]
31 | except ImportError:
32 | # No pip, or not the expected version. Give up & return as-is.
33 | pass
34 | return required
35 |
36 |
37 | setup(
38 | setup_requires = ['wheel'],
39 | install_requires = requirements('requirements.txt'),
40 | extras_require={'dev': requirements('requirements-dev.txt')},
41 | )
42 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.github/workflows/sync_repo.yml:
--------------------------------------------------------------------------------
1 | name: Sync with mirror repo
2 | on:
3 | push:
4 | branches:
5 | - dev
6 | jobs:
7 | sync:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout
11 | uses: actions/checkout@master
12 | - name: Set up Python 3.7
13 | uses: actions/setup-python@v1
14 | with:
15 | python-version: 3.7
16 | - name: Set up Node.js v13.5
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: 13.5
20 | - name: Build frontend
21 | working-directory: ./webiojs
22 | run: |
23 | npm install
24 | DEV=1 gulp
25 | cp dist/pywebio.min.* ../pywebio/html/js
26 | - name: Build doc demos
27 | run: |
28 | pip3 install -e ".[all]"
29 | cd docs && CODE_EXPORT_PATH=../demos/doc_demos make clean text
30 | - name: Set dev version
31 | run: python3 tools/build_dev_version.py
32 | - name: Push
33 | run: |
34 | git fetch --unshallow origin
35 | git remote add aliyun "https://code.aliyun.com/wang0618/pywebio.git"
36 | git config credential.helper '!f() { sleep 1; echo "username=${ALIYUN_GIT_USER}"; echo "password=${ALIYUN_GIT_PASSWORD}"; }; f'
37 | rm .gitignore
38 | git add pywebio/__version__.py
39 | git add pywebio/html/js
40 | git add demos/doc_demos
41 | git config user.email "${ALIYUN_GIT_USER}"
42 | git config user.name "${ALIYUN_GIT_USER}"
43 | git commit --amend --no-edit
44 | git push -f -u aliyun --tags || exit 0
45 | git push -f -u aliyun || exit 0
46 | env:
47 | ALIYUN_GIT_USER: ${{ secrets.ALIYUN_GIT_USER }}
48 | ALIYUN_GIT_PASSWORD: ${{ secrets.ALIYUN_GIT_PASSWORD }}
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/demos/bmi.py:
--------------------------------------------------------------------------------
1 | """
2 | BMI指数计算
3 | ^^^^^^^^^^^
4 |
5 | 计算 `BMI指数 `_ 的简单应用
6 |
7 | :demo_host:`Demo地址 ?pywebio_api=bmi>` `源码 `_
8 | """
9 | from pywebio import start_server
10 | from pywebio.input import *
11 | from pywebio.output import *
12 | from pywebio.session import set_env
13 |
14 |
15 | def main():
16 | """BMI Calculation
17 |
18 | 计算BMI指数的简单应用
19 | """
20 |
21 | put_markdown("""# BMI指数
22 |
23 | [`BMI指数`](https://baike.baidu.com/item/%E4%BD%93%E8%B4%A8%E6%8C%87%E6%95%B0/1455733)(Body Mass Index,BMI),是用体重千克数除以身高米数的平方得出的数字,是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。
24 |
25 | 成年人的BMI值处于以下阶段
26 |
27 | | 体形分类 | BMI值范围 |
28 | | -------- | --------- |
29 | | 极瘦 | BMI<14.9 |
30 | | 偏瘦 | 14.9≤BMI<18.4 |
31 | | 正常 | 18.4≤BMI<22.9 |
32 | | 过重 | 22.9≤BMI<27.5 |
33 | | 肥胖 | 27.5≤BMI<40 |
34 | | 非常肥胖 | BMI≥40 |
35 |
36 | ## BMI指数计算器
37 | 本程序的源代码[链接](https://github.com/wang0618/PyWebIO/blob/dev/demos/bmi.py)
38 |
39 | """, strip_indent=4)
40 |
41 | info = input_group('计算BMI:', [
42 | input("请输入你的身高(cm)", name="height", type=FLOAT),
43 | input("请输入你的体重(kg)", name="weight", type=FLOAT),
44 | ])
45 |
46 | BMI = info['weight'] / (info['height'] / 100) ** 2
47 |
48 | top_status = [(14.9, '极瘦'), (18.4, '偏瘦'),
49 | (22.9, '正常'), (27.5, '过重'),
50 | (40.0, '肥胖'), (float('inf'), '非常肥胖')]
51 |
52 | for top, status in top_status:
53 | if BMI <= top:
54 | put_markdown('你的 BMI 值: `%.1f`,身体状态:`%s`' % (BMI, status))
55 | break
56 |
57 |
58 | if __name__ == '__main__':
59 | start_server(main, debug=True, port=8080, cdn=False)
60 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/demos/set_env_demo.py:
--------------------------------------------------------------------------------
1 | """
2 | `pywebio.session.set_env()` demo
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 | """
5 | from pywebio import start_server
6 | from pywebio.input import *
7 | from pywebio.output import *
8 | from pywebio.session import *
9 | import datetime
10 | import asyncio
11 |
12 |
13 | async def main():
14 | """`pywebio.session.set_env()` demo"""
15 |
16 | set_scope('time')
17 | put_markdown('> 可用于观察 `output_animation` 项的动画效果')
18 | put_markdown('---')
19 |
20 | async def bg_task():
21 | while 1:
22 | with use_scope('time', clear=True):
23 | put_text('当前时间:', datetime.datetime.now())
24 |
25 | await asyncio.sleep(1)
26 |
27 | run_async(bg_task())
28 |
29 | put_buttons(['输出文本'], [lambda: put_text(datetime.datetime.now())])
30 | put_markdown('> 可用于观察 `auto_scroll_bottom` 项的自动滚动效果')
31 | put_markdown('---')
32 | put_text('Some text.\n' * 10)
33 |
34 | state = {
35 | 'title': 'PyWebIO set_env() Demo',
36 | 'output_animation': True,
37 | 'auto_scroll_bottom': False,
38 | }
39 | set_env(**state)
40 |
41 | while 1:
42 | curr_state_info = ', '.join('%s=%r' % (k, v) for k, v in state.items())
43 | key = await actions('选择要更改的会话环境设置项', list(state.keys()), help_text='当前状态:' + curr_state_info)
44 | if key == 'title':
45 | state['title'] = await input('请输入标题', value=state['title'])
46 | set_env(title=state['title'])
47 | toast('已将标题设置为%r' % state['title'])
48 | elif key in state:
49 | state[key] = not (state[key])
50 | set_env(**{key: state[key]})
51 | toast('已将`%s`设置为%r' % (key, state[key]))
52 |
53 |
54 | if __name__ == '__main__':
55 | start_server(main, debug=True, port=8080, cdn=False)
56 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/demos/bokeh_app.py:
--------------------------------------------------------------------------------
1 | from bokeh.io import output_notebook
2 | from bokeh.io import show
3 | from bokeh.layouts import column
4 | from bokeh.models import ColumnDataSource, Slider
5 | from bokeh.plotting import figure
6 | from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
7 |
8 | from pywebio import start_server
9 | from pywebio.output import *
10 |
11 |
12 | def bkapp(doc):
13 | df = sea_surface_temperature.copy()
14 | source = ColumnDataSource(data=df)
15 |
16 | plot = figure(x_axis_type='datetime', y_range=(0, 25),
17 | y_axis_label='Temperature (Celsius)',
18 | title="Sea Surface Temperature at 43.18, -70.43")
19 | plot.line('time', 'temperature', source=source)
20 |
21 | def callback(attr, old, new):
22 | if new == 0:
23 | data = df
24 | else:
25 | data = df.rolling('{0}D'.format(new)).mean()
26 | source.data = ColumnDataSource.from_df(data)
27 |
28 | slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
29 | slider.on_change('value', callback)
30 |
31 | doc.add_root(column([slider, plot], sizing_mode='stretch_width'))
32 |
33 |
34 | def main():
35 | output_notebook(verbose=False, notebook_type='pywebio')
36 |
37 | put_markdown("""# Bokeh Applications in PyWebIO
38 |
39 | [Bokeh Applications](https://docs.bokeh.org/en/latest/docs/user_guide/server.html) 支持向图表的添加按钮、输入框等交互组件,并向组件添加Python回调,从而创建可以与Python代码交互的可视化图表。
40 |
41 | 在PyWebIO中,你也可以使用 `bokeh.io.show()` 来显示一个Bokeh App,和输出普通图表一样,只需要在会话开始时调用 `bokeh.io.output_notebook(notebook_type='pywebio')` 来设置PyWebIO输出环境。
42 |
43 | 以下为一个 Bokeh App demo:
44 |
45 | """, lstrip=True)
46 |
47 | show(bkapp)
48 |
49 |
50 | if __name__ == '__main__':
51 | start_server(main, port=8080, debug=True, cdn=False)
52 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file Makefile
3 | # @brief Makefile for building docs using Sphinx and MyST
4 | # @created 2021-01-25
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | # =============================================================================
8 |
9 | # Before we go any further, test if certain programs are available.
10 | # The following is based on the approach posted by Jonathan Ben-Avraham to
11 | # Stack Overflow in 2014 at https://stackoverflow.com/a/25668869
12 |
13 | PROGRAMS_NEEDED = sphinx-build
14 | TEST := $(foreach p,$(PROGRAMS_NEEDED),\
15 | $(if $(shell which $(p)),_,$(error Cannot find program "$(p)")))
16 |
17 |
18 | # Gather values that we need ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 |
20 | # You can set the following variables from the command line, and also from
21 | # the environment for the first two.
22 |
23 | SPHINXOPTS ?=
24 | SPHINXBUILD ?= sphinx-build
25 | SPHINXAUTO = sphinx-autobuild
26 | SOURCEDIR = .
27 | BUILDDIR = _build
28 |
29 | # Actions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 |
31 | # Put it first so that "make" without argument is like "make help".
32 | help:
33 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
34 |
35 | auto autobuild live livehtml:
36 | @$(SPHINXAUTO) "$(SOURCEDIR)" "$(BUILDDIR)"/html $(SPHINXOPTS) $(O)
37 |
38 | # Catch-all target: route all unknown targets to Sphinx using the new
39 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
40 | %: Makefile
41 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
42 |
43 |
44 | # Cleanup and miscellaneous directives ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45 |
46 | .PHONY: help auto autobuild livehtml Makefile
47 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | create:
5 | tags:
6 | - v*
7 |
8 | jobs:
9 | release:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@master
14 | - name: Set up Python 3
15 | uses: actions/setup-python@v1
16 | with:
17 | python-version: 3.7
18 | - name: Set up Node.js v13.5
19 | uses: actions/setup-node@v1
20 | with:
21 | node-version: 13.5
22 | - name: Build frontend
23 | working-directory: ./webiojs
24 | run: |
25 | npm install
26 | gulp
27 | cp dist/pywebio.min.js ../pywebio/html/js
28 | - name: PyPi Upload
29 | run: |
30 | pip3 install twine
31 | python3 setup.py sdist
32 | twine upload --username "__token__" --disable-progress-bar --verbose dist/*
33 | env:
34 | TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
35 | - name: Set tag
36 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
37 | - name: Push asset
38 | run: |
39 | git config --global user.email "wang0.618@qq.com"
40 | git config --global user.name "${{ github.actor }}"
41 | git config --global credential.helper '!f() { sleep 1; echo "username=${{ github.actor }}"; echo "password=${GH_TOKEN}"; }; f'
42 |
43 | git clone https://github.com/wang0618/pywebio-assets.git
44 | rm -rf pywebio-assets/*
45 | cp -r pywebio/html/* pywebio-assets
46 |
47 | cd pywebio-assets
48 | git add .
49 | git commit -m "Build from https://github.com/wang0618/PyWebIO/commit/$GITHUB_SHA"
50 | git tag $RELEASE_VERSION
51 |
52 | git push -u origin --tags
53 | git push -u origin
54 | env:
55 | GH_TOKEN: ${{ secrets.ASSET_REPO_TOKEN }}
56 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/10.aiohttp_multiple_session_impliment.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | import time
4 | from aiohttp import web
5 | from selenium.webdriver import Chrome
6 |
7 | import pywebio
8 | import template
9 | import util
10 | from pywebio import STATIC_PATH
11 | from pywebio.input import *
12 | from pywebio.platform.aiohttp import static_routes, webio_handler
13 | from pywebio.utils import to_coroutine, run_as_function
14 |
15 |
16 | def target():
17 | template.basic_output()
18 | template.background_output()
19 |
20 | run_as_function(template.basic_input())
21 | actions(buttons=['Continue'])
22 | template.background_input()
23 |
24 |
25 | async def async_target():
26 | template.basic_output()
27 | await template.coro_background_output()
28 |
29 | await to_coroutine(template.basic_input())
30 | await actions(buttons=['Continue'])
31 | await template.coro_background_input()
32 |
33 |
34 | def test(server_proc: subprocess.Popen, browser: Chrome):
35 | template.test_output(browser)
36 | time.sleep(1)
37 | template.test_input(browser)
38 | time.sleep(1)
39 | template.save_output(browser, '10.aiohttp_multiple_session_impliment_p1.html')
40 |
41 | browser.get('http://localhost:8080/io2?_pywebio_debug=1')
42 | template.test_output(browser)
43 | time.sleep(1)
44 | template.test_input(browser)
45 |
46 | time.sleep(1)
47 | template.save_output(browser, '10.aiohttp_multiple_session_impliment_p2.html')
48 |
49 |
50 | def start_test_server():
51 | pywebio.enable_debug()
52 |
53 | app = web.Application()
54 | app.add_routes([web.get('/io', webio_handler(target, cdn=False))])
55 | app.add_routes([web.get('/io2', webio_handler(async_target, cdn=False))])
56 | app.add_routes(static_routes())
57 |
58 | web.run_app(app, host='127.0.0.1', port=8080)
59 |
60 |
61 | if __name__ == '__main__':
62 | util.run_test(start_test_server, test, 'http://localhost:8080/io?_pywebio_debug=1')
63 |
--------------------------------------------------------------------------------
/dev/dev-docs/making-a-new-release.md:
--------------------------------------------------------------------------------
1 | # Making a new release of Foliage
2 |
3 | Here is the overall sequence of steps I use to create a new release of Foliage.
4 |
5 | In the current workflow, certain steps must be performed on a non-Windows system. (I only use Windows to generate the Windows binaries, not to develop software or do other work.) The steps here assume that you have a shared file system between your Mac or Linux system, and the Windows system.
6 |
7 | ## 1. First generate a working macOS binary
8 |
9 | This step will update some in the Foliage source directory, and those changes are assumed to be visible in your Windows computing environment via a shared file system. (If you don't have a shared file system established between the computers, you will need to copy files to a Windows system, and that's much more error prone and time-consuming that using a shared file system.)
10 |
11 | 1. Cd to the top level of the Foliage source directory
12 | 2. Open `setup.py` in a text editor, update the version number inside, and commit the change to git
13 | 3. Run `make update-init`
14 | 4. Run `make really-clean`
15 | 5. Run `make binary`
16 | 6. Test the binary that gets built:
17 | 1. Run it from the command line by starting `dist/macos/foliage`
18 | 2. Run it by double-clicking `dist/macos/Foliage.app` in the macOS Finder
19 |
20 |
21 | ## 2. Next, generate a working Windows binary
22 |
23 | Start up a Window environment, then in a terminal emulator:
24 |
25 | 1. Cd to the top level of the Foliage source directory
26 | 2. Run `make`
27 | 3. Test the binary that gets built:
28 | 1. Run it from the command line by starting `dist/win/Foliage.exe`
29 | 2. Run it by double-clicking `dist/win/Foliage.exe` in the Windows File Explorer.
30 |
31 |
32 | ## 3. If all seems to work, only then make a release
33 |
34 | 1. Run `make release`
35 | 2. Run `make print-instructions`
36 | 3. Run `make update-doi`
37 | 4. Run `make packages`
38 | 5. Run `make test-pypi`
39 | 6. Check the test release at
40 |
41 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/releases/v1.0.0.rst:
--------------------------------------------------------------------------------
1 | What's new in PyWebIO 1.0
2 | ==========================
3 |
4 | 2021 1/17
5 | ----------
6 |
7 | 经过快一年的开发,PyWebIO 1.0 终于完成了。与上一版本 v0.3 相比有非常多的变化:
8 |
9 | Highlights
10 | ^^^^^^^^^^^
11 | * ``start_server`` 对多任务函数的支持,PyWebIO应用可以包含多个任务函数,并提供了 `go_app() ` 用于任务函数之间的跳转
12 | * 不再使用基于锚点的输出控制模型,改用基于Scope的模型
13 | * 添加布局支持( `put_grid() ` , `put_row() ` , `put_column() ` )和自定义样式支持( `style() ` )
14 | * 添加新的输出函数: `toast() ` , `popup() ` , `put_widget() ` ,
15 | `put_collapse() ` , `put_link() ` , `put_scrollable() ` ,
16 | `put_loading() ` , `put_processbar() `
17 | * 添加 `span() ` , `output() ` 输出控制函数
18 | * 添加JS执行函数: `run_js() ` , `eval_js() `
19 | * 更新UI: 显示输入时,使用浮动式输入框;发生未捕获异常时,前端使用console日志记录异常
20 |
21 | Backwards-incompatible changes
22 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23 | * 不再使用基于锚点的输出控制模型
24 | * 不支持固定高度的输出区,移除 `pywebio.output.set_output_fixed_height()`
25 | * 移除 `pywebio.output.set_title()` , `pywebio.output.set_auto_scroll_bottom()`,改用 `pywebio.session.set_env()` 进行控制
26 | * 移除 `pywebio.output.table_cell_buttons()` ,使用 `pywebio.output.put_buttons()` 替代
27 |
28 | Detailed changes by module
29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
30 | * `input() ` 支持 ``action`` 参数动态设置输入项的值
31 | * `file_upload() ` 支持多文件上传,支持限制上传文件大小,添加上传进度显示
32 | * `put_buttons() ` 支持指定按钮颜色
33 | * `put_widget() ` 、 `popup() ` 、 `put_table() ` 将字符串内容不再视作Html,而是作为纯文本
34 | * `put_text() ` 支持输出多个对象
35 | * `put_image() ` 支持使用Url指定图片
36 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/7.multiple_session_impliment.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | from selenium.webdriver import Chrome
4 |
5 | import pywebio
6 | import template
7 | import util, time
8 | from pywebio.input import *
9 | from pywebio.output import *
10 | from pywebio.utils import to_coroutine, run_as_function
11 |
12 |
13 | def target():
14 | template.basic_output()
15 | template.background_output()
16 |
17 | run_as_function(template.basic_input())
18 | actions(buttons=['Continue'])
19 | template.background_input()
20 |
21 |
22 | async def async_target():
23 | template.basic_output()
24 | await template.coro_background_output()
25 |
26 | await to_coroutine(template.basic_input())
27 | await actions(buttons=['Continue'])
28 | await template.coro_background_input()
29 |
30 |
31 | def test(server_proc: subprocess.Popen, browser: Chrome):
32 | template.test_output(browser)
33 | time.sleep(1)
34 | template.test_input(browser)
35 | time.sleep(1)
36 | template.save_output(browser, '7.multiple_session_impliment_p1.html')
37 |
38 | browser.get('http://localhost:8080/io2?_pywebio_debug=1')
39 | template.test_output(browser)
40 | time.sleep(1)
41 | template.test_input(browser)
42 |
43 | time.sleep(1)
44 | template.save_output(browser, '7.multiple_session_impliment_p2.html')
45 |
46 |
47 | def start_test_server():
48 | pywebio.enable_debug()
49 |
50 | import tornado.ioloop
51 | import tornado.web
52 | from pywebio.platform.tornado import webio_handler
53 | from pywebio import STATIC_PATH
54 |
55 | application = tornado.web.Application([
56 | (r"/", webio_handler(async_target, cdn=False)),
57 | (r"/io2", webio_handler(target, cdn=False)),
58 | (r"/(.*)", tornado.web.StaticFileHandler,
59 | {"path": STATIC_PATH, 'default_filename': 'index.html'})
60 | ])
61 | application.listen(port=8080, address='127.0.0.1')
62 | tornado.ioloop.IOLoop.current().start()
63 |
64 |
65 | if __name__ == '__main__':
66 | util.run_test(start_test_server, test)
67 |
--------------------------------------------------------------------------------
/.github/workflows/iga.yml:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # GitHub Action workflow for using the InvenioRDM GitHub Archiver (IGA).
3 | # A copy of this file is available from https://github.com/caltechlibrary/iga/.
4 | # At the time this file was copied, IGA was at version 0.0.12.
5 | # =============================================================================
6 |
7 | env:
8 | INVENIO_SERVER: https://data.caltech.edu
9 |
10 | draft: false
11 | all_assets: false
12 | all_metadata: false
13 | community: none
14 | parent_record: none
15 | debug: false
16 |
17 | on:
18 | release:
19 | types: [published]
20 | workflow_dispatch:
21 | inputs:
22 | release_tag:
23 | description: "The tag of the release to archive:"
24 | draft:
25 | default: false
26 | description: "Mark the record as a draft:"
27 | all_assets:
28 | default: false
29 | description: "Attach all GitHub assets:"
30 | all_metadata:
31 | default: false
32 | description: "Include additional GitHub metadata:"
33 | community:
34 | description: "Send record to InvenioRDM community:"
35 | parent_record:
36 | description: "ID of parent record (for versioning):"
37 | jobs:
38 | Send_to_InvenioRDM:
39 | runs-on: ubuntu-latest
40 | steps:
41 | - uses: caltechlibrary/iga@main
42 | with:
43 | INVENIO_SERVER: ${{env.INVENIO_SERVER}}
44 | INVENIO_TOKEN: ${{secrets.INVENIO_TOKEN}}
45 | all_assets: ${{github.event.inputs.all_assets || env.all_assets}}
46 | all_metadata: ${{github.event.inputs.all_metadata || env.all_metadata}}
47 | debug: ${{github.event.inputs.debug || 'false'}}
48 | draft: ${{github.event.inputs.draft || env.draft}}
49 | community: ${{github.event.inputs.community || env.community}}
50 | parent_record: ${{github.event.inputs.parent_record || env.parent_record}}
51 | release_tag: ${{github.event.inputs.release_tag || 'latest'}}
52 |
53 | name: InvenioRDM GitHub Archiver
54 |
--------------------------------------------------------------------------------
/.github/workflows/build-sphinx.yml:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file build-myst.yml
3 | # @brief GitHub Actions workflow to build FOLIAGE docs using MyST
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # This workflow file was originally based on work by GitHub user "peaceiris":
9 | # https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-static-site-generators-with-python
10 | # =============================================================================
11 |
12 | name: Build & publish Sphinx docs
13 |
14 | on:
15 | push:
16 | branches:
17 | - main
18 | pull_request:
19 |
20 | jobs:
21 | Workflow:
22 | runs-on: ubuntu-22.04
23 | permissions:
24 | contents: write
25 | concurrency:
26 | group: ${{ github.workflow }}-${{ github.ref }}
27 | steps:
28 | - uses: actions/checkout@v3
29 |
30 | - name: Set up Python
31 | uses: actions/setup-python@v4
32 | with:
33 | python-version: '3.8'
34 |
35 | - name: Upgrade pip
36 | run: |
37 | # Need pip=>20.1 to use "pip cache dir".
38 | python3 -m pip install --upgrade pip
39 |
40 | - name: Get pip cache dir
41 | id: pip-cache
42 | run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
43 |
44 | - name: Cache dependencies
45 | uses: actions/cache@v3
46 | with:
47 | path: ${{ steps.pip-cache.outputs.dir }}
48 | key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }}
49 | restore-keys: |
50 | ${{ runner.os }}-pip-
51 |
52 | - name: Install dependencies
53 | run: python3 -m pip install -r ./requirements-dev.txt
54 |
55 | - name: Generate HTML files
56 | run: |
57 | cd docs
58 | make html
59 |
60 | - name: Publish HTML files on GitHub pages
61 | uses: peaceiris/actions-gh-pages@v3
62 | if: ${{ github.ref == 'refs/heads/main' }}
63 | with:
64 | github_token: ${{ secrets.GITHUB_TOKEN }}
65 | publish_dir: ./docs/_build/html
66 |
--------------------------------------------------------------------------------
/dev/one-page-docs/pandoc-template/template.html5:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | $for(author-meta)$
8 |
9 | $endfor$
10 | $if(date-meta)$
11 |
12 | $endif$
13 | $if(keywords)$
14 |
15 | $endif$
16 | $if(description-meta)$
17 |
18 | $endif$
19 | $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$
20 | $for(css)$
21 |
22 | $endfor$
23 | $if(math)$
24 | $math$
25 | $endif$
26 | $for(header-includes)$
27 | $header-includes$
28 | $endfor$
29 |
30 |
31 | $for(include-before)$
32 | $include-before$
33 | $endfor$
34 |
35 | $if(toc)$
36 |
44 | $endif$
45 |
46 |
47 | $body$
48 |
49 |
50 | $if(return-url)$
51 |
56 | $endif$
57 |
69 | $for(include-after)$
70 | $include-after$
71 | $endfor$
72 |
73 |
74 |
--------------------------------------------------------------------------------
/docs/glossary.md:
--------------------------------------------------------------------------------
1 | # Glossary
2 |
3 | A glossary of common terms used in Foliage and FOLIO.
4 |
5 | ```{glossary}
6 | API
7 | "Application programm interface." An API is a well-defined interface
8 | through which interactions between software can take place. It is an
9 | approach for software systems to communicate with each other. In the
10 | context of FOLIO and Foliage, the APIs used are network-based:
11 | Foliage makes calls to network APIs provided by FOLIO.
12 |
13 | CQL
14 | "[Contextual Query Language](http://zing.z3950.org/cql/intro.html)."
15 | A syntax for writing information queries. Here is an example of what
16 | a CQL expression looks like:
17 | `(username=="ab*" or personal.firstName=="ab*" or personal.lastName=="ab*")`
18 |
19 | CSV
20 | "Comma-separated values." A spreadsheet format stored as text, in which
21 | values of different columns are separated by commas.
22 |
23 | Foliage
24 | **FOLI**O ch**a**n**g**e **e**ditor.
25 |
26 | FOLIO
27 | "The Future Of Libraries Is Open." FOLIO is an open-source library services
28 | platform that integrates print and electronic resource management.
29 |
30 | HRID
31 | "Human readable identifier" (_not_ a holdings identifier!). Many
32 | of the record types in FOLIO have an `hrid` field.
33 |
34 |
35 | JSON
36 | "JavaScript Object Notation." An open-standard format for storing
37 | data. The format uses a textual notation that is more or less
38 | human readable. It can be used to store lists, texts, numbers,
39 | attribute-value pairs, and more.
40 |
41 | LSP
42 | "Library services platform." The kind of system that FOLIO is.
43 |
44 | Microservices
45 | A type of software system architecture in which a single server provides
46 | a service to multiple tenants.
47 |
48 | OKAPI
49 | "Okay API." The FOLIO API system. (Technically, the FOLIO middleware and
50 | API gateway.)
51 |
52 | SRS
53 | FOLIO's "Source Record Storage." The server-side storage system
54 | underlying FOLIO's database facilities.
55 |
56 | UUID
57 | "Universally unique identifier." A label used for information in computer
58 | systems. In FOLIO, UUIDs are the values of the `id` fields in records. An
59 | example UUID is `e9559bdb-868e-4f8b-bebc-6b482b0d91ea`.
60 |
61 | ```
62 |
--------------------------------------------------------------------------------
/dev/misc/t.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import json
4 | import sys
5 | import csv
6 | from commonpy.network_utils import net
7 | from decouple import config
8 |
9 | if len(sys.argv[1:]) < 1:
10 | sys.exit('Missing argument: file containing list of users')
11 |
12 | user_ids = []
13 | try:
14 | with open(sys.argv[1], 'r') as csv_file:
15 | user_ids = [row['id'] for row in csv.DictReader(csv_file)]
16 | except Exception as ex:
17 | sys.exit(ex)
18 |
19 | print(f'Read {len(user_ids)} users from file {sys.argv[1]}')
20 |
21 |
22 | base_url = config('FOLIO_OKAPI_URL', default = None)
23 |
24 | headers = {
25 | "x-okapi-token": config('FOLIO_OKAPI_TOKEN', default = None),
26 | "x-okapi-tenant": config('FOLIO_OKAPI_TENANT_ID', default = None),
27 | "content-type": "application/json",
28 | }
29 |
30 | loans = dict()
31 | items = dict()
32 | users = dict()
33 |
34 | for index, user_id in enumerate(user_ids):
35 | url = f'{base_url}/users?query=id={user_id}'
36 | (result, error) = net('get', url, headers = headers)
37 | if error:
38 | sys.exit('Got error: ' + str(error))
39 | users[user_id] = json.loads(result.text)['users'][0]
40 |
41 | url = f'{base_url}/loan-storage/loans?query=userId={user_id}'
42 | (result, error) = net('get', url, headers = headers)
43 | if error:
44 | sys.exit('Got error: ' + str(error))
45 | loans[user_id] = json.loads(result.text)['loans']
46 |
47 | for loan in loans[user_id]:
48 | item_id = loan['itemId']
49 | url = f'{base_url}/inventory/items?query=id={item_id}'
50 | (result, error) = net('get', url, headers = headers)
51 | if error:
52 | sys.exit('Got error: ' + str(error))
53 | items[item_id] = json.loads(result.text)['items'][0]
54 | print(str(index).zfill(3), flush = True)
55 | if index > 1:
56 | break
57 |
58 |
59 | for user_id in users:
60 | r = users[user_id]
61 | cituid = r['barcode'].lstrip('0')
62 | print('\nuser ' + cituid + ' (' + r['personal']['lastName'] + '):')
63 | if user_id in loans:
64 | for loan in loans[user_id]:
65 | item = items[loan['itemId']]
66 | title = item['title']
67 | if len(title) > 60:
68 | title = title[0:60] + ' ...'
69 | print(' ' + item['barcode'] + ' ' + title)
70 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/js/bs-custom-file-input.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * bsCustomFileInput v1.3.4 (https://github.com/Johann-S/bs-custom-file-input)
3 | * Copyright 2018 - 2020 Johann-S
4 | * Licensed under MIT (https://github.com/Johann-S/bs-custom-file-input/blob/master/LICENSE)
5 | */
6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).bsCustomFileInput=t()}(this,function(){"use strict";var s={CUSTOMFILE:'.custom-file input[type="file"]',CUSTOMFILELABEL:".custom-file-label",FORM:"form",INPUT:"input"},l=function(e){if(0 "7 dogs are in the kitchen"
33 | // eg: strfmt("I like %1, bananas and %1", "apples"); => "I like apples, bananas and apples"
34 | function strfmt(fmt: string) {
35 | let args = arguments;
36 |
37 | return fmt
38 | // put space after double % to prevent placeholder replacement of such matches
39 | .replace(/%%/g, '%% ')
40 | // replace placeholders
41 | .replace(/%(\d+)/g, function (str, p1) {
42 | return args[p1];
43 | })
44 | // replace double % and space with single %
45 | .replace(/%% /g, '%')
46 | }
47 |
48 | export function t(msgid: string, ...args:string[]): string {
49 | let fmt = null;
50 | for (let lang of [userLangCode, userLang, 'en']) {
51 | if (translations[lang] && translations[lang][msgid]){
52 | fmt = translations[lang][msgid];
53 | break;
54 | }
55 | }
56 | if (fmt === null)
57 | throw Error(`No translation for "${msgid}" in "${userLangCode}"`);
58 |
59 | return strfmt.apply(null, [fmt, ...args]);
60 | }
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/8.flask_multiple_session_impliment.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 |
3 | from selenium.webdriver import Chrome
4 |
5 | import pywebio
6 | import template
7 | import time
8 | import util
9 | from pywebio.input import *
10 | from pywebio.output import *
11 | from pywebio.utils import to_coroutine, run_as_function
12 |
13 |
14 | def target():
15 | template.basic_output()
16 | template.background_output()
17 |
18 | run_as_function(template.basic_input())
19 | actions(buttons=['Continue'])
20 | template.background_input()
21 |
22 |
23 | async def async_target():
24 | template.basic_output()
25 | await template.coro_background_output()
26 |
27 | await to_coroutine(template.basic_input())
28 | await actions(buttons=['Continue'])
29 | await template.coro_background_input()
30 |
31 |
32 | def test(server_proc: subprocess.Popen, browser: Chrome):
33 | template.test_output(browser)
34 | time.sleep(1)
35 | template.test_input(browser)
36 | time.sleep(1)
37 | template.save_output(browser, '8.flask_multiple_session_impliment_p1.html')
38 |
39 | browser.get('http://localhost:8080/io2?_pywebio_debug=1&_pywebio_http_pull_interval=400')
40 | template.test_output(browser)
41 | time.sleep(1)
42 | template.test_input(browser)
43 |
44 | time.sleep(1)
45 | template.save_output(browser, '8.flask_multiple_session_impliment_p2.html')
46 |
47 |
48 | def start_test_server():
49 | pywebio.enable_debug()
50 | from flask import Flask, send_from_directory
51 | from pywebio.platform.flask import webio_view, run_event_loop
52 | from pywebio import STATIC_PATH
53 | import threading
54 | import logging
55 |
56 | app = Flask(__name__)
57 | app.add_url_rule('/io', 'webio_view', webio_view(target, cdn=False), methods=['GET', 'POST', 'OPTIONS'])
58 | app.add_url_rule('/io2', 'webio_view_async_target', webio_view(async_target, cdn=False), methods=['GET', 'POST', 'OPTIONS'])
59 |
60 | @app.route('/')
61 | @app.route('/')
62 | def serve_static_file(static_file='index.html'):
63 | return send_from_directory(STATIC_PATH, static_file)
64 |
65 | threading.Thread(target=run_event_loop, daemon=True).start()
66 |
67 | logging.getLogger('werkzeug').setLevel(logging.WARNING)
68 |
69 | app.run(port=8080, host='127.0.0.1')
70 |
71 |
72 | if __name__ == '__main__':
73 | util.run_test(start_test_server, test, address='http://localhost:8080/io?_pywebio_debug=1&_pywebio_http_pull_interval=400')
74 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/codemirror/loadmode.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"), "cjs");
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); });
9 | else // Plain browser env
10 | mod(CodeMirror, "plain");
11 | })(function(CodeMirror, env) {
12 | if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js";
13 |
14 | var loading = {};
15 | function splitCallback(cont, n) {
16 | var countDown = n;
17 | return function() { if (--countDown == 0) cont(); };
18 | }
19 | function ensureDeps(mode, cont) {
20 | var deps = CodeMirror.modes[mode].dependencies;
21 | if (!deps) return cont();
22 | var missing = [];
23 | for (var i = 0; i < deps.length; ++i) {
24 | if (!CodeMirror.modes.hasOwnProperty(deps[i]))
25 | missing.push(deps[i]);
26 | }
27 | if (!missing.length) return cont();
28 | var split = splitCallback(cont, missing.length);
29 | for (var i = 0; i < missing.length; ++i)
30 | CodeMirror.requireMode(missing[i], split);
31 | }
32 |
33 | CodeMirror.requireMode = function(mode, cont) {
34 | if (typeof mode != "string") mode = mode.name;
35 | if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont);
36 | if (loading.hasOwnProperty(mode)) return loading[mode].push(cont);
37 |
38 | var file = CodeMirror.modeURL.replace(/%N/g, mode);
39 | if (env == "plain") {
40 | var script = document.createElement("script");
41 | script.src = file;
42 | var others = document.getElementsByTagName("script")[0];
43 | var list = loading[mode] = [cont];
44 | CodeMirror.on(script, "load", function() {
45 | ensureDeps(mode, function() {
46 | for (var i = 0; i < list.length; ++i) list[i]();
47 | });
48 | });
49 | others.parentNode.insertBefore(script, others);
50 | } else if (env == "cjs") {
51 | require(file);
52 | cont();
53 | } else if (env == "amd") {
54 | requirejs([file], cont);
55 | }
56 | };
57 |
58 | CodeMirror.autoLoadMode = function(instance, mode) {
59 | if (!CodeMirror.modes.hasOwnProperty(mode))
60 | CodeMirror.requireMode(mode, function() {
61 | instance.setOption("mode", instance.getOption("mode"));
62 | });
63 | };
64 | });
65 |
--------------------------------------------------------------------------------
/foliage/data/macos-systray-widget/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4=
3 | github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
4 | github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So=
5 | github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
6 | github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk=
7 | github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc=
8 | github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0=
9 | github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
10 | github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc=
11 | github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
12 | github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA=
13 | github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
14 | github.com/getlantern/systray v1.1.0 h1:U0wCEqseLi2ok1fE6b88gJklzriavPJixZysZPkZd/Y=
15 | github.com/getlantern/systray v1.1.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
16 | github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
17 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
18 | github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
19 | github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
20 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
21 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
22 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
23 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
24 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
25 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/js/FileSaver.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(b,c,d){var e=new XMLHttpRequest;e.open("GET",b),e.responseType="blob",e.onload=function(){a(e.response,c,d)},e.onerror=function(){console.error("could not download file")},e.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(a,b,d,e){if(e=e||open("","_blank"),e&&(e.document.title=e.document.body.innerText="downloading..."),"string"==typeof a)return c(a,b,d);var g="application/octet-stream"===a.type,h=/constructor/i.test(f.HTMLElement)||f.safari,i=/CriOS\/[\d]+/.test(navigator.userAgent);if((i||g&&h)&&"undefined"!=typeof FileReader){var j=new FileReader;j.onloadend=function(){var a=j.result;a=i?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),e?e.location.href=a:location=a,e=null},j.readAsDataURL(a)}else{var k=f.URL||f.webkitURL,l=k.createObjectURL(a);e?e.location=l:location.href=l,e=null,setTimeout(function(){k.revokeObjectURL(l)},4E4)}});f.saveAs=a.saveAs=a,"undefined"!=typeof module&&(module.exports=a)});
2 |
3 | //# sourceMappingURL=FileSaver.min.js.map
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # =========================================================== -*- gitignore -*-
2 | # @file .gitignore
3 | # @brief Files and patterns for files and subdirs that git should ignore
4 | # @date 2022-07-14
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # The approach we suggest is to add ONLY project-specific rules here. Put
9 | # rules that apply to your way of doing things (and the particular tools you
10 | # happen to use) into a global git ignore file as described in the section
11 | # "Configuring ignored files for all repositories on your computer" here:
12 | # https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
13 | # (accessed on 2022-07-14). For example, Emacs checkpoint and backup files are
14 | # things that are not specific to a given project; rather, Emacs users will
15 | # see them created everywhere, in all projects, because they're a byproduct
16 | # of using Emacs, not a consequence of working on a particular project. Thus,
17 | # they belong in a user's global ignores list, not in this project .gitignore.
18 | #
19 | # A useful starting point for global .gitignore file contents can be found at
20 | # https://github.com/github/gitignore/tree/main/Global (as of 2022-07-14).
21 | # =============================================================================
22 |
23 | # Ignore backup files created by our Makefile
24 | # .............................................................................
25 |
26 | *.bak
27 |
28 | # InnoSetup-specific things to ignore:
29 | # .............................................................................
30 |
31 | *.~is
32 |
33 | # Python-specific things to ignore (relevant because this is a Python project).
34 | # .............................................................................
35 |
36 | __pycache__/
37 | *.py[cod]
38 | *$py.class
39 | *.egg-info/
40 | .eggs/
41 | .pytest_cache
42 | .coverage
43 |
44 | # Project-specific things to ignore:
45 | # .............................................................................
46 |
47 | dev/experiments/settings.ini
48 | build
49 | dist
50 | dev/windows/version.py
51 | dev/splash-screen/foliage-splash-screen.png
52 | docs/_build
53 | foliage/data/macos-systray-widget/macos-systray-widget
54 | ABOUT.md
55 | ABOUT.html
56 | dev/installers/windows/version.py
57 | dev/installers/windows/foliage_innosetup_script.iss
58 | dev/installers/macos/READ THIS PLEASE.html
59 | tests/settings.ini
60 | *.tmp
61 | dev/one-page-docs/read-me-first-macos/read-me-first.html
62 | dev/one-page-docs/read-me-first-windows/read-me-first.html
63 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/docs/libraries_support.rst:
--------------------------------------------------------------------------------
1 | 第三方库生态
2 | ==============
3 |
4 | .. _visualization:
5 |
6 | 数据可视化
7 | -------------
8 | PyWebIO支持使用第三方库进行数据可视化
9 |
10 | Bokeh
11 | ^^^^^^^^^^^^^^^^^^^^^^
12 | `Bokeh `_ 是一个支持创建实时交互的数据可视化库。
13 |
14 | 在 PyWebIO 会话中调用 ``bokeh.io.output_notebook(notebook_type='pywebio')`` 来设置Bokeh输出到PyWebIO::
15 |
16 | from bokeh.io import output_notebook
17 | from bokeh.io import show
18 |
19 | output_notebook(notebook_type='pywebio')
20 | fig = figure(...)
21 | ...
22 | show(fig)
23 |
24 | 相应demo见 :charts_demo_host:`bokeh demo ?app=bokeh>`
25 |
26 | 除了创建普通图表,Bokeh还可以通过启动Bokeh server来显示Bokeh app,Bokeh app支持向图表的添加按钮、输入框等交互组件,并向组件注册Python回调,从而创建可以与Python代码交互的图表。
27 |
28 | 在PyWebIO中,你也可以使用 ``bokeh.io.show()`` 来显示一个Bokeh App,代码示例见 `bokeh_app.py `_。
29 |
30 | .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/bokeh.png
31 |
32 | pyecharts
33 | ^^^^^^^^^^^^^^^^^^^^^^
34 | `pyecharts `_ 是一个使用Python创建 `Echarts `_ 可视化图表的库。
35 |
36 | 在 PyWebIO 中使用 `put_html() ` 可以输出 pyecharts 库创建的图表::
37 |
38 | # chart 为 pyecharts 的图表实例
39 | pywebio.output.put_html(chart.render_notebook())
40 |
41 | 相应demo见 :charts_demo_host:`pyecharts demo ?app=pyecharts>`
42 |
43 | .. only:: not latex
44 |
45 | .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/pyecharts.gif
46 |
47 | plotly
48 | ^^^^^^^^^^^^^^^^^^^^^^
49 | `plotly.py `_ 是一个非常流行的Python数据可视化库,可以生成高质量的交互式图表。
50 |
51 | PyWebIO 支持输出使用 plotly 库创建的图表。使用方式为在PyWebIO会话中调用::
52 |
53 | # fig 为 plotly 的图表实例
54 | html = fig.to_html(include_plotlyjs="require", full_html=False)
55 | pywebio.output.put_html(html)
56 |
57 | 相应demo见 :charts_demo_host:`plotly demo ?app=plotly>`
58 |
59 | .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/plotly.png
60 |
61 | cutecharts.py
62 | ^^^^^^^^^^^^^^^^^^^^^^
63 |
64 | `cutecharts.py `_ 是一个可以创建具有卡通风格的可视化图表的python库。
65 | 底层使用了 `chart.xkcd `_ Javascript库。
66 |
67 | 在 PyWebIO 中使用 `put_html() ` 可以输出 cutecharts.py 库创建的图表::
68 |
69 | # chart 为 cutecharts 的图表实例
70 | pywebio.output.put_html(chart.render_notebook())
71 |
72 | 相应demo见 :charts_demo_host:`cutecharts demo ?app=cutecharts>`
73 |
74 | .. image:: https://cdn.jsdelivr.net/gh/wang0618/pywebio-chart-gallery@master/assets/cutecharts.png
75 |
--------------------------------------------------------------------------------
/tests/test_folio.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 |
4 | @pytest.fixture
5 | def define_env_vars(monkeypatch):
6 | from os import path
7 | monkeypatch.chdir(path.dirname(__file__))
8 |
9 | from decouple import Config, RepositoryIni
10 | source = Config(RepositoryIni(source = 'settings.ini'))
11 | url = source.get('FOLIO_OKAPI_URL')
12 | tenant = source.get('FOLIO_OKAPI_TENANT_ID')
13 | token = source.get('FOLIO_OKAPI_TOKEN')
14 |
15 | monkeypatch.setenv('FOLIO_OKAPI_URL', url)
16 | monkeypatch.setenv('FOLIO_OKAPI_TENANT_ID', tenant)
17 | monkeypatch.setenv('FOLIO_OKAPI_TOKEN', token)
18 |
19 |
20 | def test_record_id_type(define_env_vars):
21 | from foliage.folio import Folio, IdKind
22 | folio = Folio()
23 | assert folio.id_kind('35047019219716') == IdKind.ITEM_BARCODE
24 | assert folio.id_kind('d893839b-0309-4856-b496-0db89a0a6a04') == IdKind.ITEM_ID
25 | assert folio.id_kind('it00002135242') == IdKind.ITEM_HRID
26 | assert folio.id_kind('946cce1b-0451-460e-816f-51436182efaa') == IdKind.HOLDINGS_ID
27 | assert folio.id_kind(r'\35047018212589') == IdKind.ITEM_BARCODE
28 | assert folio.id_kind(r'\35047019565233') == IdKind.ITEM_BARCODE
29 | assert folio.id_kind('nobarcode1') == IdKind.ITEM_BARCODE
30 | assert folio.id_kind('nobarcode10') == IdKind.ITEM_BARCODE
31 | assert folio.id_kind('nobarcode10000') == IdKind.ITEM_BARCODE
32 | assert folio.id_kind('nobarcode10001') == IdKind.ITEM_BARCODE
33 | assert folio.id_kind('nobarcode10002') == IdKind.ITEM_BARCODE
34 | assert folio.id_kind('350470106306') == IdKind.ITEM_BARCODE
35 | assert folio.id_kind('350470106969') == IdKind.ITEM_BARCODE
36 | assert folio.id_kind('93') == IdKind.ITEM_BARCODE
37 | assert folio.id_kind('95') == IdKind.ITEM_BARCODE
38 | assert folio.id_kind('101') == IdKind.ITEM_BARCODE
39 | assert folio.id_kind('TEMP-D1234') == IdKind.ITEM_BARCODE
40 | assert folio.id_kind('TEMP-FFF123') == IdKind.ITEM_BARCODE
41 | assert folio.id_kind('tmp-21924070') == IdKind.ITEM_BARCODE
42 | assert folio.id_kind('cit.oai.caltech.folio.ebsco.com.fs00001057.17c5c348.8796.4b11.90a8.6b31ff9509ed') == IdKind.ACCESSION
43 | assert folio.id_kind('cit.oai.edge.caltech.folio.ebsco.com.fs00001057.17c5c348.8796.4b11.90a8.6b31ff9509ed') == IdKind.ACCESSION
44 |
45 |
46 | def test_extracting_instance_id():
47 | from foliage.folio import instance_id_from_accession
48 | instance_id_from_accession('cit.oai.caltech.folio.ebsco.com.fs00001057.17c5c348.8796.4b11.90a8.6b31ff9509ed') == '17c5c348-8796-4b11-90a8-6b31ff9509ed'
49 | instance_id_from_accession('cit.oai.edge.caltech.folio.ebsco.com.fs00001057.17c5c348.8796.4b11.90a8.6b31ff9509ed') == '17c5c348-8796-4b11-90a8-6b31ff9509ed'
50 |
--------------------------------------------------------------------------------
/.graphics/caltech-round.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/pywebio/html/codemirror/active-line.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: https://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | "use strict";
13 | var WRAP_CLASS = "CodeMirror-activeline";
14 | var BACK_CLASS = "CodeMirror-activeline-background";
15 | var GUTT_CLASS = "CodeMirror-activeline-gutter";
16 |
17 | CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
18 | var prev = old == CodeMirror.Init ? false : old;
19 | if (val == prev) return
20 | if (prev) {
21 | cm.off("beforeSelectionChange", selectionChange);
22 | clearActiveLines(cm);
23 | delete cm.state.activeLines;
24 | }
25 | if (val) {
26 | cm.state.activeLines = [];
27 | updateActiveLines(cm, cm.listSelections());
28 | cm.on("beforeSelectionChange", selectionChange);
29 | }
30 | });
31 |
32 | function clearActiveLines(cm) {
33 | for (var i = 0; i < cm.state.activeLines.length; i++) {
34 | cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
35 | cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
36 | cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS);
37 | }
38 | }
39 |
40 | function sameArray(a, b) {
41 | if (a.length != b.length) return false;
42 | for (var i = 0; i < a.length; i++)
43 | if (a[i] != b[i]) return false;
44 | return true;
45 | }
46 |
47 | function updateActiveLines(cm, ranges) {
48 | var active = [];
49 | for (var i = 0; i < ranges.length; i++) {
50 | var range = ranges[i];
51 | var option = cm.getOption("styleActiveLine");
52 | if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty())
53 | continue
54 | var line = cm.getLineHandleVisualStart(range.head.line);
55 | if (active[active.length - 1] != line) active.push(line);
56 | }
57 | if (sameArray(cm.state.activeLines, active)) return;
58 | cm.operation(function() {
59 | clearActiveLines(cm);
60 | for (var i = 0; i < active.length; i++) {
61 | cm.addLineClass(active[i], "wrap", WRAP_CLASS);
62 | cm.addLineClass(active[i], "background", BACK_CLASS);
63 | cm.addLineClass(active[i], "gutter", GUTT_CLASS);
64 | }
65 | cm.state.activeLines = active;
66 | });
67 | }
68 |
69 | function selectionChange(cm, sel) {
70 | updateActiveLines(cm, sel.ranges);
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/models/input/select.ts:
--------------------------------------------------------------------------------
1 | import {InputItem} from "./base";
2 | import {Session} from "../../session";
3 | import {deep_copy} from "../../utils"
4 |
5 |
6 | const select_input_tpl = `
7 |
11 |
12 | After a short pause while Google automatically checks the file for viruses, you will get a dialog saying "This file type might be dangerous" and a button for "Download anyway". **Click "Download anyway"**.
13 |
14 |
15 |
16 |
17 |
18 | What you need to do next will depend on the browser you are using.
19 |
20 |
21 | ## Google Chrome
22 |
23 | Google Chrome will interrupt the download and show a warning in the bottom left of the browser window:
24 |
25 |
26 |
27 |
28 |
29 | Do **not** click the "Discard" button. Instead, click the **⋁** symbol next to the bottom, and it will show a pop-up menu in which there is a "Keep" option. **Click "Keep"**.
30 |
31 |
32 |
33 |
34 |
35 | Google Chrome will save the installer and you can proceed normally. (Find the installer where it was downloaded on your computer and start the installer program.)
36 |
37 |
38 | ## Microsoft Edge
39 |
40 | Microsoft Edge will block the download and you may see a pop-up such as the following:
41 |
42 |
43 |
44 |
45 |
46 | You must move your cursor to **hover over the Foliage item in the list**, at which point, the browser will show a trash can icon and three dots (•••). **Click on the three dots** to show the action menu, and **select "Keep"** from that menu:
47 |
48 |
49 |
50 |
51 |
52 | You will get _yet another menu_ from which it is not obvious what to do:
53 |
54 |
55 |
56 |
57 |
58 | Do **not** click "Delete". Instead, **click "Show more "** to get a list of options, from which you can **select "Keep anyway"**:
59 |
60 |
61 |
62 |
63 |
64 | It is only at this point, _finally_, that the browser will actually download the Foliage installer program to your computer.
65 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/webiojs/src/models/input/base.ts:
--------------------------------------------------------------------------------
1 | import {Session} from "../../session";
2 |
3 | export class InputItem {
4 | static accept_input_types: string[] = [];
5 |
6 | session: Session;
7 | task_id: string;
8 | spec: any;
9 |
10 | element: JQuery = null; // 在 create_element() 时赋值
11 |
12 | constructor(session: Session, task_id: string, spec: any) {
13 | this.session = session;
14 | this.task_id = task_id;
15 | this.spec = spec;
16 | }
17 |
18 | create_element(): JQuery {
19 | throw new Error("Not implement!");
20 | }
21 |
22 | update_input(spec: any): any {
23 | throw new Error("Not implement!");
24 | }
25 |
26 | get_value(): any {
27 | throw new Error("Not implement!");
28 | }
29 |
30 | // 检查输入项的有效性,在表单提交时调用
31 | check_valid():boolean{
32 | return true;
33 | }
34 |
35 | //在表单加入DOM树后触发
36 | after_add_to_dom(): any {
37 |
38 | }
39 |
40 | //在表单被显示后触发
41 | after_show(first_show:boolean): any {
42 |
43 | }
44 |
45 | protected send_value_listener(input_item: this, event: { type: string }) {
46 | // let this_elem = $(this);
47 | input_item.session.send_message({
48 | event: "input_event",
49 | task_id: input_item.task_id,
50 | data: {
51 | event_name: event.type.toLowerCase(),
52 | name: input_item.spec.name,
53 | value: input_item.get_value()
54 | }
55 | });
56 | };
57 |
58 | /*
59 | * input_idx: 更新作用对象input标签的索引, -1 为不指定对象
60 | * attributes:更新值字典
61 | * */
62 | protected update_input_helper(input_idx: number, attributes: { [i: string]: any }) {
63 | let attr2selector: { [i: string]: string } = {
64 | 'invalid_feedback': 'div.invalid-feedback',
65 | 'valid_feedback': 'div.valid-feedback',
66 | 'help_text': 'small.text-muted'
67 | };
68 | for (let attribute in attr2selector) {
69 | if (attribute in attributes) {
70 | if (input_idx === -1)
71 | this.element.find(attr2selector[attribute]).text(attributes[attribute]);
72 | else
73 | this.element.find(attr2selector[attribute]).eq(input_idx).text(attributes[attribute]);
74 | delete attributes[attribute];
75 | }
76 | }
77 | let input_elem = this.element.find('input,select,textarea');
78 | if (input_idx >= 0)
79 | input_elem = input_elem.eq(input_idx);
80 |
81 | if ('valid_status' in attributes) {
82 | let class_name = attributes.valid_status ? 'is-valid' : 'is-invalid';
83 | if(attributes.valid_status===0) class_name = ''; // valid_status为0时,表示清空valid_status标志
84 | input_elem.removeClass('is-valid is-invalid').addClass(class_name);
85 | delete attributes.valid_status;
86 | }
87 | input_elem.prop(attributes);
88 | }
89 | }
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/dev/installers/windows/create-zip.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # @file create-zip.py
3 | # @brief Create zip file
4 | # @author Michael Hucka
5 | # @license Please see the file named LICENSE in the project directory
6 | # @website https://github.com/caltechlibrary/foliage
7 | #
8 | # Needed on Windows because Windows doesn't have a command-line zip utility.
9 | # =============================================================================
10 |
11 | import os
12 | from os.path import exists, dirname, join, basename, abspath, realpath, isdir
13 | import plac
14 | import sys
15 | from zipfile import ZipFile, ZIP_STORED, ZIP_DEFLATED
16 |
17 |
18 | # Internal constants.
19 | # .............................................................................
20 |
21 | _ZIP_COMMENT = '''\
22 | ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
23 | ┃ This Zip archive file includes a self-contained, runnable ┃
24 | ┃ version of the program Foliage for macOS. To learn ┃
25 | ┃ more about Foliage, please visit the following site: ┃
26 | ┃ ┃
27 | ┃ https://github.com/caltechlibrary/foliage ┃
28 | ┃ ┃
29 | ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
30 | '''
31 |
32 |
33 | # Main function.
34 | # .............................................................................
35 |
36 | @plac.annotations(
37 | dest_dir = ('the destination directory for the output', 'option', 'd'),
38 | overwrite = ('overwrite the destination if it exists', 'flag', 'o'),
39 | files = 'one or more files to be put into the ZIP archive',
40 | )
41 |
42 | def main(dest_dir = 'D', overwrite = False, *files):
43 | '''Put one or more files into a ZIP archive.'''
44 |
45 | here = abspath(dirname(__file__))
46 | with open(join(here, '../../../setup.cfg')) as setup_file:
47 | for line in setup_file.readlines():
48 | if line.startswith('version'):
49 | version = line.split('=')[1].strip()
50 | break
51 |
52 | dest_dir = '.' if dest_dir == 'D' else dest_dir
53 | zip_file = join(dest_dir, f'foliage-{version}-win.zip')
54 | if exists(zip_file) and not overwrite:
55 | raise RuntimeError(f'Output destination already exists: {zip_file}')
56 |
57 | inner_folder = f'foliage-{version}-win'
58 | with ZipFile(zip_file, 'w', ZIP_STORED) as zf:
59 | for file in files:
60 | zf.write(file, arcname = join(inner_folder, basename(file)))
61 | zf.comment = _ZIP_COMMENT.encode()
62 |
63 |
64 | # Main entry point.
65 | # .............................................................................
66 |
67 | # The following allows users to invoke this using "python3 -m create-zip".
68 | if __name__ == '__main__':
69 | if len(sys.argv) == 1 or (len(sys.argv) > 1 and sys.argv[1] == 'help'):
70 | plac.call(main, ['-h'])
71 | else:
72 | plac.call(main)
73 |
--------------------------------------------------------------------------------
/vendor/github.com/mhucka/PyWebIO/test/util.py:
--------------------------------------------------------------------------------
1 | import asyncio
2 | import signal
3 | import subprocess
4 | import sys
5 | import threading
6 | from functools import partial
7 | from urllib.parse import urlparse
8 |
9 | from selenium import webdriver
10 |
11 | from pywebio import STATIC_PATH
12 | from pywebio.utils import wait_host_port
13 |
14 | default_chrome_options = webdriver.ChromeOptions()
15 | default_chrome_options.add_argument('--no-sandbox')
16 | default_chrome_options.add_argument('--disable-extensions')
17 | default_chrome_options.add_argument('--disable-dev-shm-usage')
18 | default_chrome_options.add_argument('--disable-setuid-sandbox')
19 |
20 | USAGE = """
21 | python {name}
22 | 启动PyWebIO服务器
23 |
24 | python {name} auto
25 | 使用无头浏览器进行自动化测试,并使用coverage检测代码覆盖率
26 |
27 | python {name} debug
28 | 使用带界面的浏览器自动化测试
29 | """
30 |
31 |
32 | def run_test(server_func, test_func, address='http://localhost:8080?_pywebio_debug=1', chrome_options=None):
33 | """
34 | :param server_func: 启动PyWebIO服务器的函数
35 | :param test_func: 测试的函数。人工测试时不会被运行 (server_proc, browser)
36 | :param port: 启动的PyWebIO服务器的端口
37 | """
38 | if len(sys.argv) not in (1, 2) or (len(sys.argv) == 2 and sys.argv[-1] not in ('server', 'auto', 'debug')):
39 | print(USAGE.format(name=sys.argv[0]))
40 | return
41 |
42 | if len(sys.argv) != 2:
43 | try:
44 | server_func()
45 | except KeyboardInterrupt:
46 | pass
47 | sys.exit()
48 |
49 | if chrome_options is None:
50 | chrome_options = default_chrome_options
51 |
52 | if sys.argv[-1] == 'auto':
53 | default_chrome_options.add_argument('--headless')
54 | proc = subprocess.Popen(['coverage', 'run', '--source', 'pywebio', '--append',
55 | sys.argv[0]], stdout=sys.stdout, stderr=subprocess.STDOUT, text=True)
56 | elif sys.argv[-1] == 'debug':
57 | proc = subprocess.Popen(['python3', sys.argv[0]], stdout=sys.stdout, stderr=subprocess.STDOUT, text=True)
58 |
59 | browser = None
60 | try:
61 | browser = webdriver.Chrome(chrome_options=chrome_options)
62 | browser.set_window_size(1000, 900)
63 | port_str = urlparse(address).netloc.split(':', 1)[-1] or '80'
64 | asyncio.run(wait_host_port('localhost', int(port_str)))
65 | browser.get(address)
66 | browser.implicitly_wait(10)
67 | test_func(proc, browser)
68 | finally:
69 | if browser:
70 | if sys.argv[-1] == 'debug':
71 | input('press ENTER to exit')
72 |
73 | browser.quit()
74 |
75 | # 不要使用 proc.terminate() ,因为coverage会无法保存分析数据
76 | proc.send_signal(signal.SIGINT)
77 | print("Closed browser and PyWebIO server")
78 |
79 |
80 | def start_static_server(port=5000):
81 | from http.server import SimpleHTTPRequestHandler, test
82 |
83 | handler_class = partial(SimpleHTTPRequestHandler, directory=STATIC_PATH)
84 | threading.Thread(target=test, kwargs=dict(HandlerClass=handler_class, port=port, bind='localhost'), daemon=True).start()
85 |
--------------------------------------------------------------------------------