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
3 changes: 3 additions & 0 deletions src/Fable.Python.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
<Compile Include="stdlib/Math.fs" />
<Compile Include="stdlib/Random.fs" />
<Compile Include="stdlib/Os.fs" />
<Compile Include="stdlib/Heapq.fs" />
<Compile Include="stdlib/Queue.fs" />
<Compile Include="stdlib/String.fs" />
<Compile Include="stdlib/Sys.fs" />
<Compile Include="stdlib/Threading.fs" />
<Compile Include="stdlib/Time.fs" />
<Compile Include="stdlib/TkInter.fs" />
<Compile Include="stdlib/Traceback.fs" />

<Compile Include="cognite-sdk/CogniteSdk.fs" />
<Compile Include="flask/Flask.fs" />
Expand Down
29 changes: 29 additions & 0 deletions src/stdlib/Builtins.fs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,26 @@ type IExports =
?opener: _Opener ->
TextIOWrapper

/// Return the value of the named attribute of object. name must be a string.
/// See https://docs.python.org/3/library/functions.html#getattr
abstract getattr: obj: obj * name: string -> 'T
/// Return the value of the named attribute of object. If the attribute does not exist,
/// default is returned.
/// See https://docs.python.org/3/library/functions.html#getattr
abstract getattr: obj: obj * name: string * ``default``: 'T -> 'T
/// Sets the named attribute on the given object to the specified value.
/// See https://docs.python.org/3/library/functions.html#setattr
abstract setattr: obj: obj * name: string * value: obj -> unit
/// Return True if the string is the name of one of the object's attributes.
/// See https://docs.python.org/3/library/functions.html#hasattr
abstract hasattr: obj: obj * name: string -> bool
/// Return True if the object argument is an instance of the classinfo argument.
/// See https://docs.python.org/3/library/functions.html#isinstance
abstract isinstance: obj: obj * classinfo: obj -> bool
/// Return the type of an object.
/// See https://docs.python.org/3/library/functions.html#type
abstract ``type``: obj -> obj

[<ImportAll("builtins")>]
let builtins: IExports = nativeOnly

Expand Down Expand Up @@ -331,3 +351,12 @@ let __name__: string = nativeOnly

/// Python print function. Takes a single argument, so can be used with e.g string interpolation.
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)

/// Sets the named attribute on the given object to the specified value.
let setattr obj name value = builtins.setattr (obj, name, value)

/// Return True if the string is the name of one of the object's attributes.
let hasattr obj name = builtins.hasattr (obj, name)
34 changes: 34 additions & 0 deletions src/stdlib/Heapq.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/// Type bindings for Python heapq module: https://docs.python.org/3/library/heapq.html
module Fable.Python.Heapq

open Fable.Core

// fsharplint:disable MemberNames

[<Erase>]
type IExports =
/// Push the value item onto the heap, maintaining the heap invariant
/// See https://docs.python.org/3/library/heapq.html#heapq.heappush
abstract heappush: heap: ResizeArray<'T> * item: 'T -> unit
/// Pop and return the smallest item from the heap, maintaining the heap invariant
/// See https://docs.python.org/3/library/heapq.html#heapq.heappop
abstract heappop: heap: ResizeArray<'T> -> 'T
/// Push item on the heap, then pop and return the smallest item from the heap
/// See https://docs.python.org/3/library/heapq.html#heapq.heappushpop
abstract heappushpop: heap: ResizeArray<'T> * item: 'T -> 'T
/// Transform list into a heap, in-place, in linear time
/// See https://docs.python.org/3/library/heapq.html#heapq.heapify
abstract heapify: x: ResizeArray<'T> -> unit
/// Pop and return the smallest item from the heap, and also push the new item
/// See https://docs.python.org/3/library/heapq.html#heapq.heapreplace
abstract heapreplace: heap: ResizeArray<'T> * item: 'T -> 'T
/// Return a list with the n largest elements from the dataset
/// See https://docs.python.org/3/library/heapq.html#heapq.nlargest
abstract nlargest: n: int * iterable: 'T seq -> ResizeArray<'T>
/// Return a list with the n smallest elements from the dataset
/// See https://docs.python.org/3/library/heapq.html#heapq.nsmallest
abstract nsmallest: n: int * iterable: 'T seq -> ResizeArray<'T>

