FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
pythonnative/src/pythonnative/storage.py at v0.43.1 · 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
/
storage.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
184 lines (141 loc) · 6 KB
Breadcrumbs
pythonnative
/
src
/
pythonnative
/
storage.py
Copy path
File metadata and controls
184 lines (141 loc) · 6 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
"""Cross-platform key/value persistence (``AsyncStorage``).
Mirrors React Native's ``AsyncStorage`` API but with native ``async``
coroutines and a JSON convenience layer. Values are persisted by the
native ``Storage`` module:
- **iOS**: ``NSUserDefaults`` (standard user defaults).
- **Android**: ``SharedPreferences`` (file ``"pn_async_storage"``).
- **Browser preview / tests**: an in-memory dict optionally backed by a JSON
file under ``PN_STORAGE_DIR`` for inter-run persistence during local
development (see
[`FallbackStorage`][pythonnative.native_modules.fallback.FallbackStorage]).
Every operation is a coroutine. The platform stores answer in
microseconds, so calls complete inline on the framework loop without
a thread hop.
Example:
```python
import pythonnative as pn
async def remember_user(user):
await pn.AsyncStorage.set_json("current_user", user.to_dict())
async def restore_session():
user_dict = await pn.AsyncStorage.get_json("current_user")
if user_dict is None:
return None
return User.from_dict(user_dict)
```
"""
from
__future__
import
annotations
import
json
from
typing
import
Any
,
Callable
,
List
,
Optional
,
Tuple
,
TypeVar
from
.
native_modules
.
registry
import
NativeModule
,
native_module
T
=
TypeVar
(
"T"
)
def
_storage
()
->
NativeModule
:
return
native_module
(
"Storage"
)
class
AsyncStorage
:
"""Async key/value persistence layered on platform-native stores.
Every method is a coroutine that returns when the underlying
native operation completes. Strings round-trip directly via
[`get`][pythonnative.storage.AsyncStorage.get] /
[`set`][pythonnative.storage.AsyncStorage.set]; richer values can
use [`get_json`][pythonnative.storage.AsyncStorage.get_json] /
[`set_json`][pythonnative.storage.AsyncStorage.set_json] which
add a JSON encode/decode step.
"""
@
staticmethod
async
def
get
(
key
:
str
)
->
Optional
[
str
]:
"""Return the string stored at ``key``, or ``None`` if missing."""
value
=
_storage
().
call
(
"get"
,
key
=
key
)
return
None
if
value
is
None
else
str
(
value
)
@
staticmethod
async
def
set
(
key
:
str
,
value
:
str
)
->
None
:
"""Persist ``value`` under ``key``.
``value`` must be a ``str``. For non-string values, use
[`set_json`][pythonnative.storage.AsyncStorage.set_json].
"""
if
not
isinstance
(
value
,
str
):
raise
TypeError
(
"AsyncStorage.set requires a str value; use set_json for richer types"
)
_storage
().
call
(
"set"
,
key
=
key
,
value
=
value
)
@
staticmethod
async
def
delete
(
key
:
str
)
->
None
:
"""Remove the entry at ``key`` if present (no-op otherwise)."""
_storage
().
call
(
"delete"
,
key
=
key
)
@
staticmethod
async
def
all_keys
()
->
List
[
str
]:
"""Return every persisted key (order is platform-dependent)."""
keys
=
_storage
().
call
(
"all_keys"
)
return
[
str
(
k
)
for
k
in
keys
]
if
isinstance
(
keys
,
list
)
else
[]
@
staticmethod
async
def
clear
()
->
None
:
"""Remove every entry written through ``AsyncStorage``."""
_storage
().
call
(
"clear"
)
@
staticmethod
async
def
get_json
(
key
:
str
)
->
Any
:
"""Return the JSON-decoded value stored at ``key``, or ``None``.
If the stored value isn't valid JSON, returns ``None`` rather
than raising; assume the entry was written by another
process or an older version of the app.
"""
raw
=
await
AsyncStorage
.
get
(
key
)
if
raw
is
None
:
return
None
try
:
return
json
.
loads
(
raw
)
except
(
json
.
JSONDecodeError
,
TypeError
):
return
None
@
staticmethod
async
def
set_json
(
key
:
str
,
value
:
Any
)
->
None
:
"""JSON-encode ``value`` and persist it under ``key``."""
await
AsyncStorage
.
set
(
key
,
json
.
dumps
(
value
,
default
=
str
))
def
use_persisted_state
(
key
:
str
,
initial
:
T
,
)
->
Tuple
[
T
,
Callable
[[
Any
],
None
]]:
"""Persisted [`use_state`][pythonnative.hooks.use_state] variant.
Backed by [`AsyncStorage`][pythonnative.storage.AsyncStorage]:
behaves like ``use_state`` but loads the prior value (if any) on
mount and persists every subsequent update. Until the load
completes the value is ``initial``, the same fallback React
Native users get with ``AsyncStorage.getItem``.
The setter accepts either a value or a ``current -> new``
callable, matching
[`use_state`][pythonnative.use_state]. Writes are
fire-and-forget; failures are silently absorbed (storage is
best-effort by design).
Args:
key: Storage key. Pass a stable, namespaced string
(e.g. ``"settings.theme"``).
initial: Value used before the first load completes.
Returns:
``(value, setter)``, same shape as
[`use_state`][pythonnative.use_state].
Example:
```python
import pythonnative as pn
@pn.component
def ThemeToggle():
theme, set_theme = pn.use_persisted_state("settings.theme", "light")
return pn.Button(
f"Theme: {theme}",
on_press=lambda: set_theme("dark" if theme == "light" else "light"),
)
```
"""
from
.
hooks
import
use_callback
,
use_effect
,
use_ref
,
use_state
from
.
runtime
import
run_async
state
,
set_state
=
use_state
(
initial
)
loaded
=
use_ref
(
False
)
async
def
_load
()
->
None
:
stored
=
await
AsyncStorage
.
get_json
(
key
)
if
stored
is
not
None
:
set_state
(
stored
)
loaded
.
current
=
True
use_effect
(
_load
, [
key
])
def
setter
(
value_or_updater
:
Any
)
->
None
:
def
_reducer
(
current
:
Any
)
->
Any
:
new_value
=
value_or_updater
(
current
)
if
callable
(
value_or_updater
)
else
value_or_updater
if
loaded
.
current
is
True
:
run_async
(
AsyncStorage
.
set_json
(
key
,
new_value
))
return
new_value
set_state
(
_reducer
)
stable_setter
=
use_callback
(
setter
, [
key
])
return
state
,
stable_setter
__all__
=
[
"AsyncStorage"
,
"use_persisted_state"
]
Back
|
FazBrowse Home
|
New Git URL