Skip to content
Closed
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
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ It consists of: Java (Truffle) + C (CPython C-API compatibility) + Python stdlib
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Build / run | `docs/contributor/CONTRIBUTING.md`, `mx.graalpython/` | This repo is `mx`-first (not a typical Maven/Gradle-only build). |
| Build / run | `docs/contributor/CONTRIBUTING.md`, `mx.graalpython/` | This repo is `mx`-first. The project build command is `mx python-jvm`; do not substitute generic `mx build` for normal build/test workflows. |
| Java runtime & Truffle nodes | `graalpython/com.oracle.graal.python/src/com/oracle/graal/python/{runtime,nodes,builtins}` | Main interpreter implementation. |
| C-API / native extensions | `graalpython/com.oracle.graal.python.cext/{include,src,modules}` | Mirrors CPython naming; many files are adapted from CPython. |
| Python stdlib overrides | `graalpython/lib-graalpython/` | GraalPy-specific modules executed at startup and/or used by builtins. |
Expand All @@ -42,6 +42,7 @@ It consists of: Java (Truffle) + C (CPython C-API compatibility) + Python stdlib

## ANTI-PATTERNS (THIS PROJECT)
- **Do not** base edits or reviews on `mxbuild/**` or `*.dist/**` outputs; change sources under `graalpython/**`, `mx.graalpython/**`, etc.
- To build the project locally, use `mx python-jvm`. Do **not** treat generic `mx build` as the repo's normal build command unless a task explicitly requires something narrower.
- Security reports: follow `SECURITY.md` (do **NOT** file public issues for vulnerabilities).
- C-API: heed CPython-style invariants in headers (e.g. `ceval.h`: **NEVER** nest `Py_BEGIN_ALLOW_THREADS` blocks; avoid mixing PyMem/PyObject allocators with `malloc`).
- Interop: foreign `executable` / `instantiable` objects are **never** called with keyword arguments (see `docs/user/Interoperability.md`).
Expand All @@ -55,8 +56,9 @@ It consists of: Java (Truffle) + C (CPython C-API compatibility) + Python stdlib

* Import dependent suites / download deps
`mx sforceimport`
* Build and run
* Build the project
`mx python-jvm`
* Run after building
`mx python -c 'print(42)'`
* Common local testing
* Run cpyext tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -82,6 +82,14 @@ def test_views():
assert set(mp.items()) == {('a', 1), ('b', 2), ('c', 3)}, "items view invalid"


def test_values_descriptor_rejects_non_mappingproxy():
class NotADict:
values = type(object.__dict__).values

assert_raises(TypeError, type(object.__dict__).values.__get__, NotADict(), NotADict)
assert_raises(TypeError, lambda: NotADict().values)


def test_init():
class CustomMappingObject:
def __init__(self, keys, values):
Expand Down Expand Up @@ -130,8 +138,8 @@ def test_iter():

mp_keys = set([k for k in mp])
assert d.keys() == mp_keys
def test_create():

def test_create():
_mappingproxy(dict())
mp = _mappingproxy({'a': 1})
_mappingproxy(mp)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -183,6 +183,11 @@ def test_descr_call_with_none():
assert None.__bool__() is False
assert_raises(TypeError, descr.__get__, None, None)


def test_builtin_descriptors_reject_invalid_receivers():
assert_raises(TypeError, dict.get.__get__, 1, int)
assert_raises(TypeError, str.__str__.__get__, 1, int)

def test_custom_getattribute():
class AAA:
__slots__ = '__wrapped__'
Expand Down Expand Up @@ -210,14 +215,14 @@ def __getattr__(self, name):
raise ValueError('wrapper has not been initialised')

return getattr(self.__wrapped__, name)

def __iter__(self):
return iter(self.__wrapped__)

class BBB(AAA):
def __init__(self, wrapped_dict=None):
AAA.__init__(self, wrapped_dict)

def __getattribute__(self, name):
if (hasattr(type(self), name)
and isinstance(getattr(type(self), name), property)):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -56,13 +56,16 @@
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.DescrGetBuiltinNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.object.DescriptorCheckNode;
import com.oracle.graal.python.runtime.object.PFactory;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.strings.TruffleString;

