diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 9a13d8b0..84607ec8 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,6 +1,6 @@ [bumpversion] commit = True -current_version = 0.11.0 +current_version = 0.14.0 files = plugin/pymode.vim tag = True tag_name = {new_version} @@ -8,3 +8,7 @@ tag_name = {new_version} [bumpversion:file:doc/pymode.txt] search = Version: {current_version} replace = Version: {new_version} + +[bumpversion:file:CHANGELOG.md] +search = Version: {current_version} +replace = Version: {new_version} diff --git a/.github/workflows/build_base_image.yml b/.github/workflows/build_base_image.yml new file mode 100644 index 00000000..45eca00d --- /dev/null +++ b/.github/workflows/build_base_image.yml @@ -0,0 +1,76 @@ +name: Build and Push Base Docker Image + +on: + push: + branches: [main, master, develop] + paths: + - 'Dockerfile.base' + - '.github/workflows/build_base_image.yml' + pull_request: + branches: [main, master, develop] + paths: + - 'Dockerfile.base' + - '.github/workflows/build_base_image.yml' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-and-push-base: + runs-on: ubuntu-latest + strategy: + matrix: + pyver: ["3.10.13", "3.11.9", "3.12.4", "3.13.0"] + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract repo name + id: repo + run: | + echo "REPO=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT + + - name: Extract short Python version + id: pyver_short + run: | + echo "PYVER_SHORT=$(echo ${{ matrix.pyver }} | cut -d'.' -f1,2)" >> $GITHUB_OUTPUT + + - name: Build and push base image (on push) + if: github.event_name != 'pull_request' + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.base + push: true + build-args: | + PYTHON_VERSION=${{ matrix.pyver }} + tags: | + ghcr.io/${{ steps.repo.outputs.REPO }}-base:${{ steps.pyver_short.outputs.PYVER_SHORT }}-latest + + - name: Build base image (on PR) + if: github.event_name == 'pull_request' + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.base + push: false + build-args: | + PYTHON_VERSION=${{ matrix.pyver }} + tags: | + ghcr.io/${{ steps.repo.outputs.REPO }}-base:${{ steps.pyver_short.outputs.PYVER_SHORT }}-pr-test \ No newline at end of file diff --git a/.github/workflows/test_pymode.yml b/.github/workflows/test_pymode.yml index 7b6bab70..ea36b04c 100644 --- a/.github/workflows/test_pymode.yml +++ b/.github/workflows/test_pymode.yml @@ -1,36 +1,57 @@ name: Testing python-mode -on: [push] +on: + push: + branches: [main, master, develop] + pull_request: + branches: [main, master, develop] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - test-python-3_6: + test-python-versions: runs-on: ubuntu-latest + strategy: + matrix: + python_version: + - short: "3.10" + full: "3.10.13" + - short: "3.11" + full: "3.11.9" + - short: "3.12" + full: "3.12.4" + - short: "3.13" + full: "3.13.0" + fail-fast: false + name: Test Python ${{ matrix.python_version.short }} (${{ matrix.python_version.full }}) steps: - - uses: actions/checkout@v1 - - name: Install dependencies - run: | - sudo apt update - sudo apt install -yqq libncurses5-dev libatk1.0-dev python-dev python3-dev lua5.1 lua5.1-dev libperl-dev git - sudo apt remove --purge vim vim-runtime gvim - - name: build and install vim from source - working-directory: /tmp - run: | - git clone https://github.com/vim/vim.git - cd vim - ./configure --with-features=huge --enable-multibyte --enable-python3interp=yes --with-python3-config-dir=/usr/lib/python3.6/config-3.6m-x86_64-linux-gnu --enable-perlinterp=yes --enable-luainterp=yes --enable-cscope --prefix=/usr/local - sudo make && sudo make install - - name: Install python-mode - run: | - export PYMODE_DIR="${HOME}/work/python-mode/python-mode" - mkdir -p ${HOME}/.vim/pack/foo/start/ - ln -s ${PYMODE_DIR} ${HOME}/.vim/pack/foo/start/python-mode - cp ${PYMODE_DIR}/tests/utils/pymoderc ${HOME}/.pymoderc - cp ${PYMODE_DIR}/tests/utils/vimrc ${HOME}/.vimrc - touch ${HOME}/.vimrc.before ${HOME}/.vimrc.after - - name: Run python-mode test script - run: | - alias python=python3 - cd ${HOME}/work/python-mode/python-mode - git submodule update --init --recursive - git submodule sync - bash tests/test.sh + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build Docker image + run: | + docker compose build -q \ + --build-arg PYTHON_VERSION="${{ matrix.python_version.full }}" \ + --build-arg PYTHON_VERSION_SHORT="${{ matrix.python_version.short }}" \ + python-mode-tests + + - name: Run tests with Python ${{ matrix.python_version.short }} + run: | + docker compose run --rm \ + -e PYTHON_VERSION="${{ matrix.python_version.full }}" \ + -e PYTHON_VERSION_SHORT="${{ matrix.python_version.short }}" \ + python-mode-tests diff --git a/.gitmodules b/.gitmodules index 15a5dd75..59d00541 100644 --- a/.gitmodules +++ b/.gitmodules @@ -45,3 +45,15 @@ path = submodules/pylama url = https://github.com/klen/pylama shallow = true +[submodule "submodules/toml"] + path = submodules/toml + url = https://github.com/uiri/toml.git +[submodule "submodules/pytoolconfig"] + path = submodules/pytoolconfig + url = https://github.com/bagel897/pytoolconfig.git +[submodule "submodules/tomli"] + path = submodules/tomli + url = https://github.com/hukkin/tomli.git +[submodule "submodules/appdirs"] + path = submodules/appdirs + url = https://github.com/ActiveState/appdirs.git diff --git a/AUTHORS b/AUTHORS index 926c2737..a4bcbf28 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,6 +42,7 @@ Contributors: * Kurtis Rader (https://github.com/krader1961); * Lawrence Akka (https://github.com/lawrenceakka); * lee (https://github.com/loyalpartner); +* Lie Ryan (https://github.com/lieryan/); * Lowe Thiderman (http://github.com/thiderman); * Martin Brochhaus (http://github.com/mbrochh); * Matt Dodge (https://github.com/mattdodge); @@ -74,3 +75,4 @@ Contributors: * Yury A. Kartynnik (https://github.com/kartynnik); * Xiangyu Xu (https://github.com/bkbncn); * Zach Himsel (https://github.com/zhimsel); +* Nathan Pemberton (https://github.com/NathanTP); diff --git a/CHANGELOG.md b/CHANGELOG.md index 001a9194..4e7668dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,38 @@ ## TODO +## 2023-07-02 0.14.0 + +- Update submodules + - Fix Errors related to these updates +- Improve tests outputs +- Fix Global and Module MoveRefactoring (#1141) Thanks to @lieryan +- Text object/operator/motion mapping to select logical line (#1145). Thanks to + @lieryan +- Remove dead keywords and builtins; add match, case (#1149). Thanks to + @NeilGirdhar +- Add syntax highlight for walrus (#1147) Thanks to @fpob +- Add configurable prefix for rope commands (#1137) TThanks to @NathanTP +- Add option g:pymode_indent_hanging_width for different hanging indentation + width (#1138). Thanks to @wookayin + +## 2020-10-08 0.13.0 + +- Add toml submodule + +## 2020-10-08 0.12.0 + +- Improve breakpoint feature +- Improve debugging script +- Update submodules +- Improve tests + +## 2020-05-28 0.11.0 + - Move changelog rst syntax to markdown - `pymode_rope`: check disables -- Remove supoort for python 2. From 0.11.0 on we will focus on supporting - python 3+ (probably 3.5+). +- BREAKING CHANGE: Remove supoort for python 2. From 0.11.0 on we will focus on + supporting python 3+ (probably 3.5+). - Inspect why files starting with the following code do not get loaded: ```python @@ -16,6 +44,12 @@ main() ``` +- added github actions test suit and remove travis +- improved submodules cloning (shallow) +- Removes `six` submodule +- Fix motion mapping +- Fix breakpoint feature + ## 2019-05-11 0.10.0 After many changes, including moving most of our dependencies from copied diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..bc70218f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +ARG PYTHON_VERSION_SHORT +ARG PYTHON_VERSION +ARG REPO_OWNER=python-mode +FROM ghcr.io/${REPO_OWNER}/python-mode-base:${PYTHON_VERSION_SHORT}-latest + +ENV PYTHON_VERSION=${PYTHON_VERSION} +ENV PYTHONUNBUFFERED=1 +ENV PYMODE_DIR="/workspace/python-mode" + +# Set up working directory +WORKDIR /workspace + +# Copy the python-mode plugin +COPY . /workspace/python-mode + +# Set up python-mode in the test environment +RUN mkdir -p /root/.vim/pack/foo/start/ && \ + ln -s ${PYMODE_DIR} /root/.vim/pack/foo/start/python-mode && \ + cp ${PYMODE_DIR}/tests/utils/pymoderc /root/.pymoderc && \ + cp ${PYMODE_DIR}/tests/utils/vimrc /root/.vimrc && \ + touch /root/.vimrc.before /root/.vimrc.after + +# Initialize git submodules +WORKDIR /workspace/python-mode + +# Create a script to run tests +RUN echo '#!/bin/bash\n\ +# export PYENV_ROOT="/opt/pyenv"\n\ +# export PATH="${PYENV_ROOT}/bin:${PYENV_ROOT}/shims:${PATH}"\n\ +eval "$(pyenv init -)"\n\ +eval "$(pyenv init --path)"\n\ +# Use specified Python version\n\ +pyenv shell ${PYTHON_VERSION}\n\ +cd /workspace/python-mode\n\ +echo "Using Python: $(python --version)"\n\ +bash ./tests/test.sh\n\ +rm -f tests/.swo tests/.swp 2>&1 >/dev/null \n\ +' > /usr/local/bin/run-tests && \ + chmod +x /usr/local/bin/run-tests + +# Default command +CMD ["/usr/local/bin/run-tests"] diff --git a/Dockerfile.base b/Dockerfile.base new file mode 100644 index 00000000..0513f4a1 --- /dev/null +++ b/Dockerfile.base @@ -0,0 +1,76 @@ +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive +ENV PYTHON_CONFIGURE_OPTS="--enable-shared" +ENV PYENV_ROOT="/opt/pyenv" +ENV PATH="$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH" +ARG PYTHON_VERSION=3.13.0 +ENV PYTHON_VERSION=${PYTHON_VERSION} + +# Install system dependencies for pyenv and Python builds +# TODO: Remove GUI dependencies +RUN apt-get update && apt-get install -yqq \ + libncurses5-dev \ + libgtk2.0-dev \ + libatk1.0-dev \ + libcairo2-dev \ + libx11-dev \ + libxpm-dev \ + libxt-dev \ + lua5.2 \ + liblua5.2-dev \ + libperl-dev \ + git \ + build-essential \ + curl \ + wget \ + ca-certificates \ + libssl-dev \ + libbz2-dev \ + libreadline-dev \ + libsqlite3-dev \ + zlib1g-dev \ + libffi-dev \ + liblzma-dev \ + && rm -rf /var/lib/apt/lists/* + +# Remove existing vim packages +RUN apt-get remove --purge -yqq vim vim-runtime gvim 2>&1 > /dev/null || true + +# Install pyenv +RUN git clone --depth 1 https://github.com/pyenv/pyenv.git $PYENV_ROOT && \ + cd $PYENV_ROOT && \ + git checkout $(git describe --tags --abbrev=0) && \ + eval "$(pyenv init -)" && \ + eval "$(pyenv init --path)" + +# Set up bash profile for pyenv +RUN echo 'export PYENV_ROOT="/opt/pyenv"' >> /root/.bashrc && \ + echo 'export PATH="${PYENV_ROOT}/bin:${PYENV_ROOT}/shims:$PATH"' >> /root/.bashrc && \ + echo 'eval "$(pyenv init -)"' >> /root/.bashrc && \ + echo 'eval "$(pyenv init --path)"' >> /root/.bashrc && \ + echo 'alias python=python3' >> /root/.bashrc + +# Install Python versions with pyenv +RUN pyenv install ${PYTHON_VERSION} && \ + pyenv global ${PYTHON_VERSION} && \ + rm -rf /tmp/python-build* + +# Upgrade pip and add some other dependencies +RUN eval "$(pyenv init -)" && \ + echo "Upgrading pip for Python ($(python --version): $(which python))..." && \ + pip install --upgrade pip setuptools wheel && \ + ## Python-mode dependency + pip install pytoolconfig + +# Build and install Vim from source with Python support for each Python version +RUN cd /tmp && \ + git clone --depth 1 https://github.com/vim/vim.git && \ + cd vim && \ + # Build Vim for each Python version + echo "Building Vim with python support: Python ($(python --version): $(which python))..." && \ + make clean || true && \ + ./configure --with-features=huge --enable-multibyte --enable-python3interp=yes --with-python3-config-dir=$(python-config --configdir) --enable-perlinterp=yes --enable-luainterp=yes --enable-cscope --prefix=/usr/local --exec-prefix=/usr/local && \ + make && \ + make install && \ + echo "Vim for Python $pyver installed as vim" diff --git a/README-Docker.md b/README-Docker.md new file mode 100644 index 00000000..a432ef07 --- /dev/null +++ b/README-Docker.md @@ -0,0 +1,132 @@ +# Docker Test Environment for python-mode + +This directory contains Docker configuration to run python-mode tests in a containerized environment that matches the GitHub Actions CI environment. + +## Prerequisites + +- Docker +- Docker Compose + +## Quick Start + +### Run Tests + +To run all tests in Docker (default version 3.13.0): + +```bash +# Using the convenience script +./scripts/run-tests-docker.sh + +# Or manually with docker-compose +docker compose run --rm python-mode-tests +``` + +### Interactive Development + +To start an interactive shell for development: + +```bash +docker compose run --rm python-mode-dev +``` + +## What's Included + +The Docker environment includes: + +- **Ubuntu 24.04** base image +- **pyenv** for Python version management +- **Multiple Python versions**: 3.10.13, 3.11.9, 3.12.4, 3.13.0 +- **Python 3.13.0** as default +- **Vim built from source** with Python support for each Python version +- All required system dependencies: + - GUI libraries (GTK, X11, etc.) + - Lua 5.2 + - Perl + - Build tools + - Python build dependencies +- **python-mode plugin** properly installed and configured +- **Git submodules** initialized +- **Test environment** matching the CI setup + +## Environment Details + +The container replicates the GitHub Actions environment: + +- Vim is built with `--enable-python3interp=yes` for each Python version +- pyenv is installed at `/opt/pyenv` +- Python versions are managed by pyenv: + - 3.10.13 + - 3.11.9 + - 3.12.4 + - 3.13.0 (default) +- Each Python version has its own Vim binary: `vim-3.10.13`, `vim-3.11.9`, etc. +- Python config directory is automatically detected using `python-config --configdir` +- python-mode is installed in `/root/.vim/pack/foo/start/python-mode` +- Test configuration files are copied to the appropriate locations +- All required environment variables are set + +## Test Execution + +Tests are run using the same `tests/test.sh` script as in CI: + +1. **test_autopep8.sh** - Tests automatic code formatting +2. **test_autocommands.sh** - Tests Vim autocommands +3. **test_folding.sh** - Tests code folding functionality +4. **test_textobject.sh** - Tests text object operations + +## Testing with Different Python Versions + +You can test python-mode with different Python versions: + +```bash +# Test with Python 3.11.9 +./scripts/run-tests-docker.sh 3.11 + +# Test with Python 3.12.4 +./scripts/run-tests-docker.sh 3.12 + +# Test with Python 3.13.0 +./scripts/run-tests-docker.sh 3.13 +``` + +Available Python versions: 3.10.13, 3.11.9, 3.12.4, 3.13.0 + +Note: Use the major.minor format (e.g., 3.11) when specifying versions. + +## Troubleshooting + +### Python Config Directory Issues + +The Dockerfile uses `python-config --configdir` to automatically detect the correct Python config directory. If you encounter issues: + +1. Check that pyenv is properly initialized +2. Verify that the requested Python version is available +3. Ensure all environment variables are set correctly + +### Build Failures + +If the Docker build fails: + +1. Check that all required packages are available in Ubuntu 24.04 +2. Verify that pyenv can download and install Python versions +3. Ensure the Vim source code is accessible +4. Check that pyenv is properly initialized in the shell + +### Test Failures + +If tests fail in Docker but pass locally: + +1. Check that the Vim build includes Python support for the correct version +2. Verify that all git submodules are properly initialized +3. Ensure the test environment variables are correctly set +4. Confirm that the correct Python version is active +5. Verify that pyenv is properly initialized + +## Adding More Python Versions + +To add support for additional Python versions: + +1. Add the new version to the `pyenv install` commands in the Dockerfile.base +2. Update the test scripts to include the new version +4. Test that the new version works with the python-mode plugin +5. Update this documentation with the new version information \ No newline at end of file diff --git a/after/ftplugin/python.vim b/after/ftplugin/python.vim index 0fdd01a3..6b5a8839 100644 --- a/after/ftplugin/python.vim +++ b/after/ftplugin/python.vim @@ -42,6 +42,8 @@ if g:pymode_motion vnoremap aM :call pymode#motion#select('^s*(asyncs+)=@', '^s*(asyncs+)=defs', 0) vnoremap iM :call pymode#motion#select('^s*(asyncs+)=@', '^s*(asyncs+)=defs', 1) + onoremap V :call pymode#rope#select_logical_line() + endif if g:pymode_rope && g:pymode_rope_completion diff --git a/autoload/pymode/indent.vim b/autoload/pymode/indent.vim index efd41f29..e964f378 100644 --- a/autoload/pymode/indent.vim +++ b/autoload/pymode/indent.vim @@ -24,7 +24,9 @@ function! pymode#indent#get_indent(lnum) if closing_paren return indent(parlnum) else - return indent(parlnum) + &shiftwidth + let l:indent_width = (g:pymode_indent_hanging_width > 0 ? + \ g:pymode_indent_hanging_width : &shiftwidth) + return indent(parlnum) + l:indent_width endif else return parcol diff --git a/autoload/pymode/motion.vim b/autoload/pymode/motion.vim index a930f35a..c88fb913 100644 --- a/autoload/pymode/motion.vim +++ b/autoload/pymode/motion.vim @@ -51,7 +51,7 @@ fun! pymode#motion#select(first_pattern, second_pattern, inner) "{{{ endif call cursor(snum, 1) - normal! v + normal! V call cursor(enum, len(getline(enum))) endif endfunction "}}} diff --git a/autoload/pymode/rope.vim b/autoload/pymode/rope.vim index c1a2de0c..36344d0a 100644 --- a/autoload/pymode/rope.vim +++ b/autoload/pymode/rope.vim @@ -194,3 +194,7 @@ fun! pymode#rope#generate_package() "{{{ endif PymodePython rope.GenerateElementRefactoring('package').run() endfunction "}}} + +fun! pymode#rope#select_logical_line() "{{{ + PymodePython rope.select_logical_line() +endfunction "}}} diff --git a/doc/pymode.txt b/doc/pymode.txt index de98f17b..ec328429 100644 --- a/doc/pymode.txt +++ b/doc/pymode.txt @@ -6,7 +6,7 @@ (__) (__) (__) (_) (_)(_____)(_)\_) (_/\/\_)(_____)(____/(____) ~ - Version: 0.11.0 + Version: 0.14.0 =============================================================================== CONTENTS *pymode-contents* @@ -54,7 +54,7 @@ Python-mode contains all you need to develop python applications in Vim. Features: *pymode-features* -- Support Python version 2.6+ and 3.2+ +- Support Python version 3.10.13, 3.11.9, 3.12.4, 3.13.0 - Syntax highlighting - Virtualenv support - Run python code (``r``) @@ -161,6 +161,11 @@ python-features of **pymode** will be disabled. Set value to `python3` if you are working with python3 projects. You could use |exrc| ++ Currently supported Python versions: 3.10.13, 3.11.9, 3.12.4, 3.13.0 ++ ++ For testing with different Python versions, see the Docker testing environment ++ described in the Development section. + ------------------------------------------------------------------------------- 2.2 Python indentation ~ *pymode-indent* @@ -170,6 +175,16 @@ Enable pymode indentation *'g:pymode_indent' > let g:pymode_indent = 1 + +Customization: + +Hanging indent size after an open parenthesis or bracket (but nothing after the +parenthesis), when vertical alignment is not used. Defaults to `&shiftwidth`. + *'g:pymode_indent_hanging_width'* +> + let g:pymode_indent_hanging_width = &shiftwidth + let g:pymode_indent_hanging_width = 4 + ------------------------------------------------------------------------------- 2.3 Python folding ~ *pymode-folding* @@ -199,10 +214,11 @@ Key Command ]] Jump to next class or function (normal, visual, operator modes) [M Jump to previous class or method (normal, visual, operator modes) ]M Jump to next class or method (normal, visual, operator modes) -aC Select a class. Ex: vaC, daC, yaC, caC (normal, operator modes) -iC Select inner class. Ex: viC, diC, yiC, ciC (normal, operator modes) -aM Select a function or method. Ex: vaM, daM, yaM, caM (normal, operator modes) -iM Select inner function or method. Ex: viM, diM, yiM, ciM (normal, operator modes) +aC Select a class. Ex: vaC, daC, yaC, caC (operator modes) +iC Select inner class. Ex: viC, diC, yiC, ciC (operator modes) +aM Select a function or method. Ex: vaM, daM, yaM, caM (operator modes) +iM Select inner function or method. Ex: viM, diM, yiM, ciM (operator modes) +V Select logical line. Ex: dV, yV, cV (operator modes), also works with count ==== ============================ Enable pymode-motion *'g:pymode_motion'* @@ -282,7 +298,7 @@ Manually set breakpoint command (leave empty for automatic detection) 3. Code checking ~ *pymode-lint* -Pymode supports `pylint`, `pep257`, `pep8`, `pyflakes`, `mccabe` code +Pymode supports `pylint`, `pep257`, `pycodestyle`, `pyflakes`, `mccabe` code checkers. You could run several similar checkers. Pymode uses Pylama library for code checking. Many options like skip @@ -319,9 +335,9 @@ Show error message if cursor placed at the error line *'g:pymode_lint_message' Default code checkers (you could set several) *'g:pymode_lint_checkers'* > - let g:pymode_lint_checkers = ['pyflakes', 'pep8', 'mccabe'] + let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle', 'mccabe'] -Values may be chosen from: `pylint`, `pep8`, `mccabe`, `pep257`, `pyflakes`. +Values may be chosen from: `pylint`, `pycodestyle`, `mccabe`, `pep257`, `pyflakes`. Skip errors and warnings *'g:pymode_lint_ignore'* E.g. ["W", "E2"] (Skip all Warnings and the Errors starting with E2) etc. @@ -365,9 +381,9 @@ Definitions for |signs| Pymode has the ability to set code checkers options from pymode variables: -Set PEP8 options *'g:pymode_lint_options_pep8'* +Set PEP8 options *'g:pymode_lint_options_pycodestyle'* > - let g:pymode_lint_options_pep8 = + let g:pymode_lint_options_pycodestyle = \ {'max_line_length': g:pymode_options_max_line_length} See https://pep8.readthedocs.org/en/1.4.6/intro.html#configuration for more @@ -413,6 +429,10 @@ Turn on the rope script *'g:pymode_rope' > let g:pymode_rope = 1 +Set the prefix for rope commands *'g:pymode_rope_prefix'* +> + let g:pymode_rope_refix = '' + .ropeproject Folder ~ *.ropeproject* @@ -603,14 +623,31 @@ code to call it instead. let g:pymode_rope_use_function_bind = 'ru' -Move method/fields ~ +Move refactoring ~ *pymode-rope-move* +Moving method/fields + It happens when you perform move refactoring on a method of a class. In this refactoring, a method of a class is moved to the class of one of its attributes. The old method will call the new method. If you want to change all of the occurrences of the old method to use the new method you can inline it afterwards. + +Moving global variable/class/function into another module + +It happens when you perform move refactoring on global variable/class/function. +In this refactoring, the object being refactored will be moved to a destination +module. All references to the object being moved will be updated to point to +the new location. + +Moving module variable/class/function into a package + +It happens when you perform move refactoring on a name referencing a module. +In this refactoring, the module being refactored will be moved to a destination +package. All references to the object being moved will be updated to point to +the new location. + > let g:pymode_rope_move_bind = 'rv' @@ -660,6 +697,10 @@ Highlight '=' operator *'g:pymode_syntax_highlight_equal_operator' > let g:pymode_syntax_highlight_equal_operator = g:pymode_syntax_all +Highlight ':=' operator *'g:pymode_syntax_highlight_walrus_operator'* +> + let g:pymode_syntax_highlight_walrus_operator = g:pymode_syntax_all + Highlight '*' operator *'g:pymode_syntax_highlight_stars_operator'* > let g:pymode_syntax_highlight_stars_operator = g:pymode_syntax_all @@ -826,6 +867,22 @@ newly added file (2). This latter file should invoke vim which in turn sources file (3). File (3) may then read (4) as a first part of its assertion structure and then execute the remaning of the instructions/assertions. +6. Testing Environment: The project uses Docker for consistent testing across +different Python versions. See `README-Docker.md` for detailed information about +the Docker testing environment. + +7. CI/CD: The project uses GitHub Actions for continuous integration, building +Docker images for each supported Python version and running tests automatically. + +8. Supported Python Versions: The project currently supports Python 3.10.13, +3.11.9, 3.12.4, and 3.13.0. All tests are run against these versions in the +CI environment. + +9. Docker Testing: To run tests locally with Docker: + - Use `./scripts/run-tests-docker.sh` to run tests with the default Python version + - Use `./scripts/run-tests-docker.sh 3.11` to test with Python 3.11.9 + - Use `./scripts/test-all-python-versions.sh` to test with all supported versions + =============================================================================== 8. Credits ~ *pymode-credits* diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..28959f48 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +services: + python-mode-tests: + build: + context: . + dockerfile: Dockerfile + args: + - PYTHON_VERSION_SHORT + - PYTHON_VERSION + volumes: + # Mount the current directory to allow for development and testing + - .:/workspace/python-mode + environment: + - PYTHON_CONFIGURE_OPTS=--enable-shared + - PYMODE_DIR=/workspace/python-mode + - PYENV_ROOT=/opt/pyenv + - PATH=/usr/local/bin:/opt/pyenv/bin:/opt/pyenv/shims:$PATH + # Optional: Set PYTHON_VERSION to test with a specific Python version + # - PYTHON_VERSION=3.11.9 + # Run tests by default + command: ["/usr/local/bin/run-tests"] + + # Alternative service for interactive development + python-mode-dev: + build: + context: . + dockerfile: Dockerfile + args: + - PYTHON_VERSION_SHORT + - PYTHON_VERSION + volumes: + - .:/workspace/python-mode + environment: + - PYTHON_CONFIGURE_OPTS=--enable-shared + - PYMODE_DIR=/workspace/python-mode + - PYENV_ROOT=/opt/pyenv + - PATH=/usr/local/bin:/opt/pyenv/bin:/opt/pyenv/shims:$PATH + # Optional: Set PYTHON_VERSION to test with a specific Python version + # - PYTHON_VERSION=3.11.9 + # Start an interactive shell for development + command: ["/bin/bash"] + stdin_open: true + tty: true diff --git a/plugin/pymode.vim b/plugin/pymode.vim index 1be44ad8..b0d99270 100644 --- a/plugin/pymode.vim +++ b/plugin/pymode.vim @@ -1,5 +1,6 @@ " vi: fdl=1 -let g:pymode_version = "0.11.0" +let g:pymode_version = "0.14.0" + " Enable pymode by default :) call pymode#default('g:pymode', 1) @@ -38,6 +39,9 @@ call pymode#default('g:pymode_doc_bind', 'K') " Enable/Disable pymode PEP8 indentation call pymode#default("g:pymode_indent", 1) +" Customize hanging indent size different than &shiftwidth +call pymode#default("g:pymode_indent_hanging_width", -1) + " TODO: currently folding suffers from a bad performance and incorrect " implementation. This feature should be considered experimental. " Enable/disable pymode folding for pyfiles. @@ -118,8 +122,8 @@ call pymode#default("g:pymode_lint_on_fly", 0) " Show message about error in command line call pymode#default("g:pymode_lint_message", 1) -" Choices are: pylint, pyflakes, pep8, mccabe and pep257 -call pymode#default("g:pymode_lint_checkers", ['pyflakes', 'pep8', 'mccabe']) +" Choices are: pylint, pyflakes, pycodestyle, mccabe and pep257 +call pymode#default("g:pymode_lint_checkers", ['pyflakes', 'pycodestyle', 'mccabe']) " Skip errors and warnings (e.g. E4,W) call pymode#default("g:pymode_lint_ignore", []) @@ -148,8 +152,8 @@ call pymode#default("g:pymode_lint_info_symbol", "II") call pymode#default("g:pymode_lint_pyflakes_symbol", "FF") " Code checkers options -" TODO: check if most adequate name name is pep8 or pycodestyle. -call pymode#default("g:pymode_lint_options_pep8", +" TODO: check if most adequate name name is pycodestyle. +call pymode#default("g:pymode_lint_options_pycodestyle", \ {'max_line_length': g:pymode_options_max_line_length}) call pymode#default("g:pymode_lint_options_pylint", @@ -182,6 +186,7 @@ call pymode#default('g:pymode_breakpoint_cmd', '') " " Rope support call pymode#default('g:pymode_rope', 0) +call pymode#default('g:pymode_rope_prefix', '') " System plugin variable if g:pymode_rope @@ -210,7 +215,7 @@ if g:pymode_rope call pymode#default('g:pymode_rope_autoimport_modules', ['os', 'shutil', 'datetime']) " Bind keys to autoimport module for object under cursor - call pymode#default('g:pymode_rope_autoimport_bind', 'ra') + call pymode#default('g:pymode_rope_autoimport_bind', g:pymode_rope_prefix . 'ra') " Automatic completion on dot call pymode#default('g:pymode_rope_complete_on_dot', 1) @@ -219,56 +224,56 @@ if g:pymode_rope call pymode#default('g:pymode_rope_completion_bind', '') " Bind keys for goto definition (leave empty for disable) - call pymode#default('g:pymode_rope_goto_definition_bind', 'g') + call pymode#default('g:pymode_rope_goto_definition_bind', g:pymode_rope_prefix . 'g') " set command for open definition (e, new, vnew) call pymode#default('g:pymode_rope_goto_definition_cmd', 'new') " Bind keys for show documentation (leave empty for disable) - call pymode#default('g:pymode_rope_show_doc_bind', 'd') + call pymode#default('g:pymode_rope_show_doc_bind', g:pymode_rope_prefix . 'd') " Bind keys for find occurencies (leave empty for disable) - call pymode#default('g:pymode_rope_find_it_bind', 'f') + call pymode#default('g:pymode_rope_find_it_bind', g:pymode_rope_prefix . 'f') " Bind keys for organize imports (leave empty for disable) - call pymode#default('g:pymode_rope_organize_imports_bind', 'ro') + call pymode#default('g:pymode_rope_organize_imports_bind', g:pymode_rope_prefix . 'ro') " Bind keys for rename variable/method/class in the project (leave empty for disable) - call pymode#default('g:pymode_rope_rename_bind', 'rr') + call pymode#default('g:pymode_rope_rename_bind', g:pymode_rope_prefix . 'rr') " Bind keys for rename module - call pymode#default('g:pymode_rope_rename_module_bind', 'r1r') + call pymode#default('g:pymode_rope_rename_module_bind', g:pymode_rope_prefix . 'r1r') " Bind keys for convert module to package - call pymode#default('g:pymode_rope_module_to_package_bind', 'r1p') + call pymode#default('g:pymode_rope_module_to_package_bind', g:pymode_rope_prefix . 'r1p') " Creates a new function or method (depending on the context) from the selected lines - call pymode#default('g:pymode_rope_extract_method_bind', 'rm') + call pymode#default('g:pymode_rope_extract_method_bind', g:pymode_rope_prefix . 'rm') " Creates a variable from the selected lines - call pymode#default('g:pymode_rope_extract_variable_bind', 'rl') + call pymode#default('g:pymode_rope_extract_variable_bind', g:pymode_rope_prefix . 'rl') " Inline refactoring - call pymode#default('g:pymode_rope_inline_bind', 'ri') + call pymode#default('g:pymode_rope_inline_bind', g:pymode_rope_prefix . 'ri') " Move refactoring - call pymode#default('g:pymode_rope_move_bind', 'rv') + call pymode#default('g:pymode_rope_move_bind', g:pymode_rope_prefix . 'rv') " Generate function - call pymode#default('g:pymode_rope_generate_function_bind', 'rnf') + call pymode#default('g:pymode_rope_generate_function_bind', g:pymode_rope_prefix . 'rnf') " Generate class - call pymode#default('g:pymode_rope_generate_class_bind', 'rnc') + call pymode#default('g:pymode_rope_generate_class_bind', g:pymode_rope_prefix . 'rnc') " Generate package - call pymode#default('g:pymode_rope_generate_package_bind', 'rnp') + call pymode#default('g:pymode_rope_generate_package_bind', g:pymode_rope_prefix . 'rnp') " Change signature - call pymode#default('g:pymode_rope_change_signature_bind', 'rs') + call pymode#default('g:pymode_rope_change_signature_bind', g:pymode_rope_prefix . 'rs') " Tries to find the places in which a function can be used and changes the " code to call it instead - call pymode#default('g:pymode_rope_use_function_bind', 'ru') + call pymode#default('g:pymode_rope_use_function_bind', g:pymode_rope_prefix . 'ru') " Regenerate project cache on every save call pymode#default('g:pymode_rope_regenerate_on_write', 1) diff --git a/pymode/__init__.py b/pymode/__init__.py index aba22870..906d7059 100644 --- a/pymode/__init__.py +++ b/pymode/__init__.py @@ -6,7 +6,13 @@ import vim # noqa if not hasattr(vim, 'find_module'): - vim.find_module = _PathFinder.find_module + try: + vim.find_module = _PathFinder.find_module # deprecated + except AttributeError: + def _find_module(package_name): + spec = _PathFinder.find_spec(package_name) + return spec.loader if spec else None + vim.find_module = _find_module def auto(): diff --git a/pymode/environment.py b/pymode/environment.py index 30ae0e50..86527f56 100644 --- a/pymode/environment.py +++ b/pymode/environment.py @@ -242,5 +242,8 @@ def goto_buffer(bufnr): if str(bufnr) != '-1': vim.command('buffer %s' % bufnr) + def select_line(self, start, end): + vim.command('normal %sggV%sgg' % (start, end)) + env = VimPymodeEnviroment() diff --git a/pymode/libs/appdirs.py b/pymode/libs/appdirs.py new file mode 120000 index 00000000..da7cbf20 --- /dev/null +++ b/pymode/libs/appdirs.py @@ -0,0 +1 @@ +../../submodules/appdirs/appdirs.py \ No newline at end of file diff --git a/pymode/libs/pytoolconfig b/pymode/libs/pytoolconfig new file mode 120000 index 00000000..0a2d520c --- /dev/null +++ b/pymode/libs/pytoolconfig @@ -0,0 +1 @@ +../../submodules/pytoolconfig/pytoolconfig/ \ No newline at end of file diff --git a/pymode/libs/toml b/pymode/libs/toml new file mode 120000 index 00000000..dc960a0a --- /dev/null +++ b/pymode/libs/toml @@ -0,0 +1 @@ +../../submodules/toml/toml \ No newline at end of file diff --git a/pymode/libs/tomli b/pymode/libs/tomli new file mode 120000 index 00000000..2413e2b5 --- /dev/null +++ b/pymode/libs/tomli @@ -0,0 +1 @@ +../../submodules/tomli/src/tomli \ No newline at end of file diff --git a/pymode/lint.py b/pymode/lint.py index ba187558..b0103a50 100644 --- a/pymode/lint.py +++ b/pymode/lint.py @@ -6,7 +6,7 @@ import os.path -from pylama.lint.extensions import LINTERS +from pylama.lint import LINTERS try: from pylama.lint.pylama_pylint import Linter @@ -35,13 +35,19 @@ def code_check(): # Fixed in v0.9.3: these two parameters may be passed as strings. # DEPRECATE: v:0.10.0: need to be set as lists. if isinstance(env.var('g:pymode_lint_ignore'), str): - raise ValueError ('g:pymode_lint_ignore should have a list type') + raise ValueError('g:pymode_lint_ignore should have a list type') else: ignore = env.var('g:pymode_lint_ignore') if isinstance(env.var('g:pymode_lint_select'), str): - raise ValueError ('g:pymode_lint_select should have a list type') + raise ValueError('g:pymode_lint_select should have a list type') else: select = env.var('g:pymode_lint_select') + if 'pep8' in linters: + # TODO: Add a user visible deprecation warning here + env.message('pep8 linter is deprecated, please use pycodestyle.') + linters.remove('pep8') + linters.append('pycodestyle') + options = parse_options( linters=linters, force=1, ignore=ignore, @@ -65,7 +71,8 @@ def code_check(): return env.stop() if env.options.get('debug'): - from pylama.core import LOGGER, logging + import logging + from pylama.core import LOGGER LOGGER.setLevel(logging.DEBUG) errors = run(path, code='\n'.join(env.curbuf) + '\n', options=options) @@ -83,11 +90,16 @@ def __sort(e): env.debug("Find sorting: ", sort_rules) errors = sorted(errors, key=__sort) + errors_list = [] for e in errors: - e._info['bufnr'] = env.curbuf.number - if e._info['col'] is None: - e._info['col'] = 1 - - env.run('g:PymodeLocList.current().extend', [e._info for e in errors]) + if e.col is None: + e.col = 1 + err_dict = e.to_dict() + err_dict['bufnr'] = env.curbuf.number + err_dict['type'] = e.etype + err_dict['text'] = e.message + errors_list.append(err_dict) + + env.run('g:PymodeLocList.current().extend', errors_list) # pylama:ignore=W0212,E1103 diff --git a/pymode/rope.py b/pymode/rope.py index ba5f55b2..65c54257 100644 --- a/pymode/rope.py +++ b/pymode/rope.py @@ -5,7 +5,7 @@ import site import sys -from rope.base import project, libutils, exceptions, change, worder, pycore +from rope.base import project, libutils, exceptions, change, worder, pycore, codeanalyze from rope.base.fscommands import FileSystemCommands # noqa from rope.base.taskhandle import TaskHandle # noqa from rope.contrib import autoimport as rope_autoimport, codeassist, findit, generate # noqa @@ -463,10 +463,11 @@ def run(self): if not input_str: return False + code_actions = self.get_code_actions() action = env.user_input_choices( - 'Choose what to do:', 'perform', 'preview', - 'perform in class hierarchy', - 'preview in class hierarchy') + 'Choose what to do:', + *code_actions, + ) in_hierarchy = action.endswith("in class hierarchy") @@ -492,6 +493,12 @@ def run(self): except Exception as e: # noqa env.error('Unhandled exception in Pymode: %s' % e) + def get_code_actions(self): + return [ + 'perform', + 'preview', + ] + @staticmethod def get_refactor(ctx): """ Get refactor object. """ @@ -546,6 +553,14 @@ def get_input_str(self, refactor, ctx): return newname + def get_code_actions(self): + return [ + 'perform', + 'preview', + 'perform in class hierarchy', + 'preview in class hierarchy', + ] + @staticmethod def get_changes(refactor, input_str, in_hierarchy=False): """ Get changes. @@ -701,6 +716,15 @@ def get_refactor(ctx): offset = None return move.create_move(ctx.project, ctx.resource, offset) + @staticmethod + def get_changes(refactor, input_str, in_hierarchy=False): + with RopeContext() as ctx: + if isinstance(refactor, (move.MoveGlobal, move.MoveModule)): + dest = ctx.project.pycore.find_module(input_str) + else: + dest = input_str + return super(MoveRefactoring, MoveRefactoring).get_changes(refactor, dest) + class ChangeSignatureRefactoring(Refactoring): @@ -728,6 +752,14 @@ def get_refactor(ctx): return change_signature.ChangeSignature( ctx.project, ctx.resource, offset) + def get_code_actions(self): + return [ + 'perform', + 'preview', + 'perform in class hierarchy', + 'preview in class hierarchy', + ] + def get_changes(self, refactor, input_string, in_hierarchy=False): """ Function description. @@ -921,6 +953,22 @@ def _insert_import(name, module, ctx): reload_changes(changes) +@env.catch_exceptions +def select_logical_line(): + source, offset = env.get_offset_params() + count = int(env.var('v:count1')) + + lines = codeanalyze.SourceLinesAdapter(source) + start_line = lines.get_line_number(offset) + line_finder = codeanalyze.LogicalLineFinder(lines) + + start_lineno, end_lineno = line_finder.logical_line_in(start_line) + for _, (_, end_lineno) in zip(range(count), line_finder.generate_regions(start_lineno)): + pass + + env.select_line(start_lineno, end_lineno) + + # Monkey patch Rope def find_source_folders(self, folder): """Look only python files an packages.""" diff --git a/readme.md b/readme.md index 47660e45..2ba7e2d4 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -[![Build Status](https://travis-ci.org/python-mode/python-mode.svg?branch=develop)](https://travis-ci.org/python-mode/python-mode) +[![Testing python-mode](https://github.com/python-mode/python-mode/workflows/Testing%20python-mode/badge.svg?branch=develop)](https://github.com/python-mode/python-mode/actions?query=workflow%3A%22Testing+python-mode%22+branch%3Adevelop) ![](https://raw.github.com/python-mode/python-mode/develop/logo.png) # Python-mode, a Python IDE for Vim @@ -56,7 +56,7 @@ Why Python-mode? The plugin contains all you need to develop python applications in Vim. -* Support Python and 3.6+ +* Support Python 3.10.13, 3.11.9, 3.12.4, 3.13.0 * Syntax highlighting * Virtualenv support * Run python code (`r`) @@ -143,6 +143,41 @@ Then rebuild **helptags** in vim: **filetype-plugin** (`:help filetype-plugin-on`) and **filetype-indent** (`:help filetype-indent-on`) must be enabled to use python-mode. +# Docker Testing Environment + +For consistent testing across different Python versions, python-mode provides a +Docker-based testing environment. This is especially useful for contributors +and developers who want to test the plugin with different Python versions. + +## Quick Start + +```bash +# Run tests with default Python version (3.13.0) +./scripts/run-tests-docker.sh + +# Run tests with specific Python version +./scripts/run-tests-docker.sh 3.11 + +# Run tests with all supported Python versions +./scripts/test-all-python-versions.sh +``` + +## Supported Python Versions + +The Docker environment supports the following Python versions: +- 3.10.13 +- 3.11.9 +- 3.12.4 +- 3.13.0 (default) + +For detailed information about the Docker testing environment, see +[README-Docker.md](README-Docker.md). + +## Prerequisites + +- Docker +- Docker Compose + # Troubleshooting/Debugging First read our short @@ -188,6 +223,12 @@ Please, also provide more contextual information such as: * `git status` (under your _python-mode_ directory) * `tree ` or something similar (such as `ls -lR`) +If you're using the Docker testing environment, also provide: +* The output of `docker --version` and `docker compose version` +* The Python version used in Docker (if testing with a specific version) +* Any Docker-related error messages +* The output of `./scripts/run-tests-docker.sh --help` (if available) + # Frequent problems Read this section before opening an issue on the tracker. @@ -207,12 +248,50 @@ is a good reference on how to build vim from source. help you that much. Look for our branch with python2-support (old version, not maintained anymore) (`last-py2-support`). +## Python 3 Support + +`python-mode` supports only Python 3. The project has completely removed Python 2 +support since version 0.11.0. Currently supported Python versions are: +3.10.13, 3.11.9, 3.12.4, and 3.13.0. + +If you need Python 2 support, you can use the legacy `last-py2-support` branch, +but it is no longer maintained. + +## Vim Python Support + +Vim [has issues](https://github.com/vim/vim/issues/3585) when compiled with +both Python 2 and Python 3 support. For best compatibility with python-mode, +build Vim with only Python 3 support. See +[this guide](https://github.com/ycm-core/YouCompleteMe/wiki/Building-Vim-from-source) +for building Vim from source. + ## Symlinks on Windows Users on Windows OS might need to add `-c core.symlinks=true` switch to correctly clone / pull repository. Example: `git clone --recurse-submodules https://github.com/python-mode/python-mode -c core.symlinks=true` +## Docker Testing Issues + +If you encounter issues with the Docker testing environment: + +1. **Build Failures**: Ensure Docker and Docker Compose are properly installed + and up to date. The Dockerfile requires Ubuntu 24.04 packages. + +2. **Python Version Issues**: Verify that the requested Python version is + supported (3.10.13, 3.11.9, 3.12.4, 3.13.0). Use the major.minor format + (e.g., `3.11`) when specifying versions. + +3. **Vim Build Issues**: The Docker environment builds Vim from source with + Python support for each version. Ensure sufficient disk space and memory + for the build process. + +4. **Test Failures**: If tests fail in Docker but pass locally, check that + all git submodules are properly initialized and the correct Python version + is active. + +For detailed troubleshooting, see [README-Docker.md](README-Docker.md). + ## Error updating the plugin If you are trying to update the plugin (using a plugin manager or manually) and @@ -242,6 +321,19 @@ the issue tracker at: The contributing guidelines for this plugin are outlined at `:help pymode-development`. +Before contributing, please: + +1. **Test with Docker**: Use the Docker testing environment to ensure your + changes work across all supported Python versions (3.10.13, 3.11.9, 3.12.4, 3.13.0) + +2. **Run Full Test Suite**: Use `./scripts/test-all-python-versions.sh` to test + with all supported Python versions + +3. **Check CI**: Ensure the GitHub Actions CI passes for your changes + +4. **Follow Development Guidelines**: See `:help pymode-development` for detailed + development guidelines + * Author: Kirill Klenov () * Maintainers: * Felipe Vieira () diff --git a/scripts/run-tests-docker.sh b/scripts/run-tests-docker.sh new file mode 100755 index 00000000..56f9cbd3 --- /dev/null +++ b/scripts/run-tests-docker.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +# Script to run python-mode tests in Docker +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Mapping of major.minor to full version +declare -A PYTHON_VERSIONS +PYTHON_VERSIONS["3.10"]="3.10.13" +PYTHON_VERSIONS["3.11"]="3.11.9" +PYTHON_VERSIONS["3.12"]="3.12.4" +PYTHON_VERSIONS["3.13"]="3.13.0" + +show_usage() { + echo -e "${YELLOW}Usage: $0 [major.minor]${NC}" + echo -e "${YELLOW}Available versions:${NC}" + for short_version in "${!PYTHON_VERSIONS[@]}"; do + full_version="${PYTHON_VERSIONS[$short_version]}" + echo -e " ${BLUE}${short_version}${NC} (${full_version})" + done + echo "" + echo -e "${YELLOW}Examples:${NC}" + echo -e " ${BLUE}$0${NC} # Use default Python version" + echo -e " ${BLUE}$0 3.10${NC} # Test with Python 3.10.13" + echo -e " ${BLUE}$0 3.11${NC} # Test with Python 3.11.9" + echo -e " ${BLUE}$0 3.12${NC} # Test with Python 3.12.4" + echo -e " ${BLUE}$0 3.13${NC} # Test with Python 3.13.0" +} + +PYTHON_VERSION_SHORT="3.13" +PYTHON_VERSION="" + +if [ $# -eq 1 ]; then + PYTHON_VERSION_SHORT=$1 + + # Check if the version is valid + valid_version=false + for short_version in "${!PYTHON_VERSIONS[@]}"; do + if [ "${PYTHON_VERSION_SHORT}" = "${short_version}" ]; then + valid_version=true + PYTHON_VERSION="${PYTHON_VERSIONS[$short_version]}" + break + fi + done + + if [ "${valid_version}" = false ]; then + echo -e "${RED}Error: Invalid Python version '${PYTHON_VERSION_SHORT}'${NC}" + show_usage + exit 1 + fi +else + # Use default version + PYTHON_VERSION="${PYTHON_VERSIONS[$PYTHON_VERSION_SHORT]}" +fi + +echo -e "${YELLOW}Building python-mode test environment...${NC}" + +DOCKER_BUILD_ARGS=( + --build-arg PYTHON_VERSION="${PYTHON_VERSION}" + --build-arg PYTHON_VERSION_SHORT="${PYTHON_VERSION_SHORT}" +) + +# Build the Docker image +docker compose build -q ${DOCKER_BUILD_ARGS[@]} python-mode-tests + +echo -e "${YELLOW}Running python-mode tests with Python ${PYTHON_VERSION}...${NC}" +# Run the tests with specific Python version +if docker compose run --rm python-mode-tests; then + echo -e "${GREEN}✓ All tests passed with Python ${PYTHON_VERSION}!${NC}" + exit 0 +else + echo -e "${RED}✗ Some tests failed with Python ${PYTHON_VERSION}. Check the output above for details.${NC}" + exit 1 +fi diff --git a/scripts/test-all-python-versions.sh b/scripts/test-all-python-versions.sh new file mode 100755 index 00000000..647ff82e --- /dev/null +++ b/scripts/test-all-python-versions.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# Script to run python-mode tests with all Python versions +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Mapping of major.minor to full version (same as run-tests-docker.sh) +declare -A PYTHON_VERSIONS +PYTHON_VERSIONS["3.10"]="3.10.13" +PYTHON_VERSIONS["3.11"]="3.11.9" +PYTHON_VERSIONS["3.12"]="3.12.4" +PYTHON_VERSIONS["3.13"]="3.13.0" + +echo -e "${YELLOW}Running python-mode tests with all Python versions...${NC}" +echo "" + +# Build the Docker image once +echo -e "${YELLOW}Building python-mode test environment...${NC}" +docker compose build -q python-mode-tests +echo "" + +# Track overall results +OVERALL_SUCCESS=true +FAILED_VERSIONS=() + +# Test each Python version +for short_version in "${!PYTHON_VERSIONS[@]}"; do + full_version="${PYTHON_VERSIONS[$short_version]}" + echo -e "${BLUE}========================================${NC}" + echo -e "${BLUE}Testing with Python $short_version ($full_version)${NC}" + echo -e "${BLUE}========================================${NC}" + + if docker compose run --rm -e PYTHON_VERSION="$full_version" -e PYTHON_VERSION_SHORT="$short_version" python-mode-tests; then + echo -e "${GREEN}✓ Tests passed with Python $short_version${NC}" + else + echo -e "${RED}✗ Tests failed with Python $short_version${NC}" + OVERALL_SUCCESS=false + FAILED_VERSIONS+=("$short_version") + fi + echo "" +done + +# Summary +echo -e "${YELLOW}========================================${NC}" +echo -e "${YELLOW}TEST SUMMARY${NC}" +echo -e "${YELLOW}========================================${NC}" + +if [ "$OVERALL_SUCCESS" = true ]; then + echo -e "${GREEN}✓ All tests passed for all Python versions!${NC}" + exit 0 +else + echo -e "${RED}✗ Some tests failed for the following Python versions:${NC}" + for version in "${FAILED_VERSIONS[@]}"; do + echo -e "${RED} - Python $version (${PYTHON_VERSIONS[$version]})${NC}" + done + echo "" + echo -e "${YELLOW}To run tests for a specific version:${NC}" + echo -e "${BLUE} ./scripts/run-tests-docker.sh ${NC}" + echo -e "${BLUE} Example: ./scripts/run-tests-docker.sh 3.11${NC}" + exit 1 +fi \ No newline at end of file diff --git a/submodules/appdirs b/submodules/appdirs new file mode 160000 index 00000000..193a2cbb --- /dev/null +++ b/submodules/appdirs @@ -0,0 +1 @@ +Subproject commit 193a2cbba58cce2542882fcedd0e49f6763672ed diff --git a/submodules/astroid b/submodules/astroid index a672051f..a3623682 160000 --- a/submodules/astroid +++ b/submodules/astroid @@ -1 +1 @@ -Subproject commit a672051f4406da0beb01e88767e8e46488eb71eb +Subproject commit a3623682a5e1e07f4f331b6b0a5f77e257d81b96 diff --git a/submodules/autopep8 b/submodules/autopep8 index 84cb34ca..4046ad49 160000 --- a/submodules/autopep8 +++ b/submodules/autopep8 @@ -1 +1 @@ -Subproject commit 84cb34cad9b3e6fe520cb5b355eb52e6b6dd5758 +Subproject commit 4046ad49e25b7fa1db275bf66b1b7d60600ac391 diff --git a/submodules/mccabe b/submodules/mccabe index e92e9e79..835a5400 160000 --- a/submodules/mccabe +++ b/submodules/mccabe @@ -1 +1 @@ -Subproject commit e92e9e79799c5796f76f3da821dbb5aa56e41028 +Subproject commit 835a5400881b7460998be51d871fd36f836db3c9 diff --git a/submodules/pycodestyle b/submodules/pycodestyle index d4143838..814a0d12 160000 --- a/submodules/pycodestyle +++ b/submodules/pycodestyle @@ -1 +1 @@ -Subproject commit d414383860c483c57d1fafc12c630b46a5616d3c +Subproject commit 814a0d1259444a21ed318e64edaf6a530c2aeeb8 diff --git a/submodules/pydocstyle b/submodules/pydocstyle index 59396eb5..07f6707e 160000 --- a/submodules/pydocstyle +++ b/submodules/pydocstyle @@ -1 +1 @@ -Subproject commit 59396eb50d1d1a59fdccdd71cf4031577c02ab54 +Subproject commit 07f6707e2c5612960347f7c00125620457f490a7 diff --git a/submodules/pyflakes b/submodules/pyflakes index c72d6cf1..59ec4593 160000 --- a/submodules/pyflakes +++ b/submodules/pyflakes @@ -1 +1 @@ -Subproject commit c72d6cf1a9a119c1dd7a7674f36da21aea32d828 +Subproject commit 59ec4593efd4c69ce00fdb13c40fcf5f3212ab10 diff --git a/submodules/pylama b/submodules/pylama index f436ccc6..53ad214d 160000 --- a/submodules/pylama +++ b/submodules/pylama @@ -1 +1 @@ -Subproject commit f436ccc6b55b33381a295ded753e467953cf4379 +Subproject commit 53ad214de0aa9534e59bcd5f97d9d723d16cfdb8 diff --git a/submodules/pylint b/submodules/pylint index 6c6ffc30..f798a4a3 160000 --- a/submodules/pylint +++ b/submodules/pylint @@ -1 +1 @@ -Subproject commit 6c6ffc306f9c9614072bcb2c83fefa838bef1102 +Subproject commit f798a4a3508bcbb8ad0773ae14bf32d28dcfdcbe diff --git a/submodules/pytoolconfig b/submodules/pytoolconfig new file mode 160000 index 00000000..68410edb --- /dev/null +++ b/submodules/pytoolconfig @@ -0,0 +1 @@ +Subproject commit 68410edb910891659c3a65d58b641b26c62914ad diff --git a/submodules/rope b/submodules/rope index bc6908a8..5409da05 160000 --- a/submodules/rope +++ b/submodules/rope @@ -1 +1 @@ -Subproject commit bc6908a82b6f0eb7bb248b600adb3367f42714da +Subproject commit 5409da0556f0aed2a892e5ca876824b22e69c915 diff --git a/submodules/toml b/submodules/toml new file mode 160000 index 00000000..3f637dba --- /dev/null +++ b/submodules/toml @@ -0,0 +1 @@ +Subproject commit 3f637dba5f68db63d4b30967fedda51c82459471 diff --git a/submodules/tomli b/submodules/tomli new file mode 160000 index 00000000..73c3d102 --- /dev/null +++ b/submodules/tomli @@ -0,0 +1 @@ +Subproject commit 73c3d102eb81fe0d2b87f905df4f740f8878d8da diff --git a/syntax/python.vim b/syntax/python.vim index b7666d86..5a76d2b0 100644 --- a/syntax/python.vim +++ b/syntax/python.vim @@ -23,6 +23,9 @@ call pymode#default("g:pymode_syntax_highlight_async_await", g:pymode_syntax_all " Highlight '=' operator call pymode#default('g:pymode_syntax_highlight_equal_operator', g:pymode_syntax_all) +" Highlight ':=' operator +call pymode#default('g:pymode_syntax_highlight_walrus_operator', g:pymode_syntax_all) + " Highlight '*' operator call pymode#default('g:pymode_syntax_highlight_stars_operator', g:pymode_syntax_all) @@ -91,7 +94,7 @@ endif syn match pythonClassParameters "[^,\*]*" contained contains=pythonBuiltin,pythonBuiltinObj,pythonBuiltinType,pythonExtraOperatorpythonStatement,pythonBrackets,pythonString,pythonComment skipwhite syn keyword pythonRepeat for while - syn keyword pythonConditional if elif else + syn keyword pythonConditional if elif else match case syn keyword pythonInclude import from syn keyword pythonException try except finally syn keyword pythonOperator and in is not or @@ -114,6 +117,10 @@ endif syn match pythonExtraOperator "\%(=\)" endif + if g:pymode_syntax_highlight_walrus_operator + syn match pythonExtraOperator "\%(:=\)" + endif + if g:pymode_syntax_highlight_stars_operator syn match pythonExtraOperator "\%(\*\|\*\*\)" endif @@ -262,26 +269,29 @@ endif " Builtin objects and types if g:pymode_syntax_builtin_objs - syn keyword pythonBuiltinObj True False Ellipsis None NotImplemented - syn keyword pythonBuiltinObj __debug__ __doc__ __file__ __name__ __package__ + " True, False, Ellipsis, and None are in fact keywords. + syn keyword pythonBuiltinObj True False Ellipsis None + syn keyword pythonBuiltinObj NotImplemented + syn keyword pythonBuiltinObj __debug__ __doc__ __file__ __name__ __package__ __loader__ + syn keyword pythonBuiltinObj __spec__ __cached__ __annotations__ endif if g:pymode_syntax_builtin_types syn keyword pythonBuiltinType type object - syn keyword pythonBuiltinType str basestring unicode buffer bytearray bytes chr unichr - syn keyword pythonBuiltinType dict int long bool float complex set frozenset list tuple - syn keyword pythonBuiltinType file super + syn keyword pythonBuiltinType str bytearray bytes chr + syn keyword pythonBuiltinType dict int bool float complex set frozenset list tuple + syn keyword pythonBuiltinType super endif " Builtin functions if g:pymode_syntax_builtin_funcs - syn keyword pythonBuiltinFunc __import__ abs all any apply - syn keyword pythonBuiltinFunc bin callable classmethod cmp coerce compile + syn keyword pythonBuiltinFunc __import__ abs all any + syn keyword pythonBuiltinFunc bin callable classmethod compile syn keyword pythonBuiltinFunc delattr dir divmod enumerate eval execfile filter syn keyword pythonBuiltinFunc format getattr globals locals hasattr hash help hex id - syn keyword pythonBuiltinFunc input intern isinstance issubclass iter len map max min - syn keyword pythonBuiltinFunc next oct open ord pow property range xrange - syn keyword pythonBuiltinFunc raw_input reduce reload repr reversed round setattr + syn keyword pythonBuiltinFunc input isinstance issubclass iter len map max min + syn keyword pythonBuiltinFunc next oct open ord pow property range + syn keyword pythonBuiltinFunc repr reversed round setattr syn keyword pythonBuiltinFunc slice sorted staticmethod sum vars zip if g:pymode_syntax_print_as_function @@ -292,31 +302,31 @@ endif " Builtin exceptions and warnings if g:pymode_syntax_highlight_exceptions - syn keyword pythonExClass BaseException - syn keyword pythonExClass Exception StandardError ArithmeticError - syn keyword pythonExClass LookupError EnvironmentError - syn keyword pythonExClass AssertionError AttributeError BufferError EOFError - syn keyword pythonExClass FloatingPointError GeneratorExit IOError - syn keyword pythonExClass ImportError IndexError KeyError - syn keyword pythonExClass KeyboardInterrupt MemoryError NameError + syn keyword pythonExClass BaseException Exception ArithmeticError + syn keyword pythonExClass BufferError LookupError + syn keyword pythonExClass AssertionError AttributeError EOFError + syn keyword pythonExClass FloatingPointError GeneratorExit + syn keyword pythonExClass ImportError ModuleNotFoundError IndexError + syn keyword pythonExClass KeyError KeyboardInterrupt MemoryError NameError syn keyword pythonExClass NotImplementedError OSError OverflowError - syn keyword pythonExClass ReferenceError RuntimeError StopIteration - syn keyword pythonExClass SyntaxError IndentationError TabError + syn keyword pythonExClass RecursionError ReferenceError RuntimeError StopIteration + syn keyword pythonExClass StopAsyncIteration SyntaxError IndentationError TabError syn keyword pythonExClass SystemError SystemExit TypeError syn keyword pythonExClass UnboundLocalError UnicodeError syn keyword pythonExClass UnicodeEncodeError UnicodeDecodeError - syn keyword pythonExClass UnicodeTranslateError ValueError VMSError + syn keyword pythonExClass UnicodeTranslateError ValueError + syn keyword pythonExClass ZeroDivisionError EnvironmentError IOError + syn keyword pythonExClass WindowsError syn keyword pythonExClass BlockingIOError ChildProcessError ConnectionError syn keyword pythonExClass BrokenPipeError ConnectionAbortedError syn keyword pythonExClass ConnectionRefusedError ConnectionResetError syn keyword pythonExClass FileExistsError FileNotFoundError InterruptedError syn keyword pythonExClass IsADirectoryError NotADirectoryError PermissionError syn keyword pythonExClass ProcessLookupError TimeoutError - syn keyword pythonExClass WindowsError ZeroDivisionError - syn keyword pythonExClass Warning UserWarning BytesWarning DeprecationWarning - syn keyword pythonExClass PendingDepricationWarning SyntaxWarning - syn keyword pythonExClass RuntimeWarning FutureWarning - syn keyword pythonExClass ImportWarning UnicodeWarning + syn keyword pythonExClass Warning UserWarning DeprecationWarning PendingDeprecationWarning + syn keyword pythonExClass SyntaxWarning RuntimeWarning FutureWarning + syn keyword pythonExClass ImportWarning UnicodeWarning EncodingWarning + syn keyword pythonExClass BytesWarning ResourceWarning endif " }}} diff --git a/tests/test.sh b/tests/test.sh index b7747308..1e750e5c 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -1,10 +1,11 @@ #! /bin/bash +# We don't want to exit on the first error that appears +set +e # Check before starting. -set -e which vim 1>/dev/null 2>/dev/null -cd $(dirname $0) +cd "$(dirname "$0")" # Source common variables. source ./test_helpers_bash/test_variables.sh @@ -15,44 +16,49 @@ source ./test_helpers_bash/test_prepare_once.sh # Initialize permanent files.. source ./test_helpers_bash/test_createvimrc.sh +TESTS=( + test_bash/test_autopep8.sh + test_bash/test_autocommands.sh + # test_bash/test_folding.sh + test_bash/test_pymodelint.sh + test_bash/test_textobject.sh +) + # Execute tests. -declare -a TEST_ARRAY=( - "./test_bash/test_autopep8.sh" - "./test_bash/test_autocommands.sh" - "./test_bash/test_folding.sh" - ) +MAIN_RETURN=0 ## now loop through the above array -set +e -for ONE_TEST in "${TEST_ARRAY[@]}" +for TEST in "${TESTS[@]}"; do - echo "Starting test: $ONE_TEST" >> $VIM_OUTPUT_FILE - bash -x "$ONE_TEST" - echo -e "\n$ONE_TEST: Return code: $?" >> $VIM_OUTPUT_FILE - bash ./test_helpers_bash/test_prepare_between_tests.sh + source ./test_helpers_bash/test_prepare_between_tests.sh + echo "Starting test: ${TEST##*/}" | tee -a "${VIM_OUTPUT_FILE}" + bash "$(pwd)/${TEST}" + R=$? + MAIN_RETURN=$(( MAIN_RETURN + R )) + echo -e " ${TEST##*/}: Return code: ${R}\n" | tee -a "${VIM_OUTPUT_FILE}" done -# Show errors: -E1=$(grep -E "^E[0-9]+:" $VIM_OUTPUT_FILE) -E2=$(grep -E "^Error" $VIM_OUTPUT_FILE) -E3="$E1\n$E2" -if [ "$E3" = "\n" ] -then - echo "No errors." -else - echo "Errors:" - echo -e "$E3\n" +if [ -f "${VIM_DISPOSABLE_PYFILE}" ]; then + rm "${VIM_DISPOSABLE_PYFILE}" fi +echo "=========================================================================" +echo " RESULTS" +echo "=========================================================================" + # Show return codes. -RETURN_CODES=$(cat $VIM_OUTPUT_FILE | grep -i "Return code") +RETURN_CODES=$(grep -i "Return code" < "${VIM_OUTPUT_FILE}" | grep -v "Return code: 0") echo -e "${RETURN_CODES}" -# Exit the script with error if there are any return codes different from 0. -if echo $RETURN_CODES | grep -E "Return code: [1-9]" 1>/dev/null 2>/dev/null -then - exit 1 +# Show errors: +E1=$(grep -E "^E[0-9]+:" "${VIM_OUTPUT_FILE}") +E2=$(grep -Ei "^Error" "${VIM_OUTPUT_FILE}") +if [[ "${MAIN_RETURN}" == "0" ]]; then + echo "No errors." else - exit 0 + echo "Errors:" + echo -e " ${E1}\n ${E2}" fi +# Exit the script with error if there are any return codes different from 0. +exit ${MAIN_RETURN} # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_bash/test_autocommands.sh b/tests/test_bash/test_autocommands.sh index 13708c30..4946f4d1 100644 --- a/tests/test_bash/test_autocommands.sh +++ b/tests/test_bash/test_autocommands.sh @@ -3,32 +3,40 @@ # TODO XXX: improve python-mode testing asap. # Test all python commands. -# Execute tests. -declare -a TEST_PYMODE_COMMANDS_ARRAY=( - "./test_procedures_vimscript/pymodeversion.vim" - "./test_procedures_vimscript/pymodelint.vim" - "./test_procedures_vimscript/pymoderun.vim" - ) - -### Enable the following to execute one test at a time. -### FOR PINPOINT TESTING ### declare -a TEST_PYMODE_COMMANDS_ARRAY=( -### FOR PINPOINT TESTING ### "./test_procedures_vimscript/pymoderun.vim" -### FOR PINPOINT TESTING ### ) - -## now loop through the above array -set +e -for ONE_PYMODE_COMMANDS_TEST in "${TEST_PYMODE_COMMANDS_ARRAY[@]}" -do - echo "Starting test: $0:$ONE_PYMODE_COMMANDS_TEST" >> $VIM_OUTPUT_FILE - RETURN_CODE=$(vim -i NONE -u $VIM_TEST_VIMRC -c "source $ONE_PYMODE_COMMANDS_TEST" $VIM_DISPOSABLE_PYFILE > /dev/null 2>&1) +function test_autocommands() { + # Execute tests. + declare -a TEST_PYMODE_COMMANDS_ARRAY=( + "./test_procedures_vimscript/pymodeversion.vim" + "./test_procedures_vimscript/pymodelint.vim" + "./test_procedures_vimscript/pymoderun.vim" + ) ### Enable the following to execute one test at a time. - ### FOR PINPOINT TESTING ### vim -i NONE -u $VIM_TEST_VIMRC -c "source $ONE_PYMODE_COMMANDS_TEST" $VIM_DISPOSABLE_PYFILE - ### FOR PINPOINT TESTING ### exit 1 + ### FOR PINPOINT TESTING ### declare -a TEST_PYMODE_COMMANDS_ARRAY=( + ### FOR PINPOINT TESTING ### "./test_procedures_vimscript/pymoderun.vim" + ### FOR PINPOINT TESTING ### ) - RETURN_CODE=$? - echo -e "\n$0:$ONE_PYMODE_COMMANDS_TEST: Return code: $RETURN_CODE" >> $VIM_OUTPUT_FILE - bash ./test_helpers_bash/test_prepare_between_tests.sh -done + RETURN_CODE=0 + ## now loop through the above array + for ONE_PYMODE_COMMANDS_TEST in "${TEST_PYMODE_COMMANDS_ARRAY[@]}" + do + CONTENT="$(${VIM_BINARY:-vim} --not-a-term --clean -i NONE -u "${VIM_TEST_VIMRC}" -c "source ${ONE_PYMODE_COMMANDS_TEST}" "${VIM_DISPOSABLE_PYFILE}" 2>&1)" + + ### Enable the following to execute one test at a time. + ### FOR PINPOINT TESTING ### vim --clean -i NONE -u $VIM_TEST_VIMRC -c "source $ONE_PYMODE_COMMANDS_TEST" $VIM_DISPOSABLE_PYFILE + ### FOR PINPOINT TESTING ### exit 1 + + SUB_TEST_RETURN_CODE=$? + echo -e "${CONTENT}" >> "${VIM_OUTPUT_FILE}" + RETURN_CODE=$(( RETURN_CODE + SUB_TEST_RETURN_CODE )) + echo -e "\tSubTest: $0:${ONE_PYMODE_COMMANDS_TEST}: Return code: ${SUB_TEST_RETURN_CODE}" | tee -a "${VIM_OUTPUT_FILE}" + bash ./test_helpers_bash/test_prepare_between_tests.sh + done + + return ${RETURN_CODE} +} +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + test_autocommands +fi # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_bash/test_autopep8.sh b/tests/test_bash/test_autopep8.sh index eae173f3..dc428f9b 100644 --- a/tests/test_bash/test_autopep8.sh +++ b/tests/test_bash/test_autopep8.sh @@ -1,10 +1,13 @@ #! /bin/bash -# Source file. -set +e -RETURN_CODE=$(vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/autopep8.vim" $VIM_DISPOSABLE_PYFILE > /dev/null 2>&1) -RETURN_CODE=$? -set -e -exit $RETURN_CODE - +function test_autopep8() { + # Source file. + TEST_PROCEDURE="$(pwd)/test_procedures_vimscript/autopep8.vim" + CONTENT="$(${VIM_BINARY:-vim} --not-a-term --clean -i NONE -u "${VIM_TEST_VIMRC}" -c "source ${TEST_PROCEDURE}" "${VIM_DISPOSABLE_PYFILE}" 2>&1)" + RETURN_CODE=$? + return ${RETURN_CODE} +} +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + test_autopep8 +fi # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_bash/test_folding.sh b/tests/test_bash/test_folding.sh index 2902ef8d..c2704b59 100644 --- a/tests/test_bash/test_folding.sh +++ b/tests/test_bash/test_folding.sh @@ -2,35 +2,28 @@ # Note: a solution with unix 'timeout' program was tried but it was unsuccessful. The problem with folding 4 is that in the case of a crash one expects the folding to just stay in an infinite loop, thus never existing with error. An improvement is suggested to this case. -# Source file. -set +e -source ./test_helpers_bash/test_prepare_between_tests.sh -vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/folding1.vim" $VIM_DISPOSABLE_PYFILE > /dev/null -R1=$? -source ./test_helpers_bash/test_prepare_between_tests.sh -vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/folding2.vim" $VIM_DISPOSABLE_PYFILE > /dev/null -R2=$? -source ./test_helpers_bash/test_prepare_between_tests.sh -# TODO: enable folding3.vim script back. -# vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/folding3.vim" $VIM_DISPOSABLE_PYFILE > /dev/null -# R3=$? -source ./test_helpers_bash/test_prepare_between_tests.sh -vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/folding4.vim" $VIM_DISPOSABLE_PYFILE > /dev/null -R4=$? -set -e +function test_folding() { + declare -a TEST_PYMODE_FOLDING_TESTS_ARRAY=( + "test_procedures_vimscript/folding1.vim" + "test_procedures_vimscript/folding2.vim" + # "test_procedures_vimscript/folding3.vim" + "test_procedures_vimscript/folding4.vim" + ) -if [[ "$R1" -ne 0 ]] -then - exit 1 -elif [[ "$R2" -ne 0 ]] -then - exit 2 -# elif [[ "$R3" -ne 0 ]] -# then -# exit 3 -elif [[ "$R4" -ne 0 ]] -then - exit 4 -fi + RETURN_CODE=0 + + for SUB_TEST in "${TEST_PYMODE_FOLDING_TESTS_ARRAY[@]}"; do + CONTENT="$(${VIM_BINARY:-vim} --not-a-term --clean -i NONE -u "${VIM_TEST_VIMRC}" -c "source $(pwd)/tests/${SUB_TEST}" "${VIM_DISPOSABLE_PYFILE}" 2>&1)" + SUB_TEST_RETURN_CODE=$? + echo -e "${CONTENT}" >> "${VIM_OUTPUT_FILE}" + RETURN_CODE=$(( RETURN_CODE + SUB_TEST_RETURN_CODE )) + echo -e "\tSubTest: $0:${SUB_TEST}: Return code: ${SUB_TEST_RETURN_CODE}" | tee -a "${VIM_OUTPUT_FILE}" + bash ./test_helpers_bash/test_prepare_between_tests.sh + done + return ${RETURN_CODE} +} +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + test_folding +fi # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_bash/test_pymodelint.sh b/tests/test_bash/test_pymodelint.sh index cf8d626d..3d47d6d3 100644 --- a/tests/test_bash/test_pymodelint.sh +++ b/tests/test_bash/test_pymodelint.sh @@ -3,12 +3,15 @@ # TODO XXX: improve python-mode testing asap. # Test all python commands. -# Source file. -set +e -vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/pymodelint.vim" $VIM_DISPOSABLE_PYFILE -# RETURN_CODE=$(vim -i NONE -u $VIM_TEST_VIMRC -c "source ./test_procedures_vimscript/pymodeversion.vim" $VIM_DISPOSABLE_PYFILE > /dev/null 2>&1) -# RETURN_CODE=$? -set -e -# exit $RETURN_CODE +function test_pymodelint() { + # Source file. + CONTENT="$(${VIM_BINARY:-vim} --not-a-term --clean -i NONE -u "${VIM_TEST_VIMRC}" -c "source ./test_procedures_vimscript/pymodelint.vim" "${VIM_DISPOSABLE_PYFILE}" 2>&1)" + RETURN_CODE=$? + echo -e "${CONTENT}" >> "${VIM_OUTPUT_FILE}" + return ${RETURN_CODE} +} +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + test_pymodelint +fi # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_bash/test_textobject.sh b/tests/test_bash/test_textobject.sh new file mode 100644 index 00000000..6a76f97b --- /dev/null +++ b/tests/test_bash/test_textobject.sh @@ -0,0 +1,16 @@ +#! /bin/bash + +function test_textobject() { + # Source file. + # shellcheck source=../test_helpers_bash/test_prepare_between_tests.sh + source ./test_helpers_bash/test_prepare_between_tests.sh + CONTENT="$(${VIM_BINARY:-vim} --not-a-term --clean -i NONE -u "${VIM_TEST_VIMRC}" -c "source ./test_procedures_vimscript/textobject.vim" "${VIM_DISPOSABLE_PYFILE}" 2>&1)" + RETURN_CODE=$? + echo -e "${CONTENT}" >> "${VIM_OUTPUT_FILE}" + + return ${RETURN_CODE} +} +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + test_textobject +fi +# vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_helpers_bash/test_createvimrc.sh b/tests/test_helpers_bash/test_createvimrc.sh index ae763b95..23ca2881 100644 --- a/tests/test_helpers_bash/test_createvimrc.sh +++ b/tests/test_helpers_bash/test_createvimrc.sh @@ -1,26 +1,27 @@ #! /bin/bash # Create minimal vimrc. -echo -e "syntax on\nfiletype plugin indent on\nset nocompatible" >> $VIM_TEST_VIMRC -echo "call has('python3')" >> $VIM_TEST_VIMRC -echo "set paste" >> $VIM_TEST_VIMRC -echo "set shortmess=at" >> $VIM_TEST_VIMRC -echo "set cmdheight=10" >> $VIM_TEST_VIMRC -echo "set ft=python" >> $VIM_TEST_VIMRC -echo "set shell=bash" >> $VIM_TEST_VIMRC -echo "set noswapfile" >> $VIM_TEST_VIMRC -echo "set backupdir=" >> $VIM_TEST_VIMRC -echo "set undodir=" >> $VIM_TEST_VIMRC -echo "set viewdir=" >> $VIM_TEST_VIMRC -echo "set directory=" >> $VIM_TEST_VIMRC -echo -e "set runtimepath=" >> $VIM_TEST_VIMRC -echo -e "set runtimepath+=$(dirname $PWD)\n" >> $VIM_TEST_VIMRC -echo -e "set packpath+=/tmp\n" >> $VIM_TEST_VIMRC -# echo -e "redir! >> $VIM_OUTPUT_FILE\n" >> $VIM_TEST_VIMRC -echo -e "set verbosefile=$VIM_OUTPUT_FILE\n" >> $VIM_TEST_VIMRC -echo -e "let g:pymode_debug = 1" >> $VIM_TEST_VIMRC - -echo "set nomore" >> $VIM_TEST_VIMRC - - +cat <<-EOF >> "${VIM_TEST_VIMRC}" + " redir! >> "${VIM_OUTPUT_FILE}" + call has('python3') + filetype plugin indent on + let g:pymode_debug = 1 + set backupdir= + set cmdheight=10 + set directory= + set ft=python + set nocompatible + set nomore + set noswapfile + set packpath+=/tmp + set paste + set runtimepath+="$(dirname "${PWD}")" + set runtimepath= + set shell=bash + set shortmess=at + set undodir= + set verbosefile="${VIM_OUTPUT_FILE}" + set viewdir= + syntax on +EOF # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_helpers_bash/test_prepare_between_tests.sh b/tests/test_helpers_bash/test_prepare_between_tests.sh index cdce9869..ee7cbecb 100644 --- a/tests/test_helpers_bash/test_prepare_between_tests.sh +++ b/tests/test_helpers_bash/test_prepare_between_tests.sh @@ -1,12 +1,11 @@ #! /bin/bash # Prepare tests. -set +e -if [ -f $VIM_DISPOSABLE_PYFILE ]; then - rm $VIM_DISPOSABLE_PYFILE +if [ -f "${VIM_DISPOSABLE_PYFILE}" ]; then + rm "${VIM_DISPOSABLE_PYFILE}" fi -export VIM_DISPOSABLE_PYFILE=`mktemp /tmp/pymode.tmpfile.XXXXXXXXXX.py` -set -e -touch $VIM_DISPOSABLE_PYFILE +VIM_DISPOSABLE_PYFILE="/tmp/pymode.tmpfile.$(date +%s).py" +export VIM_DISPOSABLE_PYFILE -# vim: set fileformat=unix filetype=sh wrap tw=0 : +touch "${VIM_DISPOSABLE_PYFILE}" +# vim: set fileformat=unix filetype=sh wrap tw=0 : \ No newline at end of file diff --git a/tests/test_helpers_bash/test_prepare_once.sh b/tests/test_helpers_bash/test_prepare_once.sh index dad77182..dcbfd150 100644 --- a/tests/test_helpers_bash/test_prepare_once.sh +++ b/tests/test_helpers_bash/test_prepare_once.sh @@ -1,12 +1,10 @@ #! /bin/bash # Prepare tests. -set +e -rm $VIM_OUTPUT_FILE $VIM_TEST_VIMRC $VIM_TEST_PYMODECOMMANDS $VIM_DISPOSABLE_PYFILE 2&>/dev/null +rm "${VIM_OUTPUT_FILE}" "${VIM_TEST_VIMRC}" "${VIM_TEST_PYMODECOMMANDS}" "${VIM_DISPOSABLE_PYFILE}" 2&>/dev/null rm /tmp/*pymode* 2&>/dev/null rm -rf /tmp/pack mkdir -p /tmp/pack/test_plugins/start -ln -s $(dirname $(pwd)) /tmp/pack/test_plugins/start/ -set -e +ln -s "$(dirname "$(pwd)")" /tmp/pack/test_plugins/start/ # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_helpers_bash/test_variables.sh b/tests/test_helpers_bash/test_variables.sh index 53edb5e5..f1995022 100644 --- a/tests/test_helpers_bash/test_variables.sh +++ b/tests/test_helpers_bash/test_variables.sh @@ -3,9 +3,13 @@ # Define variables for common test scripts. # Set variables. -export VIM_DISPOSABLE_PYFILE=`mktemp /tmp/pymode.tmpfile.XXXXXXXXXX.py` -export VIM_OUTPUT_FILE=/tmp/pymode.out -export VIM_TEST_VIMRC=/tmp/pymode_vimrc -export VIM_TEST_PYMODECOMMANDS=/tmp/pymode_commands.txt +VIM_DISPOSABLE_PYFILE="$(mktemp /tmp/pymode.tmpfile.XXXXXXXXXX.py)" +export VIM_DISPOSABLE_PYFILE +VIM_OUTPUT_FILE=/tmp/pymode.out +export VIM_OUTPUT_FILE +VIM_TEST_VIMRC=/tmp/pymode_vimrc +export VIM_TEST_VIMRC +VIM_TEST_PYMODECOMMANDS=/tmp/pymode_commands.txt +export VIM_TEST_PYMODECOMMANDS # vim: set fileformat=unix filetype=sh wrap tw=0 : diff --git a/tests/test_procedures_vimscript/textobject.vim b/tests/test_procedures_vimscript/textobject.vim new file mode 100644 index 00000000..cbd4ef05 --- /dev/null +++ b/tests/test_procedures_vimscript/textobject.vim @@ -0,0 +1,83 @@ +set noautoindent +let g:pymode_rope=1 + +" Load sample python file. +" With 'def'. +execute "normal! idef func1():\ a = 1\" +execute "normal! idef func2():\ b = 2" +normal 3ggdaMggf(P + +" Assert changes. +let content=getline('^', '$') +call assert_true(content == ['def func2():', ' b = 2', 'def func1():', ' a = 1']) + + +" Clean file. +%delete + +" With 'class'. +execute "normal! iclass Class1():\ a = 1\" +execute "normal! iclass Class2():\ b = 2\" +normal 3ggdaCggf(P + +" Assert changes. +let content=getline('^', '$') +call assert_true(content == ['class Class2():', ' b = 2', '', 'class Class1():', ' a = 1']) + + +" Clean file. +%delete + +" With 'def'. +execute "normal! iprint(\ 1\)\" +execute "normal! iprint(\ 2\)\" +execute "normal! iprint(\ 3\)\" +normal 4ggdV + +let content=getline('^', '$') +call assert_true(content == [ +\ "print(", " 1", ")", +\ "print(", " 3", ")", +\ "" +\]) + + +" Clean file. +%delete + +" With 'def'. +execute "normal! iprint(\ 1\)\" +execute "normal! iprint(\ 2\)\" +execute "normal! iprint(\ 3\)\" +execute "normal! iprint(\ 4\)\" +normal 5ggd2V + +let content=getline('^', '$') +call assert_true(content == [ +\ "print(", " 1", ")", +\ "print(", " 4", ")", +\ "" +\]) + +" Clean file. +%delete + +" With 'def'. +execute "normal! iprint(\ 1\)\" +execute "normal! iprint(\ 2\)\" +execute "normal! iprint(\ 3\)\" +execute "normal! iprint(\ 4\)\" +normal 5ggd2V + +let content=getline('^', '$') +call assert_true(content == [ +\ "print(", " 1", ")", +\ "print(", " 4", ")", +\ "" +\]) + +if len(v:errors) > 0 + cquit! +else + quit! +endif diff --git a/tests/utils/pymoderc b/tests/utils/pymoderc index 222c6ceb..3a8477ea 100644 --- a/tests/utils/pymoderc +++ b/tests/utils/pymoderc @@ -25,7 +25,7 @@ let g:pymode_lint_on_write = 1 let g:pymode_lint_unmodified = 0 let g:pymode_lint_on_fly = 0 let g:pymode_lint_message = 1 -let g:pymode_lint_checkers = ['pyflakes', 'pep8', 'mccabe'] +let g:pymode_lint_checkers = ['pyflakes', 'pycodestyle', 'mccabe'] let g:pymode_lint_ignore = ["E501", "W",] let g:pymode_lint_select = ["E501", "W0011", "W430"] let g:pymode_lint_sort = [] @@ -37,7 +37,7 @@ let g:pymode_lint_visual_symbol = 'RR' let g:pymode_lint_error_symbol = 'EE' let g:pymode_lint_info_symbol = 'II' let g:pymode_lint_pyflakes_symbol = 'FF' -let g:pymode_lint_options_pep8 = +let g:pymode_lint_options_pycodestyle = \ {'max_line_length': g:pymode_options_max_line_length} let g:pymode_lint_options_pyflakes = { 'builtins': '_' } let g:pymode_lint_options_mccabe = { 'complexity': 12 } diff --git a/tests/utils/vimrc b/tests/utils/vimrc index 6920a0bb..2343d9d7 100644 --- a/tests/utils/vimrc +++ b/tests/utils/vimrc @@ -1,22 +1,37 @@ source /root/.vimrc.before source /root/.pymoderc -syntax on +" redir! >> "${VIM_OUTPUT_FILE}" +"set backspace=indent,eol,start +"set expandtab +"set mouse= " disable mouse +"set shiftround " always round indentation to shiftwidth +"set shiftwidth=4 " default to two spaces +"set smartindent " smart indenting +"set softtabstop=4 " default to two spaces +"set tabstop=4 " default to two spaces +"set term=xterm-256color +"set wrap " visually wrap lines +call has('python3') filetype plugin indent on -set shortmess=at +let g:pymode_debug = 1 +set backupdir= set cmdheight=10 +set directory= set ft=python -set shell=bash +set nocompatible +set nomore +set noswapfile +set packpath+=/tmp +set paste set rtp+=/root/.vim/pack/foo/start/python-mode -set term=xterm-256color -set wrap " visually wrap lines -set smartindent " smart indenting -set shiftwidth=4 " default to two spaces -set tabstop=4 " default to two spaces -set softtabstop=4 " default to two spaces -set shiftround " always round indentation to shiftwidth -set mouse= " disable mouse -set expandtab -set backspace=indent,eol,start +set runtimepath+="$(dirname "${PWD}")" +set runtimepath= +set shell=bash +set shortmess=at +set undodir= +set verbosefile="${VIM_OUTPUT_FILE}" +set viewdir= +syntax on source /root/.vimrc.after pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy