Skip to content

Commit ab81526

Browse files
committed
Implement PyModule_GetFilenameObject
Fixes #488
1 parent a16dffc commit ab81526

File tree

5 files changed

+73
-4
lines changed

5 files changed

+73
-4
lines changed

Diff for: graalpython/com.oracle.graal.python.cext/src/moduleobject.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ PyModule_GetFilenameObject(PyObject *m)
574574
Py_INCREF(fileobj);
575575
return fileobj;
576576
}
577+
#endif // GraalPy change
577578

578579
const char *
579580
PyModule_GetFilename(PyObject *m)
@@ -587,7 +588,6 @@ PyModule_GetFilename(PyObject *m)
587588
Py_DECREF(fileobj); /* module dict has still a reference */
588589
return utf8;
589590
}
590-
#endif // GraalPy change
591591

592592
PyModuleDef*
593593
PyModule_GetDef(PyObject* m)

Diff for: graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_module.py

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -54,6 +54,22 @@ def _reference_add_object(args):
5454
args[0].__dict__[args[1]] = args[2]
5555
return 0
5656

57+
58+
def _reference_get_filename(args):
59+
if not isinstance(args[0], ModuleType):
60+
raise TypeError
61+
file = getattr(args[0], '__file__', None)
62+
if isinstance(file, str):
63+
return file
64+
raise SystemError
65+
66+
67+
module_with_file = ModuleType("module")
68+
module_with_file.__file__ = 'file.py'
69+
module_with_broken_file = ModuleType("module")
70+
module_with_broken_file.__file__ = 1
71+
72+
5773
class TestPyModule(CPyExtTestCase):
5874

5975
test_PyModule_Check = CPyExtFunction(
@@ -175,3 +191,31 @@ class TestPyModule(CPyExtTestCase):
175191
arguments=["PyObject* m", "const char* k", "PyObject* v"],
176192
cmpfunc=unhandled_error_compare
177193
)
194+
195+
test_PyModule_GetFilenameObject = CPyExtFunction(
196+
_reference_get_filename,
197+
lambda: (
198+
(module_with_file,),
199+
(module_with_broken_file,),
200+
(ModuleType("no-file"),),
201+
(1,),
202+
),
203+
resultspec="O",
204+
argspec='O',
205+
arguments=["PyObject* m"],
206+
cmpfunc=unhandled_error_compare
207+
)
208+
209+
test_PyModule_GetFilename = CPyExtFunction(
210+
_reference_get_filename,
211+
lambda: (
212+
(module_with_file,),
213+
(module_with_broken_file,),
214+
(ModuleType("no-file"),),
215+
(1,),
216+
),
217+
resultspec="s",
218+
argspec='O',
219+
arguments=["PyObject* m"],
220+
cmpfunc=unhandled_error_compare
221+
)

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextModuleBuiltins.java

