@@ -204,6 +204,15 @@ public extension PythonObject {
204204 var throwing : ThrowingPythonObject {
205205 return ThrowingPythonObject ( self )
206206 }
207+
208+ /// Returns a dynamic-callable wrapper that surfaces Python exceptions as
209+ /// Swift errors instead of trapping.
210+ ///
211+ /// This keeps the existing `PythonObject` call behavior unchanged while
212+ /// offering an opt-in path to handle errors via `try`/`catch`.
213+ var throwingCallable : ThrowingDynamicCallable {
214+ return ThrowingDynamicCallable ( self )
215+ }
207216}
208217
209218/// An error produced by a failable Python operation.
@@ -415,6 +424,45 @@ public struct ThrowingPythonObject {
415424 }
416425}
417426
427+ /// A dynamic-callable wrapper around `PythonObject` that throws instead of
428+ /// trapping when a Python exception is raised.
429+ @dynamicCallable
430+ public struct ThrowingDynamicCallable {
431+ private var base : PythonObject
432+
433+ fileprivate init ( _ base: PythonObject ) {
434+ self . base = base
435+ }
436+
437+ /// Call `base` with the specified positional arguments.
438+ /// - Precondition: `base` must be a Python callable.
439+ /// - Parameter args: Positional arguments for the Python callable.
440+ @discardableResult
441+ public func dynamicallyCall(
442+ withArguments args: [ PythonConvertible ] = [ ] ) throws -> PythonObject {
443+ return try base. throwing. dynamicallyCall ( withArguments: args)
444+ }
445+
446+ /// Call `base` with the specified arguments.
447+ /// - Precondition: `base` must be a Python callable.
448+ /// - Parameter args: Positional or keyword arguments for the Python callable.
449+ @discardableResult
450+ public func dynamicallyCall(
451+ withKeywordArguments args:
452+ KeyValuePairs < String , PythonConvertible > = [ : ] ) throws -> PythonObject {
453+ return try base. throwing. dynamicallyCall ( withKeywordArguments: args)
454+ }
455+
456+ /// Alias for the function above that lets the caller dynamically construct the argument list without using a dictionary literal.
457+ /// This must be called explicitly because `@dynamicCallable` does not recognize it on `PythonObject`.
458+ @discardableResult
459+ public func dynamicallyCall(
460+ withKeywordArguments args:
461+ [ ( key: String , value: PythonConvertible ) ] = [ ] ) throws -> PythonObject {
462+ return try base. throwing. dynamicallyCall ( withKeywordArguments: args)
463+ }
464+ }
465+
418466
419467//===----------------------------------------------------------------------===//
420468// `PythonObject` member access implementation
0 commit comments