-
Notifications
You must be signed in to change notification settings - Fork 310
Python support for Fable 🎉 #2345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e7ec344
db879d6
f46b933
3fd17eb
cee5615
cfb7ed0
d052a92
f893abc
69c1177
900dc24
e68eeda
bd36059
680a9f8
591a93a
a6344f2
0701377
c0268eb
86a9fa6
2b1e138
fb50321
e987802
6d14a28
9dda9e6
08328c4
aa7013e
e1595d7
3324b81
5b58e79
2cecd0c
c83eb2c
b30cea9
5db9b89
53d0312
3863ca8
8540447
875a469
6c86af2
183dd84
7e7913a
a68cbd3
52dc5f6
12c4816
ac1fb28
1756237
b2a8ab6
4215d95
02309fb
627289f
3ab4ed5
b37affe
dc1f822
c676183
5c5d948
880596f
c63973e
ebd9868
0f87c3c
559d79e
ce1741e
fec543d
d8189e8
15af659
4209a4b
be027a6
102eb8b
e9caa73
0d8fb62
cbb90dd
fded5c6
3af2ade
06edc58
29f6129
405a938
f909256
cf17446
634f181
0515e5b
26b81e0
6518188
45fcad1
b082f4f
8dba1d2
d9f7c42
34bef83
9317fbf
677b4bd
30f9ba6
044c11a
dc399fc
2d2fc03
6e27f39
8c82c80
f0c66b3
17e703b
db90eea
a156a62
7cf8821
0e1d2e1
6dd686a
df9e0bd
5f9f9eb
021ee83
a859e33
4f0956a
31685a0
cb2ba24
7c9d349
fa78716
eba41be
0abd586
6b15331
18447c3
7dd75e4
48af9b8
6de0250
ac25680
0968fc0
4dd84a7
97ec1a3
a70f8ea
63826ba
53f89ef
9d597ca
a818b3e
0812d22
586f538
5eadd5f
956968f
484608a
e73fa6d
0115f6d
705d6e3
2ef3a00
146359b
9a60689
fe5481b
eee5696
a7294ed
516d9eb
ba679e5
fcd1d6a
5cc053f
8ee6a53
4e33158
827f0d9
5106a41
9ca3054
d3b0420
db9e196
c1c8dab
a7988cf
3f1c236
c42c106
5ff46d3
1dc225e
dfbe385
a1095de
b33d270
9f40850
c3f8b5e
b81c02b
38161ac
2eb5a52
72c972b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -201,3 +201,7 @@ docs/tools/FSharp.Formatting.svclog | |
.ionide.debug | ||
*.bak | ||
project.lock.json | ||
|
||
# Python | ||
.eggs/ | ||
__pycache__/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ type Verbosity = | |
type Language = | ||
| JavaScript | ||
| TypeScript | ||
| Python | ||
| Php | ||
|
||
type CompilerOptions = | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace Fable.Import | ||
|
||
namespace Fable.Core | ||
|
||
open System | ||
open System.Text.RegularExpressions | ||
|
||
module PY = | ||
type [<AllowNullLiteral>] ArrayConstructor = | ||
[<Emit "$0([None]*$1...)">] abstract Create: size: int -> 'T[] | ||
abstract isArray: arg: obj -> bool | ||
abstract from: arg: obj -> 'T[] | ||
|
||
[<RequireQualifiedAccess>] | ||
module Constructors = | ||
|
||
let [<Emit("list")>] Array: ArrayConstructor = pyNative |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
module Fable.Core.PyInterop | ||
|
||
open System | ||
open Fable.Core | ||
|
||
/// Has same effect as `unbox` (dynamic casting erased in compiled Python code). | ||
/// The casted type can be defined on the call site: `!!myObj?bar(5): float` | ||
let (!!) x: 'T = pyNative | ||
|
||
/// Implicit cast for erased unions (U2, U3...) | ||
let inline (!^) (x:^t1) : ^t2 = ((^t1 or ^t2) : (static member op_ErasedCast : ^t1 -> ^t2) x) | ||
|
||
/// Dynamically access a property of an arbitrary object. | ||
/// `myObj?propA` in Python becomes `myObj.propA` | ||
/// `myObj?(propA)` in Python becomes `myObj[propA]` | ||
let (?) (o: obj) (prop: obj): 'a = pyNative | ||
|
||
/// Dynamically assign a value to a property of an arbitrary object. | ||
/// `myObj?propA <- 5` in Python becomes `myObj.propA = 5` | ||
/// `myObj?(propA) <- 5` in Python becomes `myObj[propA] = 5` | ||
let (?<-) (o: obj) (prop: obj) (v: obj): unit = pyNative | ||
|
||
/// Destructure and apply a tuple to an arbitrary value. | ||
/// E.g. `myFn $ (arg1, arg2)` in Python becomes `myFn(arg1, arg2)` | ||
let ($) (callee: obj) (args: obj): 'a = pyNative | ||
|
||
/// Upcast the right operand to obj (and uncurry it if it's a function) and create a key-value tuple. | ||
/// Mostly convenient when used with `createObj`. | ||
/// E.g. `createObj [ "a" ==> 5 ]` in Python becomes `{ a: 5 }` | ||
let (==>) (key: string) (v: obj): string*obj = pyNative | ||
|
||
/// Destructure a tuple of arguments and applies to literal Python code as with EmitAttribute. | ||
/// E.g. `emitPyExpr (arg1, arg2) "$0 + $1"` in Python becomes `arg1 + arg2` | ||
let emitPyExpr<'T> (args: obj) (pyCode: string): 'T = pyNative | ||
|
||
/// Same as emitPyExpr but intended for Python code that must appear in a statement position | ||
/// E.g. `emitPyExpr aValue "while($0 < 5) doSomething()"` | ||
let emitPyStatement<'T> (args: obj) (pyCode: string): 'T = pyNative | ||
|
||
/// Create a literal Python object from a collection of key-value tuples. | ||
/// E.g. `createObj [ "a" ==> 5 ]` in Python becomes `{ a: 5 }` | ||
let createObj (fields: #seq<string*obj>): obj = pyNative | ||
|
||
/// Create a literal Python object from a collection of union constructors. | ||
/// E.g. `keyValueList CaseRules.LowerFirst [ MyUnion 4 ]` in Python becomes `{ myUnion: 4 }` | ||
let keyValueList (caseRule: CaseRules) (li: 'T seq): obj = pyNative | ||
|
||
/// Create a literal Py object from a mutator lambda. Normally used when | ||
/// the options interface has too many fields to be represented with a Pojo record. | ||
/// E.g. `pyOptions<MyOpt> (fun o -> o.foo <- 5)` in Python becomes `{ "foo": 5 }` | ||
let pyOptions<'T> (f: 'T->unit): 'T = pyNative | ||
|
||
/// Create an empty Python object: {} | ||
let createEmpty<'T> : 'T = pyNative | ||
|
||
[<Emit("type($0)")>] | ||
let pyTypeof (x: obj): string = pyNative | ||
|
||
[<Emit("isinstance($0, $1)")>] | ||
let pyInstanceof (x: obj) (cons: obj): bool = pyNative | ||
|
||
/// Works like `ImportAttribute` (same semantics as ES6 imports). | ||
/// You can use "*" or "default" selectors. | ||
let import<'T> (selector: string) (path: string):'T = pyNative | ||
|
||
/// F#: let myMember = importMember<string> "myModule" | ||
/// Py: from my_module import my_member | ||
/// Note the import must be immediately assigned to a value in a let binding | ||
let importMember<'T> (path: string):'T = pyNative | ||
|
||
/// F#: let myLib = importAll<obj> "myLib" | ||
/// Py: from my_lib import * | ||
let importAll<'T> (path: string):'T = pyNative | ||
|
||
/// Imports a file only for its side effects | ||
let importSideEffects (path: string): unit = pyNative |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ module Util = | |
try failwith "JS only" // try/catch is just for padding so it doesn't get optimized | ||
with ex -> raise ex | ||
|
||
let inline pyNative<'T> : 'T = jsNative | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we can just use a single helper ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's good idea. Perhaps in another PR? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @IltaySaeedi! They are replaced in the |
||
let inline phpNative<'T> : 'T = jsNative | ||
|
||
module Experimental = | ||
|
Uh oh!
There was an error while loading. Please reload this page.