Skip to content

Commit 42425dd

Browse files
committed
release 0.7.2a0
1 parent 4ecaa0c commit 42425dd

File tree

14 files changed

+139
-109
lines changed

14 files changed

+139
-109
lines changed

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# py5
2+
3+
[![py5 downloads](https://pepy.tech/badge/py5/month)](https://pepy.tech/project/py5)
4+
5+
[![Downloads](https://pepy.tech/badge/py5/week)](https://pepy.tech/project/py5)
6+
7+
[![mybinder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/hx2A/py5examples/HEAD?urlpath=lab)
8+
9+
py5 is a new version of [**Processing**][processing] for Python 3.8+. It makes the Java [**Processing**][processing] jars available to the CPython interpreter using [**JPype**][jpype]. It can do just about everything [**Processing**][processing] can do, except with Python instead of Java code.
10+
11+
The goal of py5 is to create a new version of Processing that is integrated into the Python ecosystem. Built into the library are thoughtful choices about how to best get py5 to work with other popular Python libraries such as [numpy](https://www.numpy.org/) or [Pillow](https://python-pillow.org/).
12+
13+
## Simple Example
14+
15+
Here is a simple example of a working py5 Sketch, written in module mode:
16+
17+
```python3
18+
import py5
19+
20+
21+
def setup():
22+
py5.size(200, 200)
23+
py5.rect_mode(py5.CENTER)
24+
25+
26+
def draw():
27+
py5.square(py5.mouse_x, py5.mouse_y, 10)
28+
29+
30+
py5.run_sketch()
31+
```
32+
33+
## Installation
34+
35+
If you have Java 17 installed on your computer, you can install py5 using pip:
36+
37+
```bash
38+
pip install py5
39+
```
40+
41+
[Detailed installation instructions](https://py5.ixora.io/content/install.html) are available on the documentation website. There are some [Special Notes for Mac Users](https://py5.ixora.io/content/osx_users.html) that you should read if you use OSX.
42+
43+
## Getting Started
44+
45+
There are currently four basic ways to use py5. They are:
46+
47+
* **module mode**: create a sketch with `setup()` and `draw()` functions that call methods provided by the `py5` library. The above example is created in module mode.
48+
* **class mode**: create a Python class inherited from `py5.Sketch`. This mode supports multiple Sketches running at the same time.
49+
* **imported mode**: simplified code that omits the `py5.` prefix. This mode is supported by the py5 Jupyter notebook kernel and the `run_sketch` command line utility.
50+
* **static mode**: functionless code to create static images. This mode is supported by the py5bot Jupyter notebook kernel, the `%%py5bot` IPython magic, and the `run_sketch` command line utility.
51+
52+
The documentation website, [https://py5.ixora.io/](https://py5.ixora.io/), is a work in progress. The reference documentation is solid but the how-to's and tutorials are a work in progress.
53+
54+
[py5generator][py5_generator_repo] is a meta-programming project that creates the py5 library. To view the actual installed py5 library code, look at the [py5 repository][py5_repo]. All py5 library development is done through py5generator.
55+
56+
## Get In Touch
57+
58+
Have a comment or question? We'd love to hear from you! The best ways to reach out are:
59+
60+
* github [discussions](https://github.com/hx2A/py5generator/discussions) and [issues](https://github.com/hx2A/py5generator/issues)
61+
* twitter [@py5coding](https://twitter.com/py5coding)
62+
* [processing foundation discourse](https://discourse.processing.org/)
63+
64+
[py5_repo]: https://github.com/hx2A/py5
65+
[py5_generator_repo]: https://github.com/hx2A/py5generator
66+
[processing]: https://github.com/processing/processing4
67+
[jpype]: https://github.com/jpype-project/jpype

README.rst

Lines changed: 0 additions & 61 deletions
This file was deleted.

py5/__init__.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@
8282
pass
8383

8484

85-
__version__ = '0.7.1a6'
85+
__version__ = '0.7.2a0'
8686

8787
_PY5_USE_IMPORTED_MODE = py5_tools.get_imported_mode()
8888

@@ -20172,7 +20172,8 @@ def request_image(image_path: Union[str, Path]) -> Py5Promise:
2017220172
def run_sketch(block: bool = None, *,
2017320173
py5_options: list[str] = None,
2017420174
sketch_args: list[str] = None,
20175-
sketch_functions: dict[str, Callable] = None) -> None:
20175+
sketch_functions: dict[str, Callable] = None,
20176+
_osx_alt_run_method: bool = True) -> None:
2017620177
"""Run the Sketch.
2017720178

2017820179
Parameters
@@ -20275,7 +20276,12 @@ def run_sketch(block: bool = None, *,
2027520276

2027620277
_prepare_dynamic_variables(caller_locals, caller_globals)
2027720278

20278-
_py5sketch._run_sketch(functions, block, py5_options, sketch_args)
20279+
_py5sketch._run_sketch(
20280+
functions,
20281+
block,
20282+
py5_options,
20283+
sketch_args,
20284+
_osx_alt_run_method)
2027920285

2028020286

2028120287
def get_current_sketch() -> Sketch:

py5/jars/py5.jar

123 Bytes
Binary file not shown.

py5/render_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def render_frame(draw: Callable, width: int, height: int,
225225
HelperClass = RenderHelperGraphicsCanvas if use_py5graphics else RenderHelperSketch
226226
ahs = HelperClass(None, draw, width, height, renderer,
227227
draw_args=draw_args, draw_kwargs=draw_kwargs)
228-
ahs.run_sketch(block=True)
228+
ahs.run_sketch(block=True, _osx_alt_run_method=False)
229229

230230
if not ahs.is_dead_from_error and ahs.output:
231231
return ahs.output[0]
@@ -325,7 +325,7 @@ def render_frame_sequence(draw: Callable,
325325
ahs = HelperClass(setup, draw, width, height, renderer, limit=limit,
326326
setup_args=setup_args, setup_kwargs=setup_kwargs,
327327
draw_args=draw_args, draw_kwargs=draw_kwargs)
328-
ahs.run_sketch(block=True)
328+
ahs.run_sketch(block=True, _osx_alt_run_method=False)
329329

330330
if not ahs.is_dead_from_error:
331331
return ahs.output

py5/sketch.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@
6161
# be aware that __IPYTHON__ and get_ipython() are inserted into the user
6262
# namespace late in the kernel startup process
6363
__IPYTHON__ # type: ignore
64-
if sys.platform == 'darwin' and get_ipython(
65-
).active_eventloop != 'osx': # type: ignore
66-
print("Importing py5 on OSX but the necessary Jupyter OSX event loop not been activated. I'll activate it for you, but next time, execute `%gui osx` before importing this library.")
64+
if sys.platform == 'darwin' and (
65+
_ipython_shell := get_ipython()).active_eventloop != 'osx': # type: ignore
66+
print("Importing py5 on OSX but the necessary Jupyter OSX event loop has not been activated. I'll activate it for you, but next time, execute `%gui osx` before importing this library.")
6767
_ipython_shell.run_line_magic('gui', 'osx')
6868
except Exception:
6969
pass
@@ -159,7 +159,8 @@ def __init__(self, *args, **kwargs):
159159
pass
160160

161161
def run_sketch(self, block: bool = None, *,
162-
py5_options: list = None, sketch_args: list = None) -> None:
162+
py5_options: list = None, sketch_args: list = None,
163+
_osx_alt_run_method: bool = True) -> None:
163164
"""Run the Sketch.
164165

165166
Parameters
@@ -237,13 +238,19 @@ def run_sketch(self, block: bool = None, *,
237238

238239
methods = dict([(e, getattr(self, e)) for e in reference.METHODS if hasattr(
239240
self, e) and callable(getattr(self, e))])
240-
self._run_sketch(methods, block, py5_options, sketch_args)
241+
self._run_sketch(
242+
methods,
243+
block,
244+
py5_options,
245+
sketch_args,
246+
_osx_alt_run_method)
241247

242248
def _run_sketch(self,
243249
methods: dict[str, Callable],
244250
block: bool,
245251
py5_options: list[str] = None,
246-
sketch_args: list[str] = None) -> None:
252+
sketch_args: list[str] = None,
253+
_osx_alt_run_method: bool = True) -> None:
247254
self._environ = _environ.Environment()
248255
self.set_println_stream(_DisplayPubPrintlnStream(
249256
) if self._environ.in_jupyter_zmq_shell else _DefaultPrintlnStream())
@@ -272,7 +279,31 @@ def _run_sketch(self,
272279
args = py5_options + [''] + sketch_args
273280

274281
try:
275-
_Sketch.runSketch(args, self._instance)
282+
if _osx_alt_run_method and platform.system() == 'Darwin':
283+
from PyObjCTools import AppHelper
284+
285+
def run():
286+
_Sketch.runSketch(args, self._instance)
287+
if not self._environ.in_ipython_session:
288+
while not self.is_dead:
289+
time.sleep(0.05)
290+
if self.is_dead_from_error:
291+
surface = self.get_surface()
292+
while not surface.is_stopped():
293+
time.sleep(0.05)
294+
AppHelper.stopEventLoop()
295+
296+
if block == False and not self._environ.in_ipython_session:
297+
self.println(
298+
"On OSX, blocking is manditory when Sketch is not run through Jupyter. This applies to all renderers.",
299+
stderr=True)
300+
301+
proxy = jpype.JProxy('java.lang.Runnable', dict(run=run))
302+
jpype.JClass('java.lang.Thread')(proxy).start()
303+
if not self._environ.in_ipython_session:
304+
AppHelper.runConsoleEventLoop()
305+
else:
306+
_Sketch.runSketch(args, self._instance)
276307
except Exception as e:
277308
self.println(
278309
'Java exception thrown by Sketch.runSketch:\n' +
@@ -283,9 +314,9 @@ def _run_sketch(self,
283314
if (renderer := self._instance.getRendererName()) in [
284315
'JAVA2D', 'P2D', 'P3D', 'FX2D']:
285316
self.println(
286-
"On OSX, blocking is not allowed in Jupyter when using the",
317+
"On OSX, blocking is not allowed when Sketch using the",
287318
renderer,
288-
"renderer.",
319+
"renderer is run though Jupyter.",
289320
stderr=True)
290321
block = False
291322

py5_tools/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@
2727
from . import translators # noqa
2828

2929

30-
__version__ = '0.7.1a6'
30+
__version__ = '0.7.2a0'

py5_tools/imported.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,6 @@
2424
from pathlib import Path
2525
import re
2626

27-
import jpype
28-
if sys.platform == 'darwin':
29-
from PyObjCTools import AppHelper
30-
else:
31-
AppHelper = None
32-
3327
import stackprinter
3428

3529
from . import jvm
@@ -245,22 +239,7 @@ def _run_sketch(sketch_path, classpath, exit_if_error):
245239
py5_ns = dict()
246240
py5_ns.update(py5.__dict__)
247241

248-
def exec_compiled_code():
249-
exec(sketch_compiled, py5_ns)
250-
251-
if sys.platform == 'darwin':
252-
def launch_exec_compiled_code():
253-
exec_compiled_code()
254-
AppHelper.stopEventLoop()
255-
256-
proxy = jpype.JProxy(
257-
'java.lang.Runnable', {
258-
'run': launch_exec_compiled_code})
259-
run_sketch_thread = jpype.JClass('java.lang.Thread')(proxy)
260-
run_sketch_thread.start()
261-
AppHelper.runConsoleEventLoop()
262-
else:
263-
exec_compiled_code()
242+
exec(sketch_compiled, py5_ns)
264243

265244
if new_process:
266245
p = Process(

py5_tools/kernel/kernel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Py5Kernel(IPythonKernel):
7575
*_PY5_HELP_LINKS]).tag(config=True)
7676

7777
implementation = 'py5'
78-
implementation_version = '0.7.1a6'
78+
implementation_version = '0.7.2a0'
7979

8080

8181
class Py5App(IPKernelApp):

py5_tools/magics/drawing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151

5252

5353
_CODE_TEMPLATE_END = """
54-
py5.run_sketch(block=True, sketch_functions=dict(settings=_py5_settings, setup=_py5_setup))
54+
py5.run_sketch(block=True, sketch_functions=dict(settings=_py5_settings, setup=_py5_setup), _osx_alt_run_method=False)
5555
if py5.is_dead_from_error:
5656
py5.exit_sketch()
5757

0 commit comments

Comments
 (0)