Skip to content

Commit 4809eb5

Browse files
committed
Python 3.13 support
1 parent 976ecbf commit 4809eb5

File tree

8 files changed

+31
-31
lines changed

8 files changed

+31
-31
lines changed

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: "${{ matrix.os }}"
1515
strategy:
1616
matrix:
17-
python-version: ["3.9", "3.10", "3.11"]
17+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
1818
os: [ubuntu-latest]
1919
steps:
2020
- uses: actions/checkout@v2

pyglove/core/coding/execution.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,9 @@ def _run():
198198
except Exception as e: # pylint: disable=broad-exception-caught
199199
q.put(e)
200200

201-
q = multiprocessing.Queue()
202-
p = multiprocessing.Process(
201+
ctx = multiprocessing.get_context('fork')
202+
q = ctx.Queue()
203+
p = ctx.Process(
203204
target=_call, args=tuple([q] + list(args)), kwargs=kwargs
204205
)
205206
try:

pyglove/core/coding/permissions.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,22 @@
2020
from pyglove.core import utils
2121

2222

23-
class CodePermission(enum.Flag):
23+
class CodePermissionMeta(enum.EnumMeta):
24+
25+
@property
26+
def BASIC(cls) -> 'CodePermission':
27+
"""Returns basic permissions."""
28+
return cls.ASSIGN | cls.CALL
29+
30+
@property
31+
def ALL(cls) -> 'CodePermission':
32+
"""Returns all permissions."""
33+
return (
34+
cls.BASIC | cls.CONDITION | cls.LOOP | cls.EXCEPTION |
35+
cls.CLASS_DEFINITION | cls.FUNCTION_DEFINITION | cls.IMPORT)
36+
37+
38+
class CodePermission(enum.Flag, metaclass=CodePermissionMeta):
2439
"""Permissions for code execution."""
2540

2641
# Allows assignment.
@@ -47,21 +62,6 @@ class CodePermission(enum.Flag):
4762
# Allows import.
4863
IMPORT = enum.auto()
4964

50-
@classmethod
51-
@property
52-
def BASIC(cls) -> 'CodePermission': # pylint: disable=invalid-name
53-
"""Returns basic permissions."""
54-
return CodePermission.ASSIGN | CodePermission.CALL
55-
56-
@classmethod
57-
@property
58-
def ALL(cls) -> 'CodePermission': # pylint: disable=invalid-name
59-
"""Returns all permissions."""
60-
return (
61-
CodePermission.BASIC | CodePermission.CONDITION | CodePermission.LOOP |
62-
CodePermission.EXCEPTION | CodePermission.CLASS_DEFINITION |
63-
CodePermission.FUNCTION_DEFINITION | CodePermission.IMPORT)
64-
6565

6666
_TLS_CODE_RUN_PERMISSION = '__code_run_permission__'
6767

pyglove/core/io/file_system_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
class StdFileSystemTest(unittest.TestCase):
2323

2424
def test_file(self):
25-
tmp_dir = tempfile.gettempdir()
25+
tmp_dir = tempfile.mkdtemp()
2626
fs = file_system.StdFileSystem()
2727

2828
file1 = os.path.join(tmp_dir, 'file1')
@@ -44,7 +44,7 @@ def test_file(self):
4444
self.assertFalse(fs.exists(file1))
4545

4646
def test_file_system(self):
47-
tmp_dir = tempfile.gettempdir()
47+
tmp_dir = tempfile.mkdtemp()
4848
fs = file_system.StdFileSystem()
4949

5050
# Create a directory.
@@ -68,7 +68,7 @@ def test_file_system(self):
6868
# Test rm.
6969
with self.assertRaises(FileNotFoundError):
7070
fs.rm(os.path.join(dir_a, 'file2'))
71-
with self.assertRaises(IsADirectoryError):
71+
with self.assertRaises((IsADirectoryError, PermissionError)):
7272
fs.rm(os.path.join(dir_a, 'b'))
7373

7474
# Test rmdir.
@@ -184,7 +184,7 @@ def test_file_system(self):
184184
class FileIoApiTest(unittest.TestCase):
185185

186186
def test_standard_filesystem(self):
187-
file1 = os.path.join(tempfile.gettempdir(), 'file1')
187+
file1 = os.path.join(tempfile.mkdtemp(), 'file1')
188188
with self.assertRaises(FileNotFoundError):
189189
file_system.readfile(file1)
190190
self.assertIsNone(file_system.readfile(file1, nonexist_ok=True))
@@ -199,7 +199,7 @@ def test_standard_filesystem(self):
199199
file_system.rm(file1)
200200
self.assertFalse(file_system.path_exists(file1))
201201

202-
dir1 = os.path.join(tempfile.gettempdir(), 'dir1')
202+
dir1 = os.path.join(tempfile.mkdtemp(), 'dir1')
203203
file_system.mkdir(dir1)
204204
self.assertEqual(file_system.listdir(dir1), [])
205205
file_system.mkdirs(os.path.join(dir1, 'a/b/c'))
@@ -208,7 +208,7 @@ def test_standard_filesystem(self):
208208
self.assertEqual(sorted(file_system.listdir(dir1)), ['a', 'file2']) # pylint: disable=g-generic-assert
209209
self.assertEqual( # pylint: disable=g-generic-assert
210210
sorted(file_system.listdir(dir1, fullpath=True)),
211-
['/tmp/dir1/a', '/tmp/dir1/file2']
211+
[os.path.join(dir1, 'a'), os.path.join(dir1, 'file2')]
212212
)
213213
file_system.rmdir(os.path.join(dir1, 'a/b/c'))
214214
file_system.rmdirs(os.path.join(dir1, 'a/b'))

pyglove/core/symbolic/functor.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ def _call(self) -> int:
8888
#
8989

9090
@classmethod
91-
@property
9291
def is_subclassed_functor(cls) -> bool:
9392
"""Returns True if this class is a subclassed Functor."""
9493
return cls.auto_schema
9594

9695
@classmethod
9796
def _update_signatures_based_on_schema(cls):
9897
# Update the return value of subclassed functors.
99-
if cls.is_subclassed_functor: # pylint: disable=using-constant-test
98+
if cls.is_subclassed_functor(): # pylint: disable=using-constant-test
10099
private_call_signature = pg_typing.Signature.from_callable(
101100
cls._call, auto_typing=True, auto_doc=True,
102101
)
@@ -235,7 +234,7 @@ def __init__(
235234

236235
# For subclassed Functor, we use thread-local storage for storing temporary
237236
# member overrides from the arguments during functor call.
238-
self._tls = threading.local() if self.is_subclassed_functor else None
237+
self._tls = threading.local() if self.is_subclassed_functor() else None
239238

240239
def _sym_inferred(self, key: str, **kwargs: Any) -> Any:
241240
"""Overrides method to allow member overrides during call."""
@@ -361,7 +360,7 @@ def __call__(self, *args, **kwargs) -> Any:
361360
args, kwargs = self._parse_call_time_overrides(*args, **kwargs)
362361
signature = self.__signature__
363362

364-
if self.is_subclassed_functor:
363+
if self.is_subclassed_functor():
365364
for arg_spec, arg_value in zip(signature.args, args):
366365
kwargs[arg_spec.name] = arg_value
367366

pyglove/core/utils/docstr_utils_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ class Foo:
111111
pass
112112

113113
self.assertIsNone(docstr_utils.docstr(Foo))
114-
self.assertIsNone(docstr_utils.docstr(None))
115114

116115
class Bar:
117116
"""bar."""

pyglove/core/utils/json_conversion.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ def _method_to_json(f: types.MethodType) -> Dict[str, str]:
624624

625625

626626
_SUPPORTED_ANNOTATIONS = {
627+
typing.Annotated: 'typing.Annotated',
627628
typing.Any: 'typing.Any',
628629
typing.Sequence: 'typing.Sequence',
629630
collections.abc.Sequence: 'typing.Sequence',

pyglove/core/utils/timing_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_basics(self):
2929

3030
tc.start()
3131
self.assertTrue(tc.has_started)
32-
self.assertGreater(tc.elapse, 0)
32+
self.assertGreaterEqual(tc.elapse, 0)
3333

3434
self.assertTrue(tc.end())
3535
self.assertTrue(tc.has_ended)

0 commit comments

Comments
 (0)