@CoreFunctions(extendClasses = PythonBuiltinClassType.PBuiltinFunction)
Expand Down Expand Up @@ -92,35 +95,49 @@ static Object doFunction(PFunction self, Object instance, Object klass) {

@Specialization(guards = {"!isNoValue(instance)", "!self.needsDeclaringType()"})
static PBuiltinMethod doBuiltinMethod(PBuiltinFunction self, Object instance, Object klass,
@Bind PythonLanguage language) {
@Bind PythonLanguage language,
@Bind Node inliningTarget,
@Shared("descriptorCheckNode") @Cached DescriptorCheckNode descriptorCheckNode) {
checkBuiltinDescriptorReceiver(self, instance, inliningTarget, descriptorCheckNode);
return PFactory.createBuiltinMethod(language, instance, self);
}

@Specialization(guards = {"!isNoValue(instance)", "self.needsDeclaringType()"})
static PBuiltinMethod doBuiltinMethodWithDeclaringClass(PBuiltinFunction self, Object instance, Object klass,
@Bind PythonLanguage language) {
@Bind PythonLanguage language,
@Bind Node inliningTarget,
@Shared("descriptorCheckNode") @Cached DescriptorCheckNode descriptorCheckNode) {
checkBuiltinDescriptorReceiver(self, instance, inliningTarget, descriptorCheckNode);
return PFactory.createBuiltinMethod(language, instance, self, self.getEnclosingType());
}

@Specialization(guards = "isNoValue(instance)")
static Object doBuiltinFunction(PBuiltinFunction self, Object instance, Object klass) {
return self;
}

private static void checkBuiltinDescriptorReceiver(PBuiltinFunction self, Object instance, Node inliningTarget, DescriptorCheckNode descriptorCheckNode) {
Object enclosingType = self.getEnclosingType();
if (enclosingType == null) {
return;
}
descriptorCheckNode.execute(inliningTarget, enclosingType, self.getName(), instance);
}
}

