API: Test Support

test_support

This package includes helper code that is only used for testing setuptools-pyproject-migration itself. The code is made available when testing by a pytest configuration option that extends sys.path.

class test_support.Project(root: Path)

Bases: object

A Python project on which setup.py pyproject can be run. Test code should not normally construct instances of Project() directly; instead, they can get one through a fixture or some helper function.

Once you have the Project object, create any files you need underneath the root by calling write() or one of its convenience wrappers like setup_py() or setup_cfg(). If you need to do anything other than creating files or if there is some reason not to use the write() method, you can work directly on root, but don’t change anything outside of root. Finally, when all necessary files have been created, call one of run(), run_cli(), or generate() to run setup.py pyproject (or an equivalent) on the project.

Parameters:

root – The root directory in which to create the project. It should already exist. Typically this might be a temporary directory created by pytest’s tmp_path fixture.

generate() Pyproject

Run the equivalent of setup.py pyproject but return the generated data structure that would go into pyproject.toml instead of writing it out.

root: Path

The directory in which the project is to be created

run(runner: ProjectRunner) ProjectRunResult

Run setup.py pyproject on the created project and return the output.

If the project doesn’t already have a setup.py file, a simple one will be automatically created by calling setup_py() with no arguments before running it.

Parameters:

runner – The callable to use to run the script

run_cli(runner: ProjectRunner) ProjectRunResult

Run the console script setuptools-pyproject-migration on the created project and return the output.

In contrast to run(), if setup.py doesn’t exist, it will not be created, because the script is supposed to work without it. If you want to test the script’s behavior with a setup.py file, create it “manually” with a call to setup_py().

Parameters:

runner – The callable to use to run the script

setup_cfg(content: str) None

Write a setup.cfg file in the project root directory.

Parameters:

content – Text content to write to the file.

setup_py(content: str | None = None) None

Write a setup.py file in the project root directory.

Parameters:

content – Text content to write to the file.

write(filename: Path | str, content: str) None

Write a file with the given content and the given filename relative to the project root. If the file already exists, it will be overwritten after issuing a warning.

Parameters:
  • filename – A filename or pathlib.Path representing the file to write. This should be a relative path, which will be interpreted relative to the project root directory. If the referenced file is not inside the project root, a warning will be issued.

  • content – Text content to write to the file.

class test_support.ProjectRunResult(*args, **kwargs)

Bases: Protocol

returncode: int
stderr: str
stdout: str
success: bool
class test_support.ProjectRunner(*args, **kwargs)

Bases: Protocol

A runner for an external command. This is basically an abstraction of ScriptRunner.run() from pytest-console-scripts, or at least the subset of its behavior which we use in this project.

class test_support.WritePyprojectFactory

Bases: object

DEFAULT_NAME = 'TestProject'
DEFAULT_VERSION = '1.2.3'
test_support.is_at_least(distribution_name: str, required_version: Version | str) bool

test_support.distribution

Support code for distribution package testing.

“Distribution package” means the same thing here that it does in importlib-metadata: basically a Python project that can be installed with pip or a compatible tool. Most distribution packages, of course, come from PyPI, but it’s also possible to use raw source code as a distribution package. Since this plugin only works on projects that use setuptools (and have not been converted to take setuptools configuration from pyproject.toml), we only test with distribution packages that have setup.py or setup.cfg in their source code.

class test_support.distribution.DistributionPackage

Bases: ABC

A “distribution package” in the sense used in importlib_metadata.

Basically, this is a Python project that can be installed with pip or a compatible tool, and that has a setup.py or setup.cfg file.

abstract prepare(path: Path) DistributionPackagePreparation

Populate a directory with the package’s source code. This might involve checking out a repository, extracting an archive, or something else, depending on the type of project.

This method will be given an empty, writable directory. It should put the distribution package’s source code somewhere inside that directory and return the path in which setuptools-pyproject-migration should be run, i.e. the parent directory of setup.py or setup.cfg (unless the distribution package does something extremely weird that involves a custom path to setuptools config files).

Parameters:

