-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathNSString+PythonPickles.m
108 lines (92 loc) · 3.13 KB
/
NSString+PythonPickles.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#import "NSString+PythonPickles.h"
#include <Python/Python.h>
NSString* const SSYPythonPicklesErrorDomain = @"SSYPythonPicklesErrorDomain" ;
NSString* const SSYPythonPicklesUnderErrorDomain = @"SSYPythonPicklesUnderErrorDomain" ;
@implementation NSString (PythonPickles)
- (NSString*)pythonUnpickledError_p:(NSError**)error_p {
NSString* answer = nil ;
NSString* errorDesc = NULL ;
NSInteger errorCode = 0 ;
Py_Initialize() ;
// Create Python Namespace (dictionary of variables)
PyObject* pythonStringArg = PyString_FromString([self UTF8String]) ;
if (!pythonStringArg) {
errorDesc = @"Cannot convert string arg to Python\n" ;
errorCode = 523001 ;
goto end ;
}
PyObject* pythonVarsDic = PyDict_New();
PyDict_SetItemString(
pythonVarsDic,
"__builtins__",
PyEval_GetBuiltins());
PyDict_SetItemString(
pythonVarsDic,
"x",
pythonStringArg) ;
// Create "hard" source code string to unpickle
// (For some strange reason, they call it loads()
// The "s" in "loads" stands for "string".)
char* pythonSource =
"from pickle import loads\n\n"
"y = loads(x)\n" ;
// Run the python source code
PyRun_String(pythonSource,
Py_file_input,
pythonVarsDic,
pythonVarsDic) ;
PyObject* unpickledPythonString = PyDict_GetItemString(pythonVarsDic, "y") ;
// unpickledPythonString is a borrowed ref, so don't DECREF it.
if (!unpickledPythonString) {
errorDesc = @"Unpickling returned NULL\n" ;
errorCode = 523002 ;
goto end ;
}
// Convert the unpickled Python string to a C string
char* unpickledString = PyString_AsString(unpickledPythonString) ;
if (!unpickledString) {
errorDesc = @"Failed converting unpickled string to C string\n" ;
errorCode = 523003 ;
goto end ;
}
// Convert the C string into a string object
answer = [NSString stringWithUTF8String:unpickledString] ;
end:
if (error_p && (errorCode != 0)) {
NSError* pythonErrorString = nil ;
if (PyErr_Occurred()) {
PyObject* errtype ;
PyObject* errvalue ;
PyObject* traceback ;
PyErr_Fetch(&errtype, &errvalue, &traceback) ;
if(errvalue != NULL) {
PyObject *pythonPythonErrorString = PyObject_Str(errvalue) ;
char* cPythonErrorString = PyString_AsString(pythonPythonErrorString) ;
if (cPythonErrorString) {
pythonErrorString = [NSString stringWithUTF8String:cPythonErrorString] ;
}
else {
NSLog(@"Failed converting python error string to C") ;
}
Py_DECREF(pythonPythonErrorString) ;
}
Py_XDECREF(errvalue) ;
Py_XDECREF(errtype) ;
Py_XDECREF(traceback) ;
}
NSError* underlyingError = [NSError errorWithDomain:SSYPythonPicklesUnderErrorDomain
code:523000
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
pythonErrorString, NSLocalizedDescriptionKey,
nil]] ;
*error_p = [NSError errorWithDomain:SSYPythonPicklesErrorDomain
code:errorCode
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
errorDesc, NSLocalizedDescriptionKey,
underlyingError, NSUnderlyingErrorKey,
nil]] ;
}
Py_Finalize() ;
return answer ;
}
@end