From 4e75dd607410cc84a464d66c14730a4b92a2c1dc Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Fri, 29 May 2026 15:47:09 +0100 Subject: [PATCH 1/2] Add PyScript examples for lazy-object-proxy Generated by apply_llm_response.py from prompts/lazy-object-proxy/response.toml. Examples included: - deferred_construction: Deferred construction with Proxy - lazy_imports_and_configs: Lazy imports and config registries Generated-By: apply_llm_response.py --- examples/lazy-object-proxy/README.md | 18 +++++ .../deferred_construction/code.py | 65 ++++++++++++++++ .../deferred_construction/config.toml | 1 + .../deferred_construction/setup.py | 39 ++++++++++ .../lazy_imports_and_configs/code.py | 76 +++++++++++++++++++ .../lazy_imports_and_configs/config.toml | 1 + .../lazy_imports_and_configs/setup.py | 22 ++++++ examples/lazy-object-proxy/order.json | 4 + 8 files changed, 226 insertions(+) create mode 100644 examples/lazy-object-proxy/README.md create mode 100644 examples/lazy-object-proxy/deferred_construction/code.py create mode 100644 examples/lazy-object-proxy/deferred_construction/config.toml create mode 100644 examples/lazy-object-proxy/deferred_construction/setup.py create mode 100644 examples/lazy-object-proxy/lazy_imports_and_configs/code.py create mode 100644 examples/lazy-object-proxy/lazy_imports_and_configs/config.toml create mode 100644 examples/lazy-object-proxy/lazy_imports_and_configs/setup.py create mode 100644 examples/lazy-object-proxy/order.json diff --git a/examples/lazy-object-proxy/README.md b/examples/lazy-object-proxy/README.md new file mode 100644 index 0000000..57771a5 --- /dev/null +++ b/examples/lazy-object-proxy/README.md @@ -0,0 +1,18 @@ +# lazy-object-proxy Examples + +Each sub-directory contains a self-contained example. The order in +which the examples are to appear is specified in `order.json` (an +array of directory names in the expected order). + +In each example directory you'll find: + +* `config.toml` - must conform to the specification outlined here: + https://docs.pyscript.net/latest/user-guide/configuration/ This is + parsed and ultimately turned into a JSON representation as part of + the package's API object. +* `setup.py` - Python code for contextual and environmental setup, + NOT SEEN BY THE END USER, but is run before the `code.py` code is + evaluated. Allows us to create useful (IPython) shims, avoid + repeating boilerplate and whatnot. +* `code.py` - the actual code added to the editor which forms the + practical example of using the package. diff --git a/examples/lazy-object-proxy/deferred_construction/code.py b/examples/lazy-object-proxy/deferred_construction/code.py new file mode 100644 index 0000000..56e68bc --- /dev/null +++ b/examples/lazy-object-proxy/deferred_construction/code.py @@ -0,0 +1,65 @@ +""" +Deferred construction with `lazy_object_proxy.Proxy`. + +A `Proxy` wraps a zero-argument callable (the "factory") and looks +and feels like the eventual return value, but the factory is only +invoked the first time the proxy is actually used. After that the +result is cached and the proxy transparently forwards every +attribute access, method call, and operator to the real object. + +Docs: https://python-lazy-object-proxy.readthedocs.io/ +""" +from IPython.core.display import display, HTML + +heading("A proxy that pretends to be an expensive report") +note( + "Imagine loading a large report from disk or the network. We " + "don't want to pay that cost unless someone actually reads it." +) + +# A counter we can inspect to see when (and how often) the factory runs. +build_calls = {"count": 0} + + +def build_quarterly_report(): + """Pretend to do expensive work and return a dict 'report'.""" + build_calls["count"] += 1 + return { + "quarter": "Q3", + "revenue": 184_500.00, + "top_product": "Aurora Notebook", + "units_sold": 1273, + } + + +# Wrap the factory. No work happens here. +report = lazy_object_proxy.Proxy(build_quarterly_report) + +note( + f"Proxy created. Factory call count so far: " + f"{build_calls['count']}" +) + +# `__resolved__` tells us whether the factory has been called yet. +note(f"Has the proxy been resolved? {report.__resolved__}") + +# First real use: indexing triggers the factory exactly once. +heading("First touch triggers the factory", level=3) +note(f"Top product: {report['top_product']}") +note( + f"Factory call count after first use: " + f"{build_calls['count']}" +) +note(f"Resolved now? {report.__resolved__}") + +# Subsequent uses reuse the cached object; the factory is NOT called again. +heading("Subsequent uses reuse the cached value", level=3) +note(f"Revenue: ${report['revenue']:,.2f}") +note(f"Units sold: {report['units_sold']}") +note( + f"Factory call count after several uses: " + f"{build_calls['count']} (still 1)" +) + +# The proxy is indistinguishable from the underlying dict for most purposes. +note(f"isinstance(report, dict)? {isinstance(report, dict)}") diff --git a/examples/lazy-object-proxy/deferred_construction/config.toml b/examples/lazy-object-proxy/deferred_construction/config.toml new file mode 100644 index 0000000..89c494b --- /dev/null +++ b/examples/lazy-object-proxy/deferred_construction/config.toml @@ -0,0 +1 @@ +packages = ["lazy-object-proxy"] diff --git a/examples/lazy-object-proxy/deferred_construction/setup.py b/examples/lazy-object-proxy/deferred_construction/setup.py new file mode 100644 index 0000000..d57ee40 --- /dev/null +++ b/examples/lazy-object-proxy/deferred_construction/setup.py @@ -0,0 +1,39 @@ +"""Shim setup for the first example: full IPython compatibility shim.""" +import sys +import types +import js +from pyscript import window, HTML, display as _display + +js.alert = window.alert + + +def display(*args, **kwargs): + return _display( + *args, **kwargs, target=__pyscript_display_target__, + ) + + +ipython = types.ModuleType("IPython") +core = types.ModuleType("IPython.core") +core_display = types.ModuleType("IPython.core.display") +core_display.display = display +core_display.HTML = HTML +ipython.core = core +core.display = core_display +ipython.get_ipython = lambda: None +ipython.display = core_display +sys.modules["IPython"] = ipython +sys.modules["IPython.core"] = core +sys.modules["IPython.core.display"] = core_display +sys.modules["IPython.display"] = core_display + + +def heading(text, level=2): + display(HTML(f"{text}"), append=True) + + +def note(text): + display(HTML(f"

{text}

"), append=True) + + +import lazy_object_proxy diff --git a/examples/lazy-object-proxy/lazy_imports_and_configs/code.py b/examples/lazy-object-proxy/lazy_imports_and_configs/code.py new file mode 100644 index 0000000..8381819 --- /dev/null +++ b/examples/lazy-object-proxy/lazy_imports_and_configs/code.py @@ -0,0 +1,76 @@ +# --------------------------------------------------------------------- +# Two practical patterns: lazy imports and a lazy settings registry. +# --------------------------------------------------------------------- + +heading("Pattern 1: lazy imports") +note( + "Wrap a module import in a Proxy so the cost of importing is " + "paid only when the module is first touched. Useful for heavy " + "optional dependencies." +) + + +def _import_json(): + """Factory that imports and returns the json module.""" + import json + return json + + +# `json_lazy` looks and behaves like the json module, but isn't loaded yet. +json_lazy = lazy_object_proxy.Proxy(_import_json) + +note(f"Resolved before use? {json_lazy.__resolved__}") + +payload = {"city": "Lisbon", "temp_c": 21, "skies": "clear"} +encoded = json_lazy.dumps(payload) # triggers the import +note(f"Encoded payload: {encoded}") +note(f"Resolved after use? {json_lazy.__resolved__}") + + +heading("Pattern 2: a registry of lazily-built settings") +note( + "Each entry is a Proxy wrapping a builder. Iterating the " + "registry's keys is cheap; only the entries you read get built." +) + +build_log = [] + + +def make_builder(name, value): + """Return a zero-arg factory that 'builds' a settings record.""" + def _build(): + build_log.append(name) + return {"name": name, "value": value, "ready": True} + return _build + + +settings = { + "database": lazy_object_proxy.Proxy( + make_builder("database", "postgres://example/db") + ), + "cache": lazy_object_proxy.Proxy( + make_builder("cache", "redis://example/0") + ), + "search": lazy_object_proxy.Proxy( + make_builder("search", "https://search.example/api") + ), +} + +note(f"Registry keys (no builders run yet): {list(settings)}") +note(f"Builders run so far: {build_log}") + +# Touch only the 'cache' entry. The other two stay un-built. +cache_value = settings["cache"]["value"] +note(f"cache value: {cache_value}") +note(f"Builders run after reading 'cache': {build_log}") + +# Reading 'cache' again does not rebuild; the proxy caches its result. +_ = settings["cache"]["ready"] +note(f"Builders run after re-reading 'cache': {build_log}") + +# Now touch 'database'; 'search' remains untouched. +note(f"database url: {settings['database']['value']}") +note(f"Final build log: {build_log}") + +resolved = {k: v.__resolved__ for k, v in settings.items()} +note(f"Per-entry resolved status: {resolved}") diff --git a/examples/lazy-object-proxy/lazy_imports_and_configs/config.toml b/examples/lazy-object-proxy/lazy_imports_and_configs/config.toml new file mode 100644 index 0000000..89c494b --- /dev/null +++ b/examples/lazy-object-proxy/lazy_imports_and_configs/config.toml @@ -0,0 +1 @@ +packages = ["lazy-object-proxy"] diff --git a/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py b/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py new file mode 100644 index 0000000..ff4e0e5 --- /dev/null +++ b/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py @@ -0,0 +1,22 @@ +"""Setup for example 2. Mirrors example 1's namespace, no IPython shim.""" +import js +from pyscript import window, HTML, display as _display + +js.alert = window.alert + + +def display(*args, **kwargs): + return _display( + *args, **kwargs, target=__pyscript_display_target__, + ) + + +def heading(text, level=2): + display(HTML(f"{text}"), append=True) + + +def note(text): + display(HTML(f"

