{"id":16682793,"url":"https://github.com/johnno1962/swiftpython","last_synced_at":"2025-09-29T03:31:26.479Z","repository":{"id":62456716,"uuid":"110455523","full_name":"johnno1962/SwiftPython","owner":"johnno1962","description":"Experiments in bridging Swift to Python","archived":false,"fork":false,"pushed_at":"2019-01-01T05:07:42.000Z","size":420,"stargazers_count":88,"open_issues_count":1,"forks_count":7,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-01-10T18:52:07.047Z","etag":null,"topics":["python","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnno1962.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-11-12T17:57:21.000Z","updated_at":"2023-10-25T15:35:30.000Z","dependencies_parsed_at":"2022-11-02T00:15:19.615Z","dependency_job_id":null,"html_url":"https://github.com/johnno1962/SwiftPython","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnno1962%2FSwiftPython","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnno1962%2FSwiftPython/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnno1962%2FSwiftPython/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnno1962%2FSwiftPython/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnno1962","download_url":"https://codeload.github.com/johnno1962/SwiftPython/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234584371,"owners_count":18856290,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","swift"],"created_at":"2024-10-12T14:08:34.641Z","updated_at":"2025-09-29T03:31:21.096Z","avatar_url":"https://github.com/johnno1962.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftPython - Experiments in bridging Swift to Python.\n\n![Icon](http://johnholdsworth.com/swift_python.png)\n\nContains a simple playground that uses a class \"Complex\" that is implemented in Python\nfrom Swift. There are two [Auxiliary files](http://help.apple.com/xcode/mac/8.0/#/devfa5bea3af)\ncontained in the playground that perform the bridging:\n\"[PythonSupport.swift](SwiftPython.playground/Sources/PythonSupport.swift)\" (most easily\nviewed using the workspace) that contains a small set of generic support code for bridging and\n\"[Complex.swift](SwiftPython.playground/Sources/Complex.swift)\" which performs the actual\nbridging and would normally  be generated automatically by a python code generator script introspecting the\nmodule. The underlying python implementation \"[complex.py](SwiftPython.playground/Resources/complex.py)\"\nis included in the playground as a resource.\n\n```Swift\n//: Playground - noun: a place where people can play\n\nimport Foundation\nvar str = \"Hello, python integration\"\n\n// This gives a stack trace when something out of the ordinary occurs\nlet _pythonWarn = pythonWarn\npythonWarn = {\n    (_ message: String) in\n    _pythonWarn(message)\n    print(dumpStrackTrace())\n}\n\n// The basic class underlying the integration is PythonObject\nPythonObject(any: \"123\").asString\n\n// PythonObject can accept most Swift types specifically:\n// Arrays, Dictionaries, Strings, Ints, Doubles, Data \u0026 Bool\nlet pythonObject = PythonObject(any: [\"list\": Array(0 ..\u003c 100)])\n\n// this is converted back to a concrete Swift type using \"asAny(of:)\"\nlet arrayDictionary = pythonObject.asAny(of: [String: [Int]].self)\nprint(arrayDictionary[\"list\"]![4])\n\n// Leave the Object as Python structures to access it more efficiently\nprint(PythonDict\u003c[Int]\u003e(any: [\"list\": Array(0 ..\u003c 100)])[\"list\"]![4])\nprint(PythonDict\u003cPythonList\u003cInt\u003e\u003e(any: [\"list\": Array(0 ..\u003c 100)])[\"list\"]![4])\n\n// PythonObject are passed to python methods and functions and returned.\n// This Complex class is as wrapper generated by the script \"bridgegen.py\"\nlet cplx = Complex(realpart: 11.0, imagpart: 12.0)\n\n// There are named and unnamed versions of initialisers and methods generated\ncplx.add(c: Complex(1.0, 2.0))\n\n// __doc__ comments in the Python class can specify the return type for \"asAny\"\nprint(cplx.toDictionary())\n\n// global functions in the module are also exported\nprint(newComplex(real: 123, imag: 456).toString(extra: cplx.toDictionary()))\nprint(newComplex(123, 456).toString(extra: cplx.toDictionary()))\n\n// Basic operators work when defined\nvar c = Complex(1, 2)\nc = c + c\nc += c\n\n// A closure or function can be used to have Python call back to Swift\ncplx.callme(closure: {\n    (args: [PythonObject]) -\u003e PythonObject? in\n    print(args[0].asString)\n    return cplx\n}, str: \"Swift closure called from Python called from Swift\")\n\nfunc callback(args: [PythonObject]) -\u003e PythonObject? {\n    print(args[0].asString)\n    return Complex(11.0, 22.0)\n}\n\nPythonObject(any: [cplx, cplx]).asAny(of: [Complex].self)[1]\n    .callme(callback, \"Swift function called from Python called from Swift\")\n\n// PythonList and PythonDict conform to Sequence\nlet list = PythonList\u003cString\u003e()\nlist.append(\"123\")\nlist.append(\"234\")\nlist.append(\"345\")\n\n// Setting an element at the end of a list is an implicit append\nlist[3] = \"456\"\n\nfor item in list {\n    print(item)\n}\n\nlet dict = PythonDict\u003cInt\u003e()\ndict[\"ABC\"] = 123\ndict[\"DEF\"] = 456\n\nfor (key, value) in dict {\n    print(\"\\(key): \\(value)\")\n}\n\n// Oddly, a PythonList can be initialised from PythonDict and vice versa\nlet dictAsList = PythonList\u003cAny\u003e(dictionary: dict).asTypeArray\nPythonDict\u003cInt\u003e(array: dictAsList)\n\n// Wherever possible conversion between types is available\nlet a1 = PythonObject(any: [1, 2, 3]).asArray(of: Int.self)\nlet a2 = PythonObject(any: [1, 2, 3]).asArray(of: Double.self)\nlet a3 = PythonObject(any: [1.5, 2.5, 3.5]).asArray(of: Int.self)\nlet a4 = PythonObject(any: [1.5, 2.5, 3.5]).asArray(of: Double.self)\nlet a5 = PythonObject(any: a4).asArray(of: String.self)\nlet a6 = PythonObject(any: a5).asArray(of: Double.self)\nlet d1 = PythonObject(any: [\"a\": 123, \"b\": 456]).asAny(of: [String: Double].self)\n\n// \"PythonAny\" is SwiftyJSON-like omni-type useful for processing recursive data\nPythonAny(any: [\"a\": 1.0, \"b\": 2.0, \"c\": [1,2,3]])[\"c\"]?[1].asInt\n\n// Processing large arrays of primitive types is optimised\nlet start = Date()\ncplx.echoArray(value: [\"data\": Array(0 ..\u003c 1_000_000)])\n    .asAny(of: [String: [Int]].self)[\"data\"]![1000]\nprint(Date().timeIntervalSince(start))\n\n// With Anaconda 2.7 installed and a small patch to the Python framework\n// (only required on Sierra) you can use 3d plots. Details in myplot.py:\n//let myplotModule = PythonModule(named: \"myplot\")\n\n// Finally, Python's plot routines can be made available manually\nlet matplotlib_pyplotModule = PythonModule(named: \"matplotlib.pyplot\")\nlet imshowFunction = matplotlib_pyplotModule.function(named: \"imshow\")\nlet showFunction = matplotlib_pyplotModule.function(named: \"show\")\n\n// This is the code normally generated by the script bridgegen.py\nfunc imshow(_ X: Any? = nil, _ cmap: Any? = nil, _ norm: Any? = nil, _ aspect: Any? = nil, _ interpolation: Any? = nil, _ alpha: Any? = nil, _ vmin: Any? = nil, _ vmax: Any? = nil, _ origin: Any? = nil, _ extent: Any? = nil, _ shape: Any? = nil, _ filternorm: Any = 1, _ filterrad: Any = 4.0, _ imlim: Any? = nil, _ resample: Any? = nil, _ url: Any? = nil, _ hold: Any? = nil, kw: [String: Any]? = nil) -\u003e PythonObject {\n    return imshowFunction.call(args: [X, cmap, norm, aspect, interpolation, alpha, vmin, vmax, origin, extent, shape, filternorm, filterrad, imlim, resample, url, hold], kw: kw)\n}\n\nfunc show(_ kw: [String: Any]? = nil) -\u003e PythonObject {\n    return showFunction.call(args: [], kw: kw)\n}\n\nprint(\"Mandelbrot window may appear behind the playground/workspace\")\nimshow(mandelbrot(400,400))\nshow([\"block\": false])\n\nimport PlaygroundSupport\nPlaygroundPage.current.needsIndefiniteExecution = true\n```\n\n### Code generator\n\nAn example code generator [bridgegen.py](bridgegen.py) is included. Its first argument\nis the module to be generated then an optional path to the module so python can find it and\nSwift code will be printed to stdout. Use doc comments as shown in complex.py to control\nthe return type of functions or specify instance variables.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnno1962%2Fswiftpython","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnno1962%2Fswiftpython","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnno1962%2Fswiftpython/lists"}