Skip to content

Commit 8e2c103

Browse files
eregonabdelberni
authored andcommitted
Only register_interop_behavior() for datetime & time when they are imported
* Otherwise just loading polyglot has the heavy cost of loading datetime too. * This way the interop behavior is defined regardless of whether `import polyglot` was done (without relying on polyglot to be loaded at startup). (cherry picked from commit 0892329)
1 parent 3747119 commit 8e2c103

File tree

5 files changed

+153
-65
lines changed

5 files changed

+153
-65
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2024, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -49,6 +49,7 @@
4949
import java.util.List;
5050
import java.util.TimeZone;
5151

52+
import com.oracle.graal.python.nodes.statement.AbstractImportNode;
5253
import org.graalvm.nativeimage.ImageInfo;
5354

5455
import com.oracle.graal.python.annotations.ArgumentClinic;
@@ -153,6 +154,7 @@ public final class TimeModuleBuiltins extends PythonBuiltins {
153154
public static final TruffleString T_DAYLIGHT = tsLiteral("daylight");
154155
public static final TruffleString T_TIMEZONE = tsLiteral("timezone");
155156
public static final TruffleString T_ALTZONE = tsLiteral("altzone");
157+
public static final TruffleString T_POLYGLOT_TIME = tsLiteral("_polyglot_time");
156158

157159
@Override
158160
protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFactories() {
@@ -192,6 +194,9 @@ public void postInitialize(Python3Core core) {
192194
int rawOffsetSeconds = defaultTimeZone.getRawOffset() / -1000;
193195
timeModule.setAttribute(T_TIMEZONE, rawOffsetSeconds);
194196
timeModule.setAttribute(T_ALTZONE, rawOffsetSeconds - 3600);
197+
198+
// register_interop_behavior() for time.struct_time
199+
AbstractImportNode.importModule(T_POLYGLOT_TIME);
195200
}
196201

197202
@TruffleBoundary

graalpython/lib-graalpython/_polyglot.py

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2023, 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
@@ -37,9 +37,7 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
import datetime
4140
import polyglot
42-
import time
4341

4442

4543
def interop_type(foreign_class, allow_method_overwrites=False):
@@ -112,37 +110,6 @@ def wrapper(python_class):
112110
setattr(polyglot, "interop_behavior", interop_behavior)
113111

114112

115-
def _date_time_tz(dt: datetime.datetime):
116-
if dt.tzinfo is not None:
117-
utcoffset = dt.tzinfo.utcoffset(dt)
118-
return utcoffset.days * 3600 * 24 + utcoffset.seconds
119-
raise polyglot.UnsupportedMessage
120-
121-
122-
def _struct_time_tz(st: time.struct_time):
123-
if st.tm_gmtoff is not None:
124-
return st.tm_gmtoff
125-
return st.tm_zone
126-
127-
128-
polyglot.register_interop_behavior(datetime.time,
129-
is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond),
130-
is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz)
131-
132-
polyglot.register_interop_behavior(datetime.date,
133-
is_date=True, as_date=lambda d: (d.year, d.month, d.day))
134-
135-
polyglot.register_interop_behavior(datetime.datetime,
136-
is_date=True, as_date=lambda d: (d.year, d.month, d.day),
137-
is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond),
138-
is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz)
139-
140-
polyglot.register_interop_behavior(time.struct_time,
141-
is_date=True, as_date=lambda t: (t.tm_year, t.tm_mon, t.tm_mday),
142-
is_time=True, as_time=lambda t: (t.tm_hour, t.tm_min, t.tm_sec, 0),
143-
is_time_zone=lambda t: t.tm_zone is not None or t.tm_gmtoff is not None,
144-
as_time_zone=_struct_time_tz)
145-
146113
# loading arrow structures on demand
147114
def __getattr__(name):
148115
if name == "arrow":
@@ -153,33 +120,3 @@ def __getattr__(name):
153120

