pyglove 0.5.0.dev202508250811__py3-none-any.whl → 0.5.0.dev202511300809__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyglove/core/__init__.py +8 -1
- pyglove/core/geno/base.py +7 -3
- pyglove/core/io/file_system.py +295 -2
- pyglove/core/io/file_system_test.py +291 -0
- pyglove/core/logging.py +45 -1
- pyglove/core/logging_test.py +12 -21
- pyglove/core/monitoring.py +657 -0
- pyglove/core/monitoring_test.py +289 -0
- pyglove/core/symbolic/__init__.py +7 -0
- pyglove/core/symbolic/base.py +89 -35
- pyglove/core/symbolic/base_test.py +3 -3
- pyglove/core/symbolic/dict.py +31 -12
- pyglove/core/symbolic/dict_test.py +49 -0
- pyglove/core/symbolic/list.py +17 -3
- pyglove/core/symbolic/list_test.py +24 -2
- pyglove/core/symbolic/object.py +3 -1
- pyglove/core/symbolic/object_test.py +13 -10
- pyglove/core/symbolic/ref.py +19 -7
- pyglove/core/symbolic/ref_test.py +94 -7
- pyglove/core/symbolic/unknown_symbols.py +147 -0
- pyglove/core/symbolic/unknown_symbols_test.py +100 -0
- pyglove/core/typing/annotation_conversion.py +8 -1
- pyglove/core/typing/annotation_conversion_test.py +14 -19
- pyglove/core/typing/class_schema.py +24 -1
- pyglove/core/typing/json_schema.py +221 -8
- pyglove/core/typing/json_schema_test.py +508 -12
- pyglove/core/typing/type_conversion.py +17 -3
- pyglove/core/typing/type_conversion_test.py +7 -2
- pyglove/core/typing/value_specs.py +5 -1
- pyglove/core/typing/value_specs_test.py +5 -0
- pyglove/core/utils/__init__.py +2 -0
- pyglove/core/utils/contextual.py +9 -4
- pyglove/core/utils/contextual_test.py +10 -0
- pyglove/core/utils/error_utils.py +59 -25
- pyglove/core/utils/json_conversion.py +360 -63
- pyglove/core/utils/json_conversion_test.py +146 -13
- pyglove/core/views/html/controls/tab.py +33 -0
- pyglove/core/views/html/controls/tab_test.py +37 -0
- pyglove/ext/evolution/base_test.py +1 -1
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/METADATA +8 -1
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/RECORD +44 -40
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/WHEEL +0 -0
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/licenses/LICENSE +0 -0
- {pyglove-0.5.0.dev202508250811.dist-info → pyglove-0.5.0.dev202511300809.dist-info}/top_level.txt +0 -0
|
@@ -1930,8 +1930,12 @@ class Object(Generic, ValueSpecBase):
|
|
|
1930
1930
|
elif isinstance(t, type):
|
|
1931
1931
|
if t is object:
|
|
1932
1932
|
raise TypeError('<class \'object\'> is too general for Object spec.')
|
|
1933
|
+
elif getattr(t, '__no_type_check__', False):
|
|
1934
|
+
t = object
|
|
1933
1935
|
elif not pg_inspect.is_generic(t):
|
|
1934
|
-
raise TypeError(
|
|
1936
|
+
raise TypeError(
|
|
1937
|
+
f'"cls" for Object spec should be a type or str. Encountered: {t!r}.'
|
|
1938
|
+
)
|
|
1935
1939
|
|
|
1936
1940
|
self._forward_ref = forward_ref
|
|
1937
1941
|
self._type_args = type_args
|
|
@@ -2193,6 +2193,11 @@ class ObjectTest(ValueSpecTest):
|
|
|
2193
2193
|
self.assertEqual(
|
|
2194
2194
|
vs.Object(forward_ref('Foo')).forward_refs, set([forward_ref('Foo')]))
|
|
2195
2195
|
|
|
2196
|
+
def test_no_type_check_special_handling(self):
|
|
2197
|
+
x = self.A()
|
|
2198
|
+
setattr(x, '__no_type_check__', True)
|
|
2199
|
+
self.assertIs(vs.Object(x).cls, object)
|
|
2200
|
+
|
|
2196
2201
|
def test_default(self):
|
|
2197
2202
|
self.assertEqual(vs.Object(self.A).default, typed_missing.MISSING_VALUE)
|
|
2198
2203
|
a = self.A()
|
pyglove/core/utils/__init__.py
CHANGED
|
@@ -74,6 +74,7 @@ modules with the following features:
|
|
|
74
74
|
from pyglove.core.utils.json_conversion import Nestable
|
|
75
75
|
from pyglove.core.utils.json_conversion import JSONValueType
|
|
76
76
|
|
|
77
|
+
from pyglove.core.utils.json_conversion import JSONConversionContext
|
|
77
78
|
from pyglove.core.utils.json_conversion import JSONConvertible
|
|
78
79
|
from pyglove.core.utils.json_conversion import from_json
|
|
79
80
|
from pyglove.core.utils.json_conversion import to_json
|
|
@@ -148,6 +149,7 @@ from pyglove.core.utils.docstr_utils import docstr
|
|
|
148
149
|
|
|
149
150
|
# Handling exceptions.
|
|
150
151
|
from pyglove.core.utils.error_utils import catch_errors
|
|
152
|
+
from pyglove.core.utils.error_utils import match_error
|
|
151
153
|
from pyglove.core.utils.error_utils import CatchErrorsContext
|
|
152
154
|
from pyglove.core.utils.error_utils import ErrorInfo
|
|
153
155
|
|
pyglove/core/utils/contextual.py
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import contextlib
|
|
17
17
|
import dataclasses
|
|
18
|
+
import inspect
|
|
18
19
|
import threading
|
|
19
20
|
from typing import Any, Callable, ContextManager, Iterator, Optional
|
|
20
21
|
|
|
@@ -89,10 +90,14 @@ def with_contextual_override(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
|
89
90
|
with contextual_override() as current_context:
|
|
90
91
|
pass
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
if inspect.iscoroutinefunction(func):
|
|
94
|
+
async def _func(*args, **kwargs) -> Any:
|
|
95
|
+
with contextual_override(**current_context):
|
|
96
|
+
return await func(*args, **kwargs)
|
|
97
|
+
else:
|
|
98
|
+
def _func(*args, **kwargs) -> Any:
|
|
99
|
+
with contextual_override(**current_context):
|
|
100
|
+
return func(*args, **kwargs)
|
|
96
101
|
return _func
|
|
97
102
|
|
|
98
103
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
# See the License for the specific language governing permissions and
|
|
13
13
|
# limitations under the License.
|
|
14
|
+
import asyncio
|
|
14
15
|
import concurrent.futures
|
|
15
16
|
import unittest
|
|
16
17
|
from pyglove.core.utils import contextual
|
|
@@ -83,6 +84,15 @@ class ContextualTest(unittest.TestCase):
|
|
|
83
84
|
[3]
|
|
84
85
|
)
|
|
85
86
|
|
|
87
|
+
def test_with_contextual_override_async_func(self):
|
|
88
|
+
async def func(i):
|
|
89
|
+
del i
|
|
90
|
+
return contextual.contextual_value('x')
|
|
91
|
+
|
|
92
|
+
with contextual.contextual_override(x=3):
|
|
93
|
+
self.assertEqual(
|
|
94
|
+
asyncio.run(contextual.with_contextual_override(func)(0)), 3
|
|
95
|
+
)
|
|
86
96
|
|
|
87
97
|
if __name__ == '__main__':
|
|
88
98
|
unittest.main()
|
|
@@ -108,6 +108,64 @@ def catch_errors(
|
|
|
108
108
|
Yields:
|
|
109
109
|
A CatchErrorsContext object.
|
|
110
110
|
"""
|
|
111
|
+
errors = _parse_error_spec(errors)
|
|
112
|
+
context = CatchErrorsContext()
|
|
113
|
+
try:
|
|
114
|
+
yield context
|
|
115
|
+
except BaseException as e: # pylint: disable=broad-exception-caught
|
|
116
|
+
if match_error(e, errors):
|
|
117
|
+
context.error = e
|
|
118
|
+
if error_handler is not None:
|
|
119
|
+
error_handler(e)
|
|
120
|
+
else:
|
|
121
|
+
raise
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def match_error(
|
|
125
|
+
error: BaseException,
|
|
126
|
+
errors: Union[
|
|
127
|
+
Union[Type[BaseException], Tuple[Type[BaseException], str]],
|
|
128
|
+
Sequence[Union[Type[BaseException], Tuple[Type[BaseException], str]]],
|
|
129
|
+
Dict[Type[BaseException], List[str]],
|
|
130
|
+
],
|
|
131
|
+
) -> bool:
|
|
132
|
+
"""Returns True if the error matches the specification, .
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
error: The error to match.
|
|
136
|
+
errors: A sequence of exception types or tuples of exception type and error
|
|
137
|
+
messages (described in regular expression) as the desired exception types
|
|
138
|
+
to match.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
True if the error matches the specification, False otherwise.
|
|
142
|
+
"""
|
|
143
|
+
error_mapping = _parse_error_spec(errors)
|
|
144
|
+
error_message = error.__class__.__name__ + ': ' + str(error)
|
|
145
|
+
for error_type, error_regexes in error_mapping.items():
|
|
146
|
+
if isinstance(error, error_type):
|
|
147
|
+
if not error_regexes:
|
|
148
|
+
return True
|
|
149
|
+
else:
|
|
150
|
+
for regex in error_regexes:
|
|
151
|
+
assert regex is not None
|
|
152
|
+
if not regex.startswith(('^', '.*')):
|
|
153
|
+
regex = '.*' + regex
|
|
154
|
+
if re.match(regex, error_message):
|
|
155
|
+
return True
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _parse_error_spec(
|
|
160
|
+
errors: Union[
|
|
161
|
+
Union[Type[BaseException], Tuple[Type[BaseException], str]],
|
|
162
|
+
Sequence[Union[Type[BaseException], Tuple[Type[BaseException], str]]],
|
|
163
|
+
Dict[Type[BaseException], List[str]],
|
|
164
|
+
]
|
|
165
|
+
) -> Dict[Type[BaseException], List[str]]:
|
|
166
|
+
"""Parses a sequence of error specifications into a dictionary."""
|
|
167
|
+
if isinstance(errors, dict):
|
|
168
|
+
return errors
|
|
111
169
|
if not isinstance(errors, (tuple, list)):
|
|
112
170
|
errors = [errors]
|
|
113
171
|
elif (
|
|
@@ -136,28 +194,4 @@ def catch_errors(
|
|
|
136
194
|
error_mapping[error_type] = []
|
|
137
195
|
if regex is not None:
|
|
138
196
|
error_mapping[error_type].append(regex)
|
|
139
|
-
|
|
140
|
-
context = CatchErrorsContext()
|
|
141
|
-
try:
|
|
142
|
-
yield context
|
|
143
|
-
except tuple(error_mapping.keys()) as e:
|
|
144
|
-
error_message = e.__class__.__name__ + ': ' + str(e)
|
|
145
|
-
found_match = False
|
|
146
|
-
for error_type, error_regexes in error_mapping.items():
|
|
147
|
-
if isinstance(e, error_type):
|
|
148
|
-
if not error_regexes:
|
|
149
|
-
found_match = True
|
|
150
|
-
else:
|
|
151
|
-
for regex in error_regexes:
|
|
152
|
-
assert regex is not None
|
|
153
|
-
if not regex.startswith(('^', '.*')):
|
|
154
|
-
regex = '.*' + regex
|
|
155
|
-
if re.match(regex, error_message):
|
|
156
|
-
found_match = True
|
|
157
|
-
break
|
|
158
|
-
if found_match:
|
|
159
|
-
context.error = e
|
|
160
|
-
if error_handler is not None:
|
|
161
|
-
error_handler(e)
|
|
162
|
-
else:
|
|
163
|
-
raise e
|
|
197
|
+
return error_mapping
|