{text}

"), append=True) + + +import lazy_object_proxy diff --git a/examples/lazy-object-proxy/order.json b/examples/lazy-object-proxy/order.json new file mode 100644 index 0000000..214adcf --- /dev/null +++ b/examples/lazy-object-proxy/order.json @@ -0,0 +1,4 @@ +[ + "deferred_construction", + "lazy_imports_and_configs" +] From 4c4218e9ed27369d8aff8168c5c77cc447e13d9b Mon Sep 17 00:00:00 2001 From: "Nicholas H.Tollervey" Date: Thu, 4 Jun 2026 15:56:20 +0100 Subject: [PATCH 2/2] Fix imports. --- examples/lazy-object-proxy/deferred_construction/code.py | 3 +++ examples/lazy-object-proxy/deferred_construction/setup.py | 3 --- examples/lazy-object-proxy/lazy_imports_and_configs/code.py | 3 +++ examples/lazy-object-proxy/lazy_imports_and_configs/setup.py | 3 --- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/lazy-object-proxy/deferred_construction/code.py b/examples/lazy-object-proxy/deferred_construction/code.py index 56e68bc..c321695 100644 --- a/examples/lazy-object-proxy/deferred_construction/code.py +++ b/examples/lazy-object-proxy/deferred_construction/code.py @@ -11,6 +11,9 @@ """ from IPython.core.display import display, HTML +import lazy_object_proxy + + heading("A proxy that pretends to be an expensive report") note( "Imagine loading a large report from disk or the network. We " diff --git a/examples/lazy-object-proxy/deferred_construction/setup.py b/examples/lazy-object-proxy/deferred_construction/setup.py index d57ee40..050df73 100644 --- a/examples/lazy-object-proxy/deferred_construction/setup.py +++ b/examples/lazy-object-proxy/deferred_construction/setup.py @@ -34,6 +34,3 @@ def heading(text, level=2): def note(text): display(HTML(f"

{text}

"), append=True) - - -import lazy_object_proxy diff --git a/examples/lazy-object-proxy/lazy_imports_and_configs/code.py b/examples/lazy-object-proxy/lazy_imports_and_configs/code.py index 8381819..fb5164f 100644 --- a/examples/lazy-object-proxy/lazy_imports_and_configs/code.py +++ b/examples/lazy-object-proxy/lazy_imports_and_configs/code.py @@ -2,6 +2,9 @@ # Two practical patterns: lazy imports and a lazy settings registry. # --------------------------------------------------------------------- +import lazy_object_proxy + + heading("Pattern 1: lazy imports") note( "Wrap a module import in a Proxy so the cost of importing is " diff --git a/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py b/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py index ff4e0e5..b38ee6c 100644 --- a/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py +++ b/examples/lazy-object-proxy/lazy_imports_and_configs/setup.py @@ -17,6 +17,3 @@ def heading(text, level=2): def note(text): display(HTML(f"

{text}

"), append=True) - - -import lazy_object_proxy