@Slot(value = SlotKind.tp_repr, isComplex = true)
@GenerateNodeFactory
abstract static class ReprNode extends PythonUnaryBuiltinNode {
@Specialization(guards = "self.getEnclosingType() == null")
static TruffleString reprModuleFunction(PBuiltinFunction self,
@Cached.Shared("formatter") @Cached StringUtils.SimpleTruffleStringFormatNode simpleTruffleStringFormatNode) {
@Shared("formatter") @Cached StringUtils.SimpleTruffleStringFormatNode simpleTruffleStringFormatNode) {
// (tfel): these really shouldn't be accessible, I think
return simpleTruffleStringFormatNode.format("<built-in function %s>", self.getName());
}

@Specialization(guards = "self.getEnclosingType() != null")
static TruffleString reprClassFunction(PBuiltinFunction self,
@Cached.Shared("formatter") @Cached StringUtils.SimpleTruffleStringFormatNode simpleTruffleStringFormatNode) {
@Shared("formatter") @Cached StringUtils.SimpleTruffleStringFormatNode simpleTruffleStringFormatNode) {
return simpleTruffleStringFormatNode.format("<method '%s' of '%s' objects>", self.getName(), TypeNodes.GetNameNode.executeUncached(self.getEnclosingType()));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -56,13 +56,15 @@
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.DescrGetBuiltinNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.object.DescriptorCheckNode;
import com.oracle.graal.python.runtime.object.PFactory;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.strings.TruffleString;

@CoreFunctions(extendClasses = PythonBuiltinClassType.WrapperDescriptor)
Expand Down Expand Up @@ -92,14 +94,25 @@ static Object doFunction(PFunction self, Object instance, Object klass) {

@Specialization(guards = {"!isNoValue(instance)"})
static PBuiltinMethod doBuiltinMethod(PBuiltinFunction self, Object instance, Object klass,
@Bind PythonLanguage language) {
@Bind PythonLanguage language,
@Bind Node inliningTarget,
@Cached DescriptorCheckNode descriptorCheckNode) {
checkBuiltinDescriptorReceiver(self, instance, inliningTarget, descriptorCheckNode);
return PFactory.createBuiltinMethod(PythonBuiltinClassType.MethodWrapper, PythonBuiltinClassType.MethodWrapper.getInstanceShape(language), instance, self);
}

@Specialization(guards = "isNoValue(instance)")
static Object doBuiltinFunction(PBuiltinFunction self, Object instance, Object klass) {
return self;
}

private static void checkBuiltinDescriptorReceiver(PBuiltinFunction self, Object instance, Node inliningTarget, DescriptorCheckNode descriptorCheckNode) {
Object enclosingType = self.getEnclosingType();
if (enclosingType == null) {
return;
}
descriptorCheckNode.execute(inliningTarget, enclosingType, self.getName(), instance);
}
}

@Slot(value = SlotKind.tp_repr, isComplex = true)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -60,7 +60,6 @@
import com.oracle.graal.python.nodes.attributes.GetFixedAttributeNode;
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
import com.oracle.graal.python.nodes.classes.IsSubtypeNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.object.GetClassNode;
Expand Down Expand Up @@ -130,25 +129,6 @@ static TruffleString doIndexedSlotDescriptor(IndexedSlotDescriptor self) {
}
}

@GenerateInline
@GenerateCached(false)
@GenerateUncached
abstract static class DescriptorCheckNode extends Node {
public abstract void execute(Node inliningTarget, Object descrType, Object nameObj, Object obj);

// https://github.com/python/cpython/blob/e8b19656396381407ad91473af5da8b0d4346e88/Objects/descrobject.c#L70
@Specialization
static void check(Node inliningTarget, Object descrType, Object name, Object obj,
@Cached GetClassNode getClassNode,
@Cached(inline = false) IsSubtypeNode isSubtypeNode,
@Cached PRaiseNode raiseNode) {
Object type = getClassNode.execute(inliningTarget, obj);
if (!isSubtypeNode.execute(type, descrType)) {
throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.DESC_S_FOR_N_DOESNT_APPLY_TO_N, name, descrType, type);
}
}
}

@GenerateUncached
@GenerateInline(value = false)
public abstract static class DescrGetNode extends Node {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -53,14 +53,14 @@
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrDeleteNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrGetNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrSetNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescriptorCheckNode;
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
import com.oracle.graal.python.builtins.objects.type.TpSlots;
import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetNameNode;
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrGet.DescrGetBuiltinNode;
import com.oracle.graal.python.builtins.objects.type.slots.TpSlotDescrSet.DescrSetBuiltinNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.object.DescriptorCheckNode;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -55,7 +55,6 @@
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrDeleteNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrGetNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescrSetNode;
import com.oracle.graal.python.builtins.objects.getsetdescriptor.DescriptorBuiltins.DescriptorCheckNode;
import com.oracle.graal.python.builtins.objects.object.ObjectNodes.GetIdNode;
import com.oracle.graal.python.builtins.objects.str.StringUtils.SimpleTruffleStringFormatNode;
import com.oracle.graal.python.builtins.objects.type.TpSlots;
Expand All @@ -66,6 +65,7 @@
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromModuleNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
import com.oracle.graal.python.nodes.object.DescriptorCheckNode;
import com.oracle.graal.python.runtime.object.PFactory;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,13 @@ public StackWalkResult visitFrame(FrameInstance frameInstance) {
if (!selector.skip(pRootNode)) {
if (i == level) {
Frame frame = ReadFrameNode.getFrame(frameInstance, frameAccess);
assert PArguments.assertIsPythonFrame(frame);
/*
* It's possible that an async action interrupts a frame before the
* callee context initialized the frame reference, skip it then
*/
if (PArguments.getCurrentFrameInfo(frame) == null) {
return null;
}
IndirectCallData.setCallerFlagsOnIndirectCallData(callNode, callerFlags);
if (prevRootNode instanceof PRootNode prevPRootNode && prevPRootNode.setsUpCalleeContext()) {
// Update the flags in the callee
Expand Down
Loading
Loading