mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 02:37:41 -05:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52bd64c80d | ||
|
|
5c90b19707 | ||
|
|
eb0d1ff740 | ||
|
|
ca8a22e5db | ||
|
|
63fab105b2 | ||
|
|
71ca7753e1 | ||
|
|
6dced95954 | ||
|
|
ffd9e6f4d0 | ||
|
|
b9c3eb6442 | ||
|
|
be79f70f66 | ||
|
|
71e2555213 | ||
|
|
1b9cb562ec | ||
|
|
55cf6b9e4c | ||
|
|
9a70943a36 | ||
|
|
7765a629c7 | ||
|
|
848d77b1c2 | ||
|
|
e4e8f2edae | ||
|
|
ea9bdcc961 | ||
|
|
79ad39260e | ||
|
|
f4936316ab | ||
|
|
8879187e6a | ||
|
|
258b80a6a5 | ||
|
|
a108e6e97e | ||
|
|
dfef7eda3b |
6
.github/workflows/build-unstable.yml
vendored
6
.github/workflows/build-unstable.yml
vendored
@@ -20,7 +20,7 @@ on:
|
||||
|
||||
jobs:
|
||||
BuildAndTest:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
path: pyscriptjs/test_results
|
||||
if-no-files-found: error
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
run: npx eslint src -c .eslintrc.js
|
||||
|
||||
Deploy:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
needs: BuildAndTest
|
||||
if: github.ref == 'refs/heads/main' # Only deploy on merge into main
|
||||
permissions:
|
||||
|
||||
2
.github/workflows/docs-release.yml
vendored
2
.github/workflows/docs-release.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
2
.github/workflows/docs-review.yml
vendored
2
.github/workflows/docs-review.yml
vendored
@@ -19,7 +19,7 @@ concurrency:
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository_owner == 'pyscript'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
2
.github/workflows/docs-unstable.yml
vendored
2
.github/workflows/docs-unstable.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
62
.github/workflows/next-build-snapshot.yml
vendored
Normal file
62
.github/workflows/next-build-snapshot.yml
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
name: "Next Build Snapshot"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
snapshot_version:
|
||||
description: "The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1"
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
next-build-snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: next
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Install Dependencies
|
||||
working-directory: ./pyscript.core
|
||||
run: npm install
|
||||
|
||||
- name: Build Pyscript.core
|
||||
working-directory: ./pyscript.core
|
||||
run: npm run build
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
- name: Generate index.html in snapshot
|
||||
working-directory: .
|
||||
run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html
|
||||
|
||||
- name: Copy to Snapshot
|
||||
working-directory: ./pyscript.core/dist
|
||||
run: >
|
||||
aws s3 sync . s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/
|
||||
18
.github/workflows/prepare-release.yml
vendored
18
.github/workflows/prepare-release.yml
vendored
@@ -15,7 +15,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -44,8 +44,20 @@ jobs:
|
||||
- name: Setup Environment
|
||||
run: make setup
|
||||
|
||||
- name: Build and Test
|
||||
run: make test
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: TypeScript Tests
|
||||
run: make test-ts
|
||||
|
||||
- name: Python Tests
|
||||
run: make test-py
|
||||
|
||||
- name: Integration Tests
|
||||
run: make test-integration-parallel
|
||||
|
||||
- name: Examples Tests
|
||||
run: make test-examples
|
||||
|
||||
- name: Zip build folder
|
||||
run: zip -r -q ./build.zip ./build
|
||||
|
||||
18
.github/workflows/publish-release.yml
vendored
18
.github/workflows/publish-release.yml
vendored
@@ -14,7 +14,7 @@ defaults:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -46,8 +46,20 @@ jobs:
|
||||
- name: Setup Environment
|
||||
run: make setup
|
||||
|
||||
- name: Build and Test
|
||||
run: make test
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: TypeScript Tests
|
||||
run: make test-ts
|
||||
|
||||
- name: Python Tests
|
||||
run: make test-py
|
||||
|
||||
- name: Integration Tests
|
||||
run: make test-integration-parallel
|
||||
|
||||
- name: Examples Tests
|
||||
run: make test-examples
|
||||
|
||||
# Upload to S3
|
||||
- name: Configure AWS credentials
|
||||
|
||||
2
.github/workflows/publish-snapshot.yml
vendored
2
.github/workflows/publish-snapshot.yml
vendored
@@ -11,7 +11,7 @@ on:
|
||||
|
||||
jobs:
|
||||
snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
2
.github/workflows/sync-examples.yml
vendored
2
.github/workflows/sync-examples.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
119
.github/workflows/test-next.yml
vendored
Normal file
119
.github/workflows/test-next.yml
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
name: "[CI] Test Next"
|
||||
|
||||
on:
|
||||
push: # Only run on merges into main that modify files under pyscriptjs/ and examples/
|
||||
branches:
|
||||
- next
|
||||
paths:
|
||||
- pyscript.core/**
|
||||
- pyscriptjs/**
|
||||
- examples/**
|
||||
- .github/workflows/test-next.yml # Test that workflow works when changed
|
||||
|
||||
pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/
|
||||
branches:
|
||||
- next
|
||||
paths:
|
||||
- pyscript.core/**
|
||||
- examples/**
|
||||
- .github/workflows/test-next.yml # Test that workflow works when changed
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
BuildAndTest:
|
||||
runs-on: ubuntu-latest-8core
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: next
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: setup Miniconda
|
||||
uses: conda-incubator/setup-miniconda@v2
|
||||
|
||||
- name: Setup Environment
|
||||
working-directory: ./pyscriptjs
|
||||
run: make setup
|
||||
|
||||
- name: Python Tests
|
||||
working-directory: ./pyscriptjs
|
||||
run: make test
|
||||
|
||||
- name: Integration Tests
|
||||
working-directory: ./pyscriptjs
|
||||
run: make test-integration
|
||||
#run: make test-integration-parallel
|
||||
|
||||
- name: Examples Tests
|
||||
working-directory: ./pyscriptjs
|
||||
run: make test-examples
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: pyscript
|
||||
path: |
|
||||
pyscriptjs/build/
|
||||
if-no-files-found: error
|
||||
retention-days: 7
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: success() || failure()
|
||||
with:
|
||||
name: test_results
|
||||
path: pyscriptjs/test_results
|
||||
if-no-files-found: error
|
||||
eslint:
|
||||
runs-on: ubuntu-latest-8core
|
||||
defaults:
|
||||
run:
|
||||
working-directory: pyscriptjs
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: next
|
||||
|
||||
- name: Install node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18.x
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: npm install
|
||||
run: npm install
|
||||
|
||||
- name: Eslint
|
||||
run: npx eslint src -c .eslintrc.js
|
||||
2
.github/workflows/test_report.yml
vendored
2
.github/workflows/test_report.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
- completed
|
||||
jobs:
|
||||
report:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-latest-8core
|
||||
steps:
|
||||
- uses: dorny/test-reporter@v1.6.0
|
||||
with:
|
||||
|
||||
4
LICENSE
4
LICENSE
@@ -186,7 +186,9 @@
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright (c) 2022-present, PyScript Development Team
|
||||
|
||||
Originated at Anaconda, Inc. in 2022
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -32,6 +32,7 @@ Features
|
||||
- Added a `stderr` attribute of `py-repl` tags to route `sys.stderr` to a DOM element with the given ID. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||
- Resored the `output-mode` attribute of `py-repl` tags. If `output-mode` == 'append', the DOM element where output is printed is _not_ cleared before writing new results.
|
||||
- Load code from the attribute src of py-repl and preload it into the corresponding py-repl tag by use the attribute `str` in your `py-repl` tag([#1292](https://github.com/pyscript/pyscript/pull/1292))
|
||||
- <py-repl> elements now have a `getPySrc()` method, which returns the code inside the REPL as a string.([#1516](https://github.com/pyscript/pyscript/pull/1292))
|
||||
|
||||
### Plugins
|
||||
- Plugins may now implement the `beforePyReplExec()` and `afterPyReplExec()` hooks, which are called immediately before and after code in a `py-repl` tag is executed. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||
@@ -57,7 +58,7 @@ Docs
|
||||
|
||||
- Add docs for event handlers
|
||||
|
||||
2023.01.1
|
||||
2023.03.1
|
||||
=========
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ The `@when` decorator attaches the decorated function or Callable as an event ha
|
||||
|
||||
If the decorated function takes a single (non-self) argument, it will be passed the [Event object](https://developer.mozilla.org/en-US/docs/Web/API/Event) corresponding to the triggered event. If the function takes no (non-self) argument, it will be called with no arguments.
|
||||
|
||||
You will need to import `when` to get access to this feature:
|
||||
`from pyscript import when`
|
||||
|
||||
## Parameters
|
||||
|
||||
`event_type` - A string representing the event type to match against. This can be any of the [https://developer.mozilla.org/en-US/docs/Web/Events#event_listing](https://developer.mozilla.org/en-US/docs/Web/Events) that HTML elements may emit, as appropriate to their element type.
|
||||
|
||||
@@ -28,6 +28,14 @@ The ID of an element in the DOM that `stderr` will be written to. Defaults to No
|
||||
### `src`
|
||||
If a \<py-repl\> tag has the `src` attribute, during page initialization, resource in the `src` will be preloaded into the REPL. Please note that this will not run in advance. If there is content in the \<py-repl\> tag, it will be cleared and replaced with preloaded resource.
|
||||
|
||||
## Methods
|
||||
|
||||
The following are methods that can be called on the \<py-repl\> element, from within Python or JavaScript
|
||||
|
||||
### `getPySrc()`
|
||||
|
||||
Returns the current code contents of the REPL as a string.
|
||||
|
||||
## Examples
|
||||
|
||||
### `<py-repl>` element set to auto-generate
|
||||
|
||||
@@ -46,7 +46,7 @@ open an HTML by double-clicking it in your file explorer.
|
||||
|
||||
In some situations, your browser may forbid loading remote resources like `pyscript.js` and `pyscript.css` when you open an HTML file directly. When this is the case, you may see your Python code in the text of the webpage, and the [browser developer console](https://balsamiq.com/support/faqs/browserconsole/) may show an error like *"Cross origin requests are only supported for HTTP."* The fix for this is to use a [simple local server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Tools_and_setup/set_up_a_local_testing_server) to make your html file available to the browser.
|
||||
|
||||
If you have python installed on your system, you can use it's basic built-in server for this purpose via the command line. Change the current working directory of your terminal or command line to the folder where your HTML file is stored. From this folder, run `python -m http.server 8080 --bind 127.0.0.1` in your terminal or command line. With the server program running, point your browser to `http://localhost:8080` to view the contents of that folder. (If a file in that folder is called `index.html`, it will be displayed by default.)
|
||||
If you have python installed on your system, you can use its basic built-in server for this purpose via the command line. Change the current working directory of your terminal or command line to the folder where your HTML file is stored. From this folder, run `python -m http.server 8080 --bind 127.0.0.1` in your terminal or command line. With the server program running, point your browser to `http://localhost:8080` to view the contents of that folder. (If a file in that folder is called `index.html`, it will be displayed by default.)
|
||||
|
||||
## A more complex example
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Handling click events
|
||||
|
||||
This tutorial will show you how to use the `py-click` attribute to handle mouse clicks on elements on your page. The `py-click` attribute is a special attribute that allows you to specify a Python function that will be called when the element is clicked. There are many other events such as py-mouseover, py-focus, py-input, py-keyress etc, which can be used as well. They are listed here [Attr-to-Event](../reference/API/attr_to_event.html)
|
||||
This tutorial will show you how to use the `py-click` attribute to handle mouse clicks on elements on your page. The `py-click` attribute is a special attribute that allows you to specify a Python function that will be called when the element is clicked. There are many other events such as py-mouseover, py-focus, py-input, py-keyress etc, which can be used as well. They are listed here [Attr-to-Event](../reference/API/attr_to_event.md)
|
||||
|
||||
## Development setup
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/>
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
|
||||
<style>
|
||||
.loading {
|
||||
display: inline-block;
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"
|
||||
src="https://cdn.jsdelivr.net/npm/h3-js@3.7.2/dist/h3-js.umd.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -52,7 +52,7 @@
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"
|
||||
src="https://cdn.jsdelivr.net/npm/mapbox-gl@2.6.1/dist/mapbox-gl.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -68,7 +68,7 @@
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.js"
|
||||
src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/panel.js"
|
||||
></script>
|
||||
|
||||
<link
|
||||
@@ -77,11 +77,11 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
src="https://cdn.jsdelivr.net/npm/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -56,7 +56,7 @@
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
></script>
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
@@ -68,11 +68,11 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
src="https://cdn.jsdelivr.net/npm/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
@@ -44,7 +44,7 @@
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
></script>
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
@@ -56,11 +56,11 @@
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
href="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
|
||||
|
||||
@@ -10,7 +10,6 @@ canvas {
|
||||
height: 100%;
|
||||
}
|
||||
.header {
|
||||
/*top:45%;*/
|
||||
top: 45%;
|
||||
color: #dddddd;
|
||||
}
|
||||
|
||||
20
pyscriptjs/package-lock.json
generated
20
pyscriptjs/package-lock.json
generated
@@ -34,7 +34,7 @@
|
||||
"prettier": "2.7.1",
|
||||
"pyodide": "0.23.2",
|
||||
"synclink": "0.2.4",
|
||||
"ts-jest": "29.0.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"typescript": "5.0.4",
|
||||
"xterm": "^5.1.0"
|
||||
}
|
||||
@@ -5674,15 +5674,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-jest": {
|
||||
"version": "29.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz",
|
||||
"integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==",
|
||||
"version": "29.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz",
|
||||
"integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"bs-logger": "0.x",
|
||||
"fast-json-stable-stringify": "2.x",
|
||||
"jest-util": "^29.0.0",
|
||||
"json5": "^2.2.1",
|
||||
"json5": "^2.2.3",
|
||||
"lodash.memoize": "4.x",
|
||||
"make-error": "1.x",
|
||||
"semver": "7.x",
|
||||
@@ -5699,7 +5699,7 @@
|
||||
"@jest/types": "^29.0.0",
|
||||
"babel-jest": "^29.0.0",
|
||||
"jest": "^29.0.0",
|
||||
"typescript": ">=4.3"
|
||||
"typescript": ">=4.3 <6"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@babel/core": {
|
||||
@@ -10247,15 +10247,15 @@
|
||||
}
|
||||
},
|
||||
"ts-jest": {
|
||||
"version": "29.0.3",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz",
|
||||
"integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==",
|
||||
"version": "29.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz",
|
||||
"integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bs-logger": "0.x",
|
||||
"fast-json-stable-stringify": "2.x",
|
||||
"jest-util": "^29.0.0",
|
||||
"json5": "^2.2.1",
|
||||
"json5": "^2.2.3",
|
||||
"lodash.memoize": "4.x",
|
||||
"make-error": "1.x",
|
||||
"semver": "7.x",
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"prettier": "2.7.1",
|
||||
"pyodide": "0.23.2",
|
||||
"synclink": "0.2.4",
|
||||
"ts-jest": "29.0.3",
|
||||
"ts-jest": "29.1.0",
|
||||
"typescript": "5.0.4",
|
||||
"xterm": "^5.1.0"
|
||||
},
|
||||
|
||||
@@ -191,7 +191,7 @@ export function make_PyRepl(interpreter: InterpreterClient, app: PyScriptApp) {
|
||||
pyReplTag: this,
|
||||
result,
|
||||
});
|
||||
|
||||
await interpreter._remote.destroyIfProxy(result);
|
||||
this.autogenerateMaybe();
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp)
|
||||
await app.plugins.beforePyScriptExec({ interpreter, src, pyScriptTag });
|
||||
const { result } = await pyExec(interpreter, src, pyScriptTag);
|
||||
await app.plugins.afterPyScriptExec({ interpreter, src, pyScriptTag, result });
|
||||
await interpreter._remote.destroyIfProxy(result);
|
||||
} finally {
|
||||
releaseLock();
|
||||
app.decrementPendingTags();
|
||||
|
||||
@@ -71,6 +71,7 @@ export let runtime;
|
||||
export class PyScriptApp {
|
||||
config: AppConfig;
|
||||
interpreter: InterpreterClient;
|
||||
unwrapped_remote: RemoteInterpreter;
|
||||
readyPromise: Promise<void>;
|
||||
PyScript: ReturnType<typeof make_PyScript>;
|
||||
plugins: PluginManager;
|
||||
@@ -139,10 +140,10 @@ export class PyScriptApp {
|
||||
await this.plugins.configure(this.config);
|
||||
this.plugins.beforeLaunch(this.config);
|
||||
await this.loadInterpreter();
|
||||
interpreter = this.interpreter;
|
||||
interpreter = this.unwrapped_remote;
|
||||
// TODO: This is for backwards compatibility, it should be removed
|
||||
// when we finish the deprecation cycle of `runtime`
|
||||
runtime = this.interpreter;
|
||||
runtime = this.unwrapped_remote;
|
||||
}
|
||||
|
||||
// lifecycle (2)
|
||||
@@ -193,6 +194,7 @@ export class PyScriptApp {
|
||||
logger.info('Starting the interpreter in the main thread');
|
||||
// this is basically equivalent to worker_initialize()
|
||||
const remote_interpreter = new RemoteInterpreter(interpreter_cfg.src);
|
||||
this.unwrapped_remote = remote_interpreter;
|
||||
const { port1, port2 } = new Synclink.FakeMessageChannel() as unknown as MessageChannel;
|
||||
port1.start();
|
||||
port2.start();
|
||||
|
||||
@@ -4,7 +4,7 @@ from contextlib import contextmanager
|
||||
|
||||
from js import Object
|
||||
from pyodide.code import eval_code
|
||||
from pyodide.ffi import JsProxy
|
||||
from pyodide.ffi import JsProxy, to_js
|
||||
|
||||
from ._event_loop import (
|
||||
defer_user_asyncio,
|
||||
@@ -103,7 +103,7 @@ def run_pyscript(code: str, id: str = None) -> JsProxy:
|
||||
with display_target(id), defer_user_asyncio():
|
||||
result = eval_code(code, globals=__main__.__dict__)
|
||||
|
||||
return Object.new(result=result)
|
||||
return to_js({"result": result}, depth=1, dict_converter=Object.fromEntries)
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
||||
@@ -274,6 +274,20 @@ export class RemoteInterpreter extends Object {
|
||||
this.FS.writeFile(path, data, { canOwn: true });
|
||||
}
|
||||
|
||||
destroyIfProxy(px: any): void {
|
||||
if (this.interface.ffi) {
|
||||
// Pyodide 0.23
|
||||
if (px instanceof this.interface.ffi.PyProxy) {
|
||||
px.destroy();
|
||||
}
|
||||
} else {
|
||||
// older Pyodide
|
||||
if (this.interface.isPyProxy(px)) {
|
||||
px.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delegates clearing importlib's module path
|
||||
* caches to the underlying interface
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
* circular imports.
|
||||
*/
|
||||
|
||||
export const version = '2022.12.1.dev';
|
||||
export const version = '2023.05.1.dev';
|
||||
|
||||
@@ -293,7 +293,7 @@ class TestBasic(PyScriptTest):
|
||||
)
|
||||
assert (
|
||||
re.match(
|
||||
r"version_info\(year=\d{4}, month=\d{2}, "
|
||||
r"version_info\(year=\d{4}, month=\d{1,2}, "
|
||||
r"minor=\d+, releaselevel='([a-zA-Z0-9]+)?'\)",
|
||||
self.console.log.lines[-1],
|
||||
)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from .support import PyScriptTest
|
||||
from .support import PyScriptTest, skip_worker
|
||||
|
||||
|
||||
class TestInterpreterAccess(PyScriptTest):
|
||||
"""Test accessing Python objects from JS via pyscript.interpreter"""
|
||||
|
||||
@skip_worker("WONTFIX: used without synclink to avoid awaits")
|
||||
def test_interpreter_python_access(self):
|
||||
self.pyscript_run(
|
||||
"""
|
||||
@@ -17,9 +18,9 @@ class TestInterpreterAccess(PyScriptTest):
|
||||
|
||||
self.run_js(
|
||||
"""
|
||||
const x = await pyscript.interpreter.globals.get('x');
|
||||
const py_func = await pyscript.interpreter.globals.get('py_func');
|
||||
const py_func_res = await py_func();
|
||||
const x = pyscript.interpreter.globals.get('x');
|
||||
const py_func = pyscript.interpreter.globals.get('py_func');
|
||||
const py_func_res = py_func();
|
||||
console.log(`x is ${x}`);
|
||||
console.log(`py_func() returns ${py_func_res}`);
|
||||
"""
|
||||
@@ -29,13 +30,14 @@ class TestInterpreterAccess(PyScriptTest):
|
||||
"py_func() returns 2",
|
||||
]
|
||||
|
||||
@skip_worker("WONTFIX: used without synclink")
|
||||
def test_interpreter_script_execution(self):
|
||||
"""Test running Python code from js via pyscript.interpreter"""
|
||||
self.pyscript_run("")
|
||||
|
||||
self.run_js(
|
||||
"""
|
||||
const interface = pyscript.interpreter._remote.interface;
|
||||
const interface = pyscript.interpreter.interface;
|
||||
await interface.runPython('print("Interpreter Ran This")');
|
||||
"""
|
||||
)
|
||||
@@ -46,13 +48,14 @@ class TestInterpreterAccess(PyScriptTest):
|
||||
py_terminal = self.page.wait_for_selector("py-terminal")
|
||||
assert py_terminal.text_content() == expected_message
|
||||
|
||||
@skip_worker("WONTFIX: used without synclink")
|
||||
def test_backward_compatibility_runtime_script_execution(self):
|
||||
"""Test running Python code from js via pyscript.runtime"""
|
||||
self.pyscript_run("")
|
||||
|
||||
self.run_js(
|
||||
"""
|
||||
const interface = pyscript.runtime._remote.interpreter;
|
||||
const interface = pyscript.runtime.interpreter;
|
||||
await interface.runPython('print("Interpreter Ran This")');
|
||||
"""
|
||||
)
|
||||
@@ -63,6 +66,7 @@ class TestInterpreterAccess(PyScriptTest):
|
||||
py_terminal = self.page.wait_for_selector("py-terminal")
|
||||
assert py_terminal.text_content() == expected_message
|
||||
|
||||
@skip_worker("WONTFIX: used without synclink to avoid awaits")
|
||||
def test_backward_compatibility_runtime_python_access(self):
|
||||
"""Test accessing Python objects from JS via pyscript.runtime"""
|
||||
self.pyscript_run(
|
||||
@@ -77,9 +81,9 @@ class TestInterpreterAccess(PyScriptTest):
|
||||
|
||||
self.run_js(
|
||||
"""
|
||||
const x = await pyscript.interpreter.globals.get('x');
|
||||
const py_func = await pyscript.interpreter.globals.get('py_func');
|
||||
const py_func_res = await py_func();
|
||||
const x = pyscript.runtime.globals.get('x');
|
||||
const py_func = pyscript.runtime.globals.get('py_func');
|
||||
const py_func_res = py_func();
|
||||
console.log(`x is ${x}`);
|
||||
console.log(`py_func() returns ${py_func_res}`);
|
||||
"""
|
||||
|
||||
@@ -595,6 +595,26 @@ class TestPyRepl(PyScriptTest):
|
||||
alert_banner = self.page.wait_for_selector(".alert-banner")
|
||||
assert expected_alert_banner_msg in alert_banner.inner_text()
|
||||
|
||||
def test_getPySrc_Contents(self):
|
||||
"""Test that an empty REPL returns an empty string as src, and that the typed contents
|
||||
are returned as the source
|
||||
"""
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-repl>
|
||||
</py-repl>
|
||||
"""
|
||||
)
|
||||
py_repl = self.page.locator("py-repl")
|
||||
src = py_repl.evaluate("node => node.getPySrc()")
|
||||
assert src == ""
|
||||
assert type(src) == str
|
||||
|
||||
py_repl.focus()
|
||||
py_repl.type("Hello, world!")
|
||||
src = py_repl.evaluate("node => node.getPySrc()")
|
||||
assert src == "Hello, world!"
|
||||
|
||||
def test_repl_load_content_from_src(self):
|
||||
self.writefile("loadReplSrc1.py", "print('1')")
|
||||
self.pyscript_run(
|
||||
@@ -654,3 +674,47 @@ class TestPyRepl(PyScriptTest):
|
||||
"Are your filename and path correct?"
|
||||
)
|
||||
assert self.console.error.lines[-1] == errorMsg
|
||||
|
||||
@skip_worker("dont-care")
|
||||
def test_repl_results(self):
|
||||
self.writefile("loadReplSrc2.py", "2")
|
||||
self.writefile("loadReplSrc3.py", "print('3')")
|
||||
|
||||
self.pyscript_run(
|
||||
"""
|
||||
<py-repl id="py-repl1" output="out1">
|
||||
42
|
||||
</py-repl>
|
||||
<div id="out1"></div>
|
||||
|
||||
<py-repl id="py-repl2" output="out2">
|
||||
c = [1,2,3]
|
||||
from sys import getrefcount
|
||||
# should print 2: 1 from the reference c and 1 since getrefcount
|
||||
# holds a reference to its argument
|
||||
print(getrefcount(c))
|
||||
c
|
||||
</py-repl>
|
||||
<div id="out2"></div>
|
||||
|
||||
<py-repl id="py-repl3" output="out3">
|
||||
# should also print 2: if it prints 3 that would mean that c was not properly
|
||||
# released by py-repl
|
||||
getrefcount(c)
|
||||
</py-repl>
|
||||
<div id="out3"></div>
|
||||
"""
|
||||
)
|
||||
py_repl1 = self.page.locator("py-repl#py-repl1")
|
||||
py_repl1.locator("button").click()
|
||||
|
||||
py_repl2 = self.page.locator("py-repl#py-repl2")
|
||||
py_repl2.locator("button").click()
|
||||
|
||||
py_repl3 = self.page.locator("py-repl#py-repl3")
|
||||
py_repl3.locator("button").click()
|
||||
|
||||
assert self.page.wait_for_selector("#out1").inner_text() == "42"
|
||||
assert self.page.wait_for_selector("#out2").inner_text() == "2\n\n[1, 2, 3]"
|
||||
# Check that c was released
|
||||
assert self.page.wait_for_selector("#out3").inner_text() == "2"
|
||||
|
||||
Reference in New Issue
Block a user