How to use my own python packages/modules with PyScript?
Asked Answered
M

2

7

Question

I came across pyscript hoping to use it to document python code with mkdocs. I have looked into importing my own module. Individual files work. How do I import my own module using pyscript instead?

  • Requirements for running the example:
    • python package numpy ($ pip install numpy)
    • python package matplotlib ($ pip install matplotlib)
    • local webserver for live preview on localhost (eq. $ npm install -g live-server)

  • Below is an example that works with the 'just import a python file' approach, see line from example import myplot.

  • When I change the line to from package.example import myplot it is not working and I get the following error in firefox/chromium:

    JsException(PythonError: Traceback (most recent call last): File "/lib/python3.10/site-packages/_pyodide/_base.py", line 429, in eval_code .run(globals, locals) File "/lib/python3.10/site-packages/_pyodide/_base.py", line 300, in run coroutine = eval(self.code, globals, locals) File "", line 1, in ModuleNotFoundError: No module named 'package' )
    

Any help is appreciated. I found this discussion on github, but I am lost when trying to follow.

Example

Folder structure

├── index.html
└── pycode/
    ├── example.py
    └── package/
        ├── example.py
        └── __init__.py

index.html

<!doctype html>
<html>
<head>
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/alpha/pyscript.css"/>
<py-env>
- numpy
- matplotlib
- paths:
  - ./pycode/example.py
  - ./pycode/package
</py-env>
</head>
  
<body>    
    
<div id="lineplot"></div>

<py-script>
from example import myplot
import matplotlib.pyplot as plt

theta,r = myplot(4)

fig, ax = plt.subplots(
  subplot_kw = {'projection': 'polar'} 
)
ax.plot(theta, r)
ax.set_rticks([0.5, 1, 1.5, 2])
ax.grid(True)

pyscript.write('lineplot',fig)

</py-script>

</body>
</html>

example.py

import numpy as np

def myplot(val:int):
    r = np.arange(0, 2, 0.01)
    theta = val * np.pi * r
    return theta,r

__init__.py

__all__ = [ 'example.py' ]

Intended result in the webbrowser

enter image description here

Morava answered 7/2, 2023 at 16:33 Comment(0)
E
5

The folder structure you want to achieve wasn't possible in PyScipt Alpha - <py-env>'s paths functionality was fairly limited. Thankfully, it is possible in PyScript 2022.12.1, the latest version at time of writing.

First, you'll want want to point your <script> and <link> tags at the newest release:

<script defer src="https://pyscript.net/releases/2022.12.1/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2022.12.1/pyscript.css"/>

<py-env> has been renamed <py-config> and its syntax is quite different. To load packages, the keyword is packages:

<py-config>
    packages = ['numpy', 'matplotlib']
</py-config>

Finally, to load your files into the in-browser file system in a structured way, you can make use of a fetch configuration, another new feature of <py-config>. Check out the use cases section of the py-config docs, in in particular example #6, which is similar to your situation:

<py-config>
    packages = ['numpy', 'matplotlib']

    [[fetch]]
    files = ['__init__.py', 'example.py']
    from = 'package'
    to_folder = 'package'
</py-config>

So finally, your full working example looks like:

<!doctype html>
<html>
<head>
<script defer src="https://pyscript.net/releases/2022.12.1/pyscript.js"></script>
<link rel="stylesheet" href="https://pyscript.net/releases/2022.12.1/pyscript.css"/>
</head>
<body>    
    <py-config>
        packages = ['numpy', 'matplotlib']

        [[fetch]]
        files = ['__init__.py', 'example.py']
        from = 'package'
        to_folder = 'package'
    </py-config>
    
<div id="lineplot"></div>

<py-script>
from package.example import myplot
import matplotlib.pyplot as plt

theta,r = myplot(4)

fig, ax = plt.subplots(
  subplot_kw = {'projection': 'polar'} 
)
ax.plot(theta, r)
ax.set_rticks([0.5, 1, 1.5, 2])
ax.grid(True)

pyscript.write('lineplot',fig)
</py-script>

</body>
</html>

For more context on fetch configurations and how they work, see this writeup from the 2022.12.1 release blog post.

Emmalineemmalyn answered 7/2, 2023 at 16:57 Comment(0)
I
-1

https://realpython.com/pyscript-python-in-browser/#modules-missing-from-the-python-standard-library

This page has in depth analysis of modules within pyscript

    <body>
  <py-env>
    - matplotlib
    - numpy
    - paths:
        - src/waves.py
  </py-env>
  <py-script>
import matplotlib.pyplot as plt
import numpy as np
import waves

time = np.linspace(0, 2 * np.pi, 100)
plt.plot(time, waves.wave(440)(time))
plt
  </py-script>
</body>

You will need something as above with your own filenames. The file path is relative to your HTML page

You also can't import a package directly only modules, you may be able to use the above code and figure out a solution, or you could do:

You can’t load Python packages using paths, only modules. If you have a pure-Python package, then build a wheel distribution and host it with your other files or upload it to PyPI.

Iasis answered 7/2, 2023 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.