Latest 1.0
Homepage https://github.com/johnno1962/SwiftPython
License MIT
Platforms osx 10.11
Authors

SwiftPython – Experiments in bridging Swift to Python.

Icon Icon

Contains a simple playground that uses a class "Complex" that is implemented in Python
from Swift. There are two Auxiliary files
contained in the playground that perform the bridging:
"PythonSupport.swift" (most easily
viewed using the workspace) that contains a small set of generic support code for bridging and
"Complex.swift" which performs the actual
bridging and would normally be generated automatically by a python code generator script introspecting the
module. The underlying python implementation "complex.py"
is included in the playground as a resource.

//: Playground - noun: a place where people can play

import Foundation
var str = "Hello, python integration"

// This gives a stack trace when something out of the ordinary occurs
let _pythonWarn = pythonWarn
pythonWarn = {
    (_ message: String) in
    _pythonWarn(message)
    print(dumpStrackTrace())
}

// The basic class underlying the integration is PythonObject
PythonObject(any: "123").asString

// PythonObject can accept most Swift types specifically:
// Arrays, Dictionaries, Strings, Ints, Doubles, Data & Bool
let pythonObject = PythonObject(any: ["list": Array(0 ..< 100)])

// this is converted back to a concrete Swift type using "asAny(of:)"
let arrayDictionary = pythonObject.asAny(of: [String: [Int]].self)
print(arrayDictionary["list"]![4])

// Leave the Object as Python structures to access it more efficiently
print(PythonDict<[Int]>(any: ["list": Array(0 ..< 100)])["list"]![4])
print(PythonDict<PythonList<Int>>(any: ["list": Array(0 ..< 100)])["list"]![4])

// PythonObject are passed to python methods and functions and returned.
// This Complex class is as wrapper generated by the script "bridgegen.py"
let cplx = Complex(realpart: 11.0, imagpart: 12.0)

// There are named and unnamed versions of initialisers and methods generated
cplx.add(c: Complex(1.0, 2.0))

// __doc__ comments in the Python class can specify the return type for "asAny"
print(cplx.toDictionary())

// global functions in the module are also exprted
print(newComplex(real: 123, imag: 456).toString(extra: cplx.toDictionary()))
print(newComplex(123, 456).toString(extra: cplx.toDictionary()))

// A closure or function can be used to have Python call back to Swift
cplx.callme(closure: {
    (args: [PythonObject]) -> PythonObject? in
    print(args[0].asString)
    return cplx
}, str: "Swift closure called from Python called from Swift")

func callback(args: [PythonObject]) -> PythonObject? {
    print(args[0].asString)
    return Complex(11.0, 22.0)
}

PythonObject(any: [cplx, cplx]).asAny(of: [Complex].self)[1]
    .callme(callback, "Swift function called from Python called from Swift")

// PythonList and PythonDict conform to Sequence

let list = PythonList<String>()
list.append("123")
list.append("234")
list.append("345")

// Setting an element at the end of a list is an implicit append
list[3] = "456"

for item in list {
    print(item)
}

let dict = PythonDict<Int>()
dict["ABC"] = 123
dict["DEF"] = 456

for (key, value) in dict {
    print("(key): (value)")
}

// Oddly, a PythonList can be initialised from PythonDict and vice versa
let dictAsList = PythonList<Any>(dictionary: dict).asTypeArray
PythonDict<Int>(array: dictAsList)

// Wherever possible conversion between types is available
let a1 = PythonObject(any: [1, 2, 3]).asArray(of: Int.self)
let a2 = PythonObject(any: [1, 2, 3]).asArray(of: Double.self)
let a3 = PythonObject(any: [1.5, 2.5, 3.5]).asArray(of: Int.self)
let a4 = PythonObject(any: [1.5, 2.5, 3.5]).asArray(of: Double.self)
let a5 = PythonObject(any: a4).asArray(of: String.self)
let a6 = PythonObject(any: a5).asArray(of: Double.self)
let d1 = PythonObject(any: ["a": 123, "b": 456]).asAny(of: [String: Double].self)

// "PythonAny" is SwiftyJSON-like omni-type useful for processing recursive data
PythonAny(any: ["a": 1.0, "b": 2.0, "c": [1,2,3]])["c"]?[1].asInt

// Processing of large arrays of primitive type is optimised
let start = Date()
(cplx.echoArray(value: Array(0 ..< 1_000_000)).asAny(of: [Int].self))[1000]
print(Date().timeIntervalSince(start))

// Finally, Python's plot routines can be made available
print("Mandelbrot window may be behind the playground/workspace")
imshow(mandelbrot(400,400,20), PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, PythonNone, 1, 4, PythonNone, PythonNone, PythonNone, PythonNone)
show()

Code generator

An example code generator bridgegen.py is included. Its first argument
is the module to be generated then an optional path to the module so python can find it and
Swift code will be printed to stdout. Use doc comments as shown in complex.py to control
the return type of functions or specify instance variables.

Latest podspec

{
    "name": "SwiftPython",
    "version": "1.0",
    "summary": "Swift Integration with Python",
    "homepage": "https://github.com/johnno1962/SwiftPython",
    "social_media_url": "https://twitter.com/Injection4Xcode",
    "documentation_url": "https://github.com/johnno1962/SwiftPython/blob/master/README.md",
    "license": {
        "type": "MIT"
    },
    "authors": {
        "johnno1962": "[email protected]"
    },
    "platforms": {
        "osx": "10.11"
    },
    "source": {
        "git": "https://github.com/johnno1962/SwiftPython.git",
        "tag": "1.0"
    },
    "source_files": "SwiftPython.playground/Sources/*.swift",
    "pushed_with_swift_version": "4.0"
}

Pin It on Pinterest

Share This