diff --git a/.circleci/config.yml b/.circleci/config.yml index 1f0ff779..c0b9caf1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -48,7 +48,7 @@ test-tmpl: &test-tmpl job-tmpl: &job-tmpl machine: - image: ubuntu-2004:edge + image: ubuntu-2204:current working_directory: /home/circleci/src @@ -288,6 +288,7 @@ workflows: - "python3.11" - "python3.12" - "python3.13" + - "python3.14" - pypi-release: requires: - python-ubuntu diff --git a/CHANGES.md b/CHANGES.md index e7d7ce3e..d4e31813 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,16 @@ -## Changelog +# Changelog + +### 1.9.0 + +* All: Update `make test` runner to use `pytest` instead of deprecated `setup.py test` +* All: Build wheel and sdist using `python -m build` +* pytest-server-fixtures: Update deprecated mongo 7.* to 8.2 +* pytest-profile: add support for `cProfile` regex to filter output +* pytest-profile: update README.md args +* pytest-virtualenv: fix: Install local dir to virtualenv in later py3 +* ci: fix py3.7-3.14 ubuntu +* ci: Update support in tests for py3.7-14 for ubuntu 22.04 + ### 1.8.1 (2024-11-29) * All: Add a CircleCI Windows build with py3.6-py3.12 and remove references to TravisCI. (#246) * All: Add Ubuntu builds for py3.6-3.13 diff --git a/Makefile b/Makefile index 0e8ed168..ea104b02 100644 --- a/Makefile +++ b/Makefile @@ -30,18 +30,16 @@ copyfiles: ./foreach.sh 'for file in ${COPY_FILES}; do cp ../$$file .; done' wheels: copyfiles - pip install ${PIP_INSTALL_ARGS} -U wheel - ./foreach.sh --changed 'python setup.py bdist_wheel' + pip install ${PIP_INSTALL_ARGS} -U wheel build + ./foreach.sh --changed 'python -m build --wheel' eggs: copyfiles ./foreach.sh --changed 'python setup.py bdist_egg' sdists: copyfiles - ./foreach.sh --changed 'python setup.py sdist' + ./foreach.sh --changed 'python -m build --sdist' -install: copyfiles - pip install ${PIP_INSTALL_ARGS} -U wheel - ./foreach.sh 'python setup.py bdist_wheel' +install: copyfiles wheels ./foreach.sh 'pip install ${PIP_INSTALL_ARGS} dist/*.whl' develop: copyfiles extras @@ -49,7 +47,7 @@ develop: copyfiles extras test: rm -f FAILED-* - ./foreach.sh 'DEBUG=1 python setup.py test -sv -ra || touch ../FAILED-$$PKG' + ./foreach.sh 'DEBUG=1 python -m pytest -sv -ra || touch ../FAILED-$$PKG' bash -c "! compgen -G 'FAILED-*'" test-ci: diff --git a/VERSION b/VERSION index a8fdfda1..4803a466 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.8.1 +1.8.1.dev7+geee537a diff --git a/install.sh b/install.sh index 5e448f2a..c1af597f 100644 --- a/install.sh +++ b/install.sh @@ -28,28 +28,33 @@ function install_python_ppa { function install_python_packaging { local py=$1 $py -m pip install --upgrade pip - $py -m pip install --upgrade setuptools + $py -m pip install --upgrade setuptools wheel + $py -m pip install --upgrade packaging $py -m pip install --upgrade virtualenv } function install_python { local py=$1 - sudo apt-get install -y $py $py-dev + sudo apt-get install -y $py local version=$(echo $py | grep -oP '(?<=python)\d+\.\d+') - - if [ "$version" = "3.6" ] || [ "$version" = "3.7" ]; then - sudo apt-get install ${py}-distutils || { - curl --silent --show-error --retry 5 https://bootstrap.pypa.io/pip/$version/get-pip.py | sudo $py - sudo $py -m pip install setuptools - } - elif [ "$version" = "3.10" ] || [ "$version" = "3.11" ] || [ "$version" = "3.12" ]; then - sudo apt-get install ${py}-distutils - curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | sudo $py - else - sudo apt-get install ${py} - curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | sudo $py - fi + case $version in + "3.6" | "3.7" | "3.8" | "3.9" ) + sudo apt-get install -y $py-distutils + ;; + *) + echo "" + ;; + esac + + case $version in + "3.6" | "3.7" | "3.8" ) + curl --silent --show-error --retry 5 https://bootstrap.pypa.io/pip/$version/get-pip.py | sudo $py + ;; + *) + curl --silent --show-error --retry 5 https://bootstrap.pypa.io/get-pip.py | sudo $py + ;; + esac install_python_packaging $py } @@ -92,7 +97,7 @@ function install_windows_python() { function init_venv { local py=$1 - virtualenv venv --python=$py + $py -m virtualenv venv if [ -f venv/Scripts/activate ]; then . venv/Scripts/activate else @@ -106,11 +111,13 @@ function update_apt_sources { curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | gpg --dearmor -o /usr/share/keyrings/jenkins-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/jenkins-archive-keyring.gpg] https://pkg.jenkins.io/debian-stable binary/" | tee /etc/apt/sources.list.d/jenkins.list > /dev/null - # Add MongoDB GPG key and repository - curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \ - sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \ - --dearmor - echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list + MONGODB_MAJOR="8.0" + MONGODB_MINOR="8.2" + curl -fsSL https://www.mongodb.org/static/pgp/server-${MONGODB_MAJOR}.asc | \ + gpg -o /usr/share/keyrings/mongodb-server-${MONGODB_MAJOR}.gpg \ + --dearmor + echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-${MONGODB_MAJOR}.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/${MONGODB_MINOR} multiverse" | tee /etc/apt/sources.list.d/mongodb-org-${MONGODB_MINOR}.list + apt install ca-certificates apt-get update @@ -145,7 +152,7 @@ function install_jenkins { } function install_mongodb { - apt-get install -y mongodb mongodb-server + apt-get install -y mongodb-org } function install_apache { diff --git a/pytest-profiling/README.md b/pytest-profiling/README.md index 967a0949..152ed381 100644 --- a/pytest-profiling/README.md +++ b/pytest-profiling/README.md @@ -16,7 +16,7 @@ Install using your favourite package installer: # or easy_install pytest-profiling ``` - + Enable the fixture explicitly in your tests or conftest.py (not required when using setuptools entry points): ```python @@ -31,9 +31,17 @@ Once installed, the plugin provides extra options to pytest: $ py.test --help ... Profiling: - --profile generate profiling information - --profile-svg generate profiling graph (using gprof2dot and dot - -Tsvg) + --profile generate profiling information + --profile-svg generate profiling graph (using gprof2dot and dot -Tsvg) + --pstats-dir=PSTATS_DIR + configure the dump directory of profile data files + --element-number=ELEMENT_NUMBER + defines how many elements will display in a result + --profile-element-regex=ELEMENT_REGEX + filters elements displayed using regex + --strip-dirs configure to show/hide the leading path information from + file names + ``` The ``--profile`` and ``profile-svg`` options can be combined with any other option: diff --git a/pytest-profiling/pytest_profiling.py b/pytest-profiling/pytest_profiling.py index a7b38ad0..8646a655 100644 --- a/pytest-profiling/pytest_profiling.py +++ b/pytest-profiling/pytest_profiling.py @@ -31,11 +31,12 @@ class Profiling(object): dot_cmd = None gprof2dot_cmd = None - def __init__(self, svg, dir=None, element_number=20, stripdirs=False): + def __init__(self, svg, dir=None, element_number=20, stripdirs=False, element_regex=None): self.svg = svg self.dir = 'prof' if dir is None else dir[0] self.stripdirs = stripdirs self.element_number = element_number + self.element_regex = element_regex self.profs = [] self.gprof2dot = os.path.abspath(os.path.join(os.path.dirname(sys.executable), 'gprof2dot')) if not os.path.isfile(self.gprof2dot): @@ -98,7 +99,12 @@ def pytest_terminal_summary(self, terminalreporter): stats = pstats.Stats(self.combined, stream=terminalreporter) if self.stripdirs: stats.strip_dirs() - stats.sort_stats('cumulative').print_stats(self.element_number) + if self.element_regex: + print_args = self.element_regex, self.element_number + else: + print_args = (self.element_number,) + stats.sort_stats('cumulative') + stats.print_stats(*print_args) if self.svg_name: if not self.exit_code: # 0 - SUCCESS @@ -144,6 +150,8 @@ def pytest_addoption(parser): help="generate profiling graph (using gprof2dot and dot -Tsvg)") group.addoption("--pstats-dir", nargs=1, help="configure the dump directory of profile data files") + group.addoption("--profile-element-regex", type=str, default=None, + help="filters elements displayed using regex") group.addoption("--element-number", action="store", type=int, default=20, help="defines how many elements will display in a result") group.addoption("--strip-dirs", action="store_true", @@ -157,4 +165,5 @@ def pytest_configure(config): config.pluginmanager.register(Profiling(config.getvalue('profile_svg'), config.getvalue('pstats_dir'), element_number=config.getvalue('element_number'), - stripdirs=config.getvalue('strip_dirs'))) + stripdirs=config.getvalue('strip_dirs'), + element_regex=config.getvalue('profile_element_regex'))) diff --git a/pytest-profiling/tests/integration/profile/tests/unit/test_regex.py b/pytest-profiling/tests/integration/profile/tests/unit/test_regex.py new file mode 100644 index 00000000..6d62ff63 --- /dev/null +++ b/pytest-profiling/tests/integration/profile/tests/unit/test_regex.py @@ -0,0 +1,6 @@ +import os + + +def test_regex(): + os.makedirs("bar", exist_ok=True) + os.chdir("bar") diff --git a/pytest-profiling/tests/integration/test_profile_integration.py b/pytest-profiling/tests/integration/test_profile_integration.py index dddbafac..4cb039fc 100644 --- a/pytest-profiling/tests/integration/test_profile_integration.py +++ b/pytest-profiling/tests/integration/test_profile_integration.py @@ -69,3 +69,17 @@ def test_profile_chdir(pytestconfig, virtualenv): pytestconfig, cd=virtualenv.workspace, ) + + +def test_profile_limited_output(pytestconfig, virtualenv): + element_args = ["--element-number=2", r'--profile-element-regex=.*(test_regex|makedirs).*'] + # element_args = ["--element-number=100"] + print(["-m", "pytest", "--profile", *element_args, "tests/unit/test_regex.py"]) + output = virtualenv.run_with_coverage( + ["-m", "pytest", "--profile", *element_args, "tests/unit/test_regex.py"], + pytestconfig, + cd=virtualenv.workspace, + ) + assert "test_regex.py:4(test_regex)" in output + assert "makedirs" in output + assert "chdir" not in output diff --git a/pytest-profiling/tests/unit/test_profile.py b/pytest-profiling/tests/unit/test_profile.py index 1705ad75..b41ef71f 100644 --- a/pytest-profiling/tests/unit/test_profile.py +++ b/pytest-profiling/tests/unit/test_profile.py @@ -101,6 +101,10 @@ def test_adds_options(): group = parser.getgroup.return_value group.addoption.assert_any_call("--profile", action="store_true", help=ANY) group.addoption.assert_any_call("--profile-svg", action="store_true", help=ANY) + group.addoption.assert_any_call("--pstats-dir", nargs=1, help=ANY) + group.addoption.assert_any_call("--profile-element-regex", type=str, default=None, help=ANY) + group.addoption.assert_any_call("--element-number", action="store", type=int, default=20, help=ANY) + group.addoption.assert_any_call("--strip-dirs", action="store_true", help=ANY) def test_configures(): diff --git a/pytest-server-fixtures/pytest_server_fixtures/mongo.py b/pytest-server-fixtures/pytest_server_fixtures/mongo.py index dd6d9129..9b29b34e 100644 --- a/pytest-server-fixtures/pytest_server_fixtures/mongo.py +++ b/pytest-server-fixtures/pytest_server_fixtures/mongo.py @@ -89,7 +89,6 @@ def get_args(self, **kwargs): '--port=%s' % self.port, '--nounixsocket', '--syncdelay=0', - '--nojournal', '--quiet', ] diff --git a/pytest-virtualenv/pytest_virtualenv.py b/pytest-virtualenv/pytest_virtualenv.py index 92574543..53a3814f 100644 --- a/pytest-virtualenv/pytest_virtualenv.py +++ b/pytest-virtualenv/pytest_virtualenv.py @@ -210,11 +210,7 @@ def install_package(self, pkg_name, version=PackageVersion.LATEST, installer="pi installer += ' -q' if version == PackageVersion.LATEST: - self.run( - "{python} {installer} {installer_command} {spec}".format( - python=self.python, installer=installer, installer_command=installer_command, spec=pkg_name - ) - ) + spec = pkg_name elif version == PackageVersion.CURRENT: dist = next( iter([dist for dist in distributions() if _normalize(dist.name) == _normalize(pkg_name)]), None @@ -225,31 +221,22 @@ def install_package(self, pkg_name, version=PackageVersion.LATEST, installer="pi ) egg_link = _get_egg_link(dist.name) if pkg_location: - self.run( - f"{self.python} {installer} {installer_command} -e {pkg_location}" - ) + spec = f" -e {pkg_location}" elif egg_link: self._install_package_from_editable_egg_link(egg_link, dist) + return else: - spec = "{pkg_name}=={version}".format(pkg_name=pkg_name, version=dist.version) - self.run( - "{python} {installer} {installer_command} {spec}".format( - python=self.python, installer=installer, installer_command=installer_command, spec=spec - ) - ) + setup_files = ["pyproject.toml", "setup.py"] + if any(os.path.exists(dist.locate_file(f)) for f in setup_files): + spec = dist.locate_file("") + else: + spec = f"{pkg_name}=={dist.version}" else: - self.run( - "{python} {installer} {installer_command} {spec}".format( - python=self.python, installer=installer, installer_command=installer_command, spec=pkg_name - ) - ) + spec = pkg_name else: - spec = "{pkg_name}=={version}".format(pkg_name=pkg_name, version=version) - self.run( - "{python} {installer} {installer_command} {spec}".format( - python=self.python, installer=installer, installer_command=installer_command, spec=spec - ) - ) + spec = f"{pkg_name}=={version}" + cmd = f"{self.python} {installer} {installer_command} {spec}" + self.run(cmd) def installed_packages(self, package_type=None): """