154121
setattr(polyglot, "__getattr__", __getattr__)
155122
setattr(polyglot, "__path__", ".")
156-
157-
# example extending time.struct_time using the decorator wrapper
158-
#
159-
# @polyglot.interop_behavior(time.struct_time)
160-
# class StructTimeInteropBehavior:
161-
# @staticmethod
162-
# def is_date(t):
163-
# return True
164-
#
165-
# @staticmethod
166-
# def as_date(t):
167-
# return t.tm_year, t.tm_mon, t.tm_mday
168-
#
169-
# @staticmethod
170-
# def is_time(t):
171-
# return True
172-
#
173-
# @staticmethod
174-
# def as_time(t):
175-
# return t.tm_hour, t.tm_min, t.tm_sec, 0
176-
#
177-
# @staticmethod
178-
# def is_time_zone(t):
179-
# return t.tm_zone is not None or t.tm_gmtoff is not None
180-
#
181-
# @staticmethod
182-
# def as_time_zone(t):
183-
# if t.tm_gmtoff is not None:
184-
# return t.tm_gmtoff
185-
# return t.tm_zone
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
import datetime
41+
import polyglot
42+
43+
def _date_time_tz(dt: datetime.datetime):
44+
if dt.tzinfo is not None:
45+
utcoffset = dt.tzinfo.utcoffset(dt)
46+
return utcoffset.days * 3600 * 24 + utcoffset.seconds
47+
raise polyglot.UnsupportedMessage
48+
49+
50+
polyglot.register_interop_behavior(datetime.time,
51+
is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond),
52+
is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz)
53+
54+
polyglot.register_interop_behavior(datetime.date,
55+
is_date=True, as_date=lambda d: (d.year, d.month, d.day))
56+
57+
polyglot.register_interop_behavior(datetime.datetime,
58+
is_date=True, as_date=lambda d: (d.year, d.month, d.day),
59+
is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond),
60+
is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
import time
41+
import polyglot
42+
43+
44+
def _struct_time_tz(st: time.struct_time):
45+
if st.tm_gmtoff is not None:
46+
return st.tm_gmtoff
47+
return st.tm_zone
48+
49+
50+
polyglot.register_interop_behavior(time.struct_time,
51+
is_date=True, as_date=lambda t: (t.tm_year, t.tm_mon, t.tm_mday),
52+
is_time=True, as_time=lambda t: (t.tm_hour, t.tm_min, t.tm_sec, 0),
53+
is_time_zone=lambda t: t.tm_zone is not None or t.tm_gmtoff is not None,
54+
as_time_zone=_struct_time_tz)
55+
56+
# example extending time.struct_time using the decorator wrapper
57+
#
58+
# @polyglot.interop_behavior(time.struct_time)
59+
# class StructTimeInteropBehavior:
60+
# @staticmethod
61+
# def is_date(t):
62+
# return True
63+
#
64+
# @staticmethod
65+
# def as_date(t):
66+
# return t.tm_year, t.tm_mon, t.tm_mday
67+
#
68+
# @staticmethod
69+
# def is_time(t):
70+
# return True
71+
#
72+
# @staticmethod
73+
# def as_time(t):
74+
# return t.tm_hour, t.tm_min, t.tm_sec, 0
75+
#
76+
# @staticmethod
77+
# def is_time_zone(t):
78+
# return t.tm_zone is not None or t.tm_gmtoff is not None
79+
#
80+
# @staticmethod
81+
# def as_time_zone(t):
82+
# if t.tm_gmtoff is not None:
83+
# return t.tm_gmtoff
84+
# return t.tm_zone

graalpython/lib-python/3/datetime.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,3 +2642,5 @@ def _name_from_offset(delta):
26422642
# appropriate to maintain a single module level docstring and
26432643
# remove the following line.
26442644
from _datetime import __doc__
2645+
2646+
import _polyglot_datetime # GraalPy change: register interop behavior on datetime as soon as datetime is defined

0 commit comments

Comments
 (0)