diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..63d64f0 --- /dev/null +++ b/.flake8 @@ -0,0 +1,9 @@ +# Taken directly from https://github.com/ambv/black/blob/master/.flake8 +[flake8] +ignore = E203, E266, E501, W503, C901, D104, D100 +max-line-length = 88 +max-complexity = 18 +select = B,C,E,F,W,T4,B9 +per-file-ignores = + tests/**:D101,D102,D103 +docstring-convention = numpy diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..08f4e4f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @betatim @xhochy diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..175844a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + dependencies: + patterns: + - "*" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..b075c2a --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,30 @@ +name: Build and upload to PyPI +on: + push: + pull_request: + release: + types: [published] + +jobs: + build_artifacts: + name: Build artifacts + runs-on: ubuntu-latest + strategy: + fail-fast: true + steps: + - uses: actions/checkout@v4 + - name: Fetch full git history + run: git fetch --prune --unshallow + - name: Set up Conda env + uses: mamba-org/setup-micromamba@0dea6379afdaffa5d528b3d1dabc45da37f443fc + with: + environment-file: environment.yml + cache-environment: true + - shell: bash -el {0} + run: + python -m build + - uses: pypa/gh-action-pypi-publish@v1.12.3 + if: github.event_name == 'release' + with: + user: __token__ + password: ${{ secrets.PYPI_RELEASE_TOKEN }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..8304ce1 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,32 @@ +name: CI +on: [push, pull_request] + +# Automatically stop old builds on the same branch/PR +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -el {0} + +jobs: + pre-commit-checks: + name: "Linux - pre-commit checks - Python 3.10" + timeout-minutes: 30 + runs-on: ubuntu-latest + env: + PRE_COMMIT_USE_MICROMAMBA: 1 + steps: + - name: Checkout branch + uses: actions/checkout@v4 + - name: Set up micromamba + uses: mamba-org/setup-micromamba@0dea6379afdaffa5d528b3d1dabc45da37f443fc + - name: Add micromamba to GITHUB_PATH + run: echo "${HOME}/micromamba-bin" >> "$GITHUB_PATH" + - name: Install Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Run pre-commit checks + uses: pre-commit/action@v3.0.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..394e28d --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,35 @@ +repos: + - repo: https://github.com/Quantco/pre-commit-mirrors-black + rev: 23.7.0 + hooks: + - id: black-conda + args: + - --safe + - --target-version=py38 + - repo: https://github.com/Quantco/pre-commit-mirrors-flake8 + rev: 6.1.0 + hooks: + - id: flake8-conda + - repo: https://github.com/Quantco/pre-commit-mirrors-isort + rev: 5.12.0 + hooks: + - id: isort-conda + additional_dependencies: [-c, conda-forge, toml=0.10.2] + - repo: https://github.com/Quantco/pre-commit-mirrors-mypy + rev: "1.5.1" + hooks: + - id: mypy-conda + additional_dependencies: + - -c + - conda-forge + - types-mock + - types-setuptools + - types-redis + - types-boto + - boto3-stubs + - repo: https://github.com/Quantco/pre-commit-mirrors-pyupgrade + rev: 3.10.1 + hooks: + - id: pyupgrade-conda + args: + - --py38-plus diff --git a/README.md b/README.md index 554bfb0..c6a7641 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # VS Code on Binder [![PyPI](https://img.shields.io/pypi/v/jupyter-vscode-proxy)](https://pypi.org/project/jupyter-vscode-proxy/) -[![Install with conda](https://anaconda.org/conda-forge/jupyter-vscode-proxy/badges/installer/conda.svg)](https://github.com/conda-forge/jupyter-vscode-proxy-feedstock) +[![Install with conda](https://anaconda.org/conda-forge/jupyter-vscode-proxy/badges/version.svg)](https://github.com/conda-forge/jupyter-vscode-proxy-feedstock) VS Code on Binder, because sometimes you need a real editor. diff --git a/environment.yml b/environment.yml index bc2c718..7ea9cee 100644 --- a/environment.yml +++ b/environment.yml @@ -1,6 +1,8 @@ +name: vscode-binder channels: - conda-forge dependencies: - numpy + - python-build - jupyter-server-proxy - code-server >=3.2 diff --git a/jupyter_vscode_proxy/__init__.py b/jupyter_vscode_proxy/__init__.py index bc78f26..eb5ae43 100644 --- a/jupyter_vscode_proxy/__init__.py +++ b/jupyter_vscode_proxy/__init__.py @@ -1,46 +1,75 @@ import os import shutil +from typing import Any, Callable, Dict, List -def setup_vscode(): - def _get_vscode_cmd(port): - executable = "code-server" +def _get_inner_vscode_cmd() -> List[str]: + return [ + "code-server", + "--auth", + "none", + "--disable-telemetry", + ] + + +def _get_inner_openvscode_cmd() -> List[str]: + return [ + "openvscode-server", + "--without-connection-token", + "--telemetry-level", + "off", + ] + + +_CODE_EXECUTABLE_INNER_CMD_MAP: Dict[str, Callable] = { + "code-server": _get_inner_vscode_cmd, + "openvscode-server": _get_inner_openvscode_cmd, +} + + +def _get_cmd_factory(executable: str) -> Callable: + if executable not in _CODE_EXECUTABLE_INNER_CMD_MAP: + raise KeyError( + f"'{executable}' is not one of {_CODE_EXECUTABLE_INNER_CMD_MAP.keys()}." + ) + + get_inner_cmd = _CODE_EXECUTABLE_INNER_CMD_MAP[executable] + + def _get_cmd(port: int) -> List[str]: if not shutil.which(executable): - raise FileNotFoundError("Can not find code-server in PATH") - + raise FileNotFoundError(f"Can not find {executable} in PATH") + # Start vscode in CODE_WORKINGDIR env variable if set # If not, start in 'current directory', which is $REPO_DIR in mybinder # but /home/jovyan (or equivalent) in JupyterHubs working_dir = os.getenv("CODE_WORKINGDIR", ".") extensions_dir = os.getenv("CODE_EXTENSIONSDIR", None) - extra_extensions_dir = os.getenv("CODE_EXTRA_EXTENSIONSDIR", None) - cmd = [ - executable, - "--auth", - "none", - "--disable-telemetry", - "--port=" + str(port), - ] + cmd = get_inner_cmd() + + cmd.append("--port=" + str(port)) if extensions_dir: cmd += ["--extensions-dir", extensions_dir] - if extra_extensions_dir: - cmd += ["--extra-extensions-dir", extra_extensions_dir] - cmd.append(working_dir) return cmd + return _get_cmd + + +def setup_vscode() -> Dict[str, Any]: + executable = os.environ.get("CODE_EXECUTABLE", "code-server") + icon = "code-server.svg" if executable == "code-server" else "vscode.svg" return { - "command": _get_vscode_cmd, - "timeout": 20, + "command": _get_cmd_factory(executable), + "timeout": 300, "new_browser_tab": True, "launcher_entry": { "title": "VS Code", "icon_path": os.path.join( - os.path.dirname(os.path.abspath(__file__)), "icons", "vscode.svg" + os.path.dirname(os.path.abspath(__file__)), "icons", icon ), }, } diff --git a/jupyter_vscode_proxy/icons/code-server.svg b/jupyter_vscode_proxy/icons/code-server.svg new file mode 100644 index 0000000..85b701d --- /dev/null +++ b/jupyter_vscode_proxy/icons/code-server.svg @@ -0,0 +1,9 @@ +<svg width="64" viewBox="0 0 2250 2250" version="1.1" xmlns="http://www.w3.org/2000/svg" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> +<g class="jp-icon0" fill="#000" style="fill-rule:nonzero;"> + <path d="M1991.66,1034.72c-38.493,0 -64.144,-22.57 -64.144,-68.897l-0,-266.084c-0,-169.867 -69.982,-263.709 -250.762,-263.709l-83.976,0l-0,179.368l25.661,0c71.144,0 104.967,39.201 104.967,109.285l0,235.201c0,102.156 30.324,143.733 96.806,165.114c-66.482,20.196 -96.806,62.958 -96.806,165.114l0,174.621c0,48.7 0,96.216 -12.829,144.917c-12.829,45.141 -33.823,87.903 -62.98,124.726c-16.329,21.386 -34.991,39.202 -55.981,55.835l-0,23.755l83.971,-0c180.781,-0 250.763,-93.843 250.763,-263.709l-0,-266.084c-0,-47.516 24.485,-68.897 64.144,-68.897l47.822,-0l-0,-179.37l-46.656,-0l0,-1.186Z"/> + <path d="M1420.16,706.904l-258.923,0c-5.833,0 -10.495,-4.752 -10.495,-10.691l-0,-20.192c-0,-5.941 4.662,-10.692 10.495,-10.692l260.089,0c5.83,0 10.495,4.751 10.495,10.692l0,20.192c0,5.939 -5.833,10.691 -11.661,10.691Z" /> + <path d="M1464.48,963.474l-188.942,0c-5.833,0 -10.501,-4.754 -10.501,-10.693l0,-20.192c0,-5.938 4.668,-10.691 10.501,-10.691l188.942,-0c5.833,-0 10.495,4.753 10.495,10.691l-0,20.192c-0,4.754 -4.662,10.693 -10.495,10.693Z"/> + <path d="M1539.12,835.188l-377.885,0c-5.833,0 -10.495,-4.75 -10.495,-10.689l-0,-20.196c-0,-5.939 4.662,-10.69 10.495,-10.69l376.719,0c5.833,0 10.499,4.751 10.499,10.69l-0,20.196c-0,4.75 -3.5,10.689 -9.333,10.689Z"/> + <path d="M861.493,765.074c25.658,0 51.319,2.376 75.811,8.316l0,-48.705c0,-68.897 34.989,-109.285 104.971,-109.285l25.658,0l-0,-179.368l-83.977,0c-180.781,0 -250.758,93.842 -250.758,263.709l0,87.901c40.819,-14.252 83.977,-22.568 128.295,-22.568Z"/> + <path d="M1618.44,1411.25c-18.662,-150.861 -132.962,-276.776 -279.919,-305.285c-40.818,-8.314 -81.642,-9.504 -121.295,-2.376c-1.166,-0 -1.166,-1.189 -2.332,-1.189c-64.148,-136.605 -201.772,-226.884 -351.063,-226.884c-149.289,-0 -285.747,87.905 -351.062,224.51c-1.166,-0 -1.166,1.188 -2.332,1.188c-41.987,-4.753 -83.975,-2.379 -125.963,8.314c-144.623,35.634 -254.257,159.175 -274.085,308.847c-2.332,15.441 -3.499,30.883 -3.499,45.141c0,45.136 30.325,86.713 74.645,92.652c54.817,8.317 102.636,-34.448 101.469,-89.089c0,-8.317 0,-17.821 1.167,-26.134c9.331,-76.025 66.48,-140.168 141.123,-157.99c23.328,-5.939 46.654,-7.124 68.814,-3.559c71.146,9.502 141.124,-27.324 171.449,-91.467c22.162,-47.516 57.151,-89.094 103.804,-111.664c51.314,-24.946 109.633,-28.506 163.286,-9.499c55.979,20.192 97.966,62.954 123.627,116.409c26.824,52.27 39.653,89.093 96.805,96.221c23.325,3.559 88.639,2.374 113.132,1.185c47.82,0 95.64,16.631 129.463,51.079c22.156,23.757 38.485,53.455 45.486,86.715c10.495,53.455 -2.334,106.908 -33.825,147.296c-22.162,28.509 -52.485,49.89 -86.308,59.394c-16.329,4.754 -32.657,5.939 -48.986,5.939l-257.757,0c-51.314,0 -92.138,-41.573 -92.138,-93.842l0,-348.049c0,-14.251 -11.661,-26.13 -25.658,-26.13l-36.156,0c-71.148,1.185 -128.295,81.964 -128.295,167.488l-0,312.415c-0,92.652 73.476,167.488 164.451,167.488c0,0 404.714,-1.19 410.544,-1.19c93.304,-9.503 179.614,-58.204 237.927,-133.04c58.319,-72.46 85.142,-167.492 73.481,-264.894Z"/> +</g></svg> \ No newline at end of file diff --git a/postBuild b/postBuild index ff03503..542f613 100644 --- a/postBuild +++ b/postBuild @@ -1,10 +1,5 @@ #!/bin/bash -# Enable the proxy extension in notebook and lab -jupyter serverextension enable --py jupyter_server_proxy -jupyter labextension install @jupyterlab/server-proxy -jupyter lab build - code-server --install-extension ms-python.python # Install the VS code proxy diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..32f5676 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,53 @@ +[build-system] +requires = ["setuptools", "setuptools-scm", "wheel"] + +[tool.setuptools_scm] +version_scheme = "post-release" + +[project] +name = "jupyter_vscode_proxy" +description = "VS Code extension for Jupyter" +readme = "README.md" +dynamic = ["version"] +authors = [ + {name = "Tim Head", email = "noreply@example.com"}, +] +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +requires-python = ">=3.8" +license = {text = "BSD-3-clause"} + +[project.urls] +repository = "https://github.com/betatim/vscode-binder" + +[project.entry-points.jupyter_serverproxy_servers] +vscode = "jupyter_vscode_proxy:setup_vscode" + +[tool.black] +exclude = ''' +/( + \.eggs + | \.git + | \.venv + | build + | dist +)/ +''' + +[tool.isort] +profile = "black" +line_length = 88 +known_first_party = "{{ project_slug }}" +skip_glob = '\.eggs/*,\.git/*,\.venv/*,build/*,dist/*' +default_section = 'THIRDPARTY' + +[tool.mypy] +python_version = '3.8' +ignore_missing_imports = true +no_implicit_optional = true +check_untyped_defs = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8183238..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[metadata] -license_files = LICENSE diff --git a/setup.py b/setup.py deleted file mode 100644 index f51d1b7..0000000 --- a/setup.py +++ /dev/null @@ -1,31 +0,0 @@ -import setuptools - - -with open("README.md", encoding="utf8") as f: - readme = f.read() - - -setuptools.setup( - name="jupyter-vscode-proxy", - version="0.1", - url="https://github.com/betatim/vscode-binder", - author="Tim Head", - license="BSD", - description="VS Code extension for Jupyter", - long_description=readme, - long_description_content_type="text/markdown", - packages=setuptools.find_packages(), - keywords=["Jupyter", "vscode", "vs code", "editor"], - classifiers=["Framework :: Jupyter"], - install_requires=[ - 'jupyter-server-proxy' - ], - entry_points={ - "jupyter_serverproxy_servers": ["vscode = jupyter_vscode_proxy:setup_vscode",] - }, - package_data={"jupyter_vscode_proxy": ["icons/*"]}, - project_urls={ - "Source": "https://github.com/betatim/vscode-binder/", - "Tracker": "https://github.com/betatim/vscode-binder/issues", - }, -)