Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.12" # Vim on Ubuntu supports only 3.12
python-version: "3.14" # Vim on Ubuntu supports only 3.14

- name: Set up tools
run: |
Expand Down Expand Up @@ -66,4 +66,5 @@ jobs:
-c "call assert_equal('${{ matrix.tool }}', virtualenv#state('virtualenv_type'))" \
-c "call assert_equal(${MATRIX_KIND_CODE}, virtualenv#state('virtualenv_internal'))" \
-c "call assert_equal('${VIM_VIRTUALENV_TARGET}', virtualenv#state('virtualenv_directory'))" \
-c "call assert_equal('${VIM_VIRTUALENV_TARGET}', py3eval('sys.prefix'))" \
-c "call g:ExitTest()"
73 changes: 73 additions & 0 deletions .github/workflows/dyn-stable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Test dynamic stable ABI virtual environment activation

on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]

jobs:
test:
runs-on: ubuntu-latest
container: fedora:45
timeout-minutes: 10

defaults:
run:
shell: bash

strategy:
fail-fast: false
matrix:
tool: [ "venv", "virtualenv" ]
kind: [ "internal", "external" ]
system-python: [ "3.14", "3.12" ]
venv-python: [ "3.14", "3.12" ]

steps:
- name: Set up tools
run: |
dnf install -y git python3.12 python3.14 python3-virtualenv

- name: Checkout repository
uses: actions/checkout@v7

- name: Set up Python
run: |
export VIM_VIRTUALENV_PYTHON_BIN="${RUNNER_TEMP}/python-bin"
mkdir -p "${VIM_VIRTUALENV_PYTHON_BIN}"
ln -s "$(command -v python${{ matrix.system-python }})" "${VIM_VIRTUALENV_PYTHON_BIN}/python"
ln -s "$(command -v python${{ matrix.system-python }})" "${VIM_VIRTUALENV_PYTHON_BIN}/python3"
echo "${VIM_VIRTUALENV_PYTHON_BIN}" >> "${GITHUB_PATH}"

- name: Set up editor
run: |
dnf install -y vim-enhanced
vim --version | grep -F '+python3/dyn-stable'

- name: Create virtual environment
run: |
export VIM_VIRTUALENV_TARGET="$(mktemp --directory)"
if [[ "${{ matrix.tool }}" == "venv" ]]; then
python${{ matrix.venv-python }} -m venv --without-pip "${VIM_VIRTUALENV_TARGET}"
else
/usr/bin/python -m virtualenv --no-seed --python ${{ matrix.venv-python }} "${VIM_VIRTUALENV_TARGET}"
fi
echo "VIM_VIRTUALENV_TARGET=${VIM_VIRTUALENV_TARGET}" >> "${GITHUB_ENV}"

- name: Activate virtual environment
run: |
python --version
if [[ "${{ matrix.kind }}" == "internal" ]];
then cd "${VIM_VIRTUALENV_TARGET}"
else source "${VIM_VIRTUALENV_TARGET}/bin/activate"
fi
MATRIX_KIND_CODE=$([[ "${{ matrix.kind }}" == "internal" ]] && echo 1 || echo 0)
vim --not-a-term --clean -u "${GITHUB_WORKSPACE}/.github/workflows/minimal.vim" \
-c "call assert_equal('${{ matrix.tool }}', virtualenv#state('virtualenv_type'))" \
-c "call assert_equal(${MATRIX_KIND_CODE}, virtualenv#state('virtualenv_internal'))" \
-c "call assert_equal('${VIM_VIRTUALENV_TARGET}', virtualenv#state('virtualenv_directory'))" \
-c "call assert_equal('${VIM_VIRTUALENV_TARGET}', py3eval('sys.prefix'))" \
-c "call assert_equal('${{ matrix.venv-python }}', virtualenv#state('virtualenv_python'))" \
-c "call assert_equal('${{ matrix.venv-python }}', join(py3eval('sys.version_info[:2]'), '.'))" \
-c "call g:ExitTest()"
58 changes: 38 additions & 20 deletions autoload/virtualenv.vim
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
function! virtualenv#init()
let s:state = {}

if has('python3_stable')
let s:vim_major = and(v:python3_version >> 24, 0xff)
let s:vim_minor = and(v:python3_version >> 16, 0xff)
else
let s:vim_major = py3eval('sys.version_info.major')
let s:vim_minor = py3eval('sys.version_info.minor')
endif

let s:custom_project_finder = 'virtualenv#gutentags_project_root_finder'

try
execute 'py3file' fnameescape(g:virtualenv#python_script)
catch
return s:error('failed to load Python virtual environment manager')
endtry

if !empty(g:virtualenv#directory)
let g:virtualenv#directory =
\ s:normalize_path(fnamemodify(g:virtualenv#directory, ':p'))
Expand Down Expand Up @@ -125,10 +111,16 @@ function! virtualenv#force_activate(target, ...)
let [l:major, l:minor] = l:pyversion
call s:error('Python version mismatch')
call s:error('Environment version: '.l:major.'.'.l:minor)
call s:error('Vim version: '.s:vim_major.'.'.s:vim_minor)
call s:error('Vim version: '.s:python.major.'.'.s:python.minor)
return s:error(l:target.' is not supported')
endif

if exists('+pythonthreedll')
let [&pythonthreedll] = s:execute_system_python_command(
\ 'import sysconfig; print(sysconfig.get_config_var("INSTSONAME"))',
\ l:target)
endif

let s:state['virtualenv_type'] = l:env_type
let s:state['virtualenv_internal'] = l:internal
let s:state['virtualenv_python'] = join(l:pyversion, '.')
Expand Down Expand Up @@ -282,7 +274,8 @@ function! s:get_env_type(target)
return filereadable(s:join_path(a:target, 'uv.lock')) ? 'uv' : '.venv'
elseif filereadable(s:join_path(a:target, 'venv/.tox-info.json'))
return '.tox'
elseif filereadable(s:join_path(a:target, '.python-version')) && exists('$PYENV_ROOT')
elseif filereadable(s:join_path(a:target, '.python-version')) &&
\ exists('$PYENV_ROOT')
return 'pyenv'
elseif filereadable(s:join_path(a:target, 'bin/activate_this.py'))
return filereadable(s:join_path(a:target, 'bin/get_env_details'))
Expand Down Expand Up @@ -325,11 +318,25 @@ function! s:get_pyversion_external(...)
endfunction

function! s:is_python_supported(pyversion)
if !exists('s:python')
if has('python3_stable')
let s:python = {
\ 'major': and(v:python3_version >> 24, 0xff),
\ 'minor': and(v:python3_version >> 16, 0xff),
\ }
else
let s:python = {
\ 'major': py3eval('sys.version_info.major'),
\ 'minor': py3eval('sys.version_info.minor'),
\ }
endif
endif

let [l:major, l:minor] = a:pyversion
if has('python3_stable')
return (l:major >= s:vim_major) && (l:minor >= s:vim_minor)
return (l:major >= s:python.major) && (l:minor >= s:python.minor)
else
return (l:major == s:vim_major) && (l:minor == s:vim_minor)
return (l:major == s:python.major) && (l:minor == s:python.minor)
endif
endfunction

Expand Down Expand Up @@ -394,11 +401,22 @@ function! s:normalize_path(path)
endfunction

" python machinery
function! s:execute_system_python_command(command)
return systemlist("python -B -c 'import sys; ".a:command."'")
function! s:execute_system_python_command(command, root=v:null)
let l:prefix = a:root is v:null ? '' : s:join_path(a:root, 'bin/')
return systemlist(l:prefix."python -B -c 'import sys; ".a:command."'")
endfunction

function! s:execute_python_command(command, ...)
if !exists('s:python_loaded')
try
execute 'py3file' fnameescape(g:virtualenv#python_script)
catch
throw 'failed to load Python virtual environment manager: '.
\ v:exception
endtry
let s:python_loaded = 1
endif

let l:command = a:command.((a:0) ? s:build_arguments(a:000) : '')
return split(execute('python3 '.l:command), '\n')
endfunction
Expand Down
2 changes: 1 addition & 1 deletion plugin/virtualenv.vim
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ if exists('g:loaded_virtualenv')
finish
endif

if !has('python3')
if !has('python3_compiled') && !has('python3')
echoerr 'vim-virtualenv requires python3 feature to be enabled'
finish
endif
Expand Down
Loading