pypa-hatch/tests/cli/new/test_new.py

637 lines
17 KiB
Python

import pytest
from hatch.config.constants import ConfigEnvVars
def remove_trailing_spaces(text):
return ''.join(f'{line.rstrip()}\n' for line in text.splitlines(True))
class TestErrors:
def test_path_is_file(self, hatch, temp_dir):
with temp_dir.as_cwd():
path = temp_dir / 'foo'
path.touch()
result = hatch('new', 'foo')
assert result.exit_code == 1
assert result.output == f'Path `{path}` points to a file.\n'
def test_path_not_empty(self, hatch, temp_dir):
with temp_dir.as_cwd():
path = temp_dir / 'foo'
(path / 'bar').ensure_dir_exists()
result = hatch('new', 'foo')
assert result.exit_code == 1
assert result.output == f'Directory `{path}` is not empty.\n'
def test_no_plugins_found(self, hatch, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.plugins = {'foo': {}}
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 1
assert result.output == 'None of the defined plugins were found: foo\n'
def test_some_not_plugins_found(self, hatch, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.plugins['foo'] = {}
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 1
assert result.output == 'Some of the defined plugins were not found: foo\n'
def test_default(hatch, helpers, temp_dir):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.default', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_default_explicit_path(hatch, helpers, temp_dir):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name, '.')
expected_files = helpers.get_template_files('new.default', project_name)
helpers.assert_files(temp_dir, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
src
└── my_app
├── __about__.py
└── __init__.py
tests
└── __init__.py
LICENSE.txt
README.md
pyproject.toml
"""
)
def test_default_empty_plugins_table(hatch, helpers, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.plugins = {}
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.default', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
@pytest.mark.requires_internet
def test_default_no_license_cache(hatch, helpers, temp_dir):
project_name = 'My.App'
cache_dir = temp_dir / 'cache'
cache_dir.mkdir()
with temp_dir.as_cwd({ConfigEnvVars.CACHE: str(cache_dir)}):
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.default', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_licenses_multiple(hatch, helpers, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.licenses.default = ['MIT', 'Apache-2.0']
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.licenses_multiple', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── LICENSES
│ ├── Apache-2.0.txt
│ └── MIT.txt
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── README.md
└── pyproject.toml
"""
)
def test_licenses_empty(hatch, helpers, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.licenses.default = []
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.licenses_empty', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── README.md
└── pyproject.toml
"""
)
def test_projects_urls_space_in_label(hatch, helpers, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.plugins['default']['project_urls'] = {
'Documentation': 'https://github.com/{name}/{project_name_normalized}#readme',
'Source': 'https://github.com/{name}/{project_name_normalized}',
'Bug Tracker': 'https://github.com/{name}/{project_name_normalized}/issues',
}
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.projects_urls_space_in_label', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_projects_urls_empty(hatch, helpers, config_file, temp_dir):
project_name = 'My.App'
config_file.model.template.plugins['default']['project_urls'] = {}
config_file.save()
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.projects_urls_empty', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_feature_cli(hatch, helpers, temp_dir):
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name, '--cli')
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.feature_cli', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── cli
│ │ └── __init__.py
│ ├── __about__.py
│ ├── __init__.py
│ └── __main__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_feature_ci(hatch, helpers, config_file, temp_dir):
config_file.model.template.plugins['default']['ci'] = True
config_file.save()
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.feature_ci', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── .github
│ └── workflows
│ └── test.yml
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_feature_no_src_layout(hatch, helpers, config_file, temp_dir):
config_file.model.template.plugins['default']['src-layout'] = False
config_file.save()
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.feature_no_src_layout', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_feature_tests_disable(hatch, helpers, config_file, temp_dir):
config_file.model.template.plugins['default']['tests'] = False
config_file.save()
project_name = 'My.App'
with temp_dir.as_cwd():
result = hatch('new', project_name)
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.basic', project_name)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_no_project_name_error(hatch, helpers, temp_dir):
with temp_dir.as_cwd():
result = hatch('new')
assert result.exit_code == 1
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
Missing required argument for the project name, use the -i/--interactive flag.
"""
)
def test_interactive(hatch, helpers, temp_dir):
project_name = 'My.App'
description = 'foo \u2764'
with temp_dir.as_cwd():
result = hatch('new', '-i', input=f'{project_name}\n{description}')
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.default', project_name, description=description)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
f"""
Project name: {project_name}
Description []: {description}
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_no_project_name_enables_interactive(hatch, helpers, temp_dir):
project_name = 'My.App'
description = 'foo'
with temp_dir.as_cwd():
result = hatch('new', '-i', input=f'{project_name}\n{description}')
path = temp_dir / 'my-app'
expected_files = helpers.get_template_files('new.default', project_name, description=description)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
f"""
Project name: {project_name}
Description []: {description}
my-app
├── src
│ └── my_app
│ ├── __about__.py
│ └── __init__.py
├── tests
│ └── __init__.py
├── LICENSE.txt
├── README.md
└── pyproject.toml
"""
)
def test_initialize_fresh(hatch, helpers, temp_dir):
project_name = 'My.App'
description = 'foo'
with temp_dir.as_cwd():
result = hatch('new', project_name)
assert result.exit_code == 0, result.output
path = temp_dir / 'my-app'
project_file = path / 'pyproject.toml'
project_file.remove()
assert not project_file.is_file()
with path.as_cwd():
result = hatch('new', '--init', input=f'{project_name}\n{description}')
expected_files = helpers.get_template_files('new.default', project_name, description=description)
helpers.assert_files(path, expected_files)
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
f"""
Project name: {project_name}
Description []: {description}
Wrote: pyproject.toml
"""
)
def test_initialize_update(hatch, helpers, temp_dir):
project_name = 'My.App'
description = 'foo'
project_file = temp_dir / 'pyproject.toml'
project_file.write_text(
"""\
[build-system]
req = ["hatchling"]
build-backend = "build"
[project]
name = ""
description = ""
readme = "README.md"
requires-python = ">=3.8"
license = "MIT"
dynamic = ["version"]
[tool.hatch.version]
path = "o/__init__.py"
"""
)
with temp_dir.as_cwd():
result = hatch('new', '--init', input=f'{project_name}\n{description}')
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
f"""
Project name: {project_name}
Description []: {description}
Updated: pyproject.toml
"""
)
assert len(list(temp_dir.iterdir())) == 1
assert project_file.read_text() == (
f"""\
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "my-app"
description = "{description}"
readme = "README.md"
requires-python = ">=3.8"
license = "MIT"
dynamic = ["version"]
[tool.hatch.version]
path = "my_app/__init__.py"
"""
)
def test_initialize_setup_cfg_only(hatch, helpers, temp_dir):
"""
Test initializing a project with a setup.cfg file only.
"""
setup_cfg_file = temp_dir / 'setup.cfg'
setup_cfg_file.write_text(
"""\
[metadata]
name = testapp
version = attr:testapp.__version__
description = Foo
author = U.N. Owen
author_email = void@some.where
url = https://example.com
license = MIT
"""
)
with temp_dir.as_cwd():
result = hatch('new', '--init')
assert result.exit_code == 0, result.output
assert remove_trailing_spaces(result.output) == helpers.dedent(
"""
Migrating project metadata from setuptools
"""
)
project_file = temp_dir / 'pyproject.toml'
assert project_file.read_text() == (
"""\
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "testapp"
dynamic = ["version"]
description = "Foo"
license = "MIT"
authors = [
{ name = "U.N. Owen", email = "void@some.where" },
]
[project.urls]
Homepage = "https://example.com"
[tool.hatch.version]
path = "testapp/__init__.py"
[tool.hatch.build.targets.sdist]
include = [
"/testapp",
]
"""
)