Commit 0bff3b14 by Sébastien Eustace

Add support for src/ layout in packages

parent d774c58f
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
- Added the `cache:clear` command. - Added the `cache:clear` command.
- Added support for `git` dependencies in the `add` command. - Added support for `git` dependencies in the `add` command.
- Added support for `file` dependencies in the `add` command. - Added support for `file` dependencies in the `add` command.
- Added support for `src/` layout for packages.
### Changed ### Changed
......
...@@ -72,26 +72,32 @@ class Builder(object): ...@@ -72,26 +72,32 @@ class Builder(object):
src = self._module.path src = self._module.path
to_add = [] to_add = []
for root, dirs, files in os.walk(src.as_posix()): if not self._module.is_package():
root = Path(root) if self._module.is_in_src():
if root.name == '__pycache__': to_add.append(src.relative_to(src.parent.parent))
continue else:
to_add.append(src.relative_to(src.parent))
else:
for root, dirs, files in os.walk(src.as_posix()):
root = Path(root)
if root.name == '__pycache__':
continue
for file in files: for file in files:
file = root / file file = root / file
file = file.relative_to(self._path) file = file.relative_to(self._path)
if file in excluded: if file in excluded:
continue continue
if file.suffix == '.pyc': if file.suffix == '.pyc':
continue continue
self._io.writeln( self._io.writeln(
' - Adding: <comment>{}</comment>'.format(str(file)), ' - Adding: <comment>{}</comment>'.format(str(file)),
verbosity=self._io.VERBOSITY_VERY_VERBOSE verbosity=self._io.VERBOSITY_VERY_VERBOSE
) )
to_add.append(file) to_add.append(file)
# Include project files # Include project files
self._io.writeln( self._io.writeln(
......
...@@ -119,6 +119,10 @@ class SdistBuilder(Builder): ...@@ -119,6 +119,10 @@ class SdistBuilder(Builder):
'build(setup_kwargs)' 'build(setup_kwargs)'
] ]
if self._module.is_in_src():
before.append("package_dir = \\\n{}\n".format(pformat({'': 'src'})))
extra.append("'package_dir': package_dir,")
if self._module.is_package(): if self._module.is_package():
packages, package_data = self.find_packages( packages, package_data = self.find_packages(
self._module.path.as_posix() self._module.path.as_posix()
......
...@@ -133,6 +133,14 @@ class WheelBuilder(Builder): ...@@ -133,6 +133,14 @@ class WheelBuilder(Builder):
for file in sorted(files): for file in sorted(files):
full_path = self._path / file full_path = self._path / file
if self._module.is_in_src():
try:
file = file.relative_to(
self._module.path.parent.relative_to(self._path)
)
except ValueError:
pass
# Do not include topmost files # Do not include topmost files
if full_path.relative_to(self._path) == Path(file.name): if full_path.relative_to(self._path) == Path(file.name):
continue continue
......
...@@ -6,6 +6,7 @@ class Module: ...@@ -6,6 +6,7 @@ class Module:
def __init__(self, name, directory='.'): def __init__(self, name, directory='.'):
self._name = module_name(name) self._name = module_name(name)
self._in_src = False
# It must exist either as a .py file or a directory, but not both # It must exist either as a .py file or a directory, but not both
pkg_dir = Path(directory, self._name) pkg_dir = Path(directory, self._name)
...@@ -19,7 +20,23 @@ class Module: ...@@ -19,7 +20,23 @@ class Module:
self._path = py_file self._path = py_file
self._is_package = False self._is_package = False
else: else:
raise ValueError("No file/folder found for package {}".format(name)) # Searching for a src module
src_pkg_dir = Path(directory, 'src', self._name)
src_py_file = Path(directory, 'src', self._name + '.py')
if src_pkg_dir.is_dir() and src_py_file.is_file():
raise ValueError(
"Both {} and {} exist".format(pkg_dir, py_file))
elif src_pkg_dir.is_dir():
self._in_src = True
self._path = src_pkg_dir
self._is_package = True
elif src_py_file.is_file():
self._in_src = True
self._path = src_py_file
self._is_package = False
else:
raise ValueError("No file/folder found for package {}".format(name))
@property @property
def name(self): # type: () -> str def name(self): # type: () -> str
...@@ -38,3 +55,6 @@ class Module: ...@@ -38,3 +55,6 @@ class Module:
def is_package(self): # type: () -> bool def is_package(self): # type: () -> bool
return self._is_package return self._is_package
def is_in_src(self): # type: () -> bool
return self._in_src
[tool.poetry]
name = "module-src"
version = "0.1"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license = "MIT"
readme = "README.rst"
homepage = "https://poetry.eustace.io/"
[tool.poetry.dependencies]
python = "*"
[tool.poetry]
name = "package-src"
version = "0.1"
description = "Some description."
authors = [
"Sébastien Eustace <sebastien@eustace.io>"
]
license = "MIT"
readme = "README.rst"
homepage = "https://poetry.eustace.io/"
[tool.poetry.dependencies]
python = "*"
...@@ -81,7 +81,7 @@ def test_complete(): ...@@ -81,7 +81,7 @@ def test_complete():
whl = module_path / 'dist' / 'my_package-1.2.3-py3-none-any.whl' whl = module_path / 'dist' / 'my_package-1.2.3-py3-none-any.whl'
assert whl.exists assert whl.exists()
zip = zipfile.ZipFile(str(whl)) zip = zipfile.ZipFile(str(whl))
...@@ -133,3 +133,50 @@ My Package ...@@ -133,3 +133,50 @@ My Package
""" """
finally: finally:
zip.close() zip.close()
def test_module_src():
module_path = fixtures_dir / 'source_file'
builder = CompleteBuilder(Poetry.create(module_path), NullVenv(True),
NullIO())
builder.build()
sdist = module_path / 'dist' / 'module-src-0.1.tar.gz'
assert sdist.exists()
tar = tarfile.open(str(sdist), 'r')
assert 'module-src-0.1/src/module_src.py' in tar.getnames()
whl = module_path / 'dist' / 'module_src-0.1-py2.py3-none-any.whl'
assert whl.exists()
zip = zipfile.ZipFile(str(whl))
assert 'module_src.py' in zip.namelist()
def test_package_src():
module_path = fixtures_dir / 'source_package'
builder = CompleteBuilder(Poetry.create(module_path), NullVenv(True),
NullIO())
builder.build()
sdist = module_path / 'dist' / 'package-src-0.1.tar.gz'
assert sdist.exists()
tar = tarfile.open(str(sdist), 'r')
assert 'package-src-0.1/src/package_src/module.py' in tar.getnames()
whl = module_path / 'dist' / 'package_src-0.1-py2.py3-none-any.whl'
assert whl.exists()
zip = zipfile.ZipFile(str(whl))
assert 'package_src/__init__.py' in zip.namelist()
assert 'package_src/module.py' in zip.namelist()
import ast import ast
import pytest import pytest
import re
import shutil import shutil
import tarfile import tarfile
...@@ -8,6 +9,7 @@ from poetry.masonry.builders.sdist import SdistBuilder ...@@ -8,6 +9,7 @@ from poetry.masonry.builders.sdist import SdistBuilder
from poetry.packages import Package from poetry.packages import Package
from poetry.poetry import Poetry from poetry.poetry import Poetry
from poetry.utils._compat import Path from poetry.utils._compat import Path
from poetry.utils._compat import to_str
from poetry.utils.venv import NullVenv from poetry.utils.venv import NullVenv
from tests.helpers import get_dependency from tests.helpers import get_dependency
...@@ -175,6 +177,21 @@ def test_package(): ...@@ -175,6 +177,21 @@ def test_package():
assert sdist.exists() assert sdist.exists()
def test_module():
poetry = Poetry.create(project('module1'))
builder = SdistBuilder(poetry, NullVenv(), NullIO())
builder.build()
sdist = fixtures_dir / 'module1' / 'dist' / 'module1-0.1.tar.gz'
assert sdist.exists()
tar = tarfile.open(str(sdist), 'r')
assert 'module1-0.1/module1.py' in tar.getnames()
def test_prelease(): def test_prelease():
poetry = Poetry.create(project('prerelease')) poetry = Poetry.create(project('prerelease'))
...@@ -201,3 +218,58 @@ def test_with_c_extensions(): ...@@ -201,3 +218,58 @@ def test_with_c_extensions():
assert 'extended-0.1/build.py' in tar.getnames() assert 'extended-0.1/build.py' in tar.getnames()
assert 'extended-0.1/extended/extended.c' in tar.getnames() assert 'extended-0.1/extended/extended.c' in tar.getnames()
def test_with_src_module_file():
poetry = Poetry.create(project('source_file'))
builder = SdistBuilder(poetry, NullVenv(), NullIO())
# Check setup.py
setup = builder.build_setup()
setup_ast = ast.parse(setup)
setup_ast.body = [n for n in setup_ast.body if isinstance(n, ast.Assign)]
ns = {}
exec(compile(setup_ast, filename="setup.py", mode="exec"), ns)
assert ns['package_dir'] == {'': 'src'}
assert re.search('\'py_modules\': \'module_src\'', to_str(setup)) is not None
builder.build()
sdist = fixtures_dir / 'source_file' / 'dist' / 'module-src-0.1.tar.gz'
assert sdist.exists()
tar = tarfile.open(str(sdist), 'r')
assert 'module-src-0.1/src/module_src.py' in tar.getnames()
def test_with_src_module_dir():
poetry = Poetry.create(project('source_package'))
builder = SdistBuilder(poetry, NullVenv(), NullIO())
# Check setup.py
setup = builder.build_setup()
setup_ast = ast.parse(setup)
setup_ast.body = [n for n in setup_ast.body if isinstance(n, ast.Assign)]
ns = {}
exec(compile(setup_ast, filename="setup.py", mode="exec"), ns)
assert ns['package_dir'] == {'': 'src'}
assert ns['packages'] == [
'package_src',
]
builder.build()
sdist = fixtures_dir / 'source_package' / 'dist' / 'package-src-0.1.tar.gz'
assert sdist.exists()
tar = tarfile.open(str(sdist), 'r')
assert 'package-src-0.1/src/package_src/__init__.py' in tar.getnames()
assert 'package-src-0.1/src/package_src/module.py' in tar.getnames()
import pytest import pytest
import shutil import shutil
import zipfile
from poetry.io import NullIO from poetry.io import NullIO
from poetry.masonry.builders import WheelBuilder from poetry.masonry.builders import WheelBuilder
...@@ -34,6 +35,10 @@ def test_wheel_module(): ...@@ -34,6 +35,10 @@ def test_wheel_module():
assert whl.exists() assert whl.exists()
z = zipfile.ZipFile(str(whl))
assert 'module1.py' in z.namelist()
def test_wheel_package(): def test_wheel_package():
module_path = fixtures_dir / 'complete' module_path = fixtures_dir / 'complete'
...@@ -43,6 +48,10 @@ def test_wheel_package(): ...@@ -43,6 +48,10 @@ def test_wheel_package():
assert whl.exists() assert whl.exists()
z = zipfile.ZipFile(str(whl))
assert 'my_package/sub_pkg1/__init__.py' in z.namelist()
def test_wheel_prerelease(): def test_wheel_prerelease():
module_path = fixtures_dir / 'prerelease' module_path = fixtures_dir / 'prerelease'
...@@ -51,3 +60,30 @@ def test_wheel_prerelease(): ...@@ -51,3 +60,30 @@ def test_wheel_prerelease():
whl = module_path / 'dist' / 'prerelease-0.1b1-py2.py3-none-any.whl' whl = module_path / 'dist' / 'prerelease-0.1b1-py2.py3-none-any.whl'
assert whl.exists() assert whl.exists()
def test_wheel_package_src():
module_path = fixtures_dir / 'source_package'
WheelBuilder.make(Poetry.create(str(module_path)), NullVenv(), NullIO())
whl = module_path / 'dist' / 'package_src-0.1-py2.py3-none-any.whl'
assert whl.exists()
z = zipfile.ZipFile(str(whl))
assert 'package_src/__init__.py' in z.namelist()
assert 'package_src/module.py' in z.namelist()
def test_wheel_module_src():
module_path = fixtures_dir / 'source_file'
WheelBuilder.make(Poetry.create(str(module_path)), NullVenv(), NullIO())
whl = module_path / 'dist' / 'module_src-0.1-py2.py3-none-any.whl'
assert whl.exists()
z = zipfile.ZipFile(str(whl))
assert 'module_src.py' in z.namelist()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment