cprint(bridge_cfg.for_module(__name__))Helpers
DEBUG
DEBUG (iftrue:Any=True, iffalse:Any=False, k='DEBUG_BRIDGET')
Returns iftrue if debug environment variable is set, otherwise iffalse
BridgeCfg
BridgeCfg ()
Core Bridget behavior settings. if True:
- auto_show (false): FastHTML objects display as HTML instead of markdown.
- auto_mount (false): components with routes are automatically mounted.
- auto_id (false): display elements get auto-generated IDs.
- bundle_cfg (BundleCfg): configuration for dynamic import of Bridget modules.
- bootstrap (false): load bridget.js on import.
- current_did (None): the ID of the current display cell.
BundleCfg
BundleCfg ()
Store of arbitrary values
Command Execution
run_command
run_command (command:str, cwd:pathlib.Path|None=None, **kwargs)
Execute shell command synchronously, returns (stdout, stderr)
arun_command
arun_command (command:str, cwd:pathlib.Path|None=None, **kwargs)
Async version of run_command using anyio
a,_ = await arun_command('ls')
test_eq('bridget' in a, True)
_,b = await arun_command('node notfound')
test_eq('Error: Cannot find module' in b, True)
with test_raises(FileNotFoundError):
await arun_command('ls', cwd=Path('/not/found'))Time Formatting
ts
ts ()
ts()'15:02:51.496'
ms2str
ms2str (ts)
format timestamp as in milliseconds to readable time hours:minutes:seconds:milliseconds
ts = datetime.now().timestamp()
ts, ms2str(ts)(1764770571.524289, '15:02:51.524289')
Id generation
Kounter
Kounter ()
Counter that tracks occurrences of keys and returns incremented count
cntr = Kounter()
for _ in 'abaabbb': cntr(_)
test_eq(cntr.d, {'a': 3, 'b': 4})
test_eq(cntr('int'), 1)id_gen
Generate unique session IDs
import random
import re
from pathlib import Pathlines = Path("static/wordlist.txt").read_text().splitlines()
words = [line.strip() for line in lines if line.isalpha()]def modify_word(word):
# Randomly capitalize the first or second letter
if len(word) > 1:
idx_to_capitalize = random.choice([0, 1])
word = word[:idx_to_capitalize] + word[idx_to_capitalize].upper() + word[idx_to_capitalize + 1:]
else:
word = word.upper() # If single letter, capitalize it
# Randomly add a number (0–99) at the start or end
if random.choice([True, False]):
number = random.randint(0, 99)
# if random.choice([True, False]):
# word = f"{number}{word}" # Number at the start
# else:
word = f"{word}{number}" # Number at the end
return word
def generate_readable_id(num_words=3):
words_part = [modify_word(random.choice(words)) for _ in range(num_words)]
id_candidate = '-'.join(words_part)
# Ensure it's a valid CSS identifier
if not re.match(r"^[a-zA-Z_][\w\-]*$", id_candidate): # Add '_' if invalid
id_candidate = f"_{id_candidate}"
return f"{id_candidate}-{random.randint(0, 9999)}"generate_readable_id(), generate_readable_id()('lOsing-Solution49-Own-7437', 'cLosest-Won10-hIdes-5235')
id_gen
id_gen ()
Create ID generator function that produces unique session-based IDs
simple_id
simple_id ()
Generate simple hex ID using random bytes
simple_id()'bb0f5bfa4-b8ad1c79-4bc1cd7b-c96b3532'
The id_gen function creates a function that takes any object and generates an unique Id valid during the current session. Useful for creating unique element IDs in dynamic HTML content.
new_id = id_gen()
new_id(), new_id()('bd0f6d060-acc69f5f-a6ef89f6-fc1bb445',
'b6dcae08c-1ac05807-c47196d0-37cf4666')
int_id = id_gen()
int_id(7), int_id(7), int_id(888)('int_1-1764770571', 'int_2-1764770571', 'int_3-1764770571')
int_id = id_gen()
int_id('asdf'), int_id('asdf'), int_id('asdf')('asdf_1-1764770571', 'asdf_2-1764770571', 'asdf_3-1764770571')
obj_id = id_gen()
o1, o2 = object(), object()
print(obj_id(o1), obj_id(o2))
dict_id = id_gen()
print(dict_id(d1 := {'a': 1}), dict_id(d2 := {'b': 7}))
pth_id = id_gen()
print(pth_id(Path('.')), pth_id(Path()), pth_id(Path('./bin')))object_1-1764770571 object_2-1764770571
dict_1-1764770571 dict_2-1764770571
PosixPath_1-1764770571 PosixPath_2-1764770571 PosixPath_3-1764770571
Class Patching Utilities
patch_cached
patch_cached (cls, f, name:str|None=None)
Add cached method to class using functools.cache
# type: ignore
class Test:
def __init__(self): self.d = defaultdict(list)
def a(self, n:int=1):
self.d['a'].append(n)
return n+1
patch_cached(Test, a)
t1 = Test()
test_eq(t1.a(), 2)
test_eq(t1.a(), t1.a())
test_eq(t1.d['a'], [1])
test_eq(t1.a(3), 4)
test_eq(t1.a(3), t1.a(3))
test_eq(t1.d['a'], [1, 3])
t2 = Test()
test_eq(t2.a(), 2)
test_eq(t2.a(), t2.a())
test_eq(t2.d['a'], [1])
test_eq(t2.a(7), 8)
test_eq(t2.a(7), t2.a(7))
test_eq(t2.d['a'], [1, 7])patch_cached_property
patch_cached_property (cls, f, name:str|None=None)
cached_property with partial support
# type: ignore
def a(self):
"a docs"
self.d['a'].append('a'); return 2
def _b(self, n):
"b docs"
self.d['b'].append(n); return n+n
class Test:
def __init__(self): self.d = defaultdict(list)
patch_cached_property(Test, a)
patch_cached_property(Test, lambda self: _b(self, 2), 'b2')
patch_cached_property(Test, partial(_b, n=3), 'b3')
patch_cached_property(Test, partial(lambda self: _b(self, 4)), 'b4')
t1 = Test()
test_eq(t1.a, 2)
test_eq(t1.a, t1.a)
test_eq(t1.d['a'], ['a'])
test_eq(t1.b2, 4)
test_eq(t1.b2, t1.b2)
test_eq(t1.d['b'], [2])
test_eq(t1.b3, 6)
test_eq(t1.b3, t1.b3)
test_eq(t1.d['b'], [2, 3])
test_eq(t1.b4, 8)
test_eq(t1.b4, t1.b4)
test_eq(t1.d['b'], [2, 3, 4])cached_property
cached_property (func)
Enhanced cached_property that preserves function attributes
skip
skip (metadata:dict|None=None, **kwargs)
Convenience function to add skip=True to bridge metadata
bridge_metadata
bridge_metadata (metadata:dict|None=None, **kwargs)
Add or update ‘bridge’ key in metadata dict with kwargs
test_eq(bridge_metadata(), {'bridge': {}})
test_eq(bridge_metadata(skip=True), {'bridge': {'skip': True}})
test_eq(bridge_metadata({'autoshow': True}, skip=True), {'autoshow': True, 'bridge': {'skip': True}})
test_eq(skip(), {'bridge': {'skip': True}})
test_eq(skip({'bridge': {'auto_show': True}}), {'bridge': {'skip': True, 'auto_show': True}})
test_eq(skip(auto_show=True), {'bridge': {'skip': True, 'auto_show': True}})Function Composition
like fastcore.compose, but args are passed only to first function
compose_first
compose_first (*funcs:Callable, order:Optional[Callable]=None)
Create a function that composes all functions in funcs, passing remaining *args and **kwargs to first function only. order: key function to sort funcs before composing
def add_one(x): return x + 1
def multiply_two(x): return x * 2
def add_ten(x): return x + 10
single = compose_first(add_one)
test_eq(single(5), 6)
test_eq(single, add_one)
empty = compose_first()
test_eq(empty, FC.noop)
composed = compose_first(add_one, multiply_two, add_ten)
test_eq(composed(5), 22) # ((5+1) * 2) + 10 = 22def tag_a(x): return f"a({x})"
def tag_b(x): return f"b({x})"
def tag_c(x): return f"c({x})"
natural = compose_first(tag_c, tag_a, tag_b)
test_eq(natural("x"), "b(a(c(x)))")
ordered = compose_first(tag_c, tag_a, tag_b, order=lambda f: f.__name__)
test_eq(ordered("x"), "c(b(a(x)))") # Functions sorted: tag_a, tag_b, tag_cFastHTML Utilities
Basic naked FastHTML app.
nb_app
nb_app (debug=False, routes=None, middleware=None, title:str='FastHTML page', exception_handlers=None, on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, ftrs=None, exts=None, before=None, after=None, surreal=True, htmx=True, default_hdrs=True, sess_cls=<class 'starlette.middleware.sessions.SessionMiddleware'>, secret_key=None, session_cookie='session_', max_age=31536000, sess_path='/', same_site='lax', sess_https_only=False, sess_domain=None, key_fname='.sesskey', body_wrap=<function noop_body>, htmlkw=None, nb_hdrs=False, canonical=True)
app = nb_app()
test_eq(app.user_middleware, [])CLog
CLog (*o)
display(HTML(CLog('aaaa', 'bbbb')))Display Utilities
Convenience functions and definitions just to avoid the stupid wiggly reds.
displaydh
displaydh (*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, raw=False, clear=False, **kwargs)
display with display_id
| Type | Default | Details | |
|---|---|---|---|
| objs | VAR_POSITIONAL | ||
| include | NoneType | None | |
| exclude | NoneType | None | |
| metadata | NoneType | None | |
| transient | NoneType | None | |
| display_id | NoneType | None | |
| raw | bool | False | |
| clear | bool | False | |
| kwargs | VAR_KEYWORD | ||
| Returns | DisplayHandle | type: ignore |
dh = display('a', display_id=True)
# dh'a'
dh = display('b', display_id="1234567890")
dh'b'
<DisplayHandle display_id=1234567890>
dh = display('c')
dh'c'
DetailsJSON
<style>
details ul { list-style-type:none; list-style-position: outside; padding-inline-start: 22px; margin: 0px; }
</style>
<details open>
<summary>Apollo astronauts</summary>
<ul>
<li><span>1</span>: Neil Armstrong</li>
<li><span>2</span>: Alan Bean</li>
<li><details>
<summary>Apollo 11</summary>
<ul>
<li><span>1</span>: Neil Armstrong</li>
<li><span>2</span>: Alan Bean</li>
<li><div><span>3</span>: Buzz Aldrin</div></li>
<li><span>4</span>: Edgar Mitchell</li>
<li><span>5</span>: Alan Shepard</li>
</ul></li>
<li><span>4</span>: Edgar Mitchell</li>
<li><span>5</span>: Alan Shepard</li>
</ul>
</details>Apollo astronauts
- 1: Neil Armstrong
- 2: Alan Bean
Apollo 11
- 1: Neil Armstrong
- 2: Alan Bean
- 3: Buzz Aldrin
- 4: Edgar Mitchell
- 5: Alan Shepard
- 4: Edgar Mitchell
- 5: Alan Shepard
DetailsJSON
DetailsJSON (*args, summary:str='', open:bool=True, openall:bool=False, skip:Sequence[str]=(), **kwargs)
Interactive collapsible JSON viewer with HTML details/summary structure
NameVal
NameVal (k, v)
Render key-value pair with name and value styling
Val
Val (v)
Render value with appropriate CSS class based on type
dtl = DetailsJSON({
'1': 'Neil Armstrong',
'2': 'Alan Bean',
'3': 'Buzz Aldrin',
'letters': {
'a': 1,
'b': 2
},
'5': 'Edgar Mitchell',
'6': 'Alan Shepard'
}, summary='Apollo astronauts')
# test_eq(val_at(dtl, '5'), 'Edgar Mitchell')
# test_eq(val_at(dtl, 'letters.a'), 1)
# cprint(to_xml(dtl))
show(dtl)Apollo astronauts
- 1: Neil Armstrong
- 2: Alan Bean
- 3: Buzz Aldrin
- a: 1
- b: 2
- 5: Edgar Mitchell
- 6: Alan Shepard
letters
d= {
"idx": 1,
"cell_type": "code",
"source": "# cell 1\nprint('hello')",
"id": "W1sZmlsZQ==",
"metadata": {
"brd": {
"id": "717322f8-95fa-425c-839d-8b9e7d4ef921"
}
},
"outputs": [
{'output_type': 'stream', 'name': 'stdout', 'text': '1\n'},
{'output_type': 'stream', 'name': 'stdout', 'text': '2\n'}
],
"execution_count": 1
}
show(DetailsJSON(d, openall=True))summary
- idx: 1
- cell_type: code
- source: # cell 1 print('hello')
- id: W1sZmlsZQ==
- id: 717322f8-95fa-425c-839d-8b9e7d4ef921
- output_type: stream
- name: stdout
- text: 1
- output_type: stream
- name: stdout
- text: 2
- execution_count: 1
metadata
brd
outputs
0
1
Convenience IPython.display.HTML subclass that accepts fastcore.xml.FT object and adds the kwargs to metadata.
HTML
HTML (data=None, url=None, filename=None, metadata=None, **kwargs)
Create a text display object given raw data.
| Type | Default | Details | |
|---|---|---|---|
| data | NoneType | None | The raw data or a URL or file to load the data from. |
| url | NoneType | None | A URL to download the data from. |
| filename | NoneType | None | Path to a local file to load the data from. |
| metadata | NoneType | None | Dict of metadata associated to be the object when displayed |
| kwargs | VAR_KEYWORD |
Environment Detection
in_vscode_notebook
in_vscode_notebook ()
Check if the code is running in VSCode
in_vscode
in_vscode ()
Check if the code is running in VSCode
IN_VSCODE, in_vscode_notebook()(True, True)
Widgets
find_active_widgets
find_active_widgets ()
Find all active widget instances in memory
Brute force widget list.
import ipywidgets as Ww = W.IntSlider(value=10)
www = find_active_widgets()
ww[{'type': 'IntSlider',
'model_id': '60abde60b31d4df19fa679c9d67e1617',
'comm': True},
{'type': 'Layout',
'model_id': '92d6d2f7dfa74af4b2e650a280ac1fdf',
'comm': True},
{'type': 'SliderStyle',
'model_id': '137bdd0e381c4413b0fceedf8cb7cb3b',
'comm': True},
{'type': 'IntSlider',
'model_id': 'df7f5a8d2e184852be06aa0ab3357ed6',
'comm': False},
{'type': 'Layout',
'model_id': '4aca39e666394da9aff161ae7b6bceab',
'comm': False},
{'type': 'SliderStyle',
'model_id': 'e22322aa4357468fb0a605a13ed39580',
'comm': False}]
get_kernel_widgets_comms
get_kernel_widgets_comms ()
Get all widget comms from the kernel.
[_.comm_id for _ in get_kernel_widgets_comms()]['92d6d2f7dfa74af4b2e650a280ac1fdf',
'137bdd0e381c4413b0fceedf8cb7cb3b',
'60abde60b31d4df19fa679c9d67e1617']
get_active_widgets_comms
get_active_widgets_comms ()
Get “official” list of widget comms
[_.comm_id for _ in get_active_widgets_comms()]['92d6d2f7dfa74af4b2e650a280ac1fdf',
'137bdd0e381c4413b0fceedf8cb7cb3b',
'60abde60b31d4df19fa679c9d67e1617']
W.Widget.close_all()[_.comm_id for _ in get_active_widgets_comms()][]
cleanupbridget
cleanupbridget (glbs)
Cleanup bridget environment
As VSCode sandbox the front-end, each notebook opening starts anew. If the kernel has not restarted, widgets are stale, opened (or closed but not deleted) with no counter-part in the kernel.
This helper function cleans up the environment. Not needed in Lab (the extension takes care of siwtching the environment).