+25
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyObjectTransfer;
5454
import static com.oracle.graal.python.nodes.ErrorMessages.S_NEEDS_S_AS_FIRST_ARG;
5555
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___DOC__;
56+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___FILE__;
5657
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___NAME__;
5758
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___PACKAGE__;
5859
import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING;
@@ -65,6 +66,7 @@
6566
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiTernaryBuiltinNode;
6667
import com.oracle.graal.python.builtins.modules.cext.PythonCextBuiltins.CApiUnaryBuiltinNode;
6768
import com.oracle.graal.python.builtins.modules.cext.PythonCextMethodBuiltins.CFunctionNewExMethodNode;
69+
import com.oracle.graal.python.builtins.objects.PNone;
6870
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.CheckPrimitiveFunctionResultNode;
6971
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.ExternalFunctionInvokeNode;
7072
import com.oracle.graal.python.builtins.objects.cext.capi.ExternalFunctionNodes.PExternalFunctionWrapper;
@@ -94,6 +96,7 @@
9496
import com.oracle.truffle.api.dsl.Bind;
9597
import com.oracle.truffle.api.dsl.Cached;
9698
import com.oracle.truffle.api.dsl.Cached.Shared;
99+
import com.oracle.truffle.api.dsl.Fallback;
97100
import com.oracle.truffle.api.dsl.ImportStatic;
98101
import com.oracle.truffle.api.dsl.Specialization;
99102
import com.oracle.truffle.api.interop.InteropLibrary;
@@ -297,4 +300,26 @@ static int doGeneric(PythonModule self, Object visitFun, Object arg,
297300
return 0;
298301
}
299302
}
303+
304+
@CApiBuiltin(ret = PyObjectTransfer, args = {PyObject}, call = Direct)
305+
abstract static class PyModule_GetFilenameObject extends CApiUnaryBuiltinNode {
306+
@Specialization
307+
static Object getFilename(PythonModule module,
308+
@Bind Node inliningTarget,
309+
@Cached ReadAttributeFromObjectNode read,
310+
@Cached PyUnicodeCheckNode check,
311+
@Cached PRaiseNode raiseNode) {
312+
Object file = read.execute(module, T___FILE__);
313+
if (file != PNone.NO_VALUE && check.execute(inliningTarget, file)) {
314+
return file;
315+
}
316+
throw raiseNode.raise(inliningTarget, SystemError, ErrorMessages.MODULE_FILENAME_MISSING);
317+
}
318+
319+
@Fallback
320+
static Object error(@SuppressWarnings("unused") Object module,
321+
@Bind Node inliningTarget) {
322+
throw PRaiseNode.raiseStatic(inliningTarget, TypeError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC);
323+
}
324+
}
300325
}

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ public final class CApiFunction {
350350
@CApiBuiltin(name = "PyModule_ExecDef", ret = Int, args = {PyObject, PyModuleDef}, call = CImpl)
351351
@CApiBuiltin(name = "PyModule_GetDef", ret = PyModuleDef, args = {PyObject}, call = CImpl)
352352
@CApiBuiltin(name = "PyModule_GetDict", ret = PyObject, args = {PyObject}, call = CImpl)
353+
@CApiBuiltin(name = "PyModule_GetFilename", ret = ConstCharPtrAsTruffleString, args = {PyObject}, call = CImpl)
353354
@CApiBuiltin(name = "PyModule_GetName", ret = ConstCharPtrAsTruffleString, args = {PyObject}, call = CImpl)
354355
@CApiBuiltin(name = "PyModule_GetState", ret = Pointer, args = {PyObject}, call = CImpl)
355356
@CApiBuiltin(name = "PyNumber_Absolute", ret = PyObject, args = {PyObject}, call = CImpl)
@@ -827,8 +828,6 @@ public final class CApiFunction {
827828
@CApiBuiltin(name = "PyMem_SetupDebugHooks", ret = Void, args = {}, call = NotImplemented)
828829
@CApiBuiltin(name = "PyMember_GetOne", ret = PyObject, args = {ConstCharPtrAsTruffleString, PyMemberDef}, call = NotImplemented)
829830
@CApiBuiltin(name = "PyMember_SetOne", ret = Int, args = {CHAR_PTR, PyMemberDef, PyObject}, call = NotImplemented)
830-
@CApiBuiltin(name = "PyModule_GetFilename", ret = ConstCharPtrAsTruffleString, args = {PyObject}, call = NotImplemented)
831-
@CApiBuiltin(name = "PyModule_GetFilenameObject", ret = PyObject, args = {PyObject}, call = NotImplemented)
832831
@CApiBuiltin(name = "PyODict_DelItem", ret = Int, args = {PyObject, PyObject}, call = NotImplemented)
833832
@CApiBuiltin(name = "PyODict_New", ret = PyObject, args = {}, call = NotImplemented)
834833
@CApiBuiltin(name = "PyODict_SetItem", ret = Int, args = {PyObject, PyObject, PyObject}, call = NotImplemented)

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java

+1
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ public abstract class ErrorMessages {
502502
public static final TruffleString MISSING_S = tsLiteral("Missing %s");
503503
public static final TruffleString S_MISSING_REQUIRED_ARG_POS_D = tsLiteral("%s missing required argument (pos %d)");
504504
public static final TruffleString MMAP_INDEX_OUT_OF_RANGE = tsLiteral("mmap index out of range");
505+
public static final TruffleString MODULE_FILENAME_MISSING = tsLiteral("module filename missing");
505506
public static final TruffleString MODULE_HAS_NO_ATTR_S = tsLiteral("module has no attribute '%s'");
506507
public static final TruffleString MODULE_PARTIALLY_INITIALIZED_S_HAS_NO_ATTR_S = tsLiteral("partially initialized module '%s' has no attribute '%s' (most likely due to a circular import)");
507508
public static final TruffleString MODULE_S_HAS_NO_ATTR_S = tsLiteral("module '%s' has no attribute '%s'");

0 commit comments

Comments
 (0)