Commit 93b5128c by Sébastien Eustace Committed by GitHub

Per format packages support (#1133)

* Add support for per format packages

* Add documentation for per-format packages
parent 9247a8c5
......@@ -113,6 +113,20 @@ packages = [
]
```
If you want to restrict a package to a specific [build](#build) format you can specify
it by using `format`:
```toml
[tool.poetry]
# ...
packages = [
{ include = "my_package" },
{ include = "tests", format = "sdist" },
]
```
From now on, only the `sdist` build archive will include the `tests` package.
!!!note
Using `packages` disables the package auto-detection feature meaning you have to
......
......@@ -76,6 +76,13 @@
"from": {
"type": "string",
"description": "Where the source directory of the package resides."
},
"format": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
],
"description": "The format(s) for which the package must be included."
}
}
}
......
......@@ -109,6 +109,9 @@ class SdistBuilder(Builder):
packages = []
package_data = {}
for include in self._module.includes:
if include.formats and "sdist" not in include.formats:
continue
if isinstance(include, PackageInclude):
if include.is_package():
pkg_dir, _packages, _package_data = self.find_packages(include)
......
......@@ -133,6 +133,9 @@ class WheelBuilder(Builder):
to_add = []
for include in self._module.includes:
if include.formats and "wheel" not in include.formats:
continue
include.refresh()
for file in include.elements:
......
from typing import List
from typing import Optional
from poetry.utils._compat import Path
......@@ -17,9 +18,12 @@ class Include(object):
- a directory
"""
def __init__(self, base, include): # type: (Path, str) -> None
def __init__(
self, base, include, formats=None
): # type: (Path, str, Optional[List[str]]) -> None
self._base = base
self._include = str(include)
self._formats = formats
self._elements = sorted(list(self._base.glob(str(self._include))))
......@@ -31,6 +35,10 @@ class Include(object):
def elements(self): # type: () -> List[Path]
return self._elements
@property
def formats(self): # type: () -> Optional[List[str]]
return self._formats
def is_empty(self): # type: () -> bool
return len(self._elements) == 0
......
......@@ -58,8 +58,17 @@ class Module:
)
for package in packages:
formats = package.get("format")
if formats and not isinstance(formats, list):
formats = [formats]
self._includes.append(
PackageInclude(self._path, package["include"], package.get("from"))
PackageInclude(
self._path,
package["include"],
formats=formats,
source=package.get("from"),
)
)
for include in includes:
......
......@@ -2,7 +2,7 @@ from .include import Include
class PackageInclude(Include):
def __init__(self, base, include, source=None):
def __init__(self, base, include, formats=None, source=None):
self._package = None
self._is_package = False
self._is_module = False
......@@ -11,7 +11,7 @@ class PackageInclude(Include):
if source is not None:
base = base / source
super(PackageInclude, self).__init__(base, include)
super(PackageInclude, self).__init__(base, include, formats=formats)
self.check_elements()
......
......@@ -25,6 +25,8 @@ packages = [
{ include = "extra_dir/**/*.py" },
{ include = "my_module.py" },
{ include = "package_with_include" },
{ include = "tests", format = "sdist" },
{ include = "for_wheel_only", format = ["wheel"] },
]
include = [
......
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import ast
import os
import pytest
import re
......@@ -382,3 +383,85 @@ def test_package_src():
assert "package_src/module.py" in zip.namelist()
finally:
zip.close()
def test_package_with_include(mocker):
module_path = fixtures_dir / "with-include"
# Patch git module to return specific excluded files
p = mocker.patch("poetry.vcs.git.Git.get_ignored_files")
p.return_value = [
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "vcs_excluded.txt"
),
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "sub_pkg"
/ "vcs_excluded.txt"
),
]
builder = CompleteBuilder(Poetry.create(module_path), NullEnv(), NullIO())
builder.build()
sdist = fixtures_dir / "with-include" / "dist" / "with-include-1.2.3.tar.gz"
assert sdist.exists()
with tarfile.open(str(sdist), "r") as tar:
names = tar.getnames()
assert len(names) == len(set(names))
assert "with-include-1.2.3/LICENSE" in names
assert "with-include-1.2.3/README.rst" in names
assert "with-include-1.2.3/extra_dir/__init__.py" in names
assert "with-include-1.2.3/extra_dir/vcs_excluded.txt" in names
assert "with-include-1.2.3/extra_dir/sub_pkg/__init__.py" in names
assert "with-include-1.2.3/extra_dir/sub_pkg/vcs_excluded.txt" not in names
assert "with-include-1.2.3/my_module.py" in names
assert "with-include-1.2.3/notes.txt" in names
assert "with-include-1.2.3/package_with_include/__init__.py" in names
assert "with-include-1.2.3/tests/__init__.py" in names
assert "with-include-1.2.3/pyproject.toml" in names
assert "with-include-1.2.3/setup.py" in names
assert "with-include-1.2.3/PKG-INFO" in names
assert "for_wheel_only/__init__" not in names
setup = tar.extractfile("with-include-1.2.3/setup.py").read()
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 "package_dir" not in ns
assert ns["packages"] == [
"extra_dir",
"extra_dir.sub_pkg",
"package_with_include",
"tests",
]
assert ns["package_data"] == {"": ["*"]}
assert ns["modules"] == ["my_module"]
whl = module_path / "dist" / "with_include-1.2.3-py3-none-any.whl"
assert whl.exists()
with zipfile.ZipFile(str(whl)) as z:
names = z.namelist()
assert len(names) == len(set(names))
assert "with_include-1.2.3.dist-info/LICENSE" in names
assert "extra_dir/__init__.py" in names
assert "extra_dir/vcs_excluded.txt" in names
assert "extra_dir/sub_pkg/__init__.py" in names
assert "extra_dir/sub_pkg/vcs_excluded.txt" not in names
assert "for_wheel_only/__init__.py" in names
assert "my_module.py" in names
assert "notes.txt" in names
assert "package_with_include/__init__.py" in names
assert "with-include-1.2.3/tests/__init__.py" not in names
......@@ -221,7 +221,7 @@ def test_find_packages():
builder = SdistBuilder(poetry, NullEnv(), NullIO())
base = project("source_package")
include = PackageInclude(base, "package_src", "src")
include = PackageInclude(base, "package_src", source="src")
pkg_dir, packages, pkg_data = builder.find_packages(include)
......@@ -350,65 +350,6 @@ def test_with_src_module_dir():
assert "package-src-0.1/src/package_src/module.py" in tar.getnames()
def test_package_with_include(mocker):
# Patch git module to return specific excluded files
p = mocker.patch("poetry.vcs.git.Git.get_ignored_files")
p.return_value = [
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "vcs_excluded.txt"
),
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "sub_pkg"
/ "vcs_excluded.txt"
),
]
poetry = Poetry.create(project("with-include"))
builder = SdistBuilder(poetry, NullEnv(), 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 "package_dir" not in ns
assert ns["packages"] == ["extra_dir", "extra_dir.sub_pkg", "package_with_include"]
assert ns["package_data"] == {"": ["*"]}
assert ns["modules"] == ["my_module"]
builder.build()
sdist = fixtures_dir / "with-include" / "dist" / "with-include-1.2.3.tar.gz"
assert sdist.exists()
with tarfile.open(str(sdist), "r") as tar:
names = tar.getnames()
assert len(names) == len(set(names))
assert "with-include-1.2.3/LICENSE" in names
assert "with-include-1.2.3/README.rst" in names
assert "with-include-1.2.3/extra_dir/__init__.py" in names
assert "with-include-1.2.3/extra_dir/vcs_excluded.txt" in names
assert "with-include-1.2.3/extra_dir/sub_pkg/__init__.py" in names
assert "with-include-1.2.3/extra_dir/sub_pkg/vcs_excluded.txt" not in names
assert "with-include-1.2.3/my_module.py" in names
assert "with-include-1.2.3/notes.txt" in names
assert "with-include-1.2.3/package_with_include/__init__.py" in names
assert "with-include-1.2.3/pyproject.toml" in names
assert "with-include-1.2.3/setup.py" in names
assert "with-include-1.2.3/PKG-INFO" in names
def test_default_with_excluded_data(mocker):
# Patch git module to return specific excluded files
p = mocker.patch("poetry.vcs.git.Git.get_ignored_files")
......
......@@ -87,46 +87,6 @@ def test_wheel_module_src():
assert "module_src.py" in z.namelist()
def test_package_with_include(mocker):
# Patch git module to return specific excluded files
p = mocker.patch("poetry.vcs.git.Git.get_ignored_files")
p.return_value = [
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "vcs_excluded.txt"
),
str(
Path(__file__).parent
/ "fixtures"
/ "with-include"
/ "extra_dir"
/ "sub_pkg"
/ "vcs_excluded.txt"
),
]
module_path = fixtures_dir / "with-include"
WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
whl = module_path / "dist" / "with_include-1.2.3-py3-none-any.whl"
assert whl.exists()
with zipfile.ZipFile(str(whl)) as z:
names = z.namelist()
assert len(names) == len(set(names))
assert "with_include-1.2.3.dist-info/LICENSE" in names
assert "extra_dir/__init__.py" in names
assert "extra_dir/vcs_excluded.txt" in names
assert "extra_dir/sub_pkg/__init__.py" in names
assert "extra_dir/sub_pkg/vcs_excluded.txt" not in names
assert "my_module.py" in names
assert "notes.txt" in names
assert "package_with_include/__init__.py" in names
def test_dist_info_file_permissions():
module_path = fixtures_dir / "complete"
WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
......
......@@ -115,6 +115,8 @@ def test_poetry_with_packages_and_includes():
{"include": "extra_dir/**/*.py"},
{"include": "my_module.py"},
{"include": "package_with_include"},
{"include": "tests", "format": "sdist"},
{"include": "for_wheel_only", "format": ["wheel"]},
]
assert package.include == ["extra_dir/vcs_excluded.txt", "notes.txt"]
......
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