Add docs for py-event* (#1300)

* Fix markdown
Add event-handlers.md

* Address changes from Jeff + Antonion and add it to index

* how tos don't exist anymore theyre now guides

* Restore p on contributing

* Adding changelog

* Aadd space

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: Carmelo <carmelofiorello@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Mariana Meireles
2023-03-23 17:57:49 +01:00
committed by GitHub
parent a62aba83a0
commit 543a27271f
5 changed files with 211 additions and 8 deletions

View File

@@ -4,14 +4,21 @@ Thank you for wanting to contribute to the PyScript project!
## Table of contents
- [Contributing to PyScript](#contributing-to-pyscript)
- [Table of contents](#table-of-contents)
- [Code of Conduct](#code-of-conduct)
- [Contributing](#contributing)
- [Reporting bugs](#reporting-bugs)
- [Creating useful issues](#creating-useful-issues)
- [Reporting security issues](#reporting-security-issues)
- [Asking questions](#asking-questions)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [Developing](#developing)
- [Rebasing changes](#rebasing-changes)
- [Building the docs](#building-the-docs)
- [Places to start](#places-to-start)
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
- [Submitting a change](#submitting-a-change)
- [License terms for contributions](#license-terms-for-contributions)
- [Becoming a maintainer](#becoming-a-maintainer)
- [Trademarks](#trademarks)
@@ -43,7 +50,7 @@ If you have questions about the project, using PyScript, or anything else, pleas
## Places to start
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions:
- **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
- **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!

View File

@@ -35,7 +35,12 @@ Enhancements
- migrated from *rollup* to *esbuild* to create artifacts
- updated `@codemirror` dependency to its latest
2023.03.1
Docs
----
- Add docs for event handlers
2023.01.1
=========

View File

@@ -0,0 +1,179 @@
# Event handlers in PyScript
PyScript offer two ways to subscribe to Javascript event handlers:
## Subscribe to event with `py-*` attributes
The value of the attribute contains python code which will be executed when the event is fired. A very common pattern is to call a function which does further work, for example:
```html
<button id="noParam" py-click="say_hello_no_param()">
No Event - No Params py-click
</button>
<button id="withParam" py-click="say_hello_with_param('World')">
No Event - With Params py-click
</button>
```
```python
<py-script>
def say_hello_no_param():
print("Hello!")
def say_hello_with_param(name):
print("Hello " + name + "!")
</py-script>
```
Note that py-\* attributes need a _function call_
Supported py-\* attributes can be seen in the [PyScript API reference](<[../api-reference.md](https://github.com/pyscript/pyscript/blob/66b57bf812dcc472ed6ffee075ace5ced89bbc7c/pyscriptjs/src/components/pyscript.ts#L119-L260)>).
## Subscribe to event with `addEventListener`
You can also subscribe to an event using the `addEventListener` method of the DOM element. This is useful if you want to pass event object to the event handler.
```html
<button id="two">add_event_listener passes event</button>
```
```python
<py-script>
from js import console, document
from pyodide.ffi.wrappers import add_event_listener
def hello_args(*args):
console.log(f"Hi! I got some args! {args}")
add_event_listener(document.getElementById("two"), "click", hello_args)
</py-script>
```
or using the `addEventListener` method of the DOM element:
```html
<button id="three">add_event_listener passes event</button>
```
```python
<py-script>
from js import console, document
from pyodide.ffi import create_proxy
def hello_args(*args):
console.log(f"Hi! I got some args! {args}")
document.getElementById("three").addEventListener("click", create_proxy(hello_args))
</py-script>
```
or using the PyScript Element class:
```html
<button id="four">add_event_listener passes event</button>
```
```python
<py-script>
from js import console
from pyodide.ffi import create_proxy
def hello_args(*args):
console.log(f"Hi! I got some args! {args}")
Element("four").element.addEventListener("click", create_proxy(hello_args))
</py-script>
```
## JavaScript to PyScript and From PyScript to JavaScript
If you're wondering about how to pass objects from JavaScript to PyScript and/or the other way around head over to the [Passing Objects](passing-objects.md) page.
### Exporting all Global Python Objects
We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object:
```python
<py-script>
from js import createObject
from pyodide.ffi import create_proxy
createObject(create_proxy(globals()), "pyodideGlobals")
</py-script>
```
This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`.
(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a `<script>` tag, since that tag will evaluate before any PyScript has a chance to. We need to delay accessing the Python variable in JavaScript until after the Python code has a chance to run. The following example uses a button with `id="do-math"` to achieve this, but any method would be valid.)
```python
<py-script>
# create some Python objects:
symbols = {'pi': 3.1415926, 'e': 2.7182818}
def rough_exponential(x):
return symbols['e']**x
class Circle():
def __init__(self, radius):
self.radius = radius
@property
def area:
return symbols['pi'] * self.radius**2
</py-script>
```
```html
<input type="button" value="Log Python Variables" id="do-mmath" />
<script>
document.getElementById("do-math").addEventListener("click", () => {
const exp = pyodideGlobals.get("rough_exponential");
console.log("e squared is about ${exp(2)}");
const c = pyodideGlobals.get("Circle")(4);
console.log("The area of c is ${c.area}");
});
</script>
```
### Exporting Individual Python Objects
We can also export individual Python objects to the JavaScript global scope if we wish.
(As above, the following example uses a button to delay the execution of the `<script>` until after the PyScript has run.)
```python
<py-script>
import js
from pyodide.ffi import create_proxy
# Create 3 python objects
language = "Python 3"
animals = ['dog', 'cat', 'bird']
multiply3 = lambda a, b, c: a * b * c
# js object can be named the same as Python objects...
js.createObject(language, "language")
# ...but don't have to be
js.createObject(create_proxy(animals), "animals_from_py")
# functions are objects too, in both Python and Javascript
js.createObject(create_proxy(multiply3), "multiply")
</py-script>
```
```html
<input type="button" value="Log Python Variables" id="log-python-variables" />
<script>
document
.getElementById("log-python-variables")
.addEventListener("click", () => {
console.log(`Nice job using ${language}`);
for (const animal of animals_from_py) {
console.log(`Do you like ${animal}s? `);
}
console.log(`2 times 3 times 4 is ${multiply(2, 3, 4)}`);
});
</script>
```

View File

@@ -35,7 +35,8 @@ for dealing with the response, such as `json()` or `status`. See the
[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse)
for more information.
# Example
## Example
We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`.
First we write a helper function in pure Python that makes a request and returns the response. This function
makes it easier to make specific types of requests with the most common parameters.
@@ -70,6 +71,7 @@ async def request(url: str, method: str = "GET", body: Optional[str] = None,
response = await pyfetch(url, **kwargs)
return response
```
This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function,
so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools.
The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore,
@@ -160,7 +162,8 @@ concluding html code.
The very first thing to notice is the `py-config` tag. This tag is used to import Python files into the `PyScript`.
In this case, we are importing the `request.py` file, which contains the `request` function we wrote above.
### `py-script` tag for making async HTTP requests.
### `py-script` tag for making async HTTP requests
Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`,
which are required or helpful for the `request` function.
The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic
@@ -169,6 +172,7 @@ HTTP requests. The `await` keyword is required not only for the `request` functi
faster ones.
### HTTP Requests
HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from
a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the
local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also
@@ -182,31 +186,38 @@ function or to `pyfetch`. See the
HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and
[RFC 9110](https://www.rfc-editor.org/info/rfc9110).
# Conclusion
## Conclusion
This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python
code/files into the `PyScript` using the `py-config` tag is also covered.
Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`,
or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing!
## API Quick Reference
# API Quick Reference
## pyodide.http.pyfetch
### Usage
### pyfetch Usage
```python
await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse
```
Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`.
- [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch)
## pyodide.http.FetchResponse
### Usage
### FetchResponse Usage
```python
response: pyodide.http.FetchResponse = await <pyfetch call>
status = response.status
json = await response.json()
```
Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async)
methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc.

View File

@@ -18,4 +18,5 @@ passing-objects
http-requests
asyncio
custom-plugins
event-handlers
```