Skip to content

Commit f3bc2ad

Browse files
committed
Implement ForeignDate methods
1 parent d1c4bc0 commit f3bc2ad

5 files changed

Lines changed: 530 additions & 1 deletion

File tree

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,35 @@ def some_function():
213213
assert imported_fun1 is some_function
214214
assert imported_fun1() == "hello, polyglot world!"
215215

216+
def test_foreign_date_behavior(self):
217+
import datetime
218+
import java
219+
220+
LocalDate = java.type("java.time.LocalDate")
221+
222+
d = LocalDate.of(2025, 3, 23)
223+
self.assertEqual(d.year, 2025)
224+
self.assertEqual(d.month, 3)
225+
self.assertEqual(d.day, 23)
226+
self.assertEqual(str(d), "2025-03-23")
227+
self.assertEqual(d.isoformat(), "2025-03-23")
228+
self.assertEqual(d.ctime(), datetime.date(2025, 3, 23).ctime())
229+
self.assertEqual(d.strftime("%Y-%m-%d"), "2025-03-23")
230+
self.assertEqual(format(d, "%Y-%m-%d"), "2025-03-23")
231+
self.assertEqual(d.toordinal(), datetime.date(2025, 3, 23).toordinal())
232+
self.assertEqual(d.weekday(), datetime.date(2025, 3, 23).weekday())
233+
self.assertEqual(d.isoweekday(), datetime.date(2025, 3, 23).isoweekday())
234+
self.assertEqual(d.isocalendar(), datetime.date(2025, 3, 23).isocalendar())
235+
self.assertEqual(d.timetuple(), datetime.date(2025, 3, 23).timetuple())
236+
self.assertEqual(hash(d), hash(datetime.date(2025, 3, 23)))
237+
self.assertEqual(d, datetime.date(2025, 3, 23))
238+
self.assertEqual(d, LocalDate.of(2025, 3, 23))
239+
self.assertEqual(d.replace(day=24), datetime.date(2025, 3, 24))
240+
self.assertEqual(d + datetime.timedelta(days=1), datetime.date(2025, 3, 24))
241+
self.assertEqual(d - datetime.timedelta(days=1), datetime.date(2025, 3, 22))
242+
self.assertEqual(d - datetime.date(2025, 3, 20), datetime.timedelta(days=3))
243+
self.assertEqual(d - LocalDate.of(2025, 3, 20), datetime.timedelta(days=3))
244+
216245
def test_read(self):
217246
o = CustomObject()
218247
assert polyglot.__read__(o, "field") == o.field

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@
263263
import com.oracle.graal.python.builtins.objects.floats.PFloat;
264264
import com.oracle.graal.python.builtins.objects.foreign.ForeignAbstractClassBuiltins;
265265
import com.oracle.graal.python.builtins.objects.foreign.ForeignBooleanBuiltins;
266+
import com.oracle.graal.python.builtins.objects.foreign.ForeignDateBuiltins;
266267
import com.oracle.graal.python.builtins.objects.foreign.ForeignExecutableBuiltins;
267268
import com.oracle.graal.python.builtins.objects.foreign.ForeignInstantiableBuiltins;
268269
import com.oracle.graal.python.builtins.objects.foreign.ForeignIterableBuiltins;
@@ -500,6 +501,7 @@ private static PythonBuiltins[] initializeBuiltins(TruffleLanguage.Env env) {
500501
new ForeignObjectBuiltins(),
501502
new ForeignNumberBuiltins(),
502503
new ForeignBooleanBuiltins(),
504+
new ForeignDateBuiltins(),
503505
new ForeignAbstractClassBuiltins(),
504506
new ForeignExecutableBuiltins(),
505507
new ForeignInstantiableBuiltins(),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
import com.oracle.graal.python.builtins.objects.floats.FloatBuiltins;
182182
import com.oracle.graal.python.builtins.objects.foreign.ForeignAbstractClassBuiltins;
183183
import com.oracle.graal.python.builtins.objects.foreign.ForeignBooleanBuiltins;
184+
import com.oracle.graal.python.builtins.objects.foreign.ForeignDateBuiltins;
184185
import com.oracle.graal.python.builtins.objects.foreign.ForeignExecutableBuiltins;
185186
import com.oracle.graal.python.builtins.objects.foreign.ForeignInstantiableBuiltins;
186187
import com.oracle.graal.python.builtins.objects.foreign.ForeignIterableBuiltins;
@@ -842,7 +843,7 @@ It can be called either on the class (e.g. C.f()) or on an instance
842843
ForeignExecutable("ForeignExecutable", ForeignObject, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation().slots(ForeignExecutableBuiltins.SLOTS)),
843844
ForeignInstantiable("ForeignInstantiable", ForeignObject, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().slots(ForeignInstantiableBuiltins.SLOTS)),
844845
ForeignIterable("ForeignIterable", ForeignObject, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation().slots(ForeignIterableBuiltins.SLOTS)),
845-
ForeignDate("ForeignDate", PDate, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation()),
846+
ForeignDate("ForeignDate", PDate, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation().slots(ForeignDateBuiltins.SLOTS)),
846847
ForeignTime("ForeignTime", PTime, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation()),
847848
ForeignDateTime("ForeignDateTime", PDateTime, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation()),
848849
ForeignTimeZone("ForeignTimeZone", PTzInfo, newBuilder().publishInModule(J_POLYGLOT).basetype().addDict().disallowInstantiation()),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/datetime/TemporalNodes.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,96 @@ public LocalDateTime toLocalDateTime() {
151151
}
152152
}
153153