path – An empty, writable directory in which the package’s source code should be placed. Implementations can also use parts of this directory as temporary storage; everything put in here will be ignored except for the path returned.

Returns:

The root directory of the package, which contains setup.py or setup.cfg. This may be path or a subdirectory of path depending on how the source code is prepared.

class test_support.distribution.DistributionPackagePreparation(make_importable: bool = False)

Bases: object

A distribution package that has been prepared for testing. “Prepared” means the source code is downloaded/extracted/checked out/whatever in a local directory, in a state that allows setuptools-pyproject-migration to run on it to generate a pyproject.toml file.

Parameters:

make_importable – When running setuptools-pyproject-migration on the code of the distribution package, the code is in a “raw” form that may not be usable, since many distribution packages require a build step to go from their raw code to something that can be imported. So, in accordance with standard packaging conventions, by default we don’t make the distribution package’s own code available for import when running its setup.py. But some projects (that don’t have build steps) expect their own code to be importable straight from the filesystem when running their setup.py file. This flag can be set to True to make that happen during testing.

abstract property core_metadata_reference: StandardMetadata

Return the known correct core metadata for the distribution package. Typically this comes from the package’s wheel, if a wheel is available.

Returns:

The known correct core metadata for the distribution package

abstract property project: Project

Return the test_support.Project instance which can be used to compute the metadata from the prepared source code.

class test_support.distribution.HashChecker(algorithm: str, expected_hash: str)

Bases: object

check(data)
classmethod from_spec(spec: str, sep: str = '=')
class test_support.distribution.PackageInfo(package_url: str, package_hash_spec: str, metadata_hash_spec: str | None)

Bases: object

class test_support.distribution.PackageType(value, names=None, *values, module=None, qualname=None, type=None, start=1, boundary=None)

Bases: Enum

SDIST = 'sdist'
WHEEL = 'bdist_wheel'
class test_support.distribution.PyPiDistribution(name: str, version: str, *, project_root: Path | None = None, make_importable: bool = False)

Bases: DistributionPackage

A distribution package obtained from PyPI.

Parameters:
  • name – The name of the project as registered on PyPI, i.e. the name in the project’s URL: https://pypi.org/project/<name>

  • version – The version string of the project as registered on PyPI

  • project_root – The relative path within the project’s sdist to the directory containing setup.py or setup.cfg. If omitted, this defaults to <name>-<version> with <name> normalized in the manner specified by the sdist specification. Because the spec was designed to match what the vast majority of build tools actually produce in sdist files, it should be extremely rare to have to specify a custom project root.

  • make_importable – When running setuptools-pyproject-migration on the code of the distribution package, the code is in a “raw” form that may not be usable, since many distribution packages require a build step to go from their raw code to something that can be imported. So, in accordance with standard packaging conventions, by default we don’t make the distribution package’s own code available for import when running its setup.py. But some projects (that don’t have build steps) expect their own code to be importable straight from the filesystem when running their setup.py file. This flag can be set to True to make that happen during testing.

prepare(path: Path) DistributionPackagePreparation

Populate a directory with the package’s source code. This involves downloading the sdist and extracting it.

class test_support.distribution.PyPiPackagePreparation(distribution: PyPiDistribution, path: Path)

Bases: DistributionPackagePreparation

Parameters:
  • distribution_package – The distribution package to prepare

  • path – A temporary directory to use in preparing the distribution package. Typically this would be provided by pytest’s tmp_path fixture.

property core_metadata_reference: StandardMetadata

Return the known correct core metadata for the distribution package. Typically this comes from the package’s wheel, if a wheel is available.

Returns:

The known correct core metadata for the distribution package

property project: Project

Return the test_support.Project instance which can be used to compute the metadata from the prepared source code.

class test_support.distribution.RFC822Message

Bases: object

class test_support.distribution.SimplePackageListingParser(name: str, version: str)

Bases: HTMLParser

A bare-bones parser for the list of versions of a given package offered by the simple repository API. It will select releases of the given version of the package.

handle_starttag(tag: Any, attrs: Any)
class test_support.distribution.StandardMetadata

Bases: object