From 92627b971ba6885b40b0dc99d311a8427d4c8584 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 21 Apr 2026 04:05:23 +0000
Subject: [PATCH 1/2] feat(stdlib): add datetime module bindings
Adds F# bindings for the Python datetime module, covering:
- timedelta (duration with days/seconds/microseconds, total_seconds())
- date (year/month/day, isoformat, strftime, weekday, fromisoformat, replace)
- time (hour/minute/second/microsecond, isoformat, strftime, fromisoformat)
- datetime (full date+time, now, utcnow, fromisoformat, strptime, combine, timestamp, astimezone)
- timezone (fixed-offset tzinfo, utc singleton)
Each class has a separate static factory type (timedeltaStatic, dateStatic,
timeStatic, datetimeStatic, timezoneStatic) for constructors and class methods.
Int arguments use int($1) Emit wrappers to handle Fable's Int32 boxing.
Adds 30 tests covering all bound classes and their main operations.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
src/Fable.Python.fsproj | 1 +
src/stdlib/Datetime.fs | 293 ++++++++++++++++++++++++++++++++++
test/Fable.Python.Test.fsproj | 1 +
test/TestDatetime.fs | 234 +++++++++++++++++++++++++++
4 files changed, 529 insertions(+)
create mode 100644 src/stdlib/Datetime.fs
create mode 100644 test/TestDatetime.fs
diff --git a/src/Fable.Python.fsproj b/src/Fable.Python.fsproj
index 4920133..3dff498 100644
--- a/src/Fable.Python.fsproj
+++ b/src/Fable.Python.fsproj
@@ -25,6 +25,7 @@
+
diff --git a/src/stdlib/Datetime.fs b/src/stdlib/Datetime.fs
new file mode 100644
index 0000000..90dc928
--- /dev/null
+++ b/src/stdlib/Datetime.fs
@@ -0,0 +1,293 @@
+/// Type bindings for Python datetime module: https://docs.python.org/3/library/datetime.html
+module Fable.Python.Datetime
+
+open Fable.Core
+
+// fsharplint:disable MemberNames,InterfaceNames
+
+// ============================================================================
+// timedelta
+// ============================================================================
+
+/// A duration expressing the difference between two date, time, or datetime instances.
+/// See https://docs.python.org/3/library/datetime.html#datetime.timedelta
+[]
+type timedelta =
+ /// Number of full days (may be negative)
+ abstract days: int
+ /// Remaining seconds after full days have been removed; 0 <= seconds < 86400
+ abstract seconds: int
+ /// Remaining microseconds; 0 <= microseconds < 1000000
+ abstract microseconds: int
+ /// Return the total duration represented in fractional seconds
+ /// See https://docs.python.org/3/library/datetime.html#datetime.timedelta.total_seconds
+ abstract total_seconds: unit -> float
+
+/// Static factory for timedelta instances
+[]
+type timedeltaStatic =
+ /// Create a timedelta; all arguments default to 0, may be floats, and may be negative.
+ /// See https://docs.python.org/3/library/datetime.html#datetime.timedelta
+ []
+ []
+ abstract Create:
+ ?days: float *
+ ?seconds: float *
+ ?microseconds: float *
+ ?milliseconds: float *
+ ?minutes: float *
+ ?hours: float *
+ ?weeks: float ->
+ timedelta
+
+/// Factory for creating timedelta values
+[]
+let timedelta: timedeltaStatic = nativeOnly
+
+// ============================================================================
+// date
+// ============================================================================
+
+/// A naive date (year, month, day) with no time or timezone component.
+/// See https://docs.python.org/3/library/datetime.html#datetime.date
+[]
+type date =
+ /// Year in range [MINYEAR, MAXYEAR]
+ abstract year: int
+ /// Month in range [1, 12]
+ abstract month: int
+ /// Day in range [1, number of days in the month and year]
+ abstract day: int
+ /// Return a string in ISO 8601 format, e.g. "2026-04-21"
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.isoformat
+ abstract isoformat: unit -> string
+ /// Return a string representing the date, formatted with format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.strftime
+ abstract strftime: format: string -> string
+ /// Return the day of the week as an integer; Monday is 0 and Sunday is 6
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.weekday
+ abstract weekday: unit -> int
+ /// Return the day of the week as an integer; Monday is 1 and Sunday is 7
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.isoweekday
+ abstract isoweekday: unit -> int
+ /// Return the proleptic Gregorian ordinal of the date; January 1 of year 1 has ordinal 1
+ abstract toordinal: unit -> int
+ /// Return a date with the given fields replaced
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.replace
+ []
+ abstract replace: year: int * month: int * day: int -> date
+
+/// Static factory for date instances
+[]
+type dateStatic =
+ /// Create a date for the given year, month and day
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date
+ []
+ abstract Create: year: int * month: int * day: int -> date
+ /// Return the current local date
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.today
+ abstract today: unit -> date
+ /// Return the local date corresponding to a POSIX timestamp
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.fromtimestamp
+ abstract fromtimestamp: timestamp: float -> date
+ /// Return the date corresponding to the proleptic Gregorian ordinal
+ abstract fromordinal: ordinal: int -> date
+ /// Return a date from a string in any valid ISO 8601 format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.date.fromisoformat
+ abstract fromisoformat: date_string: string -> date
+ /// The earliest representable date
+ abstract min: date
+ /// The latest representable date
+ abstract max: date
+
+/// Factory for creating date values
+[]
+let date: dateStatic = nativeOnly
+
+// ============================================================================
+// time
+// ============================================================================
+
+/// A naive or aware time of day (hour, minute, second, microsecond, tzinfo).
+/// See https://docs.python.org/3/library/datetime.html#datetime.time
+[]
+type time =
+ /// Hour in range [0, 23]
+ abstract hour: int
+ /// Minute in range [0, 59]
+ abstract minute: int
+ /// Second in range [0, 59]
+ abstract second: int
+ /// Microsecond in range [0, 999999]
+ abstract microsecond: int
+ /// Fold value (0 or 1) for disambiguating wall-clock times that repeat during DST transitions
+ abstract fold: int
+ /// Return a string in ISO 8601 format, e.g. "14:30:00"
+ /// See https://docs.python.org/3/library/datetime.html#datetime.time.isoformat
+ abstract isoformat: unit -> string
+ /// Return a string representing the time, formatted with format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.time.strftime
+ abstract strftime: format: string -> string
+ /// Return the UTC offset as a timedelta for aware times; None for naive times
+ abstract utcoffset: unit -> timedelta option
+ /// Return the timezone abbreviation string for aware times; None for naive times
+ abstract tzname: unit -> string option
+
+/// Static factory for time instances
+[]
+type timeStatic =
+ /// Create a time-of-day value; all arguments default to 0
+ /// See https://docs.python.org/3/library/datetime.html#datetime.time
+ []
+ []
+ abstract Create:
+ ?hour: int *
+ ?minute: int *
+ ?second: int *
+ ?microsecond: int ->
+ time
+ /// Return a time from a string in ISO 8601 format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.time.fromisoformat
+ abstract fromisoformat: time_string: string -> time
+ /// The earliest representable time, time(0, 0, 0, 0)
+ abstract min: time
+ /// The latest representable time, time(23, 59, 59, 999999)
+ abstract max: time
+
+/// Factory for creating time-of-day values
+[]
+let time: timeStatic = nativeOnly
+
+// ============================================================================
+// datetime
+// ============================================================================
+
+/// A naive or aware date and time (year, month, day, hour, minute, second, microsecond, tzinfo).
+/// See https://docs.python.org/3/library/datetime.html#datetime.datetime
+[]
+type datetime =
+ /// Year in range [MINYEAR, MAXYEAR]
+ abstract year: int
+ /// Month in range [1, 12]
+ abstract month: int
+ /// Day in range [1, number of days in the month and year]
+ abstract day: int
+ /// Hour in range [0, 23]
+ abstract hour: int
+ /// Minute in range [0, 59]
+ abstract minute: int
+ /// Second in range [0, 59]
+ abstract second: int
+ /// Microsecond in range [0, 999999]
+ abstract microsecond: int
+ /// Fold value (0 or 1) for disambiguating wall-clock times that repeat during DST transitions
+ abstract fold: int
+ /// Return the date part as a date object
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.date
+ abstract date: unit -> date
+ /// Return the time part as a time object (tzinfo is not included)
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.time
+ abstract time: unit -> time
+ /// Return a string in ISO 8601 format, e.g. "2026-04-21T14:30:00"
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat
+ abstract isoformat: unit -> string
+ /// Return a string in ISO 8601 format with a custom separator between date and time
+ []
+ abstract isoformat: sep: string -> string
+ /// Return a string representing the datetime, formatted with format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.strftime
+ abstract strftime: format: string -> string
+ /// Return the POSIX timestamp corresponding to this datetime as a float
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.timestamp
+ abstract timestamp: unit -> float
+ /// Return the UTC offset as a timedelta for aware datetimes; None for naive
+ abstract utcoffset: unit -> timedelta option
+ /// Return the timezone abbreviation string for aware datetimes; None for naive
+ abstract tzname: unit -> string option
+ /// Return the day of the week as an integer; Monday is 0 and Sunday is 6
+ abstract weekday: unit -> int
+ /// Return the day of the week as an integer; Monday is 1 and Sunday is 7
+ abstract isoweekday: unit -> int
+ /// Return a datetime with the date fields replaced
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.replace
+ []
+ abstract replaceDate: year: int * month: int * day: int -> datetime
+ /// Return a datetime with the time fields replaced
+ []
+ abstract replaceTime: hour: int * minute: int * second: int -> datetime
+ /// Return a datetime converted to the given timezone
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.astimezone
+ abstract astimezone: tz: obj -> datetime
+
+/// Static factory for datetime instances
+[]
+type datetimeStatic =
+ /// Create a datetime for the given date components (time components default to 0)
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime
+ []
+ abstract Create: year: int * month: int * day: int -> datetime
+ /// Create a datetime for the given date and time components
+ []
+ abstract Create: year: int * month: int * day: int * hour: int * minute: int * second: int -> datetime
+ /// Return the current local date and time
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.now
+ abstract now: unit -> datetime
+ /// Return the current local date and time in the given timezone
+ []
+ abstract now: tz: obj -> datetime
+ /// Return the current UTC date and time as a naive datetime
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow
+ abstract utcnow: unit -> datetime
+ /// Return the local datetime corresponding to a POSIX timestamp
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.fromtimestamp
+ abstract fromtimestamp: timestamp: float -> datetime
+ /// Return the datetime corresponding to a POSIX timestamp in the given timezone
+ []
+ abstract fromtimestamp: timestamp: float * tz: obj -> datetime
+ /// Return a datetime from a string in any valid ISO 8601 format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat
+ abstract fromisoformat: datetime_string: string -> datetime
+ /// Return a datetime parsed from date_string according to format
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.strptime
+ abstract strptime: date_string: string * format: string -> datetime
+ /// Combine a date and time into a single datetime
+ /// See https://docs.python.org/3/library/datetime.html#datetime.datetime.combine
+ abstract combine: date: date * time: time -> datetime
+ /// The earliest representable datetime
+ abstract min: datetime
+ /// The latest representable datetime
+ abstract max: datetime
+
+/// Factory for creating datetime values
+[]
+let datetime: datetimeStatic = nativeOnly
+
+// ============================================================================
+// timezone
+// ============================================================================
+
+/// A fixed-offset implementation of tzinfo.
+/// See https://docs.python.org/3/library/datetime.html#datetime.timezone
+[]
+type timezone =
+ /// Return the UTC offset for this timezone
+ abstract utcoffset: dt: obj -> timedelta
+ /// Return the timezone name string for this timezone
+ abstract tzname: dt: obj -> string
+
+/// Static factory for timezone instances
+[]
+type timezoneStatic =
+ /// Create a timezone with the given fixed UTC offset (as a timedelta)
+ /// See https://docs.python.org/3/library/datetime.html#datetime.timezone
+ []
+ abstract Create: offset: timedelta -> timezone
+ /// Create a named timezone with the given fixed UTC offset
+ []
+ abstract Create: offset: timedelta * name: string -> timezone
+ /// The UTC timezone singleton (offset zero, name "UTC")
+ abstract utc: timezone
+
+/// Factory for creating timezone values
+[]
+let timezone: timezoneStatic = nativeOnly
diff --git a/test/Fable.Python.Test.fsproj b/test/Fable.Python.Test.fsproj
index f37dca6..441f8a7 100644
--- a/test/Fable.Python.Test.fsproj
+++ b/test/Fable.Python.Test.fsproj
@@ -32,6 +32,7 @@
+
diff --git a/test/TestDatetime.fs b/test/TestDatetime.fs
new file mode 100644
index 0000000..fd44a41
--- /dev/null
+++ b/test/TestDatetime.fs
@@ -0,0 +1,234 @@
+module Fable.Python.Tests.Datetime
+
+open Fable.Python.Testing
+open Fable.Python.Datetime
+
+// ============================================================================
+// timedelta tests
+// ============================================================================
+
+[]
+let ``test timedelta days property`` () =
+ let td = timedelta.Create(days = 3.0)
+ td.days |> equal 3
+
+[]
+let ``test timedelta hours to seconds`` () =
+ let td = timedelta.Create(hours = 2.0)
+ td.seconds |> equal 7200
+
+[]
+let ``test timedelta minutes to seconds`` () =
+ let td = timedelta.Create(minutes = 90.0)
+ td.seconds |> equal 5400
+
+[]
+let ``test timedelta total_seconds`` () =
+ let td = timedelta.Create(days = 1.0, hours = 2.0)
+ td.total_seconds() |> equal 93600.0
+
+[]
+let ``test timedelta zero`` () =
+ let td = timedelta.Create()
+ td.days |> equal 0
+ td.seconds |> equal 0
+ td.microseconds |> equal 0
+
+// ============================================================================
+// date tests
+// ============================================================================
+
+[]
+let ``test date year month day properties`` () =
+ let d = date.Create(2026, 4, 21)
+ d.year |> equal 2026
+ d.month |> equal 4
+ d.day |> equal 21
+
+[]
+let ``test date isoformat`` () =
+ let d = date.Create(2026, 4, 21)
+ d.isoformat() |> equal "2026-04-21"
+
+[]
+let ``test date strftime`` () =
+ let d = date.Create(2026, 4, 21)
+ d.strftime("%Y/%m/%d") |> equal "2026/04/21"
+
+[]
+let ``test date fromisoformat`` () =
+ let d = date.fromisoformat "2026-04-21"
+ d.year |> equal 2026
+ d.month |> equal 4
+ d.day |> equal 21
+
+[]
+let ``test date today returns date`` () =
+ let d = date.today()
+ d.year > 2024 |> equal true
+
+[]
+let ``test date weekday monday is 0`` () =
+ // 2026-04-20 is a Monday
+ let d = date.Create(2026, 4, 20)
+ d.weekday() |> equal 0
+
+[]
+let ``test date isoweekday monday is 1`` () =
+ // 2026-04-20 is a Monday
+ let d = date.Create(2026, 4, 20)
+ d.isoweekday() |> equal 1
+
+[]
+let ``test date replace`` () =
+ let d = date.Create(2026, 4, 21)
+ let d2 = d.replace(2027, 1, 15)
+ d2.year |> equal 2027
+ d2.month |> equal 1
+ d2.day |> equal 15
+
+// ============================================================================
+// time tests
+// ============================================================================
+
+[]
+let ``test time hour minute second properties`` () =
+ let t = time.Create(hour = 14, minute = 30, second = 45)
+ t.hour |> equal 14
+ t.minute |> equal 30
+ t.second |> equal 45
+
+[]
+let ``test time isoformat`` () =
+ let t = time.Create(hour = 9, minute = 5, second = 3)
+ t.isoformat() |> equal "09:05:03"
+
+[]
+let ``test time fromisoformat`` () =
+ let t = time.fromisoformat "14:30:00"
+ t.hour |> equal 14
+ t.minute |> equal 30
+ t.second |> equal 0
+
+[]
+let ``test time defaults to zero`` () =
+ let t = time.Create()
+ t.hour |> equal 0
+ t.minute |> equal 0
+ t.second |> equal 0
+ t.microsecond |> equal 0
+
+// ============================================================================
+// datetime tests
+// ============================================================================
+
+[]
+let ``test datetime year month day properties`` () =
+ let dt = datetime.Create(2026, 4, 21)
+ dt.year |> equal 2026
+ dt.month |> equal 4
+ dt.day |> equal 21
+
+[]
+let ``test datetime hour minute second properties`` () =
+ let dt = datetime.Create(2026, 4, 21, 14, 30, 59)
+ dt.hour |> equal 14
+ dt.minute |> equal 30
+ dt.second |> equal 59
+
+[]
+let ``test datetime isoformat`` () =
+ let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
+ dt.isoformat() |> equal "2026-04-21T12:00:00"
+
+[]
+let ``test datetime fromisoformat`` () =
+ let dt = datetime.fromisoformat "2026-04-21T14:30:00"
+ dt.year |> equal 2026
+ dt.month |> equal 4
+ dt.day |> equal 21
+ dt.hour |> equal 14
+ dt.minute |> equal 30
+
+[]
+let ``test datetime now returns current datetime`` () =
+ let dt = datetime.now()
+ dt.year > 2024 |> equal true
+
+[]
+let ``test datetime strptime`` () =
+ let dt = datetime.strptime("21/04/2026", "%d/%m/%Y")
+ dt.year |> equal 2026
+ dt.month |> equal 4
+ dt.day |> equal 21
+
+[]
+let ``test datetime combine date and time`` () =
+ let d = date.Create(2026, 4, 21)
+ let t = time.Create(hour = 10, minute = 0, second = 0)
+ let dt = datetime.combine(d, t)
+ dt.year |> equal 2026
+ dt.hour |> equal 10
+
+[]
+let ``test datetime date method returns date part`` () =
+ let dt = datetime.Create(2026, 4, 21, 14, 30, 0)
+ let d = dt.date()
+ d.year |> equal 2026
+ d.month |> equal 4
+ d.day |> equal 21
+
+[]
+let ``test datetime time method returns time part`` () =
+ let dt = datetime.Create(2026, 4, 21, 14, 30, 59)
+ let t = dt.time()
+ t.hour |> equal 14
+ t.minute |> equal 30
+ t.second |> equal 59
+
+[]
+let ``test datetime replaceDate`` () =
+ let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.replaceDate(2027, 6, 15)
+ dt2.year |> equal 2027
+ dt2.month |> equal 6
+ dt2.day |> equal 15
+
+[]
+let ``test datetime replaceTime`` () =
+ let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.replaceTime(9, 30, 0)
+ dt2.hour |> equal 9
+ dt2.minute |> equal 30
+
+[]
+let ``test datetime timestamp roundtrip`` () =
+ let dt1 = datetime.fromisoformat "2026-01-01T00:00:00"
+ let ts = dt1.timestamp()
+ let dt2 = datetime.fromtimestamp ts
+ dt2.year |> equal dt1.year
+ dt2.month |> equal dt1.month
+ dt2.day |> equal dt1.day
+
+// ============================================================================
+// timezone tests
+// ============================================================================
+
+[]
+let ``test timezone utc name`` () =
+ let utcName = timezone.utc.tzname(null)
+ utcName |> equal "UTC"
+
+[]
+let ``test timezone create with offset`` () =
+ let offset = timedelta.Create(hours = 5.0, minutes = 30.0)
+ let tz = timezone.Create offset
+ let name = tz.tzname(null)
+ name |> equal "UTC+05:30"
+
+[]
+let ``test timezone create with name`` () =
+ let offset = timedelta.Create(hours = -5.0)
+ let tz = timezone.Create(offset, "EST")
+ let name = tz.tzname(null)
+ name |> equal "EST"
From 89f6d697abeb576d0f98e7657d99e3955bcc1598 Mon Sep 17 00:00:00 2001
From: Dag Brattli
Date: Tue, 21 Apr 2026 23:47:42 +0200
Subject: [PATCH 2/2] refactor(stdlib): rework datetime bindings, fix justfile,
apply fantomas
Datetime:
- Switch from paired static-factory types to Queue.fs-style primary-ctor
classes. The original factory pattern combined [] with
[], which silently dropped all kwargs (generated timedelta()
instead of timedelta(days=3.0)).
- timedelta: empty primary ctor plus static ofDays/ofHours/ofMinutes/
ofSeconds/ofWeeks/ofMilliseconds/ofMicroseconds factories with float()
emit wrappers so Fable's Float64 doesn't reach Python's datetime. Added
add/sub/neg arithmetic.
- timezone: moved above datetime so datetime.astimezone/now(tz)/
fromtimestamp(tz) can take timezone instead of obj.
- date/time/datetime: collapsed replaceDate/replaceTime into a single
[] replace that supports partial replacement (any subset of
fields). Added time.replace.
- datetime: arithmetic via sub(datetime)->timedelta, sub(timedelta)->
datetime, add(timedelta)->datetime. utcnow marked [] pointing
at now(tz = timezone.utc).
- Module-level doc note about the `time` identifier collision with
Fable.Python.Time.
- Tests expanded from 30 to 37 covering partial replace, arithmetic,
datetime.now(tz), and the ofX factories.
justfile:
- Drop -r from `dotnet fantomas` invocations in `format` and `format-check`;
fantomas has no -r flag and it caused both recipes to fail.
Other files: fantomas reformatting applied by `just format` to pre-existing
files touched by the formatter.
Co-Authored-By: Claude Opus 4.7 (1M context)
---
justfile | 8 +-
src/fable/Testing.fs | 2 +-
src/stdlib/Builtins.fs | 3 +-
src/stdlib/Datetime.fs | 365 ++++++++++++++++++++++-------------------
src/stdlib/Math.fs | 2 +
src/stdlib/Queue.fs | 3 +
test/TestDatetime.fs | 179 ++++++++++++++------
test/TestFastAPI.fs | 56 +++----
test/TestFunctools.fs | 13 +-
test/TestHeapq.fs | 12 +-
test/TestItertools.fs | 30 +---
test/TestJson.fs | 2 +-
test/TestMath.fs | 64 +++-----
test/TestString.fs | 9 +-
test/TestSys.fs | 18 +-
test/TestTesting.fs | 32 +---
test/TestTime.fs | 3 +-
17 files changed, 426 insertions(+), 375 deletions(-)
diff --git a/justfile b/justfile
index de53b89..f0de065 100644
--- a/justfile
+++ b/justfile
@@ -83,13 +83,13 @@ shipit *args:
# Format code with Fantomas
format:
- dotnet fantomas {{src_path}} -r
- dotnet fantomas {{test_path}} -r
+ dotnet fantomas {{src_path}}
+ dotnet fantomas {{test_path}}
# Check code formatting without making changes
format-check:
- dotnet fantomas {{src_path}} -r --check
- dotnet fantomas {{test_path}} -r --check
+ dotnet fantomas {{src_path}} --check
+ dotnet fantomas {{test_path}} --check
# Install .NET tools (Fable, Fantomas) and Python dependencies
setup:
diff --git a/src/fable/Testing.fs b/src/fable/Testing.fs
index 70272ae..9f1aa02 100644
--- a/src/fable/Testing.fs
+++ b/src/fable/Testing.fs
@@ -47,7 +47,7 @@ let throwsError (expected: string) (f: unit -> 'a) : unit =
let throwsErrorContaining (expected: string) (f: unit -> 'a) : unit =
match run f with
| Error _ when String.IsNullOrEmpty expected -> ()
- | Error (actual: string) when actual.Contains expected -> ()
+ | Error(actual: string) when actual.Contains expected -> ()
| Error actual -> equal (sprintf "Error containing '%s'" expected) actual
| Ok _ -> equal (sprintf "Error containing '%s'" expected) "No error was thrown"
diff --git a/src/stdlib/Builtins.fs b/src/stdlib/Builtins.fs
index 8260362..f7ee0eb 100644
--- a/src/stdlib/Builtins.fs
+++ b/src/stdlib/Builtins.fs
@@ -353,7 +353,8 @@ let __name__: string = nativeOnly
let print obj = builtins.print obj
/// Return the value of the named attribute of object with a default.
-let getattr obj name defaultValue = builtins.getattr (obj, name, defaultValue)
+let getattr obj name defaultValue =
+ builtins.getattr (obj, name, defaultValue)
/// Sets the named attribute on the given object to the specified value.
let setattr obj name value = builtins.setattr (obj, name, value)
diff --git a/src/stdlib/Datetime.fs b/src/stdlib/Datetime.fs
index 90dc928..7cc0c42 100644
--- a/src/stdlib/Datetime.fs
+++ b/src/stdlib/Datetime.fs
@@ -1,9 +1,13 @@
/// Type bindings for Python datetime module: https://docs.python.org/3/library/datetime.html
+///
+/// Note: this module exposes a `time` class binding for Python's `datetime.time`. If you also
+/// open `Fable.Python.Time` (the `time` module), the `time` identifier will collide — qualify
+/// one of them, e.g. `Fable.Python.Time.time.time()` vs. `Fable.Python.Datetime.time(...)`.
module Fable.Python.Datetime
open Fable.Core
-// fsharplint:disable MemberNames,InterfaceNames
+// fsharplint:disable MemberNames
// ============================================================================
// timedelta
@@ -11,38 +15,83 @@ open Fable.Core
/// A duration expressing the difference between two date, time, or datetime instances.
/// See https://docs.python.org/3/library/datetime.html#datetime.timedelta
+///
+/// The empty `timedelta()` ctor creates a zero duration. For other durations, use the
+/// single-unit factories `ofDays`, `ofHours`, `ofMinutes`, `ofSeconds`, `ofWeeks`,
+/// `ofMilliseconds`, `ofMicroseconds`, and combine via `.add` / `.sub`.
[]
-type timedelta =
+type timedelta() =
/// Number of full days (may be negative)
- abstract days: int
+ member _.days: int = nativeOnly
/// Remaining seconds after full days have been removed; 0 <= seconds < 86400
- abstract seconds: int
+ member _.seconds: int = nativeOnly
/// Remaining microseconds; 0 <= microseconds < 1000000
- abstract microseconds: int
+ member _.microseconds: int = nativeOnly
/// Return the total duration represented in fractional seconds
/// See https://docs.python.org/3/library/datetime.html#datetime.timedelta.total_seconds
- abstract total_seconds: unit -> float
+ member _.total_seconds() : float = nativeOnly
-/// Static factory for timedelta instances
-[]
-type timedeltaStatic =
- /// Create a timedelta; all arguments default to 0, may be floats, and may be negative.
- /// See https://docs.python.org/3/library/datetime.html#datetime.timedelta
- []
- []
- abstract Create:
- ?days: float *
- ?seconds: float *
- ?microseconds: float *
- ?milliseconds: float *
- ?minutes: float *
- ?hours: float *
- ?weeks: float ->
- timedelta
-
-/// Factory for creating timedelta values
-[]
-let timedelta: timedeltaStatic = nativeOnly
+ /// Return the sum of two timedeltas
+ []
+ member _.add(other: timedelta) : timedelta = nativeOnly
+
+ /// Return the difference between two timedeltas
+ []
+ member _.sub(other: timedelta) : timedelta = nativeOnly
+
+ /// Return the negation of this timedelta
+ []
+ member _.neg() : timedelta = nativeOnly
+
+ /// The most negative timedelta representable
+ static member min: timedelta = nativeOnly
+ /// The most positive timedelta representable
+ static member max: timedelta = nativeOnly
+ /// The smallest positive difference between non-equal timedelta objects
+ static member resolution: timedelta = nativeOnly
+
+ /// Create a timedelta of N days
+ []
+ static member ofDays(days: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N seconds
+ []
+ static member ofSeconds(seconds: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N microseconds
+ []
+ static member ofMicroseconds(microseconds: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N milliseconds
+ []
+ static member ofMilliseconds(milliseconds: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N minutes
+ []
+ static member ofMinutes(minutes: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N hours
+ []
+ static member ofHours(hours: float) : timedelta = nativeOnly
+
+ /// Create a timedelta of N weeks
+ []
+ static member ofWeeks(weeks: float) : timedelta = nativeOnly
+
+// ============================================================================
+// timezone (defined before datetime so datetime members can reference it)
+// ============================================================================
+
+/// A fixed-offset implementation of tzinfo.
+/// See https://docs.python.org/3/library/datetime.html#datetime.timezone
+[]
+type timezone(offset: timedelta, ?name: string) =
+ /// Return the UTC offset for this timezone
+ member _.utcoffset(dt: obj) : timedelta = nativeOnly
+ /// Return the timezone name string for this timezone
+ member _.tzname(dt: obj) : string = nativeOnly
+ /// The UTC timezone singleton (offset zero, name "UTC")
+ static member utc: timezone = nativeOnly
// ============================================================================
// date
@@ -51,58 +100,60 @@ let timedelta: timedeltaStatic = nativeOnly
/// A naive date (year, month, day) with no time or timezone component.
/// See https://docs.python.org/3/library/datetime.html#datetime.date
[]
-type date =
+type date(year: int, month: int, day: int) =
/// Year in range [MINYEAR, MAXYEAR]
- abstract year: int
+ member _.year: int = nativeOnly
/// Month in range [1, 12]
- abstract month: int
+ member _.month: int = nativeOnly
/// Day in range [1, number of days in the month and year]
- abstract day: int
+ member _.day: int = nativeOnly
/// Return a string in ISO 8601 format, e.g. "2026-04-21"
/// See https://docs.python.org/3/library/datetime.html#datetime.date.isoformat
- abstract isoformat: unit -> string
+ member _.isoformat() : string = nativeOnly
/// Return a string representing the date, formatted with format
/// See https://docs.python.org/3/library/datetime.html#datetime.date.strftime
- abstract strftime: format: string -> string
+ member _.strftime(format: string) : string = nativeOnly
/// Return the day of the week as an integer; Monday is 0 and Sunday is 6
/// See https://docs.python.org/3/library/datetime.html#datetime.date.weekday
- abstract weekday: unit -> int
+ member _.weekday() : int = nativeOnly
/// Return the day of the week as an integer; Monday is 1 and Sunday is 7
/// See https://docs.python.org/3/library/datetime.html#datetime.date.isoweekday
- abstract isoweekday: unit -> int
+ member _.isoweekday() : int = nativeOnly
/// Return the proleptic Gregorian ordinal of the date; January 1 of year 1 has ordinal 1
- abstract toordinal: unit -> int
- /// Return a date with the given fields replaced
+ member _.toordinal() : int = nativeOnly
+
+ /// Return a date with the given fields replaced (any subset of year/month/day)
/// See https://docs.python.org/3/library/datetime.html#datetime.date.replace
- []
- abstract replace: year: int * month: int * day: int -> date
+ []
+ member _.replace(?year: int, ?month: int, ?day: int) : date = nativeOnly
+
+ /// Return the timedelta between this date and other (self - other)
+ []
+ member _.sub(other: date) : timedelta = nativeOnly
+
+ /// Return a date offset by the given timedelta (self - delta)
+ []
+ member _.sub(delta: timedelta) : date = nativeOnly
+
+ /// Return a date offset by the given timedelta (self + delta)
+ []
+ member _.add(delta: timedelta) : date = nativeOnly
-/// Static factory for date instances
-[]
-type dateStatic =
- /// Create a date for the given year, month and day
- /// See https://docs.python.org/3/library/datetime.html#datetime.date
- []
- abstract Create: year: int * month: int * day: int -> date
/// Return the current local date
/// See https://docs.python.org/3/library/datetime.html#datetime.date.today
- abstract today: unit -> date
+ static member today() : date = nativeOnly
/// Return the local date corresponding to a POSIX timestamp
/// See https://docs.python.org/3/library/datetime.html#datetime.date.fromtimestamp
- abstract fromtimestamp: timestamp: float -> date
+ static member fromtimestamp(timestamp: float) : date = nativeOnly
/// Return the date corresponding to the proleptic Gregorian ordinal
- abstract fromordinal: ordinal: int -> date
+ static member fromordinal(ordinal: int) : date = nativeOnly
/// Return a date from a string in any valid ISO 8601 format
/// See https://docs.python.org/3/library/datetime.html#datetime.date.fromisoformat
- abstract fromisoformat: date_string: string -> date
+ static member fromisoformat(date_string: string) : date = nativeOnly
/// The earliest representable date
- abstract min: date
+ static member min: date = nativeOnly
/// The latest representable date
- abstract max: date
-
-/// Factory for creating date values
-[]
-let date: dateStatic = nativeOnly
+ static member max: date = nativeOnly
// ============================================================================
// time
@@ -110,53 +161,43 @@ let date: dateStatic = nativeOnly
/// A naive or aware time of day (hour, minute, second, microsecond, tzinfo).
/// See https://docs.python.org/3/library/datetime.html#datetime.time
+///
+/// Ctor args are positional: `time(h)`, `time(h, m)`, `time(h, m, s)`, `time(h, m, s, us)`.
[]
-type time =
+type time(hour: int, ?minute: int, ?second: int, ?microsecond: int) =
/// Hour in range [0, 23]
- abstract hour: int
+ member _.hour: int = nativeOnly
/// Minute in range [0, 59]
- abstract minute: int
+ member _.minute: int = nativeOnly
/// Second in range [0, 59]
- abstract second: int
+ member _.second: int = nativeOnly
/// Microsecond in range [0, 999999]
- abstract microsecond: int
+ member _.microsecond: int = nativeOnly
/// Fold value (0 or 1) for disambiguating wall-clock times that repeat during DST transitions
- abstract fold: int
+ member _.fold: int = nativeOnly
/// Return a string in ISO 8601 format, e.g. "14:30:00"
/// See https://docs.python.org/3/library/datetime.html#datetime.time.isoformat
- abstract isoformat: unit -> string
+ member _.isoformat() : string = nativeOnly
/// Return a string representing the time, formatted with format
/// See https://docs.python.org/3/library/datetime.html#datetime.time.strftime
- abstract strftime: format: string -> string
+ member _.strftime(format: string) : string = nativeOnly
/// Return the UTC offset as a timedelta for aware times; None for naive times
- abstract utcoffset: unit -> timedelta option
+ member _.utcoffset() : timedelta option = nativeOnly
/// Return the timezone abbreviation string for aware times; None for naive times
- abstract tzname: unit -> string option
+ member _.tzname() : string option = nativeOnly
-/// Static factory for time instances
-[]
-type timeStatic =
- /// Create a time-of-day value; all arguments default to 0
- /// See https://docs.python.org/3/library/datetime.html#datetime.time
- []
+ /// Return a time with the given fields replaced (any subset)
+ /// See https://docs.python.org/3/library/datetime.html#datetime.time.replace
[]
- abstract Create:
- ?hour: int *
- ?minute: int *
- ?second: int *
- ?microsecond: int ->
- time
+ member _.replace(?hour: int, ?minute: int, ?second: int, ?microsecond: int) : time = nativeOnly
+
/// Return a time from a string in ISO 8601 format
/// See https://docs.python.org/3/library/datetime.html#datetime.time.fromisoformat
- abstract fromisoformat: time_string: string -> time
+ static member fromisoformat(time_string: string) : time = nativeOnly
/// The earliest representable time, time(0, 0, 0, 0)
- abstract min: time
+ static member min: time = nativeOnly
/// The latest representable time, time(23, 59, 59, 999999)
- abstract max: time
-
-/// Factory for creating time-of-day values
-[]
-let time: timeStatic = nativeOnly
+ static member max: time = nativeOnly
// ============================================================================
// datetime
@@ -165,129 +206,119 @@ let time: timeStatic = nativeOnly
/// A naive or aware date and time (year, month, day, hour, minute, second, microsecond, tzinfo).
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime
[]
-type datetime =
+type datetime
+ (
+ year: int,
+ month: int,
+ day: int,
+ ?hour: int,
+ ?minute: int,
+ ?second: int,
+ ?microsecond: int,
+ ?tzinfo: timezone,
+ ?fold: int
+ ) =
/// Year in range [MINYEAR, MAXYEAR]
- abstract year: int
+ member _.year: int = nativeOnly
/// Month in range [1, 12]
- abstract month: int
+ member _.month: int = nativeOnly
/// Day in range [1, number of days in the month and year]
- abstract day: int
+ member _.day: int = nativeOnly
/// Hour in range [0, 23]
- abstract hour: int
+ member _.hour: int = nativeOnly
/// Minute in range [0, 59]
- abstract minute: int
+ member _.minute: int = nativeOnly
/// Second in range [0, 59]
- abstract second: int
+ member _.second: int = nativeOnly
/// Microsecond in range [0, 999999]
- abstract microsecond: int
+ member _.microsecond: int = nativeOnly
/// Fold value (0 or 1) for disambiguating wall-clock times that repeat during DST transitions
- abstract fold: int
+ member _.fold: int = nativeOnly
/// Return the date part as a date object
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.date
- abstract date: unit -> date
+ member _.date() : date = nativeOnly
/// Return the time part as a time object (tzinfo is not included)
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.time
- abstract time: unit -> time
+ member _.time() : time = nativeOnly
/// Return a string in ISO 8601 format, e.g. "2026-04-21T14:30:00"
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.isoformat
- abstract isoformat: unit -> string
+ member _.isoformat() : string = nativeOnly
+
/// Return a string in ISO 8601 format with a custom separator between date and time
[]
- abstract isoformat: sep: string -> string
+ member _.isoformat(sep: string) : string = nativeOnly
+
/// Return a string representing the datetime, formatted with format
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.strftime
- abstract strftime: format: string -> string
+ member _.strftime(format: string) : string = nativeOnly
/// Return the POSIX timestamp corresponding to this datetime as a float
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.timestamp
- abstract timestamp: unit -> float
+ member _.timestamp() : float = nativeOnly
/// Return the UTC offset as a timedelta for aware datetimes; None for naive
- abstract utcoffset: unit -> timedelta option
+ member _.utcoffset() : timedelta option = nativeOnly
/// Return the timezone abbreviation string for aware datetimes; None for naive
- abstract tzname: unit -> string option
+ member _.tzname() : string option = nativeOnly
/// Return the day of the week as an integer; Monday is 0 and Sunday is 6
- abstract weekday: unit -> int
+ member _.weekday() : int = nativeOnly
/// Return the day of the week as an integer; Monday is 1 and Sunday is 7
- abstract isoweekday: unit -> int
- /// Return a datetime with the date fields replaced
+ member _.isoweekday() : int = nativeOnly
+
+ /// Return a datetime with the given fields replaced (any subset)
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.replace
- []
- abstract replaceDate: year: int * month: int * day: int -> datetime
- /// Return a datetime with the time fields replaced
- []
- abstract replaceTime: hour: int * minute: int * second: int -> datetime
+ []
+ member _.replace
+ (?year: int, ?month: int, ?day: int, ?hour: int, ?minute: int, ?second: int, ?microsecond: int)
+ : datetime =
+ nativeOnly
+
/// Return a datetime converted to the given timezone
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.astimezone
- abstract astimezone: tz: obj -> datetime
+ member _.astimezone(tz: timezone) : datetime = nativeOnly
+
+ /// Return the timedelta between this datetime and other (self - other)
+ []
+ member _.sub(other: datetime) : timedelta = nativeOnly
+
+ /// Return a datetime offset by the given timedelta (self - delta)
+ []
+ member _.sub(delta: timedelta) : datetime = nativeOnly
+
+ /// Return a datetime offset by the given timedelta (self + delta)
+ []
+ member _.add(delta: timedelta) : datetime = nativeOnly
-/// Static factory for datetime instances
-[]
-type datetimeStatic =
- /// Create a datetime for the given date components (time components default to 0)
- /// See https://docs.python.org/3/library/datetime.html#datetime.datetime
- []
- abstract Create: year: int * month: int * day: int -> datetime
- /// Create a datetime for the given date and time components
- []
- abstract Create: year: int * month: int * day: int * hour: int * minute: int * second: int -> datetime
/// Return the current local date and time
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.now
- abstract now: unit -> datetime
+ static member now() : datetime = nativeOnly
+
/// Return the current local date and time in the given timezone
- []
- abstract now: tz: obj -> datetime
- /// Return the current UTC date and time as a naive datetime
+ []
+ static member now(tz: timezone) : datetime = nativeOnly
+
+ /// Return the current UTC date and time as a naive datetime.
+ /// Deprecated in Python 3.12; prefer `datetime.now(tz = timezone.utc)`.
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.utcnow
- abstract utcnow: unit -> datetime
+ []
+ static member utcnow() : datetime = nativeOnly
+
/// Return the local datetime corresponding to a POSIX timestamp
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.fromtimestamp
- abstract fromtimestamp: timestamp: float -> datetime
+ static member fromtimestamp(timestamp: float) : datetime = nativeOnly
+
/// Return the datetime corresponding to a POSIX timestamp in the given timezone
- []
- abstract fromtimestamp: timestamp: float * tz: obj -> datetime
+ []
+ static member fromtimestamp(timestamp: float, tz: timezone) : datetime = nativeOnly
+
/// Return a datetime from a string in any valid ISO 8601 format
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat
- abstract fromisoformat: datetime_string: string -> datetime
+ static member fromisoformat(datetime_string: string) : datetime = nativeOnly
/// Return a datetime parsed from date_string according to format
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.strptime
- abstract strptime: date_string: string * format: string -> datetime
+ static member strptime(date_string: string, format: string) : datetime = nativeOnly
/// Combine a date and time into a single datetime
/// See https://docs.python.org/3/library/datetime.html#datetime.datetime.combine
- abstract combine: date: date * time: time -> datetime
+ static member combine(date: date, time: time) : datetime = nativeOnly
/// The earliest representable datetime
- abstract min: datetime
+ static member min: datetime = nativeOnly
/// The latest representable datetime
- abstract max: datetime
-
-/// Factory for creating datetime values
-[]
-let datetime: datetimeStatic = nativeOnly
-
-// ============================================================================
-// timezone
-// ============================================================================
-
-/// A fixed-offset implementation of tzinfo.
-/// See https://docs.python.org/3/library/datetime.html#datetime.timezone
-[]
-type timezone =
- /// Return the UTC offset for this timezone
- abstract utcoffset: dt: obj -> timedelta
- /// Return the timezone name string for this timezone
- abstract tzname: dt: obj -> string
-
-/// Static factory for timezone instances
-[]
-type timezoneStatic =
- /// Create a timezone with the given fixed UTC offset (as a timedelta)
- /// See https://docs.python.org/3/library/datetime.html#datetime.timezone
- []
- abstract Create: offset: timedelta -> timezone
- /// Create a named timezone with the given fixed UTC offset
- []
- abstract Create: offset: timedelta * name: string -> timezone
- /// The UTC timezone singleton (offset zero, name "UTC")
- abstract utc: timezone
-
-/// Factory for creating timezone values
-[]
-let timezone: timezoneStatic = nativeOnly
+ static member max: datetime = nativeOnly
diff --git a/src/stdlib/Math.fs b/src/stdlib/Math.fs
index 07a72e0..c83b28c 100644
--- a/src/stdlib/Math.fs
+++ b/src/stdlib/Math.fs
@@ -84,10 +84,12 @@ type IExports =
/// Return True if the values a and b are close to each other
/// See https://docs.python.org/3/library/math.html#math.isclose
abstract isclose: a: float * b: float -> bool
+
/// Return True if the values a and b are close to each other with custom tolerances
/// See https://docs.python.org/3/library/math.html#math.isclose
[]
abstract isclose: a: float * b: float * ?rel_tol: float * ?abs_tol: float -> bool
+
/// Return the least common multiple of the integers
/// See https://docs.python.org/3/library/math.html#math.lcm
abstract lcm: [] ints: int[] -> int
diff --git a/src/stdlib/Queue.fs b/src/stdlib/Queue.fs
index ca69760..81b7a32 100644
--- a/src/stdlib/Queue.fs
+++ b/src/stdlib/Queue.fs
@@ -34,10 +34,12 @@ type Queue<'T>() =
/// operation goes into an uninterruptible wait on an underlying lock. This means that no exceptions can occur, and
/// in particular a SIGINT will not trigger a KeyboardInterrupt.
member x.get(?block: bool, ?timeout: float) : 'T = nativeOnly
+
/// Equivalent to get(False).
/// See https://docs.python.org/3/library/queue.html#queue.Queue.get_nowait
[]
member x.get_nowait() : 'T = nativeOnly
+
/// Blocks until all items in the queue have been gotten and processed.
///
/// The count of unfinished tasks goes up whenever an item is added to the queue. The count goes down whenever a
@@ -74,6 +76,7 @@ type SimpleQueue<'T>() =
member x.put(item: 'T, ?block: bool, ?timeout: float) : unit = nativeOnly
/// Remove and return an item from the queue.
member x.get(?block: bool, ?timeout: float) : 'T = nativeOnly
+
/// Equivalent to get(False).
[]
member x.get_nowait() : 'T = nativeOnly
diff --git a/test/TestDatetime.fs b/test/TestDatetime.fs
index fd44a41..72e0d1b 100644
--- a/test/TestDatetime.fs
+++ b/test/TestDatetime.fs
@@ -9,51 +9,66 @@ open Fable.Python.Datetime
[]
let ``test timedelta days property`` () =
- let td = timedelta.Create(days = 3.0)
+ let td = timedelta.ofDays 3.0
td.days |> equal 3
[]
let ``test timedelta hours to seconds`` () =
- let td = timedelta.Create(hours = 2.0)
+ let td = timedelta.ofHours 2.0
td.seconds |> equal 7200
[]
let ``test timedelta minutes to seconds`` () =
- let td = timedelta.Create(minutes = 90.0)
+ let td = timedelta.ofMinutes 90.0
td.seconds |> equal 5400
[]
let ``test timedelta total_seconds`` () =
- let td = timedelta.Create(days = 1.0, hours = 2.0)
- td.total_seconds() |> equal 93600.0
+ let td = (timedelta.ofDays 1.0).add (timedelta.ofHours 2.0)
+ td.total_seconds () |> equal 93600.0
[]
let ``test timedelta zero`` () =
- let td = timedelta.Create()
+ let td = timedelta ()
td.days |> equal 0
td.seconds |> equal 0
td.microseconds |> equal 0
+[]
+let ``test timedelta add`` () =
+ let sum = (timedelta.ofHours 1.0).add (timedelta.ofMinutes 30.0)
+ sum.total_seconds () |> equal 5400.0
+
+[]
+let ``test timedelta sub`` () =
+ let diff = (timedelta.ofHours 2.0).sub (timedelta.ofMinutes 30.0)
+ diff.total_seconds () |> equal 5400.0
+
+[]
+let ``test timedelta neg`` () =
+ let n = (timedelta.ofHours 1.0).neg ()
+ n.total_seconds () |> equal -3600.0
+
// ============================================================================
// date tests
// ============================================================================
[]
let ``test date year month day properties`` () =
- let d = date.Create(2026, 4, 21)
+ let d = date (2026, 4, 21)
d.year |> equal 2026
d.month |> equal 4
d.day |> equal 21
[]
let ``test date isoformat`` () =
- let d = date.Create(2026, 4, 21)
- d.isoformat() |> equal "2026-04-21"
+ let d = date (2026, 4, 21)
+ d.isoformat () |> equal "2026-04-21"
[]
let ``test date strftime`` () =
- let d = date.Create(2026, 4, 21)
- d.strftime("%Y/%m/%d") |> equal "2026/04/21"
+ let d = date (2026, 4, 21)
+ d.strftime ("%Y/%m/%d") |> equal "2026/04/21"
[]
let ``test date fromisoformat`` () =
@@ -64,44 +79,73 @@ let ``test date fromisoformat`` () =
[]
let ``test date today returns date`` () =
- let d = date.today()
+ let d = date.today ()
d.year > 2024 |> equal true
[]
let ``test date weekday monday is 0`` () =
// 2026-04-20 is a Monday
- let d = date.Create(2026, 4, 20)
- d.weekday() |> equal 0
+ let d = date (2026, 4, 20)
+ d.weekday () |> equal 0
[]
let ``test date isoweekday monday is 1`` () =
// 2026-04-20 is a Monday
- let d = date.Create(2026, 4, 20)
- d.isoweekday() |> equal 1
+ let d = date (2026, 4, 20)
+ d.isoweekday () |> equal 1
[]
-let ``test date replace`` () =
- let d = date.Create(2026, 4, 21)
- let d2 = d.replace(2027, 1, 15)
+let ``test date replace all fields`` () =
+ let d = date (2026, 4, 21)
+ let d2 = d.replace (year = 2027, month = 1, day = 15)
d2.year |> equal 2027
d2.month |> equal 1
d2.day |> equal 15
+[]
+let ``test date replace single field`` () =
+ let d = date (2026, 4, 21)
+ let d2 = d.replace (year = 2030)
+ d2.year |> equal 2030
+ d2.month |> equal 4
+ d2.day |> equal 21
+
+[]
+let ``test date add timedelta`` () =
+ let d = date (2026, 4, 21)
+ let d2 = d.add (timedelta.ofDays 10.0)
+ d2.day |> equal 1
+ d2.month |> equal 5
+
+[]
+let ``test date sub date returns timedelta`` () =
+ let d1 = date (2026, 4, 21)
+ let d2 = date (2026, 4, 11)
+ let td = d1.sub d2
+ td.days |> equal 10
+
+[]
+let ``test date sub timedelta returns date`` () =
+ let d = date (2026, 4, 21)
+ let d2 = d.sub (timedelta.ofDays 21.0)
+ d2.month |> equal 3
+ d2.day |> equal 31
+
// ============================================================================
// time tests
// ============================================================================
[]
let ``test time hour minute second properties`` () =
- let t = time.Create(hour = 14, minute = 30, second = 45)
+ let t = time (14, 30, 45)
t.hour |> equal 14
t.minute |> equal 30
t.second |> equal 45
[]
let ``test time isoformat`` () =
- let t = time.Create(hour = 9, minute = 5, second = 3)
- t.isoformat() |> equal "09:05:03"
+ let t = time (9, 5, 3)
+ t.isoformat () |> equal "09:05:03"
[]
let ``test time fromisoformat`` () =
@@ -112,34 +156,42 @@ let ``test time fromisoformat`` () =
[]
let ``test time defaults to zero`` () =
- let t = time.Create()
+ let t = time 0
t.hour |> equal 0
t.minute |> equal 0
t.second |> equal 0
t.microsecond |> equal 0
+[]
+let ``test time replace single field`` () =
+ let t = time (9, 30, 0)
+ let t2 = t.replace (hour = 14)
+ t2.hour |> equal 14
+ t2.minute |> equal 30
+ t2.second |> equal 0
+
// ============================================================================
// datetime tests
// ============================================================================
[]
let ``test datetime year month day properties`` () =
- let dt = datetime.Create(2026, 4, 21)
+ let dt = datetime (2026, 4, 21)
dt.year |> equal 2026
dt.month |> equal 4
dt.day |> equal 21
[]
let ``test datetime hour minute second properties`` () =
- let dt = datetime.Create(2026, 4, 21, 14, 30, 59)
+ let dt = datetime (2026, 4, 21, 14, 30, 59)
dt.hour |> equal 14
dt.minute |> equal 30
dt.second |> equal 59
[]
let ``test datetime isoformat`` () =
- let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
- dt.isoformat() |> equal "2026-04-21T12:00:00"
+ let dt = datetime (2026, 4, 21, 12, 0, 0)
+ dt.isoformat () |> equal "2026-04-21T12:00:00"
[]
let ``test datetime fromisoformat`` () =
@@ -152,83 +204,110 @@ let ``test datetime fromisoformat`` () =
[]
let ``test datetime now returns current datetime`` () =
- let dt = datetime.now()
+ let dt = datetime.now ()
+ dt.year > 2024 |> equal true
+
+[]
+let ``test datetime now with timezone`` () =
+ let dt = datetime.now (timezone.utc)
dt.year > 2024 |> equal true
+ dt.tzname () |> equal (Some "UTC")
[]
let ``test datetime strptime`` () =
- let dt = datetime.strptime("21/04/2026", "%d/%m/%Y")
+ let dt = datetime.strptime ("21/04/2026", "%d/%m/%Y")
dt.year |> equal 2026
dt.month |> equal 4
dt.day |> equal 21
[]
let ``test datetime combine date and time`` () =
- let d = date.Create(2026, 4, 21)
- let t = time.Create(hour = 10, minute = 0, second = 0)
- let dt = datetime.combine(d, t)
+ let d = date (2026, 4, 21)
+ let t = time (10, 0, 0)
+ let dt = datetime.combine (d, t)
dt.year |> equal 2026
dt.hour |> equal 10
[]
let ``test datetime date method returns date part`` () =
- let dt = datetime.Create(2026, 4, 21, 14, 30, 0)
- let d = dt.date()
+ let dt = datetime (2026, 4, 21, 14, 30, 0)
+ let d = dt.date ()
d.year |> equal 2026
d.month |> equal 4
d.day |> equal 21
[]
let ``test datetime time method returns time part`` () =
- let dt = datetime.Create(2026, 4, 21, 14, 30, 59)
- let t = dt.time()
+ let dt = datetime (2026, 4, 21, 14, 30, 59)
+ let t = dt.time ()
t.hour |> equal 14
t.minute |> equal 30
t.second |> equal 59
[]
-let ``test datetime replaceDate`` () =
- let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
- let dt2 = dt.replaceDate(2027, 6, 15)
+let ``test datetime replace date fields`` () =
+ let dt = datetime (2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.replace (year = 2027, month = 6, day = 15)
dt2.year |> equal 2027
dt2.month |> equal 6
dt2.day |> equal 15
+ dt2.hour |> equal 12
[]
-let ``test datetime replaceTime`` () =
- let dt = datetime.Create(2026, 4, 21, 12, 0, 0)
- let dt2 = dt.replaceTime(9, 30, 0)
+let ``test datetime replace time fields`` () =
+ let dt = datetime (2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.replace (hour = 9, minute = 30, second = 0)
dt2.hour |> equal 9
dt2.minute |> equal 30
+ dt2.year |> equal 2026
[]
let ``test datetime timestamp roundtrip`` () =
let dt1 = datetime.fromisoformat "2026-01-01T00:00:00"
- let ts = dt1.timestamp()
+ let ts = dt1.timestamp ()
let dt2 = datetime.fromtimestamp ts
dt2.year |> equal dt1.year
dt2.month |> equal dt1.month
dt2.day |> equal dt1.day
+[]
+let ``test datetime add timedelta`` () =
+ let dt = datetime (2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.add (timedelta.ofHours 3.0)
+ dt2.hour |> equal 15
+
+[]
+let ``test datetime sub datetime returns timedelta`` () =
+ let dt1 = datetime (2026, 4, 21, 15, 0, 0)
+ let dt2 = datetime (2026, 4, 21, 12, 0, 0)
+ let td = dt1.sub dt2
+ td.total_seconds () |> equal 10800.0
+
+[]
+let ``test datetime sub timedelta returns datetime`` () =
+ let dt = datetime (2026, 4, 21, 12, 0, 0)
+ let dt2 = dt.sub (timedelta.ofHours 2.0)
+ dt2.hour |> equal 10
+
// ============================================================================
// timezone tests
// ============================================================================
[]
let ``test timezone utc name`` () =
- let utcName = timezone.utc.tzname(null)
+ let utcName = timezone.utc.tzname (null)
utcName |> equal "UTC"
[]
let ``test timezone create with offset`` () =
- let offset = timedelta.Create(hours = 5.0, minutes = 30.0)
- let tz = timezone.Create offset
- let name = tz.tzname(null)
+ let offset = (timedelta.ofHours 5.0).add (timedelta.ofMinutes 30.0)
+ let tz = timezone offset
+ let name = tz.tzname (null)
name |> equal "UTC+05:30"
[]
let ``test timezone create with name`` () =
- let offset = timedelta.Create(hours = -5.0)
- let tz = timezone.Create(offset, "EST")
- let name = tz.tzname(null)
+ let offset = timedelta.ofHours -5.0
+ let tz = timezone (offset, "EST")
+ let name = tz.tzname (null)
name |> equal "EST"
diff --git a/test/TestFastAPI.fs b/test/TestFastAPI.fs
index 4ec54d8..68ca17f 100644
--- a/test/TestFastAPI.fs
+++ b/test/TestFastAPI.fs
@@ -52,14 +52,14 @@ let ``test APIRouter can be created with prefix`` () =
[]
let ``test APIRouter can be created with tags`` () =
- let router = APIRouter(tags = ResizeArray ["users"; "admin"])
+ let router = APIRouter(tags = ResizeArray [ "users"; "admin" ])
notNull router |> equal true
[]
let ``test FastAPI app can include router`` () =
let app = FastAPI()
let router = APIRouter(prefix = "/api")
- app.include_router(router)
+ app.include_router (router)
// If we get here without error, the test passes
true |> equal true
@@ -186,7 +186,7 @@ let ``test Pydantic model works with FastAPI patterns`` () =
[]
let ``test Pydantic model serialization for FastAPI`` () =
let item = Item(Name = "Gadget", Price = 19.99, InStock = false)
- let json = item.model_dump_json()
+ let json = item.model_dump_json ()
json.Contains("Gadget") |> equal true
json.Contains("19.99") |> equal true
@@ -202,50 +202,47 @@ let app = FastAPI(title = "Test API", version = "1.0.0")
[]
type API() =
[]
- static member root() : obj =
- {| message = "Hello World" |}
+ static member root() : obj = {| message = "Hello World" |}
[]
static member get_item(item_id: int) : obj =
- {| item_id = item_id; name = "Test Item" |}
+ {| item_id = item_id
+ name = "Test Item" |}
[]
- static member create_item(item: Item) : obj =
- {| status = "created"; item = item |}
+ static member create_item(item: Item) : obj = {| status = "created"; item = item |}
[]
- static member update_item(item_id: int, item: Item) : obj =
- {| item_id = item_id; item = item |}
+ static member update_item(item_id: int, item: Item) : obj = {| item_id = item_id; item = item |}
[]
- static member delete_item(item_id: int) : obj =
- {| deleted = item_id |}
+ static member delete_item(item_id: int) : obj = {| deleted = item_id |}
[]
let ``test class-based API methods can be called`` () =
- let result = API.root()
+ let result = API.root ()
notNull result |> equal true
[]
let ``test class-based API with path parameter`` () =
- let result = API.get_item(42)
+ let result = API.get_item (42)
notNull result |> equal true
[]
let ``test class-based API POST method`` () =
let item = Item(Name = "Test", Price = 10.0, InStock = true)
- let result = API.create_item(item)
+ let result = API.create_item (item)
notNull result |> equal true
[]
let ``test class-based API PUT method`` () =
let item = Item(Name = "Updated", Price = 20.0, InStock = false)
- let result = API.update_item(1, item)
+ let result = API.update_item (1, item)
notNull result |> equal true
[]
let ``test class-based API DELETE method`` () =
- let result = API.delete_item(1)
+ let result = API.delete_item (1)
notNull result |> equal true
// ============================================================================
@@ -262,47 +259,42 @@ let ``test TestClient can be created`` () =
// Router-based API pattern
// ============================================================================
-let router = APIRouter(prefix = "/users", tags = ResizeArray ["users"])
+let router = APIRouter(prefix = "/users", tags = ResizeArray [ "users" ])
[]
type UsersAPI() =
[]
- static member list_users() : obj =
- {| users = [| "Alice"; "Bob" |] |}
+ static member list_users() : obj = {| users = [| "Alice"; "Bob" |] |}
[]
- static member get_user(user_id: int) : obj =
- {| user_id = user_id |}
+ static member get_user(user_id: int) : obj = {| user_id = user_id |}
[]
- static member create_user(name: string) : obj =
- {| name = name; id = 1 |}
+ static member create_user(name: string) : obj = {| name = name; id = 1 |}
[]
- static member update_user(user_id: int, name: string) : obj =
- {| user_id = user_id; name = name |}
+ static member update_user(user_id: int, name: string) : obj = {| user_id = user_id; name = name |}
[]
- static member delete_user(user_id: int) : obj =
- {| deleted = user_id |}
+ static member delete_user(user_id: int) : obj = {| deleted = user_id |}
[]
let ``test router-based API methods work`` () =
- let users = UsersAPI.list_users()
+ let users = UsersAPI.list_users ()
notNull users |> equal true
[]
let ``test router can be included in app`` () =
let mainApp = FastAPI()
let usersRouter = APIRouter(prefix = "/api/v1")
- mainApp.include_router(usersRouter)
+ mainApp.include_router (usersRouter)
true |> equal true
[]
let ``test router can be included with prefix and tags`` () =
let mainApp = FastAPI()
- let usersRouter = APIRouter(prefix = "/users", tags = ResizeArray ["users"])
- mainApp.include_router_with_prefix_and_tags(usersRouter, "/api/v1", ResizeArray ["api"])
+ let usersRouter = APIRouter(prefix = "/users", tags = ResizeArray [ "users" ])
+ mainApp.include_router_with_prefix_and_tags (usersRouter, "/api/v1", ResizeArray [ "api" ])
true |> equal true
#endif
diff --git a/test/TestFunctools.fs b/test/TestFunctools.fs
index a0f9bb1..40562a1 100644
--- a/test/TestFunctools.fs
+++ b/test/TestFunctools.fs
@@ -5,18 +5,15 @@ open Fable.Python.Functools
[]
let ``test reduce sum works`` () =
- functools.reduce ((fun a b -> a + b), [ 1; 2; 3; 4; 5 ])
- |> equal 15
+ functools.reduce ((fun a b -> a + b), [ 1; 2; 3; 4; 5 ]) |> equal 15
[]
let ``test reduce product works`` () =
- functools.reduce ((fun a b -> a * b), [ 1; 2; 3; 4; 5 ])
- |> equal 120
+ functools.reduce ((fun a b -> a * b), [ 1; 2; 3; 4; 5 ]) |> equal 120
[]
let ``test reduce with initializer works`` () =
- functools.reduce ((fun acc x -> acc + x), [ 1; 2; 3 ], 10)
- |> equal 16
+ functools.reduce ((fun acc x -> acc + x), [ 1; 2; 3 ], 10) |> equal 16
[]
let ``test reduce string fold with initializer works`` () =
@@ -26,9 +23,11 @@ let ``test reduce string fold with initializer works`` () =
[]
let ``test lruCache memoises results`` () =
let callCount = ResizeArray()
+
let expensive (x: int) =
callCount.Add x
x * x
+
let cached = functools.lruCache (128, expensive)
cached 5 |> equal 25
cached 5 |> equal 25
@@ -38,9 +37,11 @@ let ``test lruCache memoises results`` () =
[]
let ``test cache memoises results`` () =
let callCount = ResizeArray()
+
let expensive (x: int) =
callCount.Add x
x * 2
+
let cached = functools.cache expensive
cached 7 |> equal 14
cached 7 |> equal 14
diff --git a/test/TestHeapq.fs b/test/TestHeapq.fs
index 6001186..d0dd22d 100644
--- a/test/TestHeapq.fs
+++ b/test/TestHeapq.fs
@@ -15,13 +15,13 @@ let ``test heappush and heappop work`` () =
[]
let ``test heapify works`` () =
- let heap = ResizeArray [5; 3; 1; 4; 2]
+ let heap = ResizeArray [ 5; 3; 1; 4; 2 ]
heapq.heapify heap
heapq.heappop heap |> equal 1
[]
let ``test heappushpop works`` () =
- let heap = ResizeArray [2; 4; 6]
+ let heap = ResizeArray [ 2; 4; 6 ]
heapq.heapify heap
// Push 1, then pop smallest (1)
heapq.heappushpop (heap, 1) |> equal 1
@@ -30,10 +30,10 @@ let ``test heappushpop works`` () =
[]
let ``test nlargest works`` () =
- let result = heapq.nlargest (3, [1; 5; 2; 8; 3; 7])
- result |> equal (ResizeArray [8; 7; 5])
+ let result = heapq.nlargest (3, [ 1; 5; 2; 8; 3; 7 ])
+ result |> equal (ResizeArray [ 8; 7; 5 ])
[]
let ``test nsmallest works`` () =
- let result = heapq.nsmallest (3, [1; 5; 2; 8; 3; 7])
- result |> equal (ResizeArray [1; 2; 3])
+ let result = heapq.nsmallest (3, [ 1; 5; 2; 8; 3; 7 ])
+ result |> equal (ResizeArray [ 1; 2; 3 ])
diff --git a/test/TestItertools.fs b/test/TestItertools.fs
index 1f9a413..4273d10 100644
--- a/test/TestItertools.fs
+++ b/test/TestItertools.fs
@@ -5,17 +5,11 @@ open Fable.Python.Itertools
[]
let ``test count from start works`` () =
- itertools.count 1
- |> Seq.take 4
- |> Seq.toList
- |> equal [ 1; 2; 3; 4 ]
+ itertools.count 1 |> Seq.take 4 |> Seq.toList |> equal [ 1; 2; 3; 4 ]
[]
let ``test count with step works`` () =
- itertools.count (0, 2)
- |> Seq.take 4
- |> Seq.toList
- |> equal [ 0; 2; 4; 6 ]
+ itertools.count (0, 2) |> Seq.take 4 |> Seq.toList |> equal [ 0; 2; 4; 6 ]
[]
let ``test cycle works`` () =
@@ -26,9 +20,7 @@ let ``test cycle works`` () =
[]
let ``test repeat with times works`` () =
- itertools.repeat ("x", 3)
- |> Seq.toList
- |> equal [ "x"; "x"; "x" ]
+ itertools.repeat ("x", 3) |> Seq.toList |> equal [ "x"; "x"; "x" ]
[]
let ``test accumulate works`` () =
@@ -44,9 +36,7 @@ let ``test accumulate with func works`` () =
[]
let ``test chain two sequences works`` () =
- itertools.chain ([ 1; 2 ], [ 3; 4 ])
- |> Seq.toList
- |> equal [ 1; 2; 3; 4 ]
+ itertools.chain ([ 1; 2 ], [ 3; 4 ]) |> Seq.toList |> equal [ 1; 2; 3; 4 ]
[]
let ``test chain three sequences works`` () =
@@ -80,15 +70,11 @@ let ``test filterfalse works`` () =
[]
let ``test islice with stop works`` () =
- itertools.islice ([ 1; 2; 3; 4; 5 ], 3)
- |> Seq.toList
- |> equal [ 1; 2; 3 ]
+ itertools.islice ([ 1; 2; 3; 4; 5 ], 3) |> Seq.toList |> equal [ 1; 2; 3 ]
[]
let ``test islice with start and stop works`` () =
- itertools.islice ([ 1; 2; 3; 4; 5 ], 1, 4)
- |> Seq.toList
- |> equal [ 2; 3; 4 ]
+ itertools.islice ([ 1; 2; 3; 4; 5 ], 1, 4) |> Seq.toList |> equal [ 2; 3; 4 ]
[]
let ``test pairwise works`` () =
@@ -111,9 +97,7 @@ let ``test combinations works`` () =
[]
let ``test permutations with r works`` () =
- itertools.permutations ([ 1; 2; 3 ], 2)
- |> Seq.length
- |> equal 6
+ itertools.permutations ([ 1; 2; 3 ], 2) |> Seq.length |> equal 6
[]
let ``test product two sequences works`` () =
diff --git a/test/TestJson.fs b/test/TestJson.fs
index 1ba7543..5f2cf5d 100644
--- a/test/TestJson.fs
+++ b/test/TestJson.fs
@@ -66,7 +66,7 @@ let ``test Json.loads with array works`` () =
[]
let ``test Json.dumps with indent works`` () =
let obj = {| A = 1n |}
- let result = Json.dumps(obj, indent = 2)
+ let result = Json.dumps (obj, indent = 2)
result.Contains("\n") |> equal true
[]
diff --git a/test/TestMath.fs b/test/TestMath.fs
index 6141b45..9ff7aea 100644
--- a/test/TestMath.fs
+++ b/test/TestMath.fs
@@ -93,32 +93,25 @@ let ``test pow works`` () =
math.pow (10.0, 2.0) |> equal 100.0
[]
-let ``test sin works`` () =
- math.sin 0.0 |> equal 0.0
+let ``test sin works`` () = math.sin 0.0 |> equal 0.0
[]
-let ``test cos works`` () =
- math.cos 0.0 |> equal 1.0
+let ``test cos works`` () = math.cos 0.0 |> equal 1.0
[]
-let ``test tan works`` () =
- math.tan 0.0 |> equal 0.0
+let ``test tan works`` () = math.tan 0.0 |> equal 0.0
[]
-let ``test asin works`` () =
- math.asin 0.0 |> equal 0.0
+let ``test asin works`` () = math.asin 0.0 |> equal 0.0
[]
-let ``test acos works`` () =
- math.acos 1.0 |> equal 0.0
+let ``test acos works`` () = math.acos 1.0 |> equal 0.0
[]
-let ``test atan works`` () =
- math.atan 0.0 |> equal 0.0
+let ``test atan works`` () = math.atan 0.0 |> equal 0.0
[]
-let ``test atan2 works`` () =
- math.atan2 (0.0, 1.0) |> equal 0.0
+let ``test atan2 works`` () = math.atan2 (0.0, 1.0) |> equal 0.0
[]
let ``test pi constant works`` () =
@@ -133,8 +126,7 @@ let ``test tau constant works`` () =
math.tau |> fun x -> (x > 6.28318 && x < 6.28319) |> equal true
[]
-let ``test inf constant works`` () =
- math.isinf math.inf |> equal true
+let ``test inf constant works`` () = math.isinf math.inf |> equal true
[]
let ``test sqrt works`` () =
@@ -155,8 +147,7 @@ let ``test trunc works`` () =
math.trunc -2.7 |> equal -2
[]
-let ``test hypot works`` () =
- math.hypot (3.0, 4.0) |> equal 5.0
+let ``test hypot works`` () = math.hypot (3.0, 4.0) |> equal 5.0
[]
let ``test isqrt works`` () =
@@ -168,12 +159,10 @@ let ``test fsum works`` () =
math.fsum [ 1.0; 2.0; 3.0 ] |> equal 6.0
[]
-let ``test nan constant works`` () =
- math.isnan math.nan |> equal true
+let ``test nan constant works`` () = math.isnan math.nan |> equal true
[]
-let ``test prod works`` () =
- math.prod [ 1; 2; 3; 4 ] |> equal 24
+let ``test prod works`` () = math.prod [ 1; 2; 3; 4 ] |> equal 24
[]
let ``test perm works`` () =
@@ -185,36 +174,28 @@ let ``test dist works`` () =
math.dist ([| 0.0; 0.0 |], [| 3.0; 4.0 |]) |> equal 5.0
[]
-let ``test cosh works`` () =
- math.cosh 0.0 |> equal 1.0
+let ``test cosh works`` () = math.cosh 0.0 |> equal 1.0
[]
-let ``test sinh works`` () =
- math.sinh 0.0 |> equal 0.0
+let ``test sinh works`` () = math.sinh 0.0 |> equal 0.0
[]
-let ``test tanh works`` () =
- math.tanh 0.0 |> equal 0.0
+let ``test tanh works`` () = math.tanh 0.0 |> equal 0.0
[]
-let ``test acosh works`` () =
- math.acosh 1.0 |> equal 0.0
+let ``test acosh works`` () = math.acosh 1.0 |> equal 0.0
[]
-let ``test asinh works`` () =
- math.asinh 0.0 |> equal 0.0
+let ``test asinh works`` () = math.asinh 0.0 |> equal 0.0
[]
-let ``test atanh works`` () =
- math.atanh 0.0 |> equal 0.0
+let ``test atanh works`` () = math.atanh 0.0 |> equal 0.0
[]
-let ``test erf works`` () =
- math.erf 0.0 |> equal 0.0
+let ``test erf works`` () = math.erf 0.0 |> equal 0.0
[]
-let ``test erfc works`` () =
- math.erfc 0.0 |> equal 1.0
+let ``test erfc works`` () = math.erfc 0.0 |> equal 1.0
[]
let ``test gamma works`` () =
@@ -222,8 +203,7 @@ let ``test gamma works`` () =
math.gamma 5.0 |> equal 24.0
[]
-let ``test lgamma works`` () =
- math.lgamma 1.0 |> equal 0.0
+let ``test lgamma works`` () = math.lgamma 1.0 |> equal 0.0
[]
let ``test log with base works`` () =
@@ -259,8 +239,8 @@ let ``test isclose works`` () =
[]
let ``test isclose with tolerances works`` () =
- math.isclose (1.0, 1.001, rel_tol=0.01) |> equal true
- math.isclose (1.0, 2.0, abs_tol=0.1) |> equal false
+ math.isclose (1.0, 1.001, rel_tol = 0.01) |> equal true
+ math.isclose (1.0, 2.0, abs_tol = 0.1) |> equal false
[]
let ``test nextafter works`` () =
diff --git a/test/TestString.fs b/test/TestString.fs
index 5d1b808..7cb1c29 100644
--- a/test/TestString.fs
+++ b/test/TestString.fs
@@ -17,7 +17,8 @@ let ``test string format 2 works`` () =
[]
let ``test ascii_letters constant`` () =
- pyString.ascii_letters |> equal "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ pyString.ascii_letters
+ |> equal "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
[]
let ``test ascii_lowercase constant`` () =
@@ -28,16 +29,14 @@ let ``test ascii_uppercase constant`` () =
pyString.ascii_uppercase |> equal "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[]
-let ``test digits constant`` () =
- pyString.digits |> equal "0123456789"
+let ``test digits constant`` () = pyString.digits |> equal "0123456789"
[]
let ``test hexdigits constant`` () =
pyString.hexdigits |> equal "0123456789abcdefABCDEF"
[]
-let ``test octdigits constant`` () =
- pyString.octdigits |> equal "01234567"
+let ``test octdigits constant`` () = pyString.octdigits |> equal "01234567"
[]
let ``test punctuation constant`` () =
diff --git a/test/TestSys.fs b/test/TestSys.fs
index 26b7530..3033dab 100644
--- a/test/TestSys.fs
+++ b/test/TestSys.fs
@@ -4,28 +4,22 @@ open Fable.Python.Testing
open Fable.Python.Sys
[]
-let ``test sys.platform is non-empty string`` () =
- sys.platform.Length > 0 |> equal true
+let ``test sys.platform is non-empty string`` () = sys.platform.Length > 0 |> equal true
[]
-let ``test sys.version is non-empty string`` () =
- sys.version.Length > 0 |> equal true
+let ``test sys.version is non-empty string`` () = sys.version.Length > 0 |> equal true
[]
-let ``test sys.maxsize is positive`` () =
- sys.maxsize > 0n |> equal true
+let ``test sys.maxsize is positive`` () = sys.maxsize > 0n |> equal true
[