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 = [ ...@@ -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 !!!note
Using `packages` disables the package auto-detection feature meaning you have to Using `packages` disables the package auto-detection feature meaning you have to
......
...@@ -76,6 +76,13 @@ ...@@ -76,6 +76,13 @@
"from": { "from": {
"type": "string", "type": "string",
"description": "Where the source directory of the package resides." "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): ...@@ -109,6 +109,9 @@ class SdistBuilder(Builder):
packages = [] packages = []
package_data = {} package_data = {}
for include in self._module.includes: for include in self._module.includes:
if include.formats and "sdist" not in include.formats:
continue
if isinstance(include, PackageInclude): if isinstance(include, PackageInclude):
if include.is_package(): if include.is_package():
pkg_dir, _packages, _package_data = self.find_packages(include) pkg_dir, _packages, _package_data = self.find_packages(include)
......
...@@ -133,6 +133,9 @@ class WheelBuilder(Builder): ...@@ -133,6 +133,9 @@ class WheelBuilder(Builder):
to_add = [] to_add = []
for include in self._module.includes: for include in self._module.includes:
if include.formats and "wheel" not in include.formats:
continue
include.refresh() include.refresh()
for file in include.elements: for file in include.elements:
......
from typing import List from typing import List
from typing import Optional
from poetry.utils._compat import Path from poetry.utils._compat import Path
...@@ -17,9 +18,12 @@ class Include(object): ...@@ -17,9 +18,12 @@ class Include(object):
- a directory - 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._base = base
self._include = str(include) self._include = str(include)
self._formats = formats
self._elements = sorted(list(self._base.glob(str(self._include)))) self._elements = sorted(list(self._base.glob(str(self._include))))
...@@ -31,6 +35,10 @@ class Include(object): ...@@ -31,6 +35,10 @@ class Include(object):
def elements(self): # type: () -> List[Path] def elements(self): # type: () -> List[Path]
return self._elements return self._elements
@property
def formats(self): # type: () -> Optional[List[str]]
return self._formats
def is_empty(self): # type: () -> bool def is_empty(self): # type: () -> bool
return len(self._elements) == 0 return len(self._elements) == 0
......
...@@ -58,8 +58,17 @@ class Module: ...@@ -58,8 +58,17 @@ class Module:
) )
for package in packages: for package in packages:
formats = package.get("format")
if formats and not isinstance(formats, list):
formats = [formats]
self._includes.append( 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: for include in includes:
......
...@@ -2,7 +2,7 @@ from .include import Include ...@@ -2,7 +2,7 @@ from .include import Include
class PackageInclude(Include): class PackageInclude(Include):
def __init__(self, base, include, source=None): def __init__(self, base, include, formats=None, source=None):
self._package = None self._package = None
self._is_package = False self._is_package = False
self._is_module = False self._is_module = False
...@@ -11,7 +11,7 @@ class PackageInclude(Include): ...@@ -11,7 +11,7 @@ class PackageInclude(Include):
if source is not None: if source is not None:
base = base / source base = base / source
super(PackageInclude, self).__init__(base, include) super(PackageInclude, self).__init__(base, include, formats=formats)
self.check_elements() self.check_elements()
......
...@@ -25,6 +25,8 @@ packages = [ ...@@ -25,6 +25,8 @@ packages = [
{ include = "extra_dir/**/*.py" }, { include = "extra_dir/**/*.py" },
{ include = "my_module.py" }, { include = "my_module.py" },
{ include = "package_with_include" }, { include = "package_with_include" },
{ include = "tests", format = "sdist" },
{ include = "for_wheel_only", format = ["wheel"] },
] ]
include = [ include = [
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import ast
import os import os
import pytest import pytest
import re import re
...@@ -382,3 +383,85 @@ def test_package_src(): ...@@ -382,3 +383,85 @@ def test_package_src():
assert "package_src/module.py" in zip.namelist() assert "package_src/module.py" in zip.namelist()
finally: finally:
zip.close() 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(): ...@@ -221,7 +221,7 @@ def test_find_packages():
builder = SdistBuilder(poetry, NullEnv(), NullIO()) builder = SdistBuilder(poetry, NullEnv(), NullIO())
base = project("source_package") 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) pkg_dir, packages, pkg_data = builder.find_packages(include)
...@@ -350,65 +350,6 @@ def test_with_src_module_dir(): ...@@ -350,65 +350,6 @@ def test_with_src_module_dir():
assert "package-src-0.1/src/package_src/module.py" in tar.getnames() 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): def test_default_with_excluded_data(mocker):
# Patch git module to return specific excluded files # Patch git module to return specific excluded files
p = mocker.patch("poetry.vcs.git.Git.get_ignored_files") p = mocker.patch("poetry.vcs.git.Git.get_ignored_files")
......
...@@ -87,46 +87,6 @@ def test_wheel_module_src(): ...@@ -87,46 +87,6 @@ def test_wheel_module_src():
assert "module_src.py" in z.namelist() 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(): def test_dist_info_file_permissions():
module_path = fixtures_dir / "complete" module_path = fixtures_dir / "complete"
WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO()) WheelBuilder.make(Poetry.create(str(module_path)), NullEnv(), NullIO())
......
...@@ -115,6 +115,8 @@ def test_poetry_with_packages_and_includes(): ...@@ -115,6 +115,8 @@ def test_poetry_with_packages_and_includes():
{"include": "extra_dir/**/*.py"}, {"include": "extra_dir/**/*.py"},
{"include": "my_module.py"}, {"include": "my_module.py"},
{"include": "package_with_include"}, {"include": "package_with_include"},
{"include": "tests", "format": "sdist"},
{"include": "for_wheel_only", "format": ["wheel"]},
] ]
assert package.include == ["extra_dir/vcs_excluded.txt", "notes.txt"] 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