Compare commits

...

24 Commits

Author SHA1 Message Date
Ted Patrick
52bd64c80d Update CI tests (#1719) 2023-09-15 12:12:33 -05:00
Ted Patrick
5c90b19707 Update tests for CI on next (#1718) 2023-09-15 11:26:00 -05:00
Ted Patrick
eb0d1ff740 Update CI tests on Next (#1717) 2023-09-15 10:59:35 -05:00
Ted Patrick
ca8a22e5db Turn on CI tests for next (#1716) 2023-09-15 10:44:54 -05:00
Ted Patrick
63fab105b2 Fix path variable (#1710)
* Fix sed delimiter for html generation

* Fix [[PATH]] to _PATH

* Fix sed command
2023-09-14 13:36:07 -05:00
Ted Patrick
71ca7753e1 Fix sed delimiter for html generation (#1707) 2023-09-14 12:58:08 -05:00
Ted Patrick
6dced95954 Generate HTML for snapshot (#1706)
* Generate HTML for snapshot

* format
2023-09-14 12:45:33 -05:00
Ted Patrick
ffd9e6f4d0 Next Build Snapshot (#1703) 2023-09-14 11:04:13 -05:00
Kees Hink
b9c3eb6442 Fix minor spelling error in getting-started.md (#1671)
it's -> its
2023-09-04 07:00:14 -07:00
Shubhashis
be79f70f66 Fix #1577: Change script sources that include Cross-Origin Resource Policy (#1627) 2023-08-09 10:35:57 +02:00
Fabio Pliger
71e2555213 fix LICENSE info around dates and project owner (#1606)
* fix info around dates and project owner

* add originated at Anaconda, Inc to license

* add . on Inc

---------

Co-authored-by: Fabio Pliger <fpliger@anaconda.com>
2023-08-08 08:21:50 -07:00
Aapo Soukkio
1b9cb562ec Remove unused comment (#1604) 2023-07-20 11:34:30 -05:00
Neon22
55cf6b9e4c Update py-click.md (#1553)
used wrong file extension so link was missing
2023-06-22 08:12:11 -05:00
Neon22
9a70943a36 Update when.md (#1554)
* Update when.md: include info on importing when to get access

---------

Co-authored-by: Jeff Glass <glass.jeffrey@gmail.com>
2023-06-21 17:56:47 -05:00
Jeff Glass
7765a629c7 Update verison (#1552)
* Update verison

* Fix test to account for single-digit months
2023-06-21 06:23:26 -05:00
Ted Patrick
848d77b1c2 Same steps as build-unstable (#1550)
* Same steps as build-unstable

* make setup
2023-06-20 13:01:56 -05:00
Ted Patrick
e4e8f2edae Fix build unstable to run on ubuntu-latest-8core (#1549)
* Fix build unstable to run on ubuntu-latest-8core

* ubuntu-latest to ubuntu-latest-8core
2023-06-20 12:17:08 -05:00
Jeff Glass
ea9bdcc961 Fix previous changlog date (#1546)
* Previous version updated from 2023.01.1 to 2023.03.1
2023-06-20 08:08:24 -05:00
Hood Chatham
79ad39260e Fix lifetime for pyExec results (#1540)
Currently if the result from pyExec is a PyProxy, it gets destroyed.
This switches to using `to_js` to handle this (it is better to use
than an explicit `create_proxy` since it automatically decides whether
to create a proxy or not).

I also added `destroyIfProxy` which checks if something is a `PyProxy`
and then destroys it. Each use of `pyExec` needs to call `destroyIfProxy`
on the result after it is done with it.
2023-06-15 11:51:36 -07:00
Jeff Glass
f4936316ab Make getPySrc() a Documented Feature (#1516)
* Add documentation and tests (no real code changes)

* Add Changelog
2023-06-14 12:56:57 -05:00
Madhur Tandon
8879187e6a fix access to interpreter globals without awaits (#1529) 2023-06-14 19:42:38 +05:30
Fábio Rosado
258b80a6a5 Add step to install next deps and run test (#1528) 2023-06-14 14:12:42 +01:00
Fábio Rosado
a108e6e97e Add workflow to run next CI (#1527)
* Add workflow to run next CI

* Don't actually replace the whole unstable

* Unstable name

* Add empty line

* Make CI run on changes to workflow build-unstable-next

* Rename workflow for test-next instead of build

* Update path to use the next test-next

* Add pyscript.core to path
2023-06-13 15:06:19 +01:00
Peter W
dfef7eda3b Use 8-core, 32GB runners for testing and faster builds (#1524)
* swap 3 jobs to 8 core runners

* 16 core test

* test 4 core

* back to 8 core
2023-06-12 15:25:58 -05:00
33 changed files with 370 additions and 67 deletions

View File

@@ -20,7 +20,7 @@ on:
jobs: jobs:
BuildAndTest: BuildAndTest:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
defaults: defaults:
run: run:
working-directory: pyscriptjs working-directory: pyscriptjs
@@ -85,7 +85,7 @@ jobs:
path: pyscriptjs/test_results path: pyscriptjs/test_results
if-no-files-found: error if-no-files-found: error
eslint: eslint:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
defaults: defaults:
run: run:
working-directory: pyscriptjs working-directory: pyscriptjs
@@ -118,7 +118,7 @@ jobs:
run: npx eslint src -c .eslintrc.js run: npx eslint src -c .eslintrc.js
Deploy: Deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
needs: BuildAndTest needs: BuildAndTest
if: github.ref == 'refs/heads/main' # Only deploy on merge into main if: github.ref == 'refs/heads/main' # Only deploy on merge into main
permissions: permissions:

View File

@@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write

View File

@@ -19,7 +19,7 @@ concurrency:
jobs: jobs:
build: build:
if: github.repository_owner == 'pyscript' if: github.repository_owner == 'pyscript'
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write

View File

@@ -9,7 +9,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write

View 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 }}/

View File

@@ -15,7 +15,7 @@ defaults:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
@@ -44,8 +44,20 @@ jobs:
- name: Setup Environment - name: Setup Environment
run: make setup run: make setup
- name: Build and Test - name: Build
run: make test 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 - name: Zip build folder
run: zip -r -q ./build.zip ./build run: zip -r -q ./build.zip ./build

View File

@@ -14,7 +14,7 @@ defaults:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write
@@ -46,8 +46,20 @@ jobs:
- name: Setup Environment - name: Setup Environment
run: make setup run: make setup
- name: Build and Test - name: Build
run: make test 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 # Upload to S3
- name: Configure AWS credentials - name: Configure AWS credentials

View File

@@ -11,7 +11,7 @@ on:
jobs: jobs:
snapshot: snapshot:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write

View File

@@ -6,7 +6,7 @@ on:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
permissions: permissions:
contents: read contents: read
id-token: write id-token: write

119
.github/workflows/test-next.yml vendored Normal file
View 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

View File

@@ -6,7 +6,7 @@ on:
- completed - completed
jobs: jobs:
report: report:
runs-on: ubuntu-latest runs-on: ubuntu-latest-8core
steps: steps:
- uses: dorny/test-reporter@v1.6.0 - uses: dorny/test-reporter@v1.6.0
with: with:

View File

@@ -186,7 +186,9 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@@ -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)) - 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. - 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)) - 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))
- &lt;py-repl&gt; 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
- 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)) - 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 - Add docs for event handlers
2023.01.1 2023.03.1
========= =========

View File

@@ -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. 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 ## 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. `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.

View File

@@ -28,6 +28,14 @@ The ID of an element in the DOM that `stderr` will be written to. Defaults to No
### `src` ### `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. 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 ## Examples
### `<py-repl>` element set to auto-generate ### `<py-repl>` element set to auto-generate

View File

@@ -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. 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 ## A more complex example

View File

@@ -1,6 +1,6 @@
# Handling click events # 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 ## Development setup

View File

@@ -10,7 +10,7 @@
/> />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" /> <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> <style>
.loading { .loading {
display: inline-block; display: inline-block;

View File

@@ -17,18 +17,18 @@
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
<script <script
type="text/javascript" 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>
<script <script
type="text/javascript" type="text/javascript"
@@ -52,7 +52,7 @@
></script> ></script>
<script <script
type="text/javascript" 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>
<script <script
type="text/javascript" type="text/javascript"
@@ -68,7 +68,7 @@
></script> ></script>
<script <script
type="text/javascript" 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> ></script>
<link <link
@@ -77,11 +77,11 @@
/> />
<link <link
rel="stylesheet" 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 <link
rel="stylesheet" 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> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>

View File

@@ -17,12 +17,12 @@
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
@@ -40,7 +40,7 @@
></script> ></script>
<script <script
type="text/javascript" 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>
<script <script
type="text/javascript" type="text/javascript"
@@ -56,7 +56,7 @@
></script> ></script>
<script <script
type="text/javascript" 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>
<script type="text/javascript"> <script type="text/javascript">
Bokeh.set_log_level("info"); Bokeh.set_log_level("info");
@@ -68,11 +68,11 @@
/> />
<link <link
rel="stylesheet" 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 <link
rel="stylesheet" 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> <style>

View File

@@ -17,18 +17,18 @@
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
<link <link
rel="stylesheet" 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" type="text/css"
/> />
<script <script
type="text/javascript" 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>
<script <script
type="text/javascript" type="text/javascript"
@@ -44,7 +44,7 @@
></script> ></script>
<script <script
type="text/javascript" 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>
<script type="text/javascript"> <script type="text/javascript">
Bokeh.set_log_level("info"); Bokeh.set_log_level("info");
@@ -56,11 +56,11 @@
/> />
<link <link
rel="stylesheet" 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 <link
rel="stylesheet" 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> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>

View File

@@ -10,7 +10,6 @@ canvas {
height: 100%; height: 100%;
} }
.header { .header {
/*top:45%;*/
top: 45%; top: 45%;
color: #dddddd; color: #dddddd;
} }

View File

@@ -34,7 +34,7 @@
"prettier": "2.7.1", "prettier": "2.7.1",
"pyodide": "0.23.2", "pyodide": "0.23.2",
"synclink": "0.2.4", "synclink": "0.2.4",
"ts-jest": "29.0.3", "ts-jest": "29.1.0",
"typescript": "5.0.4", "typescript": "5.0.4",
"xterm": "^5.1.0" "xterm": "^5.1.0"
} }
@@ -5674,15 +5674,15 @@
} }
}, },
"node_modules/ts-jest": { "node_modules/ts-jest": {
"version": "29.0.3", "version": "29.1.0",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz",
"integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"bs-logger": "0.x", "bs-logger": "0.x",
"fast-json-stable-stringify": "2.x", "fast-json-stable-stringify": "2.x",
"jest-util": "^29.0.0", "jest-util": "^29.0.0",
"json5": "^2.2.1", "json5": "^2.2.3",
"lodash.memoize": "4.x", "lodash.memoize": "4.x",
"make-error": "1.x", "make-error": "1.x",
"semver": "7.x", "semver": "7.x",
@@ -5699,7 +5699,7 @@
"@jest/types": "^29.0.0", "@jest/types": "^29.0.0",
"babel-jest": "^29.0.0", "babel-jest": "^29.0.0",
"jest": "^29.0.0", "jest": "^29.0.0",
"typescript": ">=4.3" "typescript": ">=4.3 <6"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@babel/core": { "@babel/core": {
@@ -10247,15 +10247,15 @@
} }
}, },
"ts-jest": { "ts-jest": {
"version": "29.0.3", "version": "29.1.0",
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz",
"integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==",
"dev": true, "dev": true,
"requires": { "requires": {
"bs-logger": "0.x", "bs-logger": "0.x",
"fast-json-stable-stringify": "2.x", "fast-json-stable-stringify": "2.x",
"jest-util": "^29.0.0", "jest-util": "^29.0.0",
"json5": "^2.2.1", "json5": "^2.2.3",
"lodash.memoize": "4.x", "lodash.memoize": "4.x",
"make-error": "1.x", "make-error": "1.x",
"semver": "7.x", "semver": "7.x",

View File

@@ -36,7 +36,7 @@
"prettier": "2.7.1", "prettier": "2.7.1",
"pyodide": "0.23.2", "pyodide": "0.23.2",
"synclink": "0.2.4", "synclink": "0.2.4",
"ts-jest": "29.0.3", "ts-jest": "29.1.0",
"typescript": "5.0.4", "typescript": "5.0.4",
"xterm": "^5.1.0" "xterm": "^5.1.0"
}, },

View File

@@ -191,7 +191,7 @@ export function make_PyRepl(interpreter: InterpreterClient, app: PyScriptApp) {
pyReplTag: this, pyReplTag: this,
result, result,
}); });
await interpreter._remote.destroyIfProxy(result);
this.autogenerateMaybe(); this.autogenerateMaybe();
} }

View File

@@ -36,6 +36,7 @@ export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp)
await app.plugins.beforePyScriptExec({ interpreter, src, pyScriptTag }); await app.plugins.beforePyScriptExec({ interpreter, src, pyScriptTag });
const { result } = await pyExec(interpreter, src, pyScriptTag); const { result } = await pyExec(interpreter, src, pyScriptTag);
await app.plugins.afterPyScriptExec({ interpreter, src, pyScriptTag, result }); await app.plugins.afterPyScriptExec({ interpreter, src, pyScriptTag, result });
await interpreter._remote.destroyIfProxy(result);
} finally { } finally {
releaseLock(); releaseLock();
app.decrementPendingTags(); app.decrementPendingTags();

View File

@@ -71,6 +71,7 @@ export let runtime;
export class PyScriptApp { export class PyScriptApp {
config: AppConfig; config: AppConfig;
interpreter: InterpreterClient; interpreter: InterpreterClient;
unwrapped_remote: RemoteInterpreter;
readyPromise: Promise<void>; readyPromise: Promise<void>;
PyScript: ReturnType<typeof make_PyScript>; PyScript: ReturnType<typeof make_PyScript>;
plugins: PluginManager; plugins: PluginManager;
@@ -139,10 +140,10 @@ export class PyScriptApp {
await this.plugins.configure(this.config); await this.plugins.configure(this.config);
this.plugins.beforeLaunch(this.config); this.plugins.beforeLaunch(this.config);
await this.loadInterpreter(); await this.loadInterpreter();
interpreter = this.interpreter; interpreter = this.unwrapped_remote;
// TODO: This is for backwards compatibility, it should be removed // TODO: This is for backwards compatibility, it should be removed
// when we finish the deprecation cycle of `runtime` // when we finish the deprecation cycle of `runtime`
runtime = this.interpreter; runtime = this.unwrapped_remote;
} }
// lifecycle (2) // lifecycle (2)
@@ -193,6 +194,7 @@ export class PyScriptApp {
logger.info('Starting the interpreter in the main thread'); logger.info('Starting the interpreter in the main thread');
// this is basically equivalent to worker_initialize() // this is basically equivalent to worker_initialize()
const remote_interpreter = new RemoteInterpreter(interpreter_cfg.src); const remote_interpreter = new RemoteInterpreter(interpreter_cfg.src);
this.unwrapped_remote = remote_interpreter;
const { port1, port2 } = new Synclink.FakeMessageChannel() as unknown as MessageChannel; const { port1, port2 } = new Synclink.FakeMessageChannel() as unknown as MessageChannel;
port1.start(); port1.start();
port2.start(); port2.start();

View File

@@ -4,7 +4,7 @@ from contextlib import contextmanager
from js import Object from js import Object
from pyodide.code import eval_code from pyodide.code import eval_code
from pyodide.ffi import JsProxy from pyodide.ffi import JsProxy, to_js
from ._event_loop import ( from ._event_loop import (
defer_user_asyncio, defer_user_asyncio,
@@ -103,7 +103,7 @@ def run_pyscript(code: str, id: str = None) -> JsProxy:
with display_target(id), defer_user_asyncio(): with display_target(id), defer_user_asyncio():
result = eval_code(code, globals=__main__.__dict__) result = eval_code(code, globals=__main__.__dict__)
return Object.new(result=result) return to_js({"result": result}, depth=1, dict_converter=Object.fromEntries)
__all__ = [ __all__ = [

View File

@@ -274,6 +274,20 @@ export class RemoteInterpreter extends Object {
this.FS.writeFile(path, data, { canOwn: true }); 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 * delegates clearing importlib's module path
* caches to the underlying interface * caches to the underlying interface

View File

@@ -7,4 +7,4 @@
* circular imports. * circular imports.
*/ */
export const version = '2022.12.1.dev'; export const version = '2023.05.1.dev';

View File

@@ -293,7 +293,7 @@ class TestBasic(PyScriptTest):
) )
assert ( assert (
re.match( 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]+)?'\)", r"minor=\d+, releaselevel='([a-zA-Z0-9]+)?'\)",
self.console.log.lines[-1], self.console.log.lines[-1],
) )

View File

@@ -1,9 +1,10 @@
from .support import PyScriptTest from .support import PyScriptTest, skip_worker
class TestInterpreterAccess(PyScriptTest): class TestInterpreterAccess(PyScriptTest):
"""Test accessing Python objects from JS via pyscript.interpreter""" """Test accessing Python objects from JS via pyscript.interpreter"""
@skip_worker("WONTFIX: used without synclink to avoid awaits")
def test_interpreter_python_access(self): def test_interpreter_python_access(self):
self.pyscript_run( self.pyscript_run(
""" """
@@ -17,9 +18,9 @@ class TestInterpreterAccess(PyScriptTest):
self.run_js( self.run_js(
""" """
const x = await pyscript.interpreter.globals.get('x'); const x = pyscript.interpreter.globals.get('x');
const py_func = await pyscript.interpreter.globals.get('py_func'); const py_func = pyscript.interpreter.globals.get('py_func');
const py_func_res = await py_func(); const py_func_res = py_func();
console.log(`x is ${x}`); console.log(`x is ${x}`);
console.log(`py_func() returns ${py_func_res}`); console.log(`py_func() returns ${py_func_res}`);
""" """
@@ -29,13 +30,14 @@ class TestInterpreterAccess(PyScriptTest):
"py_func() returns 2", "py_func() returns 2",
] ]
@skip_worker("WONTFIX: used without synclink")
def test_interpreter_script_execution(self): def test_interpreter_script_execution(self):
"""Test running Python code from js via pyscript.interpreter""" """Test running Python code from js via pyscript.interpreter"""
self.pyscript_run("") self.pyscript_run("")
self.run_js( self.run_js(
""" """
const interface = pyscript.interpreter._remote.interface; const interface = pyscript.interpreter.interface;
await interface.runPython('print("Interpreter Ran This")'); await interface.runPython('print("Interpreter Ran This")');
""" """
) )
@@ -46,13 +48,14 @@ class TestInterpreterAccess(PyScriptTest):
py_terminal = self.page.wait_for_selector("py-terminal") py_terminal = self.page.wait_for_selector("py-terminal")
assert py_terminal.text_content() == expected_message assert py_terminal.text_content() == expected_message
@skip_worker("WONTFIX: used without synclink")
def test_backward_compatibility_runtime_script_execution(self): def test_backward_compatibility_runtime_script_execution(self):
"""Test running Python code from js via pyscript.runtime""" """Test running Python code from js via pyscript.runtime"""
self.pyscript_run("") self.pyscript_run("")
self.run_js( self.run_js(
""" """
const interface = pyscript.runtime._remote.interpreter; const interface = pyscript.runtime.interpreter;
await interface.runPython('print("Interpreter Ran This")'); await interface.runPython('print("Interpreter Ran This")');
""" """
) )
@@ -63,6 +66,7 @@ class TestInterpreterAccess(PyScriptTest):
py_terminal = self.page.wait_for_selector("py-terminal") py_terminal = self.page.wait_for_selector("py-terminal")
assert py_terminal.text_content() == expected_message assert py_terminal.text_content() == expected_message
@skip_worker("WONTFIX: used without synclink to avoid awaits")
def test_backward_compatibility_runtime_python_access(self): def test_backward_compatibility_runtime_python_access(self):
"""Test accessing Python objects from JS via pyscript.runtime""" """Test accessing Python objects from JS via pyscript.runtime"""
self.pyscript_run( self.pyscript_run(
@@ -77,9 +81,9 @@ class TestInterpreterAccess(PyScriptTest):
self.run_js( self.run_js(
""" """
const x = await pyscript.interpreter.globals.get('x'); const x = pyscript.runtime.globals.get('x');
const py_func = await pyscript.interpreter.globals.get('py_func'); const py_func = pyscript.runtime.globals.get('py_func');
const py_func_res = await py_func(); const py_func_res = py_func();
console.log(`x is ${x}`); console.log(`x is ${x}`);
console.log(`py_func() returns ${py_func_res}`); console.log(`py_func() returns ${py_func_res}`);
""" """

View File

@@ -595,6 +595,26 @@ class TestPyRepl(PyScriptTest):
alert_banner = self.page.wait_for_selector(".alert-banner") alert_banner = self.page.wait_for_selector(".alert-banner")
assert expected_alert_banner_msg in alert_banner.inner_text() 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): def test_repl_load_content_from_src(self):
self.writefile("loadReplSrc1.py", "print('1')") self.writefile("loadReplSrc1.py", "print('1')")
self.pyscript_run( self.pyscript_run(
@@ -654,3 +674,47 @@ class TestPyRepl(PyScriptTest):
"Are your filename and path correct?" "Are your filename and path correct?"
) )
assert self.console.error.lines[-1] == errorMsg 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"