Skip to content

Commit 034385b

Browse files
Fix Python 3.6 compatibility issues []
1 parent 435b7d1 commit 034385b

8 files changed

Lines changed: 76 additions & 62 deletions

File tree

‎dev_tools/bin/edg-docker-shell‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def _resolve_working_directory(args: argparse.Namespace,
103103
# Otherwise, calculate a working directory maintaining the same
104104
# relativity to the root project source directory.
105105
cwd = Path.cwd()
106-
if cwd.is_relative_to(src_dir):
106+
if edgutil.is_path_relative_to(cwd, src_dir):
107107
result_path = result_path.joinpath(cwd.relative_to(src_dir))
108108

109109
return result_path

‎dev_tools/bin/edg-docker-test-bisect‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def _resolve_test_path(mono_repo_dir: Path, test_path: Path) -> Optional[str]:
100100
return None
101101

102102
mono_repo_tests_dir = mono_repo_dir / 'tests' / 'tests'
103-
if not test_path.is_relative_to(mono_repo_dir):
103+
if not edgutil.is_path_relative_to(test_path, mono_repo_dir):
104104
return None
105105

106106
return str(test_path.relative_to(mono_repo_tests_dir).as_posix())

‎dev_tools/bin/edg-rematerialize-test-run‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def collect_affected_tests(test_home: Path,
126126
for diff_file in diff_files:
127127
file_path = test_home.parent.joinpath(PurePosixPath(diff_file.file_name))
128128

129-
if file_path.is_relative_to(tests_dir):
129+
if edgutil.is_path_relative_to(file_path, tests_dir):
130130
# A file in a test suite.
131131
orig_file_path = file_path
132132

@@ -166,7 +166,7 @@ def collect_affected_tests(test_home: Path,
166166
test_file_found = True
167167
# File not found, move on to the parent.
168168
file_path = file_path.parent
169-
elif (file_path.is_relative_to(expectations_dir) and
169+
elif (edgutil.is_path_relative_to(file_path, expectations_dir) and
170170
file_path.suffix == '.log'):
171171
config_name = file_path.parent.name
172172
suite_name = file_path.stem
@@ -511,7 +511,7 @@ async def simulate_test(test_home: Path, config_run_dir: Path,
511511
if len(rt_metadata_cases) > 0:
512512
# relative_test_path is already suite/... (relative to test_home/tests),
513513
# matching live runs that use path relative to top_dir.parent.
514-
await asyncio.to_thread(
514+
await edgutil.async_to_thread(
515515
edgtest.runtest.finalize_rt_tar,
516516
rt_contents,
517517
rt_metadata_cases,

‎dev_tools/pylibs/edgacknowledg/client/bench/__init__.py‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
trunc_display_content,
3535
)
3636
import edgutil
37-
from edgutil import eprint, get_running_event_loop
37+
from edgutil import eprint
3838

3939
TOOL_PATH_CG_ANNOTATE = edgutil.RequiredToolPath('cg_annotate')
4040

@@ -289,10 +289,8 @@ async def run_bench_source_handler(channel: Channel,
289289
run_path = session.run_dir / metadata.rel_benchmark_path
290290

291291
async def annotate_job() -> str:
292-
loop = get_running_event_loop()
293-
return await loop.run_in_executor(
294-
None,
295-
lambda: get_cg_annotate_output(baseline_path, run_path)
292+
return await edgutil.async_to_thread(
293+
get_cg_annotate_output, baseline_path, run_path
296294
)
297295

298296
annotate_text = await worker_pool.submit(annotate_job)

‎dev_tools/pylibs/edgdocker/__init__.py‎

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -428,16 +428,7 @@ def exec_docker_cmd(image_name: str, workspace_dir: Path,
428428
if 'EDG_BASE' in os.environ:
429429
container_workspace_dir = PurePosixPath('/', 'edg', 'workspace')
430430
host_base_path = Path(os.environ['EDG_BASE'])
431-
# Path.is_relative_to is 3.9+.
432-
if sys.version_info >= (3, 9):
433-
base_is_relative = host_base_path.is_relative_to(workspace_dir)
434-
else:
435-
try:
436-
host_base_path.relative_to(workspace_dir)
437-
base_is_relative = True
438-
except ValueError:
439-
base_is_relative = False
440-
if base_is_relative:
431+
if edgutil.is_path_relative_to(host_base_path, workspace_dir):
441432
rel_base_path = host_base_path.relative_to(workspace_dir)
442433
base_path = container_workspace_dir.joinpath(rel_base_path)
443434
_add_env_value(docker_args, 'EDG_BASE', str(base_path))

‎dev_tools/pylibs/edgtest/exec/__init__.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ def background_process_lines():
490490
# If UTF decoding fails, revert to a binary line write.
491491
output_file_handle.write(line)
492492

493-
await asyncio.to_thread(background_process_lines)
493+
await edgutil.async_to_thread(background_process_lines)
494494

495495
return tested_process.returncode
496496

@@ -925,7 +925,7 @@ async def run_executed_process(
925925
# isn't fully blocked. In free-threaded Python builds, this should also
926926
# be significantly more performant for test suites with heavy regex use.
927927
matches_file = case_artifact_dir / 'matches' / 'output.txt'
928-
missing_matches = await asyncio.to_thread(
928+
missing_matches = await edgutil.async_to_thread(
929929
verify_regex_matches,
930930
command_body_files,
931931
test_descript.match_regex,
@@ -1221,7 +1221,7 @@ async def run_test(test_path: Path, *, top_dir: Path, output_dir: Path,
12211221
if len(rt_metadata_cases) > 0:
12221222
# Metadata path is relative to top_dir's parent so the top directory
12231223
# name (e.g. the suite) remains the first path component.
1224-
await asyncio.to_thread(
1224+
await edgutil.async_to_thread(
12251225
edgtest.runtest.finalize_rt_tar,
12261226
rt_contents,
12271227
rt_metadata_cases,

‎dev_tools/pylibs/edgtest/runtest/__init__.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1258,7 +1258,7 @@ def finalize_rt_tar(contents: RtTarContents,
12581258
per-case matches diff_hash values.
12591259
12601260
Callers that need to keep an asyncio event loop responsive should run this
1261-
via ``asyncio.to_thread``.
1261+
via ``edgutil.async_to_thread``.
12621262
'''
12631263
diff_hashes: List[str] = []
12641264
for case in cases:

‎dev_tools/pylibs/edgutil/__init__.py‎

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -312,23 +312,63 @@ class AsyncLoopFatalError(Exception):
312312
'''Raised to ask ``run_asyncio_loop`` to cancel remaining tasks and stop.'''
313313
pass
314314

315-
def get_running_event_loop() -> asyncio.AbstractEventLoop:
316-
# asyncio.get_running_loop is 3.7+.
317-
if sys.version_info >= (3, 7):
315+
# The helpers below depend on the Python version, which cannot change at run
316+
# time, so each is declared once per supported API and selected at import.
317+
318+
if sys.version_info >= (3, 7):
319+
def get_running_event_loop() -> asyncio.AbstractEventLoop:
320+
'''Return the running event loop (asyncio.get_running_loop is 3.7+).'''
318321
return asyncio.get_running_loop()
319-
return asyncio.get_event_loop()
320-
321-
def _active_asyncio_tasks(
322-
loop: asyncio.AbstractEventLoop) -> Set[asyncio.Task]:
323-
# In Python 3.7 asyncio.Task.all_tasks was deprecated in favor of
324-
# asyncio.all_tasks. This was later removed in 3.9.
325-
#
326-
# To provide compatibility for both check to see if our python version is
327-
# greater than or equal to 3.7, and conditionally enable the new API,
328-
# otherwise fallback to the original API.
329-
if sys.version_info >= (3, 7):
322+
else:
323+
def get_running_event_loop() -> asyncio.AbstractEventLoop:
324+
'''Return the running event loop (asyncio.get_running_loop is 3.7+).'''
325+
return asyncio.get_event_loop()
326+
327+
if sys.version_info >= (3, 9):
328+
def is_path_relative_to(path: Path, other: Path) -> bool:
329+
'''Return whether path is equal to or located under other.'''
330+
return path.is_relative_to(other)
331+
else:
332+
def is_path_relative_to(path: Path, other: Path) -> bool:
333+
'''Return whether path is equal to or located under other.
334+
335+
Path.is_relative_to is only available in Python 3.9+.
336+
'''
337+
try:
338+
result = Path(os.path.commonpath([str(path), str(other)])) == other
339+
except ValueError:
340+
# Mixing absolute and relative paths (or differing drives).
341+
result = False
342+
return result
343+
344+
if sys.version_info >= (3, 9):
345+
async def async_to_thread(func: Callable[..., Any],
346+
*args: Any,
347+
**kwargs: Any) -> Any:
348+
'''Run func(*args, **kwargs) in a worker thread and await its result.'''
349+
return await asyncio.to_thread(func, *args, **kwargs)
350+
else:
351+
async def async_to_thread(func: Callable[..., Any],
352+
*args: Any,
353+
**kwargs: Any) -> Any:
354+
'''Run func(*args, **kwargs) in a worker thread and await its result.
355+
356+
asyncio.to_thread is only available in Python 3.9+.
357+
'''
358+
return await get_running_event_loop().run_in_executor(
359+
None, functools.partial(func, *args, **kwargs)
360+
)
361+
362+
if sys.version_info >= (3, 7):
363+
def _active_asyncio_tasks(
364+
loop: asyncio.AbstractEventLoop) -> Set[asyncio.Task]:
365+
# asyncio.Task.all_tasks was deprecated in 3.7 in favor of
366+
# asyncio.all_tasks, and removed in 3.9.
330367
return asyncio.all_tasks(loop)
331-
return asyncio.Task.all_tasks(loop) # type: ignore[attr-defined]
368+
else:
369+
def _active_asyncio_tasks(
370+
loop: asyncio.AbstractEventLoop) -> Set[asyncio.Task]:
371+
return asyncio.Task.all_tasks(loop) # type: ignore[attr-defined]
332372

333373
def _stop_asyncio_loop(loop: asyncio.AbstractEventLoop) -> None:
334374
for task in _active_asyncio_tasks(loop):
@@ -671,29 +711,14 @@ async def __aenter__(self) -> Optional[BinaryIO]:
671711
self._out_handle = open(self._temp_dir / 'diff', 'w+b')
672712

673713
if _DIFF_CMD is None:
674-
# asyncio.to_thread is 3.9+.
675-
if sys.version_info >= (3, 9):
676-
has_diff = await asyncio.to_thread(
677-
_write_unified_diff_with_difflib,
678-
self._from_file,
679-
self._to_file,
680-
self._out_handle,
681-
self._from_label,
682-
self._to_label
683-
)
684-
else:
685-
loop = get_running_event_loop()
686-
has_diff = await loop.run_in_executor(
687-
None,
688-
functools.partial(
689-
_write_unified_diff_with_difflib,
690-
self._from_file,
691-
self._to_file,
692-
self._out_handle,
693-
self._from_label,
694-
self._to_label
695-
)
696-
)
714+
has_diff = await async_to_thread(
715+
_write_unified_diff_with_difflib,
716+
self._from_file,
717+
self._to_file,
718+
self._out_handle,
719+
self._from_label,
720+
self._to_label
721+
)
697722
else:
698723
has_diff = await _write_unified_diff_with_diff_cmd(
699724
self._from_file,

0 commit comments

Comments
 (0)