Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/stdlib/Builtins.fs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,20 @@ type IExports =
abstract int: obj -> int
/// Object to float
abstract float: obj -> float
/// Object to bool
abstract bool: obj -> bool
/// Convert to bytes
abstract bytes: byte[] -> byte[]
/// Convert string to bytes with encoding
abstract bytes: string * encoding: string -> byte[]

/// Create a new empty dictionary.
abstract dict: unit -> Dictionary<string, obj>
/// Create a dictionary from an iterable of key/value pairs.
abstract dict: IEnumerable<string * 'V> -> Dictionary<string, 'V>
/// Create a list from an iterable.
abstract list: IEnumerable<'T> -> ResizeArray<'T>

/// Return the largest item in an iterable or the largest of two or more arguments.
abstract max: 'T * 'T -> 'T
/// Return the largest item in an iterable or the largest of two or more arguments.
Expand Down Expand Up @@ -349,6 +358,55 @@ type SystemError() =
[<Emit("__name__")>]
let __name__: string = nativeOnly

// ============================================================================
// Python type references
//
// These expose Python's built-in types as values, primarily for use with
// `Fable.Core.PyInterop.pyInstanceof`. F# names are prefixed with `py` to
// avoid colliding with F#/.NET built-in types.
// ============================================================================

/// Reference to Python's `int` type.
[<Emit("int")>]
let pyInt: obj = nativeOnly

/// Reference to Python's `float` type.
[<Emit("float")>]
let pyFloat: obj = nativeOnly

/// Reference to Python's `bool` type.
[<Emit("bool")>]
let pyBool: obj = nativeOnly

/// Reference to Python's `str` type.
[<Emit("str")>]
let pyStr: obj = nativeOnly

/// Reference to Python's `bytes` type.
[<Emit("bytes")>]
let pyBytes: obj = nativeOnly

/// Reference to Python's `list` type.
[<Emit("list")>]
let pyList: obj = nativeOnly

/// Reference to Python's `dict` type.
[<Emit("dict")>]
let pyDict: obj = nativeOnly

/// Reference to Python's `tuple` type.
[<Emit("tuple")>]
let pyTuple: obj = nativeOnly

/// Reference to Python's `set` type.
[<Emit("set")>]
let pySet: obj = nativeOnly

/// Python's `None` singleton, typed as `obj` for use as a sentinel
/// (e.g. JSON null) and in interop sites that need an explicit None value.
[<Emit("None")>]
let pyNone: obj = nativeOnly

/// Python print function. Takes a single argument, so can be used with e.g string interpolation.
let print obj = builtins.print obj

Expand Down
55 changes: 55 additions & 0 deletions test/TestBuiltins.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Fable.Python.Tests.Builtins

open Fable.Core.PyInterop
open Fable.Python.Testing
open Fable.Python.Builtins
open Fable.Python.Os
Expand Down Expand Up @@ -65,3 +66,57 @@ let ``test any works`` () =
builtins.any [ false; false; true ] |> equal true
builtins.any [ false; false; false ] |> equal false
builtins.any [] |> equal false

[<Fact>]
let ``test bool works`` () =
builtins.bool 1 |> equal true
builtins.bool 0 |> equal false
builtins.bool "" |> equal false
builtins.bool "x" |> equal true

[<Fact>]
let ``test dict empty works`` () =
let d = builtins.dict ()
builtins.len d |> equal 0

[<Fact>]
let ``test dict from pairs works`` () =
let d = builtins.dict [ "a", 1; "b", 2; "c", 3 ]
builtins.len d |> equal 3
d.["a"] |> equal 1
d.["b"] |> equal 2
d.["c"] |> equal 3

[<Fact>]
let ``test list works`` () =
let xs = builtins.list (seq { 1..3 })
builtins.len xs |> equal 3
xs.[0] |> equal 1
xs.[2] |> equal 3

[<Fact>]
let ``test pyInstanceof with type references`` () =
// Use emitPyExpr to construct genuinely Python-native values, since F#'s
// `int`/`float`/`bool` compile to Fable wrapper classes, not Python primitives.
let pyIntVal: obj = emitPyExpr () "42"
let pyFloatVal: obj = emitPyExpr () "3.14"
let pyBoolVal: obj = emitPyExpr () "True"
let pyStrVal: obj = emitPyExpr () "'hello'"

pyInstanceof pyIntVal pyInt |> equal true
pyInstanceof pyFloatVal pyFloat |> equal true
pyInstanceof pyBoolVal pyBool |> equal true
pyInstanceof pyStrVal pyStr |> equal true
pyInstanceof (builtins.dict ()) pyDict |> equal true
pyInstanceof (builtins.list (seq { 1..3 })) pyList |> equal true

// Cross-checks
pyInstanceof pyStrVal pyInt |> equal false
pyInstanceof (builtins.dict ()) pyList |> equal false

[<Fact>]
let ``test pyNone is None`` () =
// bool(None) is False
builtins.bool pyNone |> equal false
// None has type NoneType, so isinstance(None, type(None)) holds
builtins.isinstance (pyNone, builtins.``type`` pyNone) |> equal true
Loading