154+
@GenerateUncached
155+
@GenerateInline
156+
@GenerateCached(false)
157+
public abstract static class DateLikeCheckNode extends Node {
158+
public abstract boolean execute(Node inliningTarget, Object obj);
159+
160+
@Specialization
161+
static boolean doManaged(@SuppressWarnings("unused") PDate value) {
162+
return true;
163+
}
164+
165+
@Specialization
166+
static boolean doNative(Node inliningTarget, PythonAbstractNativeObject value,
167+
@Cached DateNodes.DateCheckNode checkNode) {
168+
return checkNode.execute(inliningTarget, value);
169+
}
170+
171+
@Specialization(guards = "isForeignObjectNode.execute(inliningTarget, value)", limit = "1")
172+
static boolean doForeign(Node inliningTarget, Object value,
173+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
174+
@CachedLibrary("value") InteropLibrary interop) {
175+
return interop.isDate(value);
176+
}
177+
178+
@Fallback
179+
static boolean doOther(@SuppressWarnings("unused") Object value) {
180+
return false;
181+
}
182+
}
183+
184+
@GenerateUncached
185+
@GenerateInline
186+
@GenerateCached(false)
187+
public abstract static class TimeLikeCheckNode extends Node {
188+
public abstract boolean execute(Node inliningTarget, Object obj);
189+
190+
@Specialization
191+
static boolean doManaged(@SuppressWarnings("unused") PTime value) {
192+
return true;
193+
}
194+
195+
@Specialization
196+
static boolean doNative(Node inliningTarget, PythonAbstractNativeObject value,
197+
@Cached TimeNodes.TimeCheckNode checkNode) {
198+
return checkNode.execute(inliningTarget, value);
199+
}
200+
201+
@Specialization(guards = "isForeignObjectNode.execute(inliningTarget, value)", limit = "1")
202+
static boolean doForeign(Node inliningTarget, Object value,
203+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
204+
@CachedLibrary("value") InteropLibrary interop) {
205+
return interop.isTime(value);
206+
}
207+
208+
@Fallback
209+
static boolean doOther(@SuppressWarnings("unused") Object value) {
210+
return false;
211+
}
212+
}
213+
214+
@GenerateUncached
215+
@GenerateInline
216+
@GenerateCached(false)
217+
public abstract static class DateTimeLikeCheckNode extends Node {
218+
public abstract boolean execute(Node inliningTarget, Object obj);
219+
220+
@Specialization
221+
static boolean doManaged(@SuppressWarnings("unused") PDateTime value) {
222+
return true;
223+
}
224+
225+
@Specialization
226+
static boolean doNative(Node inliningTarget, PythonAbstractNativeObject value,
227+
@Cached DateTimeNodes.DateTimeCheckNode checkNode) {
228+
return checkNode.execute(inliningTarget, value);
229+
}
230+
231+
@Specialization(guards = "isForeignObjectNode.execute(inliningTarget, value)", limit = "1")
232+
static boolean doForeign(Node inliningTarget, Object value,
233+
@SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode,
234+
@CachedLibrary("value") InteropLibrary interop) {
235+
return interop.isDate(value) && interop.isTime(value);
236+
}
237+
238+
@Fallback
239+
static boolean doOther(@SuppressWarnings("unused") Object value) {
240+
return false;
241+
}
242+
}
243+
154244
@GenerateUncached
155245
@GenerateInline
156246
@GenerateCached(false)

0 commit comments

Comments
 (0)