/// Heap queue algorithm
[<ImportAll("heapq")>]
let heapq: IExports = nativeOnly
49 changes: 30 additions & 19 deletions src/stdlib/Queue.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ open Fable.Core

[<Import("Queue", "queue")>]
type Queue<'T>() =
/// Return the approximate size of the queue. Note, qsize() > 0 doesnt guarantee that a subsequent get() will not
/// Return the approximate size of the queue. Note, qsize() > 0 doesn't guarantee that a subsequent get() will not
/// block, nor will qsize() < maxsize guarantee that put() will not block.
member x.qsize() : int = nativeOnly
/// Return True if the queue is empty, False otherwise. If empty() returns True it doesnt guarantee that a
/// subsequent call to put() will not block. Similarly, if empty() returns False it doesnt guarantee that a
/// Return True if the queue is empty, False otherwise. If empty() returns True it doesn't guarantee that a
/// subsequent call to put() will not block. Similarly, if empty() returns False it doesn't guarantee that a
/// subsequent call to get() will not block.
member x.empty() : bool = nativeOnly
/// Return True if the queue is full, False otherwise. If full() returns True it doesnt guarantee that a subsequent
/// call to get() will not block. Similarly, if full() returns False it doesnt guarantee that a subsequent call to
/// Return True if the queue is full, False otherwise. If full() returns True it doesn't guarantee that a subsequent
/// call to get() will not block. Similarly, if full() returns False it doesn't guarantee that a subsequent call to
/// put() will not block.
member x.full() : bool = nativeOnly
/// Put item into the queue. If optional args block is true and timeout is None (the default), block if necessary
Expand All @@ -34,6 +34,10 @@ 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
[<Emit("$0.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
Expand All @@ -57,24 +61,31 @@ type LifoQueue<'T>() =

[<Import("SimpleQueue", "queue")>]
type SimpleQueue<'T>() =
/// Return the approximate size of the queue. Note, qsize() > 0 doesnt guarantee that a subsequent get() will not
/// Return the approximate size of the queue. Note, qsize() > 0 doesn't guarantee that a subsequent get() will not
/// block, nor will qsize() < maxsize guarantee that put() will not block.
member x.qsize() : int = nativeOnly
/// Return True if the queue is empty, False otherwise. If empty() returns True it doesnt guarantee that a
/// subsequent call to put() will not block. Similarly, if empty() returns False it doesnt guarantee that a
/// Return True if the queue is empty, False otherwise. If empty() returns True it doesn't guarantee that a
/// subsequent call to put() will not block. Similarly, if empty() returns False it doesn't guarantee that a
/// subsequent call to get() will not block.
member x.empty() : bool = nativeOnly
/// Return True if the queue is full, False otherwise. If full() returns True it doesnt guarantee that a subsequent
/// call to get() will not block. Similarly, if full() returns False it doesnt guarantee that a subsequent call to
/// Return True if the queue is full, False otherwise. If full() returns True it doesn't guarantee that a subsequent
/// call to get() will not block. Similarly, if full() returns False it doesn't guarantee that a subsequent call to
/// put() will not block.
member x.put(item: 'T, ?block: bool, ?timeout: float) : unit = nativeOnly
/// Remove and return an item from the queue. If optional args block is true and timeout is None (the default),
/// block if necessary until an item is available. If timeout is a positive number, it blocks at most timeout
/// seconds and raises the Empty exception if no item was available within that time. Otherwise (block is false),
/// return an item if one is immediately available, else raise the Empty exception (timeout is ignored in that
/// case).
///
/// Prior to 3.0 on POSIX systems, and for all versions on Windows, if block is true and timeout is None, this
/// 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.
/// Remove and return an item from the queue.
member x.get(?block: bool, ?timeout: float) : 'T = nativeOnly
/// Equivalent to get(False).
[<Emit("$0.get_nowait()")>]
member x.get_nowait() : 'T = nativeOnly

/// Exception raised when non-blocking get() is called on an empty Queue
/// See https://docs.python.org/3/library/queue.html#queue.Empty
[<Import("Empty", "queue")>]
type Empty() =
inherit exn()

/// Exception raised when non-blocking put() is called on a full Queue
/// See https://docs.python.org/3/library/queue.html#queue.Full
[<Import("Full", "queue")>]
type Full() =
inherit exn()
80 changes: 80 additions & 0 deletions src/stdlib/Threading.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/// Type bindings for Python threading module: https://docs.python.org/3/library/threading.html
module Fable.Python.Threading

open Fable.Core

// fsharplint:disable MemberNames

[<Erase>]
type IExports =
/// Return the 'thread identifier' of the current thread
/// See https://docs.python.org/3/library/threading.html#threading.get_ident
abstract get_ident: unit -> int
/// Return the main Thread object
/// See https://docs.python.org/3/library/threading.html#threading.main_thread
abstract main_thread: unit -> Thread
/// Return the current Thread object
/// See https://docs.python.org/3/library/threading.html#threading.current_thread
abstract current_thread: unit -> Thread
/// Return the number of Thread objects currently alive
/// See https://docs.python.org/3/library/threading.html#threading.active_count
abstract active_count: unit -> int
/// Return a list of all Thread objects currently active
/// See https://docs.python.org/3/library/threading.html#threading.enumerate
abstract enumerate: unit -> Thread list
/// Return a new thread-local data object
/// See https://docs.python.org/3/library/threading.html#threading.local
abstract local: unit -> obj

/// A thread of execution
/// See https://docs.python.org/3/library/threading.html#threading.Thread
and [<Import("Thread", "threading")>] Thread(?target: unit -> unit, ?name: string, ?daemon: bool) =
/// Start the thread's activity
member _.start() : unit = nativeOnly
/// Wait until the thread terminates
member _.join(?timeout: float) : unit = nativeOnly
/// A boolean value indicating whether this thread is a daemon thread
member _.daemon: bool = nativeOnly
/// The thread's name
member _.name: string = nativeOnly
/// The 'thread identifier' of this thread
member _.ident: int option = nativeOnly
/// Whether the thread is alive
member _.is_alive() : bool = nativeOnly

/// A lock object (mutual exclusion)
/// See https://docs.python.org/3/library/threading.html#threading.Lock
[<Import("Lock", "threading")>]
type Lock() =
/// Acquire the lock
member _.acquire(?blocking: bool, ?timeout: float) : bool = nativeOnly
/// Release the lock
member _.release() : unit = nativeOnly
/// Return whether the lock is locked
member _.locked() : bool = nativeOnly

/// A reentrant lock object
/// See https://docs.python.org/3/library/threading.html#threading.RLock
[<Import("RLock", "threading")>]
type RLock() =
/// Acquire the lock
member _.acquire(?blocking: bool, ?timeout: float) : bool = nativeOnly
/// Release the lock
member _.release() : unit = nativeOnly

/// An event object for thread synchronization
/// See https://docs.python.org/3/library/threading.html#threading.Event
[<Import("Event", "threading")>]
type Event() =
/// Set the internal flag to true
member _.set() : unit = nativeOnly
/// Reset the internal flag to false
member _.clear() : unit = nativeOnly
/// Return true if and only if the internal flag is true
member _.is_set() : bool = nativeOnly
/// Block until the internal flag is true or timeout
member _.wait(?timeout: float) : bool = nativeOnly

/// Threading module access and utilities
[<ImportAll("threading")>]
let threading: IExports = nativeOnly
25 changes: 25 additions & 0 deletions src/stdlib/Traceback.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// Type bindings for Python traceback module: https://docs.python.org/3/library/traceback.html
module Fable.Python.Traceback

open Fable.Core

// fsharplint:disable MemberNames

[<Erase>]
type IExports =
/// Print exception information and stack trace entries
/// See https://docs.python.org/3/library/traceback.html#traceback.print_exc
abstract print_exc: unit -> unit
/// Format exception information and stack trace entries as a string
/// See https://docs.python.org/3/library/traceback.html#traceback.format_exc
abstract format_exc: unit -> string
/// Print stack trace entries
/// See https://docs.python.org/3/library/traceback.html#traceback.print_stack
abstract print_stack: unit -> unit
/// Format stack trace entries as a list of strings
/// See https://docs.python.org/3/library/traceback.html#traceback.format_stack
abstract format_stack: unit -> ResizeArray<string>

/// Extract, format and print exceptions and their tracebacks
[<ImportAll("traceback")>]
let traceback: IExports = nativeOnly
5 changes: 5 additions & 0 deletions test/Fable.Python.Test.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
<Compile Include="TestAst.fs" />
<Compile Include="TestAsyncIO.fs" />
<Compile Include="TestBuiltins.fs" />
<Compile Include="TestBuiltinsAttr.fs" />
<Compile Include="TestHeapq.fs" />
<Compile Include="TestQueue.fs" />
<Compile Include="TestThreading.fs" />
<Compile Include="TestTraceback.fs" />
<Compile Include="TestOs.fs" />
<Compile Include="TestJson.fs" />
<Compile Include="TestLogging.fs" />
Expand Down
27 changes: 27 additions & 0 deletions test/TestBuiltinsAttr.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Fable.Python.Tests.BuiltinsAttr

open Fable.Python.Testing
open Fable.Python.Builtins
open Fable.Python.Threading

[<Fact>]
let ``test hasattr works`` () =
let local = threading.local ()
setattr local "name" "test"
builtins.hasattr (local, "name") |> equal true

[<Fact>]
let ``test getattr with default works`` () =
let local = threading.local ()
builtins.getattr (local, "missing", "default") |> equal "default"

[<Fact>]
let ``test setattr and getattr work`` () =
let local = threading.local ()
builtins.setattr (local, "x", 42)
builtins.getattr (local, "x", 0) |> equal 42

[<Fact>]
let ``test hasattr returns false for missing attribute`` () =
let local = threading.local ()
builtins.hasattr (local, "nonexistent") |> equal false
39 changes: 39 additions & 0 deletions test/TestHeapq.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module Fable.Python.Tests.Heapq

open Fable.Python.Testing
open Fable.Python.Heapq

[<Fact>]
let ``test heappush and heappop work`` () =
let heap = ResizeArray<int>()
heapq.heappush (heap, 3)
heapq.heappush (heap, 1)
heapq.heappush (heap, 2)
heapq.heappop heap |> equal 1
heapq.heappop heap |> equal 2
heapq.heappop heap |> equal 3

[<Fact>]
let ``test heapify works`` () =
let heap = ResizeArray [5; 3; 1; 4; 2]
heapq.heapify heap
heapq.heappop heap |> equal 1

[<Fact>]
let ``test heappushpop works`` () =
let heap = ResizeArray [2; 4; 6]
heapq.heapify heap
// Push 1, then pop smallest (1)
heapq.heappushpop (heap, 1) |> equal 1
// Push 3, then pop smallest (2)
heapq.heappushpop (heap, 3) |> equal 2

[<Fact>]
let ``test nlargest works`` () =
let result = heapq.nlargest (3, [1; 5; 2; 8; 3; 7])
result |> equal (ResizeArray [8; 7; 5])

[<Fact>]
let ``test nsmallest works`` () =
let result = heapq.nsmallest (3, [1; 5; 2; 8; 3; 7])
result |> equal (ResizeArray [1; 2; 3])
Loading
Loading