From e620144878d35882e14a91558d5617f315ef022a Mon Sep 17 00:00:00 2001 From: Marc Skov Madsen Date: Sat, 23 Nov 2024 19:39:34 +0000 Subject: [PATCH] Initial project skeleton --- .copier-answers.yml | 13 + .gitattributes | 1 + .github/CODEOWNERS | 1 + .github/dependabot.yml | 10 + .github/workflows/build.yml | 45 +++ .github/workflows/ci.yml | 168 +++++++++++ .github/workflows/docs.yml | 55 ++++ .github/workflows/update-lockfiles.yml | 34 +++ .gitignore | 383 +++++++++++++++++++++++++ .pre-commit-config.yaml | 61 ++++ .prettierrc | 7 + LICENSE.txt | 30 ++ MANIFEST.in | 1 + README.md | 51 ++++ docs/assets/logo.svg | 157 ++++++++++ docs/index.md | 1 + docs/reference/panel_copy_paste.md | 3 + mkdocs.yml | 60 ++++ pixi.toml | 88 ++++++ pyproject.toml | 142 +++++++++ src/panel_copy_paste/__init__.py | 10 + src/panel_copy_paste/main.py | 1 + src/panel_copy_paste/py.typed | 0 tests/__init__.py | 0 tests/conftest.py | 72 +++++ tests/test_core.py | 5 + tests/ui/__init__.py | 0 tests/ui/test_ui.py | 27 ++ 28 files changed, 1426 insertions(+) create mode 100644 .copier-answers.yml create mode 100644 .gitattributes create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/update-lockfiles.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .prettierrc create mode 100644 LICENSE.txt create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 docs/assets/logo.svg create mode 100644 docs/index.md create mode 100644 docs/reference/panel_copy_paste.md create mode 100644 mkdocs.yml create mode 100644 pixi.toml create mode 100644 pyproject.toml create mode 100644 src/panel_copy_paste/__init__.py create mode 100644 src/panel_copy_paste/main.py create mode 100644 src/panel_copy_paste/py.typed create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_core.py create mode 100644 tests/ui/__init__.py create mode 100644 tests/ui/test_ui.py diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 0000000..5b1eb3a --- /dev/null +++ b/.copier-answers.yml @@ -0,0 +1,13 @@ +# This file is managed by Copier; DO NOT EDIT OR REMOVE. +_commit: dbdb5dc +_src_path: https://github.com/panel-extensions/copier-template-panel-extension +add_autobump_workflow: true +author_email: marc.skov.madsen@gmail.com +author_name: Marc Skov Madsen +docs_url: https://awesome-panel.github.io/panel-copy-paste/ +github_url: https://github.com/awesome-panel/panel-copy-paste +github_user: awesome-panel +minimal_python_version: py311 +project_short_description: Extends HoloViz Panel with functionality to copy to and + paste from the clipboard +project_slug: panel-copy-paste diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..18f6c7e --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +pixi.lock linguist-language=YAML linguist-generated=true diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..eba7ee1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @awesome-panel diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..3891848 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: monthly + groups: + gh-actions: + patterns: + - "*" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8ca45da --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,45 @@ +name: Build +on: + pull_request: + push: + branches: + - main + tags: + - "*" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - name: Set up pixi + uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1 + with: + environments: build + - name: Build project + run: pixi run -e build build-wheel + - name: Check package + run: pixi run -e build check-wheel + - name: Upload package + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: artifact + path: dist/* + + release: + name: Publish package + if: startsWith(github.ref, 'refs/tags/') + needs: [build] + runs-on: ubuntu-latest + permissions: + id-token: write + environment: pypi + steps: + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: artifact + path: dist + - name: Publish package on PyPi + uses: pypa/gh-action-pypi-publish@f7600683efdcb7656dec5b29656edb7bc586e597 # v1.10.3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..2c55330 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,168 @@ +name: CI +on: + pull_request: + push: + branches: + - main +# Automatically stop old builds on the same branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + setup: + name: Setup workflow + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + code_change: ${{ steps.filter.outputs.code }} + matrix: ${{ env.MATRIX }} + steps: + - uses: actions/checkout@v4 + if: github.event_name != 'pull_request' + - name: Check for code changes + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + code: + - 'src/**' + - 'pyproject.toml' + - '.github/workflows/ci.yaml' + - name: Set matrix option + run: | + if [[ '${{ github.event_name }}' == 'workflow_dispatch' ]]; then + OPTION=${{ github.event.inputs.target }} + elif [[ '${{ github.event_name }}' == 'schedule' ]]; then + OPTION="full" + elif [[ '${{ github.event_name }}' == 'push' && '${{ github.ref_type }}' == 'tag' ]]; then + OPTION="full" + else + OPTION="default" + fi + echo "MATRIX_OPTION=$OPTION" >> $GITHUB_ENV + - name: Set test matrix with 'default' option + if: env.MATRIX_OPTION == 'default' + run: | + MATRIX=$(jq -nsc '{ + "os": ["ubuntu-latest", "macos-latest", "windows-latest"], + "environment": ["test-310", "test-312"], + }') + echo "MATRIX=$MATRIX" >> $GITHUB_ENV + - name: Set test matrix with 'full' option + if: env.MATRIX_OPTION == 'full' + run: | + MATRIX=$(jq -nsc '{ + "os": ["ubuntu-latest", "macos-latest", "windows-latest"], + "environment": ["test-310", "test-311", "test-312"] + }') + echo "MATRIX=$MATRIX" >> $GITHUB_ENV + - name: Set test matrix with 'downstream' option + if: env.MATRIX_OPTION == 'downstream' + run: | + MATRIX=$(jq -nsc '{ + "os": ["ubuntu-latest"], + "environment": ["test-311"] + }') + echo "MATRIX=$MATRIX" >> $GITHUB_ENV + + pixi_lock: + name: Pixi lock + runs-on: ubuntu-latest + steps: + - uses: holoviz-dev/holoviz_tasks/pixi_lock@v0 + with: + cache: ${{ github.event.inputs.cache == 'true' || github.event.inputs.cache == '' }} + + pre-commit: + timeout-minutes: 30 + runs-on: ubuntu-latest + steps: + - name: Checkout branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Set up pixi + uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1 + with: + environments: default lint + - name: pre-commit + run: pixi run pre-commit-run --color=always --show-diff-on-failure + pytest: + timeout-minutes: 30 + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + environment: + - py311 + - py312 + os: + - ubuntu-latest + - macos-latest + - windows-latest + steps: + - name: Checkout branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - name: Set up pixi + uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1 + with: + environments: ${{ matrix.environment }} + - name: Install repository + run: pixi run -e ${{ matrix.environment }} postinstall + - name: Run pytest + run: pixi run -e ${{ matrix.environment }} test-coverage --color=yes + + pytest_ui: + name: ui:${{ matrix.environment }}:${{ matrix.os }} + needs: [pre-commit, setup, pixi_lock] + runs-on: ${{ matrix.os }} + if: needs.setup.outputs.code_change == 'true' + strategy: + fail-fast: false + matrix: + environment: ["test-ui"] + os: ["ubuntu-latest", "macos-latest", "windows-latest"] + timeout-minutes: 60 + env: + PANEL_LOG_LEVEL: info + steps: + - name: Checkout branch + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 0 + + - name: Set up Pixi + uses: prefix-dev/setup-pixi@v0.8.1 + with: + environments: ${{ matrix.environment }} + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 'py311' + + - name: Install Dependencies + run: | + pixi run -e ${{ matrix.environment }} postinstall + + - name: Verify Pixi Installation + run: pixi --version + + - name: Configure Coverage + run: | + echo "[run]" > .uicoveragerc + echo "concurrency = greenlet" >> .uicoveragerc + + - name: Test UI + run: | + FAIL="--screenshot only-on-failure --full-page-screenshot --output ui_screenshots --tracing retain-on-failure" + pixi run -e ${{ matrix.environment }} test-ui --cov-config=.uicoveragerc $FAIL + + - name: Upload UI Screenshots + uses: actions/upload-artifact@v4 + if: always() + with: + name: ui_screenshots_${{ runner.os }} + path: ./ui_screenshots + if-no-files-found: ignore \ No newline at end of file diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..c268cb3 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,55 @@ +name: Build documentation + +on: + push: + branches: + - main + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +# Default to bash +defaults: + run: + shell: bash + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Pixi + uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1 + with: + environments: docs + + - name: Build documentation + run: pixi run -e docs docs-build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./site + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.github/workflows/update-lockfiles.yml b/.github/workflows/update-lockfiles.yml new file mode 100644 index 0000000..2dd8cea --- /dev/null +++ b/.github/workflows/update-lockfiles.yml @@ -0,0 +1,34 @@ +name: Update lockfiles +permissions: + contents: write + pull-requests: write + +on: + workflow_dispatch: + schedule: + - cron: 0 5 1 * * + +jobs: + pixi-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Set up pixi + uses: prefix-dev/setup-pixi@ba3bb36eb2066252b2363392b7739741bb777659 # v0.8.1 + with: + run-install: false + - name: Update lockfiles + run: | + pixi update --json --no-install | pixi exec pixi-diff-to-markdown >> diff.md + - name: Create pull request + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: Update pixi lockfile + title: Update pixi lockfile + body-path: diff.md + branch: update-pixi + base: main + labels: pixi + delete-branch: true + add-paths: pixi.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..164a892 --- /dev/null +++ b/.gitignore @@ -0,0 +1,383 @@ +# Created by https://www.toptal.com/developers/gitignore/api/linux,macos,direnv,python,windows,pycharm+all,visualstudiocode,vim +# Edit at https://www.toptal.com/developers/gitignore?templates=linux,macos,direnv,python,windows,pycharm+all,visualstudiocode,vim + +### direnv ### +.direnv +.envrc + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm+all Patch ### +# Ignore everything but code style settings and run configurations +# that are supposed to be shared within teams. + +.idea/* + +!.idea/codeStyles +!.idea/runConfigurations + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/linux,macos,direnv,python,windows,pycharm+all,visualstudiocode,vim + +.pixi diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f350d49 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,61 @@ +exclude: ^(\.copier-answers\.yml)|.pixi$ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-builtin-literals + - id: check-case-conflict + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-toml + - id: check-json + - id: detect-private-key + - id: end-of-file-fixer + exclude: \.min\.js$ + - id: trailing-whitespace + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.0 + hooks: + - id: ruff + files: panel/ + - repo: https://github.com/pycqa/isort + rev: 5.13.2 + hooks: + - id: isort + name: isort (python) + - repo: https://github.com/hoxbro/clean_notebook + rev: v0.1.15 + hooks: + - id: clean-notebook + args: [-i, tags] + exclude: '^lite/files/.*/' + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + additional_dependencies: + - tomli + - repo: https://github.com/hoxbro/prettier-pre-commit + rev: v3.3.3 + hooks: + - id: prettier + entry: prettier --write --ignore-unknown --no-error-on-unmatched-pattern + types_or: [css] + - repo: https://github.com/shssoichiro/oxipng + rev: v8.0.0 + hooks: + - id: oxipng + stages: [manual] + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v9.13.0 + hooks: + - id: eslint + args: ['-c', 'panel/.eslintrc.js', 'panel/*.ts', 'panel/models/**/*.ts', '--fix'] + additional_dependencies: + - 'eslint@8.57.0' + - '@stylistic/eslint-plugin@1.6.3' + - '@typescript-eslint/eslint-plugin@7.2.0' + - '@typescript-eslint/parser@7.2.0' +ci: + autofix_prs: false + autoupdate_schedule: quarterly diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..478cc53 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": false, + "bracketSpacing": true, + "printWidth": 200, + "endOfLine": "auto", + "tabWidth": 2 +} diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..81cd5d5 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,30 @@ +Copyright (c) 2018, HoloViz team (holoviz.org). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the + distribution. + + * Neither the name of the copyright holder nor the names of any + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..15a7660 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +recursive-include panel_copy_paste models/*.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..b0e629b --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# panel-copy-paste + +[![CI](https://img.shields.io/github/actions/workflow/status/awesome-panel/panel-copy-paste/ci.yml?style=flat-square&branch=main)](https://github.com/awesome-panel/panel-copy-paste/actions/workflows/ci.yml) +[![conda-forge](https://img.shields.io/conda/vn/conda-forge/panel-copy-paste?logoColor=white&logo=conda-forge&style=flat-square)](https://prefix.dev/channels/conda-forge/packages/panel-copy-paste) +[![pypi-version](https://img.shields.io/pypi/v/panel-copy-paste.svg?logo=pypi&logoColor=white&style=flat-square)](https://pypi.org/project/panel-copy-paste) +[![python-version](https://img.shields.io/pypi/pyversions/panel-copy-paste?logoColor=white&logo=python&style=flat-square)](https://pypi.org/project/panel-copy-paste) +Extends HoloViz Panel with functionality to copy to and paste from the clipboard + +## Features + +panel-copy-paste + +## Installation + +Install it via `pip`: + +```bash +pip install panel-copy-paste +``` + +## Development + +This project is managed by [pixi](https://pixi.sh). +You can install the package in development mode using: + +```bash +git clone https://github.com/awesome-panel/panel-copy-paste +cd panel-copy-paste + +pixi run pre-commit-install +pixi run postinstall +pixi run test +``` + +## Usage + +```python +import panel_copy_paste +``` + +## Contributing + +Contributions are welcome! Please follow these steps to contribute: + +1. Fork the repository. +2. Create a new branch: `git checkout -b feature/YourFeature`. +3. Make your changes and commit them: `git commit -m 'Add some feature'`. +4. Push to the branch: `git push origin feature/YourFeature`. +5. Open a pull request. + +Please ensure your code adheres to the project's coding standards and passes all tests. diff --git a/docs/assets/logo.svg b/docs/assets/logo.svg new file mode 100644 index 0000000..a52f13c --- /dev/null +++ b/docs/assets/logo.svg @@ -0,0 +1,157 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..612c7a5 --- /dev/null +++ b/docs/index.md @@ -0,0 +1 @@ +--8<-- "README.md" diff --git a/docs/reference/panel_copy_paste.md b/docs/reference/panel_copy_paste.md new file mode 100644 index 0000000..5a3c68d --- /dev/null +++ b/docs/reference/panel_copy_paste.md @@ -0,0 +1,3 @@ +# Reference + +::: src.panel_copy_paste diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..eca957f --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,60 @@ +site_name: panel-copy-paste +site_description: Extends HoloViz Panel with functionality to copy to and paste from the clipboard +site_author: Marc Skov Madsen + +repo_url: https://github.com/awesome-panel/panel-copy-paste +repo_name: awesome-panel/panel-copy-paste + +theme: + name: material + logo: 'assets/logo.svg' + features: + - content.copy.code + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: white + accent: blue + toggle: + icon: material/brightness-7 + name: Switch to dark mode + + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: black + accent: blue + toggle: + icon: material/brightness-4 + name: Switch to light mode + +markdown_extensions: + - toc: + permalink: true + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - admonition + +plugins: + - search + - mkdocstrings: + handlers: + python: + options: + docstring_style: google + show_if_no_docstring: true + filters: + - "!^_" + +watch: + - docs + +nav: + - Home: index.md + - Reference: reference/panel_copy_paste.md diff --git a/pixi.toml b/pixi.toml new file mode 100644 index 0000000..cca82a3 --- /dev/null +++ b/pixi.toml @@ -0,0 +1,88 @@ +[project] +name = "panel-copy-paste" +channels = ["conda-forge"] +platforms = ["osx-arm64", "osx-64", "linux-64", "win-64"] + +[tasks] +postinstall = "pip install --no-build-isolation --no-deps --disable-pip-version-check -e ." +docs = "mkdocs serve" +docs-build = "mkdocs build" + +[dependencies] +python = ">=3.11" + +[host-dependencies] +pip = "*" +hatchling = "*" +hatch-vcs = "*" +panel = ">=1.5.0" +setuptools = ">=61" +setuptools-scm = "*" + +[feature.test.dependencies] +pytest = ">=6" +pytest-cov = "*" +mypy = "*" +[feature.test.tasks] +test = "pytest" +test-coverage = "pytest --cov=panel_copy_paste --cov-report=xml --cov-report=term-missing" + +[feature.build.dependencies] +python-build = "*" +twine = "*" +wheel = "*" +[feature.build.tasks] +build-wheel = "python -m build --no-isolation ." +check-wheel = "twine check dist/*" + +[feature.lint.dependencies] +pre-commit = "*" +insert-license-header = "*" +docformatter = "*" +ruff = "*" +prettier = "*" +taplo = "*" +pre-commit-hooks = "*" +typos = "*" +[feature.lint.tasks] +pre-commit-install = "pre-commit install" +pre-commit-run = "pre-commit run -a" + +[feature.py311.dependencies] +python = "3.11.*" +[feature.py312.dependencies] +python = "3.12.*" + +[feature.test-ui] +channels = ["microsoft"] + +[feature.test-ui.dependencies] +playwright = { version = "*", channel = "microsoft" } +pytest-playwright = { version = "*", channel = "microsoft" } +pytest-asyncio = "*" +pytest-rerunfailures = "*" +pytest-xdist = "*" +jupyter_server = "*" +esbuild = "*" +packaging = "*" + +[feature.test-ui.tasks] +_install-ui = 'playwright install chromium' + +[feature.test-ui.tasks.test-ui] +cmd = 'pytest tests/ui --ui --browser chromium -n logical --dist loadgroup --reruns 3 --reruns-delay 10' +depends_on = ["_install-ui"] + +[feature.docs.dependencies] +mkdocs = "*" +mkdocs-material = "*" +mkdocstrings-python = "*" + +[environments] +default = ["test"] +py311 = ["py311", "test"] +py312 = ["py312", "test"] +test-ui = ["py312", "test", "test-ui"] +docs = ["docs"] +build = ["build"] +lint = { features = ["lint"], no-default-feature = true } diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d6f4b81 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,142 @@ +[build-system] +requires = [ + "hatchling", + "hatch-vcs", + "panel>=1.5.0", + "packaging", +] +build-backend = "hatchling.build" + + +[tool.setuptools_scm] +version_scheme = "post-release" + +[project] +name = "panel-copy-paste" +dynamic = ["version"] +description = 'Extends HoloViz Panel with functionality to copy to and paste from the clipboard' +readme = "README.md" +license = { text = "BSD" } +requires-python = ">=3.11" +authors = [{ name = "Marc Skov Madsen", email = "marc.skov.madsen@gmail.com" }] +maintainers = [ + { name = "Marc Skov Madsen", email = "marc.skov.madsen@gmail.com" }, +] +classifiers = [ + "License :: OSI Approved :: BSD License", + "Development Status :: 5 - Production/Stable", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Operating System :: OS Independent", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Natural Language :: English", + "Topic :: Scientific/Engineering", + "Topic :: Software Development :: Libraries", +] + +dependencies = [ + 'panel >=1.5.0', + 'packaging', +] + +[project.urls] +Homepage = "https://github.com/awesome-panel/panel-copy-paste" +Source = "https://github.com/awesome-panel/panel-copy-paste" + +[project.optional-dependencies] +dev = [ + 'watchfiles', + 'mkdocs', + 'mkdocs-material', + 'mkdocstrings[python]', + 'pytest', + 'pytest-asyncio', + 'pytest-rerunfailures', + 'pytest-xdist', + +] +mypy = [ + "mypy", + "types-requests", + "typing-extensions", +] + +[tool.ruff] +exclude = [ + ".git", + "__pycache__", + ".tox", + ".eggs", + "*.egg", + "doc", + "dist", + "build", + "_build", + "examples", + ".ipynb_checkpoints", + "node_modules", +] +line-length = 165 +fix = true + +[tool.ruff.lint] +ignore = [ + "E402", # Module level import not at top of file + "E712", # Avoid equality comparisons to True + "E731", # Do not assign a lambda expression, use a def + "N803", # Argument name should be lowercase + "N806", # Variable name should be lowercase +] +select = [ + "B", # flake8-bugbear + "E", # pycodestyle errors + "F", # pyflakes + "W", # pycodestyle warnings + "I", # isort + "PIE", + "T20", + "RUF006", + "UP004", + "UP006", + "UP020", + "UP028", + "UP030", + "UP031", + "UP032", + "UP034", + "UP036", +] + +[tool.pytest.ini_options] +addopts = "--pyargs --doctest-ignore-import-errors --color=yes" +norecursedirs = "doc .git dist build _build .ipynb_checkpoints examples" +asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "function" +xfail_strict = true +minversion = "7" +log_cli_level = "INFO" +filterwarnings = [ + "error", + "ignore::DeprecationWarning", + "ignore::UserWarning", +] +testpaths = ["tests"] + +[tool.isort] +force_grid_wrap = 4 +multi_line_output = 5 +combine_as_imports = true +lines_between_types = 1 +include_trailing_comma = true + +[tool.mypy] +python_version = '3.11' +no_implicit_optional = true +check_untyped_defs = true + +[tool.hatch.version] +source = "vcs" +raw-options = { version_scheme = "no-guess-dev" } \ No newline at end of file diff --git a/src/panel_copy_paste/__init__.py b/src/panel_copy_paste/__init__.py new file mode 100644 index 0000000..a76c9b4 --- /dev/null +++ b/src/panel_copy_paste/__init__.py @@ -0,0 +1,10 @@ +import importlib.metadata +import warnings + +try: + __version__ = importlib.metadata.version(__name__) +except importlib.metadata.PackageNotFoundError as e: # pragma: no cover + warnings.warn(f"Could not determine version of {__name__}\n{e!s}", stacklevel=2) + __version__ = "unknown" + +__all__ = [] # <- IMPORTANT FOR DOCS: fill with imports diff --git a/src/panel_copy_paste/main.py b/src/panel_copy_paste/main.py new file mode 100644 index 0000000..846cbfd --- /dev/null +++ b/src/panel_copy_paste/main.py @@ -0,0 +1 @@ +import panel as pn \ No newline at end of file diff --git a/src/panel_copy_paste/py.typed b/src/panel_copy_paste/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..b06ed04 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,72 @@ +import pytest + +from panel.config import panel_extension +from panel.io.reload import _local_modules, _modules, _watched_files +from panel.io.state import state +from panel.theme import Design + +optional_markers = { + "ui": { + "help": "Runs UI related tests", + "marker-descr": "UI test marker", + "skip-reason": "Test only runs with the --ui option.", + }, +} + + +def pytest_addoption(parser): + for marker, info in optional_markers.items(): + parser.addoption( + f"--{marker}", action="store_true", default=False, help=info["help"] + ) + parser.addoption( + "--repeat", action="store", help="Number of times to repeat each test" + ) + + +def pytest_configure(config): + for marker, info in optional_markers.items(): + config.addinivalue_line( + "markers", "{}: {}".format(marker, info["marker-descr"]) + ) + + config.addinivalue_line( + "markers", "internet: mark test as requiring an internet connection" + ) + + +@pytest.fixture(autouse=True) +def module_cleanup(): + """ + Cleanup Panel extensions after each test. + """ + from bokeh.core.has_props import _default_resolver + from panel.reactive import ReactiveMetaBase + + to_reset = list(panel_extension._imports.values()) + _default_resolver._known_models = { + name: model for name, model in _default_resolver._known_models.items() + if not any(model.__module__.startswith(tr) for tr in to_reset) + } + ReactiveMetaBase._loaded_extensions = set() + + +@pytest.fixture(autouse=True) +def server_cleanup(): + """ + Clean up server state after each test. + """ + try: + yield + finally: + state.reset() + _watched_files.clear() + _modules.clear() + _local_modules.clear() + + +@pytest.fixture(autouse=True) +def cache_cleanup(): + state.clear_caches() + Design._resolve_modifiers.cache_clear() + Design._cache.clear() diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..bf39b92 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,5 @@ +import panel_copy_paste # noqa + + +def test_example(): + assert panel_copy_paste diff --git a/tests/ui/__init__.py b/tests/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/ui/test_ui.py b/tests/ui/test_ui.py new file mode 100644 index 0000000..1dda021 --- /dev/null +++ b/tests/ui/test_ui.py @@ -0,0 +1,27 @@ +# import time + +import pytest + +pytest.importorskip("playwright") + +# from panel.pane import panel +# from panel.tests.util import serve_component +# from playwright.sync_api import expect + +pytestmark = pytest.mark.ui + + +def test_param_defer_load(page): + """ + Example of a UI test using Playwright. + """ + # def defer_load(): + # time.sleep(0.5) + # return "I render after load!" + + # component = panel(defer_load, defer_load=True) + + # serve_component(page, component) + + # assert page.locator(".pn-loading") + # expect(page.locator(".markdown").locator("div")).to_have_text("I render after load!\n")