Skip to content

Commit

Permalink
[TF-76] file renames + split PythonConvertible protocol (#23891)
Browse files Browse the repository at this point in the history
Split `PythonConvertible` into two protocols:
* `PythonConvertible`: conversion to Python.
* `ConvertibleFromPython`: conversion from Python.
  • Loading branch information
realdoug authored and dan-zheng committed Apr 16, 2019
1 parent b30deb2 commit 3c27938
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 89 deletions.
136 changes: 82 additions & 54 deletions stdlib/public/Python/Python.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,20 @@ extension PythonObject : CustomReflectable {
//===----------------------------------------------------------------------===//

public protocol PythonConvertible {
/// A `PythonObject` instance representing this value.
var pythonObject: PythonObject { get }
}

//===----------------------------------------------------------------------===//
// `PythonConvertible` protocol
//===----------------------------------------------------------------------===//

public protocol ConvertibleFromPython {
/// Creates a new instance from the given `PythonObject`, if possible.
/// - Note: Conversion may fail if the given `PythonObject` instance is
/// incompatible (e.g. a Python `string` object cannot be converted into an
/// `Int`).
init?(_ object: PythonObject)

/// A `PythonObject` instance representing this value.
var pythonObject: PythonObject { get }
}

public extension PythonObject {
Expand All @@ -177,7 +183,7 @@ fileprivate extension PythonConvertible {
}

// `PythonObject` is trivially `PythonConvertible`.
extension PythonObject : PythonConvertible {
extension PythonObject : PythonConvertible, ConvertibleFromPython {
public init(_ object: PythonObject) {
self.init(consuming: object.ownedPyObject)
}
Expand Down Expand Up @@ -747,7 +753,7 @@ private func isType(_ object: PythonObject,
return pyObject != _Py_ZeroStruct
}

extension Bool : PythonConvertible {
extension Bool : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard isType(pythonObject, type: PyBool_Type) else { return nil }

Expand All @@ -763,7 +769,7 @@ extension Bool : PythonConvertible {
}
}

extension String : PythonConvertible {
extension String : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
let pyObject = pythonObject.ownedPyObject
defer { Py_DecRef(pyObject) }
Expand Down Expand Up @@ -808,7 +814,7 @@ fileprivate extension PythonObject {
}
}

extension Int : PythonConvertible {
extension Int : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
// `PyInt_AsLong` return -1 and sets an error if the Python object is not
// integer compatible.
Expand All @@ -825,7 +831,7 @@ extension Int : PythonConvertible {
}
}

extension UInt : PythonConvertible {
extension UInt : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
// `PyInt_AsUnsignedLongMask` isn't documented as such, but in fact it does
// return -1 and set an error if the Python object is not integer
Expand All @@ -843,7 +849,7 @@ extension UInt : PythonConvertible {
}
}

extension Double : PythonConvertible {
extension Double : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
// `PyFloat_AsDouble` return -1 and sets an error if the Python object is
// not float compatible.
Expand All @@ -867,7 +873,7 @@ extension Double : PythonConvertible {
// Any `FixedWidthInteger` type is `PythonConvertible` via the `Int`/`UInt`
// implementation.

extension Int8 : PythonConvertible {
extension Int8 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = Int(pythonObject) else { return nil }
self.init(i)
Expand All @@ -878,7 +884,7 @@ extension Int8 : PythonConvertible {
}
}

extension Int16 : PythonConvertible {
extension Int16 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = Int(pythonObject) else { return nil }
self.init(i)
Expand All @@ -889,7 +895,7 @@ extension Int16 : PythonConvertible {
}
}

extension Int32 : PythonConvertible {
extension Int32 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = Int(pythonObject) else { return nil }
self.init(i)
Expand All @@ -900,7 +906,7 @@ extension Int32 : PythonConvertible {
}
}

extension Int64 : PythonConvertible {
extension Int64 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = Int(pythonObject) else { return nil }
self.init(i)
Expand All @@ -911,7 +917,7 @@ extension Int64 : PythonConvertible {
}
}

extension UInt8 : PythonConvertible {
extension UInt8 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = UInt(pythonObject) else { return nil }
self.init(i)
Expand All @@ -922,7 +928,7 @@ extension UInt8 : PythonConvertible {
}
}

extension UInt16 : PythonConvertible {
extension UInt16 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = UInt(pythonObject) else { return nil }
self.init(i)
Expand All @@ -933,7 +939,7 @@ extension UInt16 : PythonConvertible {
}
}

extension UInt32 : PythonConvertible {
extension UInt32 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = UInt(pythonObject) else { return nil }
self.init(i)
Expand All @@ -944,7 +950,7 @@ extension UInt32 : PythonConvertible {
}
}

extension UInt64 : PythonConvertible {
extension UInt64 : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let i = UInt(pythonObject) else { return nil }
self.init(i)
Expand All @@ -957,7 +963,7 @@ extension UInt64 : PythonConvertible {

// `Float` is `PythonConvertible` via the `Double` implementation.

extension Float : PythonConvertible {
extension Float : PythonConvertible, ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard let v = Double(pythonObject) else { return nil }
self.init(v)
Expand All @@ -973,6 +979,17 @@ extension Float : PythonConvertible {
//===----------------------------------------------------------------------===//

extension Optional : PythonConvertible where Wrapped : PythonConvertible {
public var pythonObject: PythonObject {
return self?.pythonObject ?? Python.None
}
}

//===----------------------------------------------------------------------===//
// `ConvertibleFromPython` conformance for `Optional`
//===----------------------------------------------------------------------===//

extension Optional : ConvertibleFromPython
where Wrapped : ConvertibleFromPython {
public init?(_ object: PythonObject) {
if object == Python.None {
self = .none
Expand All @@ -983,27 +1000,16 @@ extension Optional : PythonConvertible where Wrapped : PythonConvertible {
self = .some(converted)
}
}

public var pythonObject: PythonObject {
return self?.pythonObject ?? Python.None
}
}

//===----------------------------------------------------------------------===//
// `PythonConvertible` conformance for `Array` and `Dictionary`
// `PythonConvertible` and `ConvertibleFromPython conformance for
// `Array` and `Dictionary`
//===----------------------------------------------------------------------===//

// `Array` conditionally conforms to `PythonConvertible` if the `Element`
// associated type does.
extension Array : PythonConvertible where Element : PythonConvertible {
public init?(_ pythonObject: PythonObject) {
self = []
for elementObject in pythonObject {
guard let element = Element(elementObject) else { return nil }
append(element)
}
}

public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
let list = PyList_New(count)!
Expand All @@ -1015,10 +1021,36 @@ extension Array : PythonConvertible where Element : PythonConvertible {
}
}

extension Array : ConvertibleFromPython where Element : ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
self = []
for elementObject in pythonObject {
guard let element = Element(elementObject) else { return nil }
append(element)
}
}
}

// `Dictionary` conditionally conforms to `PythonConvertible` if the `Key` and
// `Value` associated types do.
extension Dictionary : PythonConvertible
where Key : PythonConvertible, Value : PythonConvertible {
public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
let dict = PyDict_New()!
for (key, value) in self {
let k = key.ownedPyObject
let v = value.ownedPyObject
PyDict_SetItem(dict, k, v)
Py_DecRef(k)
Py_DecRef(v)
}
return PythonObject(consuming: dict)
}
}

extension Dictionary : ConvertibleFromPython
where Key : ConvertibleFromPython, Value : ConvertibleFromPython {
public init?(_ pythonDict: PythonObject) {
self = [:]

Expand All @@ -1042,26 +1074,21 @@ extension Dictionary : PythonConvertible
}
}
}

public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
let dict = PyDict_New()!
for (key, value) in self {
let k = key.ownedPyObject
let v = value.ownedPyObject
PyDict_SetItem(dict, k, v)
Py_DecRef(k)
Py_DecRef(v)
}
return PythonObject(consuming: dict)
}
}

//===----------------------------------------------------------------------===//
// `PythonConvertible` conformance for `Range` types
// `PythonConvertible` and `ConvertibleFromPython` conformances
// for `Range` types
//===----------------------------------------------------------------------===//

extension Range : PythonConvertible where Bound : PythonConvertible {
public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
return Python.slice(lowerBound, upperBound, Python.None)
}
}

extension Range : ConvertibleFromPython where Bound : ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard isType(pythonObject, type: PySlice_Type) else { return nil }
guard let lowerBound = Bound(pythonObject.start),
Expand All @@ -1071,14 +1098,17 @@ extension Range : PythonConvertible where Bound : PythonConvertible {
guard pythonObject.step == Python.None else { return nil }
self.init(uncheckedBounds: (lowerBound, upperBound))
}
}

extension PartialRangeFrom : PythonConvertible where Bound : PythonConvertible {
public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
return Python.slice(lowerBound, upperBound, Python.None)
return Python.slice(lowerBound, Python.None, Python.None)
}
}

extension PartialRangeFrom : PythonConvertible where Bound : PythonConvertible {
extension PartialRangeFrom : ConvertibleFromPython
where Bound : ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard isType(pythonObject, type: PySlice_Type) else { return nil }
guard let lowerBound = Bound(pythonObject.start) else { return nil }
Expand All @@ -1088,14 +1118,17 @@ extension PartialRangeFrom : PythonConvertible where Bound : PythonConvertible {
}
self.init(lowerBound)
}
}

extension PartialRangeUpTo : PythonConvertible where Bound : PythonConvertible {
public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
return Python.slice(lowerBound, Python.None, Python.None)
return Python.slice(Python.None, upperBound, Python.None)
}
}

extension PartialRangeUpTo : PythonConvertible where Bound : PythonConvertible {
extension PartialRangeUpTo : ConvertibleFromPython
where Bound : ConvertibleFromPython {
public init?(_ pythonObject: PythonObject) {
guard isType(pythonObject, type: PySlice_Type) else { return nil }
guard let upperBound = Bound(pythonObject.stop) else { return nil }
Expand All @@ -1105,11 +1138,6 @@ extension PartialRangeUpTo : PythonConvertible where Bound : PythonConvertible {
}
self.init(upperBound)
}

public var pythonObject: PythonObject {
_ = Python // Ensure Python is initialized.
return Python.slice(Python.None, upperBound, Python.None)
}
}

//===----------------------------------------------------------------------===//
Expand Down
4 changes: 2 additions & 2 deletions stdlib/public/TensorFlow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ set(SOURCES
Utilities.swift
Threading.swift
# NumPy bridging for `ShapedArray` and `Tensor`.
NumpyConversion.swift)
PythonConversion.swift)

# Copy TensorFlow bindings file, if it exists.
if (TENSORFLOW_SWIFT_BINDINGS)
Expand All @@ -65,7 +65,7 @@ if (TENSORFLOW_SWIFT_APIS)
list(APPEND SOURCES "${TENSORFLOW_SWIFT_API_SOURCES}")
endif()

# When Python exists, NumpyConversion.swift imports it, so it must be
# When Python exists, PythonConversion.swift imports it, so it must be
# available at link time.
set(TENSORFLOW_DEPENDS_PYTHON)
if (SWIFT_PYTHON_EXISTS)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- NumpyConversion.swift ---------------------------------*- swift -*-===//
//===-- PythonConversion.swift --------------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
Expand All @@ -10,8 +10,7 @@
//
//===----------------------------------------------------------------------===//
//
// This file defines conversion initializers from `numpy.ndarray` to
// `ShapedArray` and `Tensor`.
// This file defines conversions between Python types & custom TensorFlow types.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -164,4 +163,10 @@ extension Tensor where Scalar : NumpyScalarCompatible {
public func makeNumpyArray() -> PythonObject { return array.makeNumpyArray() }
}

extension TensorShape : PythonConvertible {
public var pythonObject: PythonObject {
return dimensions.pythonObject
}
}

#endif // canImport(Python)

0 comments on commit 3c27938

Please sign in to comment.