Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
90db661b
Commit
90db661b
authored
Jul 17, 2012
by
Vinay Sajip
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Closes #15307: symlinks now work on OS X with framework Python builds. Patch by Ronald Oussoren.
parent
11718620
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
115 additions
and
27 deletions
+115
-27
Doc/library/venv.rst
Doc/library/venv.rst
+1
-1
Lib/test/test_venv.py
Lib/test/test_venv.py
+41
-11
Lib/venv/__init__.py
Lib/venv/__init__.py
+1
-9
Mac/Tools/pythonw.c
Mac/Tools/pythonw.c
+38
-2
Modules/getpath.c
Modules/getpath.c
+12
-4
Modules/main.c
Modules/main.c
+22
-0
No files found.
Doc/library/venv.rst
View file @
90db661b
...
...
@@ -81,7 +81,7 @@ creation according to their needs, the :class:`EnvBuilder` class.
* ``symlinks`` -- a Boolean value indicating whether to attempt to symlink the
Python binary (and any necessary DLLs or other binaries,
e.g. ``pythonw.exe``), rather than copying. Defaults to ``True`` on Linux and
Unix systems, but ``False`` on Windows
and Mac OS X
.
Unix systems, but ``False`` on Windows.
* ``upgrade`` -- a Boolean value which, if True, will upgrade an existing
environment with the running Python - for use when that Python has been
...
...
Lib/test/test_venv.py
View file @
90db661b
...
...
@@ -154,17 +154,47 @@ class BasicTest(BaseTest):
"""
for
usl
in
(
False
,
True
):
builder
=
venv
.
EnvBuilder
(
clear
=
True
,
symlinks
=
usl
)
if
(
usl
and
sys
.
platform
==
'darwin'
and
'__PYVENV_LAUNCHER__'
in
os
.
environ
):
self
.
assertRaises
(
ValueError
,
builder
.
create
,
self
.
env_dir
)
else
:
builder
.
create
(
self
.
env_dir
)
fn
=
self
.
get_env_file
(
self
.
bindir
,
self
.
exe
)
# Don't test when False, because e.g. 'python' is always
# symlinked to 'python3.3' in the env, even when symlinking in
# general isn't wanted.
if
usl
:
self
.
assertTrue
(
os
.
path
.
islink
(
fn
))
builder
.
create
(
self
.
env_dir
)
fn
=
self
.
get_env_file
(
self
.
bindir
,
self
.
exe
)
# Don't test when False, because e.g. 'python' is always
# symlinked to 'python3.3' in the env, even when symlinking in
# general isn't wanted.
if
usl
:
self
.
assertTrue
(
os
.
path
.
islink
(
fn
))
# If a venv is created from a source build and that venv is used to
# run the test, the pyvenv.cfg in the venv created in the test will
# point to the venv being used to run the test, and we lose the link
# to the source build - so Python can't initialise properly.
@
unittest
.
skipIf
(
sys
.
prefix
!=
sys
.
base_prefix
,
'Test not appropriate '
'in a venv'
)
def
test_executable
(
self
):
"""
Test that the sys.executable value is as expected.
"""
shutil
.
rmtree
(
self
.
env_dir
)
self
.
run_with_capture
(
venv
.
create
,
self
.
env_dir
)
envpy
=
os
.
path
.
join
(
os
.
path
.
realpath
(
self
.
env_dir
),
self
.
bindir
,
self
.
exe
)
cmd
=
[
envpy
,
'-c'
,
'import sys; print(sys.executable)'
]
p
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
out
,
err
=
p
.
communicate
()
self
.
assertEqual
(
out
[:
-
1
],
envpy
.
encode
())
@
unittest
.
skipUnless
(
can_symlink
(),
'Needs symlinks'
)
def
test_executable_symlinks
(
self
):
"""
Test that the sys.executable value is as expected.
"""
shutil
.
rmtree
(
self
.
env_dir
)
builder
=
venv
.
EnvBuilder
(
clear
=
True
,
symlinks
=
True
)
builder
.
create
(
self
.
env_dir
)
envpy
=
os
.
path
.
join
(
os
.
path
.
realpath
(
self
.
env_dir
),
self
.
bindir
,
self
.
exe
)
cmd
=
[
envpy
,
'-c'
,
'import sys; print(sys.executable)'
]
p
=
subprocess
.
Popen
(
cmd
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
out
,
err
=
p
.
communicate
()
self
.
assertEqual
(
out
[:
-
1
],
envpy
.
encode
())
def
test_main
():
run_unittest
(
BasicTest
)
...
...
Lib/venv/__init__.py
View file @
90db661b
...
...
@@ -82,13 +82,6 @@ class EnvBuilder:
:param env_dir: The target directory to create an environment in.
"""
if
(
self
.
symlinks
and
sys
.
platform
==
'darwin'
and
sysconfig
.
get_config_var
(
'PYTHONFRAMEWORK'
)):
# Symlinking the stub executable in an OSX framework build will
# result in a broken virtual environment.
raise
ValueError
(
'Symlinking is not supported on OSX framework Python.'
)
env_dir
=
os
.
path
.
abspath
(
env_dir
)
context
=
self
.
ensure_directories
(
env_dir
)
self
.
create_configuration
(
context
)
...
...
@@ -366,8 +359,7 @@ def main(args=None):
action
=
'store_true'
,
dest
=
'system_site'
,
help
=
'Give the virtual environment access to the '
'system site-packages dir.'
)
if
os
.
name
==
'nt'
or
(
sys
.
platform
==
'darwin'
and
sysconfig
.
get_config_var
(
'PYTHONFRAMEWORK'
)):
if
os
.
name
==
'nt'
:
use_symlinks
=
False
else
:
use_symlinks
=
True
...
...
Mac/Tools/pythonw.c
View file @
90db661b
...
...
@@ -28,6 +28,7 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <Python.h>
#include <mach-o/dyld.h>
extern
char
**
environ
;
...
...
@@ -158,9 +159,44 @@ main(int argc, char **argv) {
/* Set the original executable path in the environment. */
status
=
_NSGetExecutablePath
(
path
,
&
size
);
if
(
status
==
0
)
{
if
(
realpath
(
path
,
real_path
)
!=
NULL
)
{
setenv
(
"__PYVENV_LAUNCHER__"
,
real_path
,
1
);
/*
* Note: don't call 'realpath', that will
* erase symlink information, and that
* breaks "pyvenv --symlink"
*
* It is nice to have the directory name
* as a cleaned up absolute path though,
* therefore call realpath on dirname(path)
*/
char
*
slash
=
strrchr
(
path
,
'/'
);
if
(
slash
)
{
char
replaced
;
replaced
=
slash
[
1
];
slash
[
1
]
=
0
;
if
(
realpath
(
path
,
real_path
)
==
NULL
)
{
err
(
1
,
"realpath: %s"
,
path
);
}
slash
[
1
]
=
replaced
;
if
(
strlcat
(
real_path
,
slash
,
sizeof
(
real_path
))
>
sizeof
(
real_path
))
{
errno
=
EINVAL
;
err
(
1
,
"realpath: %s"
,
path
);
}
}
else
{
if
(
realpath
(
"."
,
real_path
)
==
NULL
)
{
err
(
1
,
"realpath: %s"
,
path
);
}
if
(
strlcat
(
real_path
,
"/"
,
sizeof
(
real_path
))
>
sizeof
(
real_path
))
{
errno
=
EINVAL
;
err
(
1
,
"realpath: %s"
,
path
);
}
if
(
strlcat
(
real_path
,
path
,
sizeof
(
real_path
))
>
sizeof
(
real_path
))
{
errno
=
EINVAL
;
err
(
1
,
"realpath: %s"
,
path
);
}
}
setenv
(
"__PYVENV_LAUNCHER__"
,
real_path
,
1
);
}
/*
...
...
Modules/getpath.c
View file @
90db661b
...
...
@@ -474,6 +474,7 @@ calculate_path(void)
wchar_t
*
defpath
;
#ifdef WITH_NEXT_FRAMEWORK
NSModule
pythonModule
;
const
char
*
modPath
;
#endif
#ifdef __APPLE__
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
...
...
@@ -568,8 +569,8 @@ calculate_path(void)
*/
pythonModule
=
NSModuleForSymbol
(
NSLookupAndBindSymbol
(
"_Py_Initialize"
));
/* Use dylib functions to find out where the framework was loaded from */
buf
=
(
wchar_t
*
)
NSLibraryNameForModule
(
pythonModule
);
if
(
buf
!=
NULL
)
{
modPath
=
NSLibraryNameForModule
(
pythonModule
);
if
(
modPath
!=
NULL
)
{
/* We're in a framework. */
/* See if we might be in the build directory. The framework in the
** build directory is incomplete, it only has the .dylib and a few
...
...
@@ -578,7 +579,12 @@ calculate_path(void)
** be running the interpreter in the build directory, so we use the
** build-directory-specific logic to find Lib and such.
*/
wcsncpy
(
argv0_path
,
buf
,
MAXPATHLEN
);
wchar_t
*
wbuf
=
_Py_char2wchar
(
modPath
,
NULL
);
if
(
wbuf
==
NULL
)
{
Py_FatalError
(
"Cannot decode framework location"
);
}
wcsncpy
(
argv0_path
,
wbuf
,
MAXPATHLEN
);
reduce
(
argv0_path
);
joinpath
(
argv0_path
,
lib_python
);
joinpath
(
argv0_path
,
LANDMARK
);
...
...
@@ -589,8 +595,9 @@ calculate_path(void)
}
else
{
/* Use the location of the library as the progpath */
wcsncpy
(
argv0_path
,
buf
,
MAXPATHLEN
);
wcsncpy
(
argv0_path
,
w
buf
,
MAXPATHLEN
);
}
PyMem_Free
(
wbuf
);
}
#endif
...
...
@@ -629,6 +636,7 @@ calculate_path(void)
FILE
*
env_file
=
NULL
;
wcscpy
(
tmpbuffer
,
argv0_path
);
joinpath
(
tmpbuffer
,
env_cfg
);
env_file
=
_Py_wfopen
(
tmpbuffer
,
L"r"
);
if
(
env_file
==
NULL
)
{
...
...
Modules/main.c
View file @
90db661b
...
...
@@ -616,7 +616,29 @@ Py_Main(int argc, wchar_t **argv)
Py_SetProgramName
(
buffer
);
/* buffer is now handed off - do not free */
}
else
{
#ifdef WITH_NEXT_FRAMEWORK
char
*
pyvenv_launcher
=
getenv
(
"__PYVENV_LAUNCHER__"
);
if
(
pyvenv_launcher
&&
*
pyvenv_launcher
)
{
/* Used by Mac/Tools/pythonw.c to forward
* the argv0 of the stub executable
*/
wchar_t
*
wbuf
=
_Py_char2wchar
(
pyvenv_launcher
,
NULL
);
if
(
wbuf
==
NULL
)
{
Py_FatalError
(
"Cannot decode __PYVENV_LAUNCHER__"
);
}
Py_SetProgramName
(
wbuf
);
/* Don't free wbuf, the argument to Py_SetProgramName
* must remain valid until the Py_Finalize is called.
*/
}
else
{
Py_SetProgramName
(
argv
[
0
]);
}
#else
Py_SetProgramName
(
argv
[
0
]);
#endif
}
#else
Py_SetProgramName
(
argv
[
0
]);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment