Skip to content

Commit c7669bd

Browse files
fix[ux]: fix relpath compiler panic on windows (#4228)
fix a bug where `os.path.relpath()` raises an exception on window - when the source path and the destination path are on different drives. this commit introduces the helper function `safe_relpath()`, which tries hard to construct a relpath (using `os.path.relpath()`), but falls back to the original path (which might be an absolute path) instead of raising an exception. references: - https://docs.python.org/3/library/os.path.html#os.path.relpath
1 parent 0f809c6 commit c7669bd

File tree

3 files changed

+16
-8
lines changed

3 files changed

+16
-8
lines changed

vyper/compiler/output_bundle.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import importlib
22
import io
33
import json
4-
import os
54
import zipfile
65
from dataclasses import dataclass
76
from functools import cached_property
@@ -13,7 +12,7 @@
1312
from vyper.compiler.settings import Settings
1413
from vyper.exceptions import CompilerPanic
1514
from vyper.semantics.analysis.module import _is_builtin
16-
from vyper.utils import get_long_version
15+
from vyper.utils import get_long_version, safe_relpath
1716

1817
# data structures and routines for constructing "output bundles",
1918
# basically reproducible builds of a vyper contract, with varying
@@ -62,7 +61,7 @@ def compiler_inputs(self) -> dict[str, CompilerInput]:
6261

6362
sources = {}
6463
for c in inputs:
65-
path = os.path.relpath(c.resolved_path)
64+
path = safe_relpath(c.resolved_path)
6665
# note: there should be a 1:1 correspondence between
6766
# resolved_path and source_id, but for clarity use resolved_path
6867
# since it corresponds more directly to search path semantics.
@@ -73,7 +72,7 @@ def compiler_inputs(self) -> dict[str, CompilerInput]:
7372
@cached_property
7473
def compilation_target_path(self):
7574
p = PurePath(self.compiler_data.file_input.resolved_path)
76-
p = os.path.relpath(p)
75+
p = safe_relpath(p)
7776
return _anonymize(p)
7877

7978
@cached_property
@@ -121,7 +120,7 @@ def used_search_paths(self) -> list[str]:
121120
sps = [sp for sp, count in tmp.items() if count > 0]
122121
assert len(sps) > 0
123122

124-
return [_anonymize(os.path.relpath(sp)) for sp in sps]
123+
return [_anonymize(safe_relpath(sp)) for sp in sps]
125124

126125

127126
class OutputBundleWriter:

vyper/semantics/analysis/module.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import os
21
from pathlib import Path, PurePath
32
from typing import Any, Optional
43

@@ -58,7 +57,7 @@
5857
from vyper.semantics.types.function import ContractFunctionT
5958
from vyper.semantics.types.module import ModuleT
6059
from vyper.semantics.types.utils import type_from_annotation
61-
from vyper.utils import OrderedSet
60+
from vyper.utils import OrderedSet, safe_relpath
6261

6362

6463
def analyze_module(
@@ -921,7 +920,7 @@ def _load_builtin_import(level: int, module_str: str) -> tuple[CompilerInput, In
921920
# hygiene: convert to relpath to avoid leaking user directory info
922921
# (note Path.relative_to cannot handle absolute to relative path
923922
# conversion, so we must use the `os` module).
924-
builtins_path = os.path.relpath(builtins_path)
923+
builtins_path = safe_relpath(builtins_path)
925924

926925
search_path = Path(builtins_path).parent.parent.parent
927926
# generate an input bundle just because it knows how to build paths.

vyper/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import enum
55
import functools
66
import hashlib
7+
import os
78
import sys
89
import time
910
import traceback
@@ -599,3 +600,12 @@ def annotate_source_code(
599600
cleanup_lines += [""] * (num_lines - len(cleanup_lines))
600601

601602
return "\n".join(cleanup_lines)
603+
604+
605+
def safe_relpath(path):
606+
try:
607+
return os.path.relpath(path)
608+
except ValueError:
609+
# on Windows, if path and curdir are on different drives, an exception
610+
# can be thrown
611+
return path

0 commit comments

Comments
 (0)