Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/_downstream-test-oracledb.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ jobs:
lld liblld-dev \
clang libclang-dev \
cmake
if sudo apt-get install -y libaio1t64; then
# Oracle Instant Client still looks for the pre-t64 SONAME on Ubuntu 24.04.
libaio_t64="$(dpkg -L libaio1t64 | grep '/libaio\.so\.1t64$')"
sudo ln -sf "$libaio_t64" "$(dirname "$libaio_t64")/libaio.so.1"
sudo ldconfig
else
sudo apt-get install -y libaio1
fi
- name: Install Oracle Instant Client
run: |
curl -fL https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linuxx64.zip -o instantclient-basiclite.zip
Expand Down
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ It consists of: Java (Truffle) + C (CPython C-API compatibility) + Python stdlib
| Vendored stdlib + CPython tests | `graalpython/lib-python/3/` | Large; treat as upstream-ish unless you are explicitly changing stdlib/tests. |
| Python-level tests | `graalpython/com.oracle.graal.python.test/src/tests/` | Includes tagged tests + C-API tests. Runner: `.../src/runner.py`. |
| CI pipelines | `.github/workflows/`, `ci.jsonnet`, `ci/` | Workflows typically drive `mx` gates/tags. |
| Launchers / helper scripts | `scripts/python.sh`, `scripts/*` | `python.sh` is the local launcher wrapper. |

## CONVENTIONS (DEVIATIONS)
- `mx` is the primary build/test entrypoint; suite definition lives in `mx.graalpython/suite.py`.
Expand Down
41 changes: 41 additions & 0 deletions graalpython/com.oracle.graal.python.test/src/tests/test_patmat.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,47 @@ def star_match(x):

assert star_match(d) == {33:33}

def test_mapping_star_rest_missing_key_falls_through():
def single_key(subject):
match subject:
case {"x": x, **rest}:
return ("x", x, rest)
case {**rest}:
return ("rest", rest)

assert single_key({"p": 1, "q": 2}) == ("rest", {"p": 1, "q": 2})
assert single_key({"x": 1, "q": 2}) == ("x", 1, {"q": 2})

def two_keys(subject):
match subject:
case {"x": x, "y": y, **rest}:
return ("xy", x, y, rest)
case {**rest}:
return ("rest", rest)

assert two_keys({"p": 1, "q": 2}) == ("rest", {"p": 1, "q": 2})
assert two_keys({"x": 1, "y": 2, "q": 3}) == ("xy", 1, 2, {"q": 3})

def test_mapping_pattern_get_called_once_per_key():
class CountingDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.get_calls = []

def get(self, key, default=None):
self.get_calls.append(key)
return super().get(key, default)

def match_x(subject):
match subject:
case {"x": x}:
return x
return None

subject = CountingDict(x=1)
assert match_x(subject) == 1
assert subject.get_calls == ["x"]

def test_mutable_dict_keys():
class MyObj:
pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5439,12 +5439,17 @@ private void doVisitPattern(PatternTy.MatchMapping node, PatternContext pc) {

if (starTarget != null) {
BytecodeLocal starVariable = pc.allocateBindVariable(starTarget);
b.beginStoreLocal(starVariable);
b.beginCopyDictWithoutKeys();
b.emitLoadLocal(pc.subject);
b.emitLoadLocal(keysChecked);
b.endCopyDictWithoutKeys();
b.endStoreLocal();
b.beginIfThen();
b.emitLoadLocal(temp);
b.beginBlock();
b.beginStoreLocal(starVariable);
b.beginCopyDictWithoutKeys();
b.emitLoadLocal(pc.subject);
b.emitLoadLocal(keysChecked);
b.endCopyDictWithoutKeys();
b.endStoreLocal();
b.endBlock();
b.endIfThen();
}

endTemporaryLocal(keysChecked);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1720,8 +1720,9 @@ public static final class MatchKeys {
public static boolean perform(VirtualFrame frame, LocalAccessor values, Object map, Object[] keys,
@Bind BytecodeNode bytecodeNode,
@Cached MatchKeysNode node) {
values.setObject(bytecodeNode, frame, node.execute(frame, map, keys));
return node.execute(frame, map, keys) != PNone.NONE;
Object match = node.execute(frame, map, keys);
values.setObject(bytecodeNode, frame, match);
return match != PNone.NONE;
}
}

Expand Down
63 changes: 53 additions & 10 deletions mx.graalpython/mx_graalpython.py
Original file line number Diff line number Diff line change
Expand Up @@ -877,7 +877,38 @@ def _dev_pythonhome():
return os.path.join(SUITE.dir, "graalpython")


def get_path_with_patchelf(graalpy=None):
DELVEEWHEEL_GRAALPY_ARTIFACT = "graal/python-native-standalone-svm-svmee-java25-windows-amd64-25.1.3.zip"
DELVEEWHEEL_GRAALPY_HOME = "graalpy3.12-25.1.3-windows-amd64"


def _downloaded_graalpy_for_delvewheel():
download_script = os.environ.get("ARTIFACT_DOWNLOAD_SCRIPT")
if not download_script:
mx.abort("Cannot build delvewheel venv: need CPython >= 3.12 or ARTIFACT_DOWNLOAD_SCRIPT")

cache_dir = Path(SUITE.get_output_root()).absolute() / "delvewheel-graalpy"
archive = cache_dir / Path(DELVEEWHEEL_GRAALPY_ARTIFACT).name
extracted = cache_dir / "extracted"
graalpy = extracted / DELVEEWHEEL_GRAALPY_HOME / "bin" / "graalpy.exe"
if graalpy.exists():
return str(graalpy)

cache_dir.mkdir(parents=True, exist_ok=True)
if not archive.exists():
mx.log(
f"{time.strftime('[%H:%M:%S] ')} Downloading GraalPy for delvewheel venv: "
f"{DELVEEWHEEL_GRAALPY_ARTIFACT}"
)
subprocess.check_call([sys.executable, download_script, DELVEEWHEEL_GRAALPY_ARTIFACT, str(archive)])

extracted.mkdir(parents=True, exist_ok=True)
mx.Extractor.create(str(archive)).extract(str(extracted))
if not graalpy.exists():
mx.abort(f"Could not find bin/graalpy.exe in downloaded artifact {archive}")
return str(graalpy)


def get_path_with_patchelf():
path = os.environ.get("PATH", "")
if mx.is_linux() and not shutil.which("patchelf"):
venv = Path(SUITE.get_output_root()).absolute() / "patchelf-venv"
Expand All @@ -892,17 +923,29 @@ def get_path_with_patchelf(graalpy=None):
venv = Path(SUITE.get_output_root()).absolute() / "delvewheel-venv"
path += os.pathsep + str(venv / "Scripts")
if not shutil.which("delvewheel", path=path):
if sys.version_info < (3, 12):
if graalpy is None:
graalpy = graalpy_standalone_jvm()
venv_python = [graalpy, "-X", "jit=0"]
else:
if sys.implementation.name == "cpython" and sys.version_info >= (3, 12):
venv_python = [sys.executable]
mx.log(f"{time.strftime('[%H:%M:%S] ')} Building delvewheel-venv with {shlex.join(venv_python)}... [delvewheel not found on PATH]")
else:
venv_python = [_downloaded_graalpy_for_delvewheel(), "-X", "jit=0"]
mx.log(
f"{time.strftime('[%H:%M:%S] ')} Building delvewheel-venv with {shlex.join(venv_python)}... "
"[delvewheel not found on PATH]"
)
t0 = time.time()
subprocess.check_call(venv_python + ["-m", "venv", str(venv)])
subprocess.check_call([str(venv / "Scripts" / "pip.exe"), "install", "delvewheel>=1.13.0"])
mx.log(f"{time.strftime('[%H:%M:%S] ')} Building delvewheel-venv with {shlex.join(venv_python)}... [duration: {time.time() - t0}]")
subprocess.check_call(
[
str(venv / "Scripts" / "python.exe"),
"-m",
"pip",
"install",
"delvewheel>=1.13.0",
]
)
mx.log(
f"{time.strftime('[%H:%M:%S] ')} Building delvewheel-venv with {shlex.join(venv_python)}... "
f"[duration: {time.time() - t0}]"
)
return path


Expand Down Expand Up @@ -1903,7 +1946,7 @@ def graalpython_gate_runner(_, tasks):
if task:
env = os.environ.copy()
graalpy = graalpy_standalone_native()
env['PATH'] = get_path_with_patchelf(graalpy)
env['PATH'] = get_path_with_patchelf()
mx.log("1. Running twice without shared engine")
run_python_unittests(
graalpy,
Expand Down
20 changes: 19 additions & 1 deletion mx.graalpython/mx_graalpython_python_benchmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@

SETUPTOOLS_PIN = "77.0.1"


def add_cpython_build_env(env=None):
if python3_home := os.environ.get("PYTHON3_HOME"):
include_dir = join(python3_home, "Include")
if os.path.exists(join(include_dir, "Python.h")):
env = env.copy() if env is not None else os.environ.copy()
python_includes = os.pathsep.join([include_dir, python3_home])
include_flags = " ".join(f"-I{path}" for path in python_includes.split(os.pathsep))
env["CPATH"] = python_includes + (os.pathsep + env["CPATH"] if env.get("CPATH") else "")
for key in ["CFLAGS", "CPPFLAGS", "CXXFLAGS"]:
env[key] = include_flags + (" " + env[key] if env.get(key) else "")
env["LIBRARY_PATH"] = python3_home + (os.pathsep + env["LIBRARY_PATH"] if env.get("LIBRARY_PATH") else "")
return env


DEFAULT_PYPERFORMANCE_BENCHMARKS = [
# "2to3",
# "chameleon",
Expand Down Expand Up @@ -703,7 +718,8 @@ def _vmRun(self, vm, workdir, command, benchmarks, bmSuiteArgs):

vm.run(workdir, ["-m", "venv", join(workdir, vm_venv)])
pip = join(workdir, vm_venv, "bin", "pip")
mx.run([pip, "install", *self.BENCHMARK_REQ], cwd=workdir)
env = add_cpython_build_env() if vm.name() == "cpython" else None
mx.run([pip, "install", *self.BENCHMARK_REQ], cwd=workdir, env=env)
if vm.name() == "cpython":
patch_asv_for_cpython_312(workdir, vm_venv)
mx.run(
Expand Down Expand Up @@ -843,6 +859,8 @@ def _vmRun(self, vm, workdir, command, benchmarks, bmSuiteArgs):
constraints.flush()
env = os.environ.copy()
env['PIP_CONSTRAINT'] = constraints.name
if vm.name() == "cpython":
env = add_cpython_build_env(env)
mx.run([pip, "install", *self.BENCHMARK_REQ], cwd=workdir, env=env)
if vm.name() == "cpython":
patch_asv_for_cpython_312(workdir, vm_venv)
Expand Down
79 changes: 0 additions & 79 deletions scripts/bench.sh

This file was deleted.

44 changes: 0 additions & 44 deletions scripts/build-tools.sh

This file was deleted.

Loading
Loading