FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
pythonnative/src/pythonnative/element.py at refs/heads/main · pythonnative/pythonnative · GitHub
pythonnative
pythonnative
Repository navigation
Code
Issues
11
(11)
Pull requests
4
(4)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
pythonnative
/
src
/
pythonnative
/
element.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
192 lines (150 loc) · 6.76 KB
Breadcrumbs
pythonnative
/
src
/
pythonnative
/
element.py
Copy path
File metadata and controls
192 lines (150 loc) · 6.76 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
"""Lightweight element descriptors for the virtual view tree.
An [`Element`][pythonnative.Element] is an immutable description of a UI
node, analogous to a React element. It captures a type, a read-only property snapshot,
and an immutable sequence of children without creating any native platform
objects. The reconciler consumes these trees to determine what native
views must be created, updated, or removed.
An element's ``type`` is one of three things:
- a ``str`` naming a **native view** (``"Text"``, ``"View"``, ...),
- a [`Component`][pythonnative.Component] produced by
[`@component`][pythonnative.component.component], or
- a **structural type**: one of the singletons defined here
([`FRAGMENT`][pythonnative.element.FRAGMENT],
[`ERROR_BOUNDARY`][pythonnative.element.ERROR_BOUNDARY],
[`SUSPENSE`][pythonnative.element.SUSPENSE]) or a
[`Context`][pythonnative.Context] (whose elements are providers).
Structural types are real objects rather than magic strings so the
reconciler can dispatch on them with identity checks and no user
element can collide with them.
Elements are produced by built-in factories such as
[`Text`][pythonnative.Text], [`Button`][pythonnative.Button], and
[`Column`][pythonnative.Column], or by calling components.
Example:
```python
from pythonnative import Element
node = Element("Text", {"text": "Hello"}, [])
```
"""
from
__future__
import
annotations
from
dataclasses
import
dataclass
from
types
import
MappingProxyType
from
typing
import
Any
,
Iterable
,
Iterator
,
Mapping
,
Optional
__all__
=
[
"ERROR_BOUNDARY"
,
"FRAGMENT"
,
"SUSPENSE"
,
"Element"
,
"Node"
,
"StructuralType"
,
"type_label"
,
]
class
StructuralType
:
"""Identity object naming a reconciler-owned element kind.
Instances are singletons compared by identity; ``repr`` shows the
kind for debugging (``<Fragment>``).
"""
__slots__
=
(
"name"
,)
def
__init__
(
self
,
name
:
str
)
->
None
:
self
.
name
=
name
def
__repr__
(
self
)
->
str
:
return
f"<
{
self
.
name
}
>"
FRAGMENT
=
StructuralType
(
"Fragment"
)
"""Type of [`Fragment`][pythonnative.Fragment] elements: a transparent group."""
ERROR_BOUNDARY
=
StructuralType
(
"ErrorBoundary"
)
"""Type of [`ErrorBoundary`][pythonnative.ErrorBoundary] elements."""
SUSPENSE
=
StructuralType
(
"Suspense"
)
"""Type of [`Suspense`][pythonnative.Suspense] elements."""
@
dataclass
(
frozen
=
True
,
init
=
False
,
eq
=
False
,
slots
=
True
)
class
Element
:
"""Immutable description of a single UI node.
Built-in elements use a string ``type`` (``"Text"``, ``"Button"``,
``"Column"``, etc.); components use the
[`Component`][pythonnative.Component] object itself as ``type``;
structural elements use a [`StructuralType`][pythonnative.element.StructuralType]
or a [`Context`][pythonnative.Context]. The reconciler dispatches on
this distinction when mounting the tree.
Attributes:
type: The element kind (see the module docstring).
props: Read-only snapshot of properties passed to the native handler or the
component function.
children: Immutable tuple of child nodes. ``None`` and ``False``
entries are permitted and dropped during reconciliation, so
conditional children (``cond and Text(...)``) need no special
casing. Components receive these as their ``*children``.
key: Optional stable identity used by the reconciler when
diffing keyed lists. Two elements with the same ``type`` and
``key`` are treated as the same logical node across renders.
"""
type
:
Any
props
:
Mapping
[
str
,
Any
]
children
:
tuple
[
Any
, ...]
key
:
Optional
[
str
]
def
__init__
(
self
,
type_
:
Any
,
props
:
Optional
[
Mapping
[
str
,
Any
]]
=
None
,
children
:
Optional
[
Iterable
[
Any
]]
=
None
,
key
:
Optional
[
str
]
=
None
,
)
->
None
:
object
.
__setattr__
(
self
,
"type"
,
type_
)
object
.
__setattr__
(
self
,
"props"
,
MappingProxyType
(
dict
(
props
or
{})))
object
.
__setattr__
(
self
,
"children"
,
tuple
(
map
(
_materialize
,
children
))
if
children
is
not
None
else
())
object
.
__setattr__
(
self
,
"key"
,
key
)
def
__repr__
(
self
)
->
str
:
return
f"Element(
{
type_label
(
self
.
type
)!r
}
, props=
{
sorted
(
self
.
props
)
}
, children=
{
len
(
self
.
children
)
}
)"
def
__eq__
(
self
,
other
:
object
)
->
bool
:
if
not
isinstance
(
other
,
Element
):
return
NotImplemented
return
(
self
.
type
==
other
.
type
and
self
.
props
==
other
.
props
and
self
.
children
==
other
.
children
and
self
.
key
==
other
.
key
)
def
__ne__
(
self
,
other
:
object
)
->
bool
:
result
=
self
.
__eq__
(
other
)
if
result
is
NotImplemented
:
return
result
return
not
result
__hash__
=
None
# type: ignore[assignment,unused-ignore]
def
with_key
(
self
,
key
:
object
)
->
"Element"
:
"""Return a copy of this element carrying ``key``.
This is the typed way to key a user component, whose call
signature can't include ``key=`` (PEP 612 forbids keyword
parameters next to a ``ParamSpec``):
```python
pn.Column(*(Row(item).with_key(item.id) for item in items))
```
Built-in factories also accept ``key=`` directly. Non-string
keys are converted with ``str``; ``None`` clears the key.
"""
text
=
None
if
key
is
None
else
(
key
if
isinstance
(
key
,
str
)
else
str
(
key
))
return
Element
(
self
.
type
,
self
.
props
,
self
.
children
,
key
=
text
)
def
_materialize
(
child
:
Any
)
->
Any
:
"""Freeze a one-shot iterator child (a generator expression) into a tuple.
Children are read on every render of the element (a component passes
its ``*children`` through again when its own state changes), so an
iterator would be empty the second time.
"""
if
child
is
None
or
isinstance
(
child
, (
Element
,
bool
,
list
,
tuple
)):
return
child
if
isinstance
(
child
,
Iterator
):
return
tuple
(
map
(
_materialize
,
child
))
return
child
type
Node
=
Element
|
None
|
bool
|
Iterable
[
Node
]
"""Anything that can appear in an element tree.
An element, ``None`` or a ``bool`` for "nothing" (so ``cond and
pn.Text(...)`` and ``pn.Text(...) if cond else None`` both work), or a
possibly nested iterable of nodes. Every built-in container declares
``*children: Node`` and component bodies return a ``Node``. Strings
aren't nodes: wrap text in [`Text`][pythonnative.Text]."""
def
type_label
(
type_obj
:
Any
)
->
str
:
"""Return a human-readable name for an element type (for messages)."""
if
isinstance
(
type_obj
,
str
):
return
type_obj
if
isinstance
(
type_obj
,
StructuralType
):
return
type_obj
.
name
name
=
getattr
(
type_obj
,
"display_name"
,
None
)
or
getattr
(
type_obj
,
"__name__"
,
None
)
if
name
:
return
str
(
name
)
return
repr
(
type_obj
)
Back
|
FazBrowse Home
|
New Git URL