NSTask没有使用正确的路径启动Python

时间:2012-12-25 00:07:10

标签: python xcode cocoa frameworks

在我的Mac OS应用程序中,我包含了一个Python.framework(v 2.7),因此我将其添加到“链接框架”中。同样在应用程序中,我正在使用NSTask启动Python脚本,如:

//...
pythonEnv = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:@"Python.framework/Versions/2.7/bin/python"];
task = [[NSTask alloc] init];
outPipe = [NSPipe pipe];
readHandle = [outPipe fileHandleForReading];
data = [[NSMutableData alloc] init];

args = [NSArray arrayWithObjects: scriptPath, kbt, server, port, username, password, nil];

[task setArguments:args];
[task setLaunchPath: pythonEnv];

readHandle = [outPipe fileHandleForReading];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput:outPipe];
[task launch];
[task waitUntilExit];
//...

当我构建应用程序时,在Python脚本中检查它与sys.path一起使用的版本,它会返回:

[“/ Users / ...脚本路径... / Contents / Resources”,“/ Library / Frameworks / Python.framework / Version / 2.7 / lib / python27.zip”,“/ Library / Frameworks / Python.framework / Versions / 2.7 / lib / python2.7“,”/ Library / Frame /Python.framework / Version / 7.7 / lib / python2.7 / plat-Darwin“,”/ Library / Frame /Python.framework /版本/ 2.7 / lib / python2.7 / plat-mac“,”/ Library / Frame /Python.framework / Version / 7.7 / lib / python2.7 /plat-make / lib -scriptpackages“,”/ Library / Frameworks / Python.framework / Versions / 2.7 / lib / python2.7 / lib-tk“,”/ Library / Frameworks / Python.framework / Version / 7.7 / lib / python2.7 / lib -old“,”/ Library / Frameworks / Python.framework / Versions / 2.7 / lib / python2.7 / lib-dynload“,”/ Users / tatiana / Library /Python / 2.7 / lib / python / site-packages“,”/ Library / Frame /Python.framework /版本/ 2.7 / lib / python2.7 / site-packages“,”/ Library /Python / 2.7 / site-package“]

...它没有使用我所包含的框架。我还应该在哪里设置正确的路径?它是构建设置中的东西我忘记了吗?

更新1 ------------------------

如果我没有设置任务环境,并且在使用sys.executable的Python测试中,我得到:

/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python

...所以看起来它没有使用我的框架。如果设置任务环境:

// pythonEnv = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:@"Python.framework/Versions/2.7/bin/python"];
NSDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys: pythonEnv, @"PYTHONPATH", nil];
[task setEnvironment:environment];

并测试它,我仍然得到相同的结果。但是,如果在Python中我使用os.environ["PYTHONPATH"]进行测试,我得到:

/Users/tatiana/Desktop/MyApp.app/Contents/Frameworks/Python.framework/Versions/2.7/bin/python

这看起来有点让人失望,但我很困惑为什么sys.executable没有给我这个。

更新2

我的 bin / python 不是可执行文件,因此我将其更改为python2.7; sys.executable仍然显示默认为Library /...

pythonEnv = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:@"Python.framework/Versions/2.7/bin/python2.7"];
NSString *searchPath = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:@"Python.framework/Versions/2.7/lib/python2.7"];
NSDictionary *environment = [NSDictionary dictionaryWithObjectsAndKeys: searchPath, @"PYTHONPATH", nil];
[task setEnvironment:environment];

2 个答案:

答案 0 :(得分:0)

听起来你混淆了两件相关的事情:

  1. 启动应用程序包内的Python可执行文件
  2. 设置Python搜索路径以包含应用程序包内的Python lib文件夹
  3. 要设置NSTask运行的Python可执行文件的路径,请设置其launchPath。在Python中,您可以使用sys.executable访问该值。

    要操纵Python的搜索路径,请调用-[NSTask setEnvironment:]并将PYTHONPATH设置为您框架的lib/python2.7文件夹。在Python中,您可以使用sys.path访问该路径。

答案 1 :(得分:0)

这可能是一个已知的错误。请参阅此old mailing list post和此much more recent bug on bugs.python.org

在Python 2.7.3的Modules / getpath.c中有这样的评论:

 /* On Mac OS X, if a script uses an interpreter of the form
  * "#!/opt/python2.3/bin/python", the kernel only passes "python"
  * as argv[0], which falls through to the $PATH search below.
  * If /opt/python2.3/bin isn't in your path, or is near the end,
  * this algorithm may incorrectly find /usr/bin/python. To work
  * around this, we can use _NSGetExecutablePath to get a better
  * hint of what the intended interpreter was, although this
  * will fail if a relative path was used. but in that case,
  * absolutize() should help us out below
  */

虽然这可能不适用于您,但这是一个提示,执行的python进程中argv[0]可能只是"python"。然后,如果注释中提到的$PATH hack失败或您的版本中没有,则Python将查看_NSGetExecutablePath并尝试查找Python解释器的绝对路径。您的框架(不在$PATH中)将被忽略,因此它会找到系统Python并使用它。

您可以通过几种方式验证这一点。您可以在调试器中设置断点,并查看NSTask最终传递给exec()的参数。或者,您可以查看ps ax并找到您的Python进程(可能有助于让您的脚本打印其PID然后永远运行)并查看第一个参数是否是框架的完整路径。或者,您可以在脚本中查看sys.argv[0](可能 - 可能已修改)。

如果这确实是问题,那么解决方法是获得正确的argv[0]设置。我没有看到使用NSTask的方法,所以你最好的选择可能是在bin/环境变量中包含Python框架PATH的路径。至少Python可以推断出sys.executable的正确值。

或者,如果您的脚本中没有任何内容真正关心sys.executable,那么在确定您的Python实际上是正在执行的Python之后,您可以保留原样,发送sys.executable