Skip to content

Commit e220f8b

Browse files
committed
Allow inline tables in includes to be similarly functional to the package directive.
Unify common logic between WheelBuilder and Builder. Move SDistBuilder logic from Builder to SDistBuilder. Resolves: #8
1 parent fc4ae2d commit e220f8b

File tree

15 files changed

+268
-81
lines changed

15 files changed

+268
-81
lines changed

poetry/core/factory.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,18 @@ def create_poetry(self, cwd=None): # type: (Optional[Path]) -> Poetry
112112
package.build = local_config["build"]
113113

114114
if "include" in local_config:
115-
package.include = local_config["include"]
115+
package.include = []
116+
117+
for include in local_config["include"]:
118+
if not isinstance(include, dict):
119+
include = {"path": include}
120+
121+
formats = include.get("format", [])
122+
if formats and not isinstance(formats, list):
123+
formats = [formats]
124+
include["format"] = formats
125+
126+
package.include.append(include)
116127

117128
if "exclude" in local_config:
118129
package.exclude = local_config["exclude"]

poetry/core/json/schemas/poetry-schema.json

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,26 +73,43 @@
7373
],
7474
"properties": {
7575
"include": {
76-
"type": "string",
77-
"description": "What to include in the package."
76+
"$ref": "#/definitions/include-path"
7877
},
7978
"from": {
8079
"type": "string",
8180
"description": "Where the source directory of the package resides."
8281
},
8382
"format": {
84-
"oneOf": [
85-
{"type": "string"},
86-
{"type": "array", "items": {"type": "string"}}
87-
],
88-
"description": "The format(s) for which the package must be included."
83+
"$ref": "#/definitions/package-format"
8984
}
9085
}
9186
}
9287
},
9388
"include": {
9489
"type": "array",
95-
"description": "A list of files and folders to include."
90+
"description": "A list of files and folders to include.",
91+
"items": {
92+
"anyOf": [
93+
{
94+
"$ref": "#/definitions/include-path"
95+
},
96+
{
97+
"type": "object",
98+
"additionalProperties": false,
99+
"required": [
100+
"path"
101+
],
102+
"properties": {
103+
"path": {
104+
"$ref": "#/definitions/include-path"
105+
},
106+
"format": {
107+
"$ref": "#/definitions/package-format"
108+
}
109+
}
110+
}
111+
]
112+
}
96113
},
97114
"exclude": {
98115
"type": "array",
@@ -190,6 +207,17 @@
190207
"type": "string"
191208
}
192209
},
210+
"include-path": {
211+
"type": "string",
212+
"description": "Path to file or directory to include."
213+
},
214+
"package-format": {
215+
"oneOf": [
216+
{"type": "string", "enum": ["sdist", "wheel"]},
217+
{"type": "array", "items": {"type": "string"}}
218+
],
219+
"description": "The format(s) for which the package must be included."
220+
},
193221
"dependencies": {
194222
"type": "object",
195223
"patternProperties": {

poetry/core/masonry/builders/builder.py

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from collections import defaultdict
88
from contextlib import contextmanager
9+
from typing import List
910
from typing import Set
1011
from typing import Union
1112

@@ -16,6 +17,7 @@
1617
from poetry.core.vcs import get_vcs
1718

1819
from ..metadata import Metadata
20+
from ..utils.include import IncludeFile
1921
from ..utils.module import Module
2022
from ..utils.package_include import PackageInclude
2123

@@ -61,11 +63,25 @@ def __init__(
6163

6264
packages.append(p)
6365

66+
includes = []
67+
for i in self._package.include:
68+
formats = i.get("format", [])
69+
70+
if (
71+
formats
72+
and self.format
73+
and self.format not in formats
74+
and not ignore_packages_formats
75+
):
76+
continue
77+
78+
includes.append(i)
79+
6480
self._module = Module(
6581
self._package.name,
6682
self._path.as_posix(),
6783
packages=packages,
68-
includes=self._package.include,
84+
includes=includes,
6985
)
7086
self._meta = Metadata.from_package(self._package)
7187

@@ -115,58 +131,68 @@ def is_excluded(self, filepath): # type: (Union[str, Path]) -> bool
115131

116132
return False
117133

118-
def find_files_to_add(self, exclude_build=True): # type: (bool) -> list
134+
def find_files_to_add(
135+
self, exclude_build=True
136+
): # type: (bool) -> List[IncludeFile]
119137
"""
120138
Finds all files to add to the tarball
121139
"""
122140
to_add = []
123141

124142
for include in self._module.includes:
143+
include.refresh()
144+
formats = include.formats or ["sdist"]
145+
125146
for file in include.elements:
126147
if "__pycache__" in str(file):
127148
continue
128149

129150
if file.is_dir():
151+
if self.format in formats:
152+
for f in file.glob("**/*"):
153+
rel_path = f.relative_to(self._path)
154+
155+
if (
156+
rel_path not in set([t.path for t in to_add])
157+
and not f.is_dir()
158+
and not self.is_excluded(rel_path)
159+
):
160+
to_add.append(
161+
IncludeFile(path=rel_path, source_root=self._path)
162+
)
130163
continue
131164

132-
file = file.relative_to(self._path)
165+
if isinstance(include, PackageInclude) and all(
166+
[include.source, self.format == "wheel"]
167+
):
168+
source_root = include.base
169+
else:
170+
source_root = self._path
171+
172+
file = file.relative_to(source_root)
173+
include_file = IncludeFile(path=file, source_root=source_root.resolve())
133174

134175
if self.is_excluded(file) and isinstance(include, PackageInclude):
135176
continue
136177

137178
if file.suffix == ".pyc":
138179
continue
139180

140-
if file in to_add:
181+
if file in set([f.path for f in to_add]):
141182
# Skip duplicates
142183
continue
143184

144185
logger.debug(" - Adding: {}".format(str(file)))
145-
to_add.append(file)
146-
147-
# Include project files
148-
logger.debug(" - Adding: pyproject.toml")
149-
to_add.append(Path("pyproject.toml"))
150-
151-
# If a license file exists, add it
152-
for license_file in self._path.glob("LICENSE*"):
153-
logger.debug(" - Adding: {}".format(license_file.relative_to(self._path)))
154-
to_add.append(license_file.relative_to(self._path))
155-
156-
# If a README is specified we need to include it
157-
# to avoid errors
158-
if "readme" in self._poetry.local_config:
159-
readme = self._path / self._poetry.local_config["readme"]
160-
if readme.exists():
161-
logger.debug(" - Adding: {}".format(readme.relative_to(self._path)))
162-
to_add.append(readme.relative_to(self._path))
163-
164-
# If a build script is specified and explicitely required
186+
to_add.append(include_file)
187+
188+
# If a build script is specified and explicitly required
165189
# we add it to the list of files
166190
if self._package.build and not exclude_build:
167-
to_add.append(Path(self._package.build))
191+
to_add.append(
192+
IncludeFile(path=Path(self._package.build), source_root=self._path)
193+
)
168194

169-
return sorted(to_add)
195+
return to_add
170196

171197
def get_metadata_content(self): # type: () -> bytes
172198
content = METADATA_BASE.format(

poetry/core/masonry/builders/sdist.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
from posixpath import join as pjoin
1414
from pprint import pformat
1515
from typing import Iterator
16+
from typing import List
1617

1718
from poetry.core.utils._compat import Path
1819
from poetry.core.utils._compat import decode
1920
from poetry.core.utils._compat import encode
2021
from poetry.core.utils._compat import to_str
2122

2223
from ..utils.helpers import normalize_file_permissions
24+
from ..utils.include import IncludeFile
2325
from ..utils.package_include import PackageInclude
2426
from .builder import Builder
2527

@@ -74,10 +76,10 @@ def build(self, target_dir=None): # type: (Path) -> Path
7476

7577
files_to_add = self.find_files_to_add(exclude_build=False)
7678

77-
for relpath in files_to_add:
78-
path = self._path / relpath
79+
for file in files_to_add:
80+
path = file.full_path
7981
tar_info = tar.gettarinfo(
80-
str(path), arcname=pjoin(tar_dir, str(relpath))
82+
str(path), arcname=pjoin(tar_dir, str(file.rel_path))
8183
)
8284
tar_info = self.clean_tarinfo(tar_info)
8385

@@ -104,7 +106,6 @@ def build(self, target_dir=None): # type: (Path) -> Path
104106
gz.close()
105107

106108
logger.info(" - Built <comment>{}</comment>".format(target.name))
107-
108109
return target
109110

110111
def build_setup(self): # type: () -> bytes
@@ -301,6 +302,38 @@ def find_nearest_pkg(rel_path):
301302

302303
return pkgdir, sorted(packages), pkg_data
303304

305+
def find_files_to_add(
306+
self, exclude_build=False
307+
): # type: (bool) -> List[IncludeFile]
308+
to_add = super(SdistBuilder, self).find_files_to_add(exclude_build)
309+
310+
# Include project files
311+
logger.debug(" - Adding: pyproject.toml")
312+
to_add.append(IncludeFile(path=Path("pyproject.toml"), source_root=self._path))
313+
314+
# If a license file exists, add it
315+
for license_file in self._path.glob("LICENSE*"):
316+
logger.debug(" - Adding: {}".format(license_file.relative_to(self._path)))
317+
to_add.append(
318+
IncludeFile(
319+
path=license_file.relative_to(self._path), source_root=self._path
320+
)
321+
)
322+
323+
# If a README is specified we need to include it
324+
# to avoid errors
325+
if "readme" in self._poetry.local_config:
326+
readme = self._path / self._poetry.local_config["readme"]
327+
if readme.exists():
328+
logger.debug(" - Adding: {}".format(readme.relative_to(self._path)))
329+
to_add.append(
330+
IncludeFile(
331+
path=readme.relative_to(self._path), source_root=self._path
332+
)
333+
)
334+
335+
return sorted(to_add, key=lambda x: x.path)
336+
304337
@classmethod
305338
def convert_dependencies(cls, package, dependencies):
306339
main = []

poetry/core/masonry/builders/wheel.py

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from ..utils.helpers import escape_name
2424
from ..utils.helpers import escape_version
2525
from ..utils.helpers import normalize_file_permissions
26-
from ..utils.package_include import PackageInclude
2726
from .builder import Builder
2827
from .sdist import SdistBuilder
2928

@@ -131,47 +130,13 @@ def _run_build_command(self, setup):
131130
[sys.executable, str(setup), "build", "-b", str(self._path / "build")]
132131
)
133132

134-
def _copy_module(self, wheel):
135-
136-
to_add = []
137-
138-
for include in self._module.includes:
139-
if include.formats and "wheel" not in include.formats:
140-
continue
141-
142-
include.refresh()
143-
144-
for file in include.elements:
145-
if "__pycache__" in str(file):
146-
continue
147-
148-
if file.is_dir():
149-
continue
150-
151-
if isinstance(include, PackageInclude) and include.source:
152-
rel_file = file.relative_to(include.base)
153-
else:
154-
rel_file = file.relative_to(self._path)
155-
156-
if self.is_excluded(rel_file.as_posix()) and isinstance(
157-
include, PackageInclude
158-
):
159-
continue
160-
161-
if file.suffix == ".pyc":
162-
continue
163-
164-
if (file, rel_file) in to_add:
165-
# Skip duplicates
166-
continue
167-
168-
logger.debug(" - Adding: {}".format(str(file)))
169-
to_add.append((file, rel_file))
133+
def _copy_module(self, wheel): # type: (zipfile.ZipFile) -> None
134+
to_add = self.find_files_to_add()
170135

171136
# Walk the files and compress them,
172137
# sorting everything so the order is stable.
173-
for full_path, rel_path in sorted(to_add, key=lambda x: x[1]):
174-
self._add_file(wheel, full_path, rel_path)
138+
for file in sorted(to_add, key=lambda x: x.path):
139+
self._add_file(wheel, file.full_path, file.rel_path)
175140

176141
def _write_metadata(self, wheel):
177142
if (

poetry/core/masonry/utils/include.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,24 @@ def refresh(self): # type: () -> Include
4646
self._elements = sorted(list(self._base.glob(self._include)))
4747

4848
return self
49+
50+
51+
class IncludeFile:
52+
def __init__(
53+
self,
54+
path, # type: Path
55+
source_root=None, # type: Optional[Path]
56+
):
57+
self.path = path
58+
self.source_root = source_root or Path(".")
59+
60+
def __repr__(self): # type: () -> str
61+
return str(self.path)
62+
63+
@property
64+
def rel_path(self): # type: () -> Path
65+
return self.path
66+
67+
@property
68+
def full_path(self): # type: () -> Path
69+
return self.source_root / self.path

poetry/core/masonry/utils/module.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ def __init__(self, name, directory=".", packages=None, includes=None):
7474
)
7575

7676
for include in includes:
77-
self._includes.append(Include(self._path, include))
77+
self._includes.append(
78+
Include(self._path, include["path"], formats=include["format"])
79+
)
7880

7981
@property
8082
def name(self): # type: () -> str

0 commit comments

Comments
 (0)