Skip to content

Commit 13e6655

Browse files
committed
[GR-60392] Update pydantic-core, make it work on windows
PullRequest: graalpython/3610
2 parents 8267af4 + 0d9cfca commit 13e6655

File tree

10 files changed

+225
-23
lines changed

10 files changed

+225
-23
lines changed

graalpython/com.oracle.graal.python.cext/CAPIFunctions.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ PyMapping_Length;Py_ssize_t;PyObject*
356356
PyMapping_SetItemString;int;PyObject*|const char*|PyObject*
357357
PyMapping_Size;Py_ssize_t;PyObject*
358358
PyMapping_Values;PyObject*;PyObject*
359+
PyMarshal_ReadLastObjectFromFile;PyObject*;FILE*
360+
PyMarshal_ReadLongFromFile;long;FILE*
361+
PyMarshal_ReadObjectFromFile;PyObject*;FILE*
362+
PyMarshal_ReadObjectFromString;PyObject*;const char*|Py_ssize_t
363+
PyMarshal_ReadShortFromFile;int;FILE*
364+
PyMarshal_WriteLongToFile;void;long|FILE*|int
365+
PyMarshal_WriteObjectToFile;void;PyObject*|FILE*|int
366+
PyMarshal_WriteObjectToString;PyObject*;PyObject*|int
359367
PyMem_Calloc;void*;size_t|size_t
360368
PyMem_Free;void;void*
361369
PyMem_GetAllocator;void;PyMemAllocatorDomain|PyMemAllocatorEx*

graalpython/com.oracle.graal.python.cext/src/listobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ PyTypeObject PyList_Type = {
132132
};
133133

134134
// alias for internal function, currently used in PyO3
135-
void _PyList_SET_ITEM(PyObject* a, Py_ssize_t b, PyObject* c) {
135+
PyAPI_FUNC(void) _PyList_SET_ITEM(PyObject* a, Py_ssize_t b, PyObject* c) {
136136
return PyList_SET_ITEM(a, b, c);
137137
}
138138

graalpython/com.oracle.graal.python.cext/src/object.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,7 +2546,7 @@ Py_ssize_t PyTruffle_REFCNT(PyObject *obj) {
25462546
}
25472547

25482548
// alias, currently used in PyO3
2549-
Py_ssize_t _Py_REFCNT(PyObject *obj) {
2549+
PyAPI_FUNC(Py_ssize_t) _Py_REFCNT(PyObject *obj) {
25502550
return PyTruffle_REFCNT(obj);
25512551
}
25522552

@@ -2589,7 +2589,7 @@ PyTypeObject* PyTruffle_TYPE(PyObject *a) {
25892589
}
25902590

25912591
// alias, currently used in PyO3
2592-
PyTypeObject* _Py_TYPE(PyObject *obj) {
2592+
PyAPI_FUNC(PyTypeObject*) _Py_TYPE(PyObject *obj) {
25932593
return PyTruffle_TYPE(obj);
25942594
}
25952595

@@ -2625,7 +2625,7 @@ Py_ssize_t PyTruffle_SIZE(PyObject *ob) {
26252625
}
26262626

26272627
// alias, currently used in PyO3
2628-
Py_ssize_t _Py_SIZE(PyObject *obj) {
2628+
PyAPI_FUNC(Py_ssize_t) _Py_SIZE(PyObject *obj) {
26292629
return PyTruffle_SIZE(obj);
26302630
}
26312631

graalpython/com.oracle.graal.python.test/src/runner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def from_test_case(cls, test_file: Path, test: unittest.TestCase):
149149
test_id = f'<{action}>'
150150
else:
151151
test_id = f'{class_name}.<{action}>'
152-
elif type(test).id is not unittest.TestCase.id:
152+
elif type(test).id is not unittest.TestCase.id and type(test) is not unittest.FunctionTestCase:
153153
# Qualify doctests so that we know what they are
154154
test_id = f'{type(test).__qualname__}.{test_id}'
155155
return cls(test_file, test_id)

graalpython/com.oracle.graal.python.test/src/tests/test_repl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ def validate_repl(stdin, python_args=(), ignore_preamble=True):
8282
rlist, _, _ = select.select([pty_parent], [], [], 60)
8383
assert pty_parent in rlist, f"Timed out waiting for REPL output. Output: {whole_out}{out}"
8484
out += os.read(pty_parent, 1024).decode('utf-8')
85-
out = out.replace('\r\n', '\n')
8685
out = re.sub(r'\x1b\[(?:\?2004[hl]|\d+[A-G])', '', out)
86+
out = out.replace('\r\n', '\n')
8787
if out == '>>> ' or out.endswith(('\n>>> ', '\n... ')):
8888
prompt = out[:3]
8989
actual = out[:-5]

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PY_UNICODE_PTR;
108108
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.Pointer;
109109
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PrimitiveResult32;
110+
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PrimitiveResult64;
110111
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyCodeAddressRange;
111112
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyCodeObject;
112113
import static com.oracle.graal.python.builtins.objects.cext.capi.transitions.ArgDescriptor.PyFrameObject;
@@ -799,6 +800,14 @@ public final class CApiFunction {
799800
@CApiBuiltin(name = "PyMapping_HasKey", ret = Int, args = {PyObject, PyObject}, call = NotImplemented)
800801
@CApiBuiltin(name = "PyMapping_HasKeyString", ret = Int, args = {PyObject, ConstCharPtrAsTruffleString}, call = NotImplemented)
801802
@CApiBuiltin(name = "PyMapping_SetItemString", ret = Int, args = {PyObject, ConstCharPtrAsTruffleString, PyObject}, call = NotImplemented)
803+
@CApiBuiltin(name = "PyMarshal_ReadLastObjectFromFile", ret = PyObject, args = {FILE_PTR}, call = NotImplemented)
804+
@CApiBuiltin(name = "PyMarshal_ReadLongFromFile", ret = PrimitiveResult64, args = {FILE_PTR}, call = NotImplemented)
805+
@CApiBuiltin(name = "PyMarshal_ReadObjectFromFile", ret = PyObject, args = {FILE_PTR}, call = NotImplemented)
806+
@CApiBuiltin(name = "PyMarshal_ReadObjectFromString", ret = PyObject, args = {ConstCharPtr, Py_ssize_t}, call = NotImplemented)
807+
@CApiBuiltin(name = "PyMarshal_ReadShortFromFile", ret = PrimitiveResult32, args = {FILE_PTR}, call = NotImplemented)
808+
@CApiBuiltin(name = "PyMarshal_WriteLongToFile", ret = Void, args = {PrimitiveResult64, FILE_PTR, PrimitiveResult32}, call = NotImplemented)
809+
@CApiBuiltin(name = "PyMarshal_WriteObjectToFile", ret = Void, args = {PyObject, FILE_PTR, PrimitiveResult32}, call = NotImplemented)
810+
@CApiBuiltin(name = "PyMarshal_WriteObjectToString", ret = PyObject, args = {PyObject, PrimitiveResult32}, call = NotImplemented)
802811
@CApiBuiltin(name = "PyMem_GetAllocator", ret = Void, args = {PYMEMALLOCATORDOMAIN, PYMEMALLOCATOREX_PTR}, call = NotImplemented)
803812
@CApiBuiltin(name = "PyMem_SetAllocator", ret = Void, args = {PYMEMALLOCATORDOMAIN, PYMEMALLOCATOREX_PTR}, call = NotImplemented)
804813
@CApiBuiltin(name = "PyMem_SetupDebugHooks", ret = Void, args = {}, call = NotImplemented)

graalpython/lib-graalpython/patches/metadata.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,18 @@ license = 'BSD-3-Clause'
451451

452452
[[pydantic.rules]]
453453
# Pin to match our pinned pydantic-core
454-
version = '== 2.4.2'
454+
version = '== 2.10.3'
455455

456456
[[pydantic-core.rules]]
457457
version = '== 2.10.1'
458458
patch = 'pydantic-core-2.10.1.patch'
459459
license = 'MIT'
460460

461+
[[pydantic-core.rules]]
462+
version = '== 2.27.1'
463+
patch = 'pydantic-core-2.27.1.patch'
464+
license = 'MIT'
465+
461466
[[pydantic-core.rules]]
462467
version = '== 2.26.0'
463468
patch = 'pydantic-core-2.26.0.patch'

graalpython/lib-graalpython/patches/pydantic-core-2.26.0.patch

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,32 +37,39 @@ index 625e474..e3ad221 100644
3737
dbg_macro = "warn"
3838
diff --git a/build_backend.py b/build_backend.py
3939
new file mode 100644
40-
index 0000000..4576d33
40+
index 0000000..471610f
4141
--- /dev/null
4242
+++ b/build_backend.py
43-
@@ -0,0 +1,23 @@
43+
@@ -0,0 +1,30 @@
4444
+import maturin
4545
+import os
4646
+import shutil
4747
+import subprocess
48+
+import tarfile
49+
+
50+
+from pathlib import Path
51+
+from urllib.request import urlopen
4852
+
4953
+build_sdist = maturin.build_sdist
5054
+
55+
+
56+
+def get_crate_and_patch(namespace, name, version, patched_crates):
57+
+ with (
58+
+ urlopen(f'https://github.com/{namespace}/{name}/archive/refs/tags/v{version}.tar.gz') as f,
59+
+ tarfile.open(fileobj=f, mode='r:gz') as tar,
60+
+ ):
61+
+ tar.extractall(patched_crates, filter='data')
62+
+ crate = patched_crates / f'{name}-{version}'
63+
+ crate = crate.rename(patched_crates / name)
64+
+ subprocess.check_call(['patch', '-p1', '-d', str(crate), '-i', str((Path('patches') / f'{name}.patch').absolute())])
65+
+
66+
+
5167
+def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
52-
+ shutil.rmtree('patched_crates', ignore_errors=True)
53-
+ os.makedirs('patched_crates')
54-
+ subprocess.check_call([
55-
+ 'git', 'clone', 'https://github.com/PyO3/pyo3.git',
56-
+ 'patched_crates/pyo3',
57-
+ '--branch', 'v0.22.5',
58-
+ ])
59-
+ subprocess.check_call(['patch', '-p1', '-d', 'patched_crates/pyo3', '-i', '../../patches/pyo3.patch'])
60-
+ subprocess.check_call([
61-
+ 'git', 'clone', 'https://github.com/pydantic/jiter.git',
62-
+ 'patched_crates/jiter',
63-
+ '--branch', 'v0.7.0',
64-
+ ])
65-
+ subprocess.check_call(['patch', '-p1', '-d', 'patched_crates/jiter', '-i', '../../patches/jiter.patch'])
68+
+ patched_crates = Path('patched_crates')
69+
+ shutil.rmtree(patched_crates, ignore_errors=True)
70+
+ patched_crates.mkdir()
71+
+ get_crate_and_patch('PyO3', 'pyo3', '0.22.5', patched_crates)
72+
+ get_crate_and_patch('pydantic', 'jiter', '0.7.0', patched_crates)
6673
+ return maturin.build_wheel(wheel_directory, config_settings, metadata_directory)
6774
diff --git a/patches/jiter.patch b/patches/jiter.patch
6875
new file mode 100644
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
diff --git a/Cargo.toml b/Cargo.toml
2+
index 3b3b8a9..718029a 100644
3+
--- a/Cargo.toml
4+
+++ b/Cargo.toml
5+
@@ -29,7 +29,7 @@ rust-version = "1.75"
6+
[dependencies]
7+
# TODO it would be very nice to remove the "py-clone" feature as it can panic,
8+
# but needs a bit of work to make sure it's not used in the codebase
9+
-pyo3 = { version = "0.22.6", features = ["generate-import-lib", "num-bigint", "py-clone"] }
10+
+pyo3 = { version = "0.22.6", features = ["generate-import-lib", "num-bigint", "py-clone"], path = "patched_crates/pyo3" }
11+
regex = "1.11.1"
12+
strum = { version = "0.26.3", features = ["derive"] }
13+
strum_macros = "0.26.4"
14+
@@ -46,7 +46,7 @@ base64 = "0.22.1"
15+
num-bigint = "0.4.6"
16+
python3-dll-a = "0.2.10"
17+
uuid = "1.11.0"
18+
-jiter = { version = "0.7.1", features = ["python"] }
19+
+jiter = { version = "0.7.1", features = ["python"], path = "patched_crates/jiter/crates/jiter" }
20+
hex = "0.4.3"
21+
22+
[lib]
23+
@@ -74,12 +74,12 @@ debug = true
24+
strip = false
25+
26+
[dev-dependencies]
27+
-pyo3 = { version = "0.22.6", features = ["auto-initialize"] }
28+
+pyo3 = { version = "0.22.6", features = ["auto-initialize"], path = "patched_crates/pyo3" }
29+
30+
[build-dependencies]
31+
version_check = "0.9.5"
32+
# used where logic has to be version/distribution specific, e.g. pypy
33+
-pyo3-build-config = { version = "0.22.6" }
34+
+pyo3-build-config = { version = "0.22.6", path = "patched_crates/pyo3/pyo3-build-config" }
35+
36+
[lints.clippy]
37+
dbg_macro = "warn"
38+
diff --git a/build_backend.py b/build_backend.py
39+
new file mode 100644
40+
index 0000000..4710e3f
41+
--- /dev/null
42+
+++ b/build_backend.py
43+
@@ -0,0 +1,30 @@
44+
+import maturin
45+
+import os
46+
+import shutil
47+
+import subprocess
48+
+import tarfile
49+
+
50+
+from pathlib import Path
51+
+from urllib.request import urlopen
52+
+
53+
+build_sdist = maturin.build_sdist
54+
+
55+
+
56+
+def get_crate_and_patch(namespace, name, version, patched_crates):
57+
+ with (
58+
+ urlopen(f'https://github.com/{namespace}/{name}/archive/refs/tags/v{version}.tar.gz') as f,
59+
+ tarfile.open(fileobj=f, mode='r:gz') as tar,
60+
+ ):
61+
+ tar.extractall(patched_crates, filter='data')
62+
+ crate = patched_crates / f'{name}-{version}'
63+
+ crate = crate.rename(patched_crates / name)
64+
+ subprocess.check_call(['patch', '-p1', '-d', str(crate), '-i', str((Path('patches') / f'{name}.patch').absolute())])
65+
+
66+
+
67+
+def build_wheel(wheel_directory, config_settings=None, metadata_directory=None):
68+
+ patched_crates = Path('patched_crates')
69+
+ shutil.rmtree(patched_crates, ignore_errors=True)
70+
+ patched_crates.mkdir()
71+
+ get_crate_and_patch('PyO3', 'pyo3', '0.22.6', patched_crates)
72+
+ get_crate_and_patch('pydantic', 'jiter', '0.7.1', patched_crates)
73+
+ return maturin.build_wheel(wheel_directory, config_settings, metadata_directory)
74+
diff --git a/patches/jiter.patch b/patches/jiter.patch
75+
new file mode 100644
76+
index 0000000..3fc59ee
77+
--- /dev/null
78+
+++ b/patches/jiter.patch
79+
@@ -0,0 +1,12 @@
80+
+diff --git a/Cargo.toml b/Cargo.toml
81+
+index 122e111..9ec9e6d 100644
82+
+--- a/Cargo.toml
83+
++++ b/Cargo.toml
84+
+@@ -29,5 +29,5 @@ inherits = "release"
85+
+ debug = true
86+
+
87+
+ [workspace.dependencies]
88+
+-pyo3 = { version = "0.22.0" }
89+
+-pyo3-build-config = { version = "0.22.0" }
90+
++pyo3 = { version = "0.22.6", path = "../pyo3" }
91+
++pyo3-build-config = { version = "0.22.6", path = "../pyo3/pyo3-build-config" }
92+
diff --git a/patches/pyo3.patch b/patches/pyo3.patch
93+
new file mode 100644
94+
index 0000000..e488ffb
95+
--- /dev/null
96+
+++ b/patches/pyo3.patch
97+
@@ -0,0 +1,31 @@
98+
+diff --git a/pyo3-ffi/src/cpython/pyerrors.rs b/pyo3-ffi/src/cpython/pyerrors.rs
99+
+index 6d17ebc812..1d206f9b18 100644
100+
+--- a/pyo3-ffi/src/cpython/pyerrors.rs
101+
++++ b/pyo3-ffi/src/cpython/pyerrors.rs
102+
+@@ -6,19 +6,19 @@ use crate::Py_ssize_t;
103+
+ #[derive(Debug)]
104+
+ pub struct PyBaseExceptionObject {
105+
+ pub ob_base: PyObject,
106+
+- #[cfg(not(any(PyPy, GraalPy)))]
107+
++ #[cfg(not(PyPy))]
108+
+ pub dict: *mut PyObject,
109+
+- #[cfg(not(any(PyPy, GraalPy)))]
110+
++ #[cfg(not(PyPy))]
111+
+ pub args: *mut PyObject,
112+
+- #[cfg(all(Py_3_11, not(any(PyPy, GraalPy))))]
113+
++ #[cfg(all(Py_3_11, not(PyPy)))]
114+
+ pub notes: *mut PyObject,
115+
+- #[cfg(not(any(PyPy, GraalPy)))]
116+
++ #[cfg(not(PyPy))]
117+
+ pub traceback: *mut PyObject,
118+
+- #[cfg(not(any(PyPy, GraalPy)))]
119+
++ #[cfg(not(PyPy))]
120+
+ pub context: *mut PyObject,
121+
+- #[cfg(not(any(PyPy, GraalPy)))]
122+
++ #[cfg(not(PyPy))]
123+
+ pub cause: *mut PyObject,
124+
+- #[cfg(not(any(PyPy, GraalPy)))]
125+
++ #[cfg(not(PyPy))]
126+
+ pub suppress_context: char,
127+
+ }
128+
+
129+
diff --git a/pyproject.toml b/pyproject.toml
130+
index de04a39..8db6756 100644
131+
--- a/pyproject.toml
132+
+++ b/pyproject.toml
133+
@@ -3,7 +3,8 @@ requires = [
134+
'maturin>=1,<2',
135+
'typing-extensions >=4.6.0,!=4.7.0'
136+
]
137+
-build-backend = 'maturin'
138+
+backend-path = ['.']
139+
+build-backend = 'build_backend'
140+
141+
[project]
142+
name = 'pydantic_core'
143+
diff --git a/src/input/return_enums.rs b/src/input/return_enums.rs
144+
index c91a6e2..d0da05a 100644
145+
--- a/src/input/return_enums.rs
146+
+++ b/src/input/return_enums.rs
147+
@@ -10,7 +10,7 @@ use pyo3::exceptions::PyTypeError;
148+
use pyo3::ffi;
149+
use pyo3::intern;
150+
use pyo3::prelude::*;
151+
-#[cfg(not(PyPy))]
152+
+#[cfg(all(not(PyPy),not(GraalPy)))]
153+
use pyo3::types::PyFunction;
154+
use pyo3::types::{PyBytes, PyComplex, PyFloat, PyFrozenSet, PyIterator, PyMapping, PySet, PyString};
155+
156+
@@ -330,14 +330,14 @@ pub(crate) fn iterate_attributes<'a, 'py>(
157+
// the PyFunction::is_type_of(attr) catches `staticmethod`, but also any other function,
158+
// I think that's better than including static methods in the yielded attributes,
159+
// if someone really wants fields, they can use an explicit field, or a function to modify input
160+
- #[cfg(not(PyPy))]
161+
+ #[cfg(all(not(PyPy),not(GraalPy)))]
162+
if !is_bound && !attr.is_instance_of::<PyFunction>() {
163+
return Some(Ok((name, attr)));
164+
}
165+
// MASSIVE HACK! PyFunction doesn't exist for PyPy,
166+
// is_instance_of::<PyFunction> crashes with a null pointer, hence this hack, see
167+
// https://github.com/pydantic/pydantic-core/pull/161#discussion_r917257635
168+
- #[cfg(PyPy)]
169+
+ #[cfg(any(PyPy,GraalPy))]
170+
if !is_bound && attr.get_type().to_string() != "<class 'function'>" {
171+
return Some(Ok((name, attr)));
172+
}

scripts/csignature.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include <frameobject.h>
6464
#include <datetime.h>
6565
#include <structmember.h>
66+
#include <marshal.h>
6667
"""
6768

6869
include_path = sysconfig.get_config_var("INCLUDEPY")

0 commit comments

Comments
 (0)