Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of inline tables in include on pyproject.toml. #6

Merged
merged 4 commits into from
Apr 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,18 @@ def create_poetry(self, cwd=None): # type: (Optional[Path]) -> Poetry
package.build_config = build or {}

if "include" in local_config:
package.include = local_config["include"]
package.include = []

for include in local_config["include"]:
if not isinstance(include, dict):
include = {"path": include}

formats = include.get("format", [])
abn marked this conversation as resolved.
Show resolved Hide resolved
if formats and not isinstance(formats, list):
formats = [formats]
include["format"] = formats

package.include.append(include)

if "exclude" in local_config:
package.exclude = local_config["exclude"]
Expand Down
49 changes: 41 additions & 8 deletions poetry/core/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,43 @@
],
"properties": {
"include": {
"type": "string",
"description": "What to include in the package."
"$ref": "#/definitions/include-path"
},
"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."
"$ref": "#/definitions/package-formats"
}
}
}
},
"include": {
"type": "array",
"description": "A list of files and folders to include."
"description": "A list of files and folders to include.",
"items": {
"anyOf": [
{
"$ref": "#/definitions/include-path"
},
{
"type": "object",
"additionalProperties": false,
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/include-path"
},
"format": {
kasteph marked this conversation as resolved.
Show resolved Hide resolved
"$ref": "#/definitions/package-formats"
}
}
}
]
}
},
"exclude": {
"type": "array",
Expand Down Expand Up @@ -189,6 +206,22 @@
"type": "string"
}
},
"include-path": {
"type": "string",
"description": "Path to file or directory to include."
},
"package-format": {
"type": "string",
"enum": ["sdist", "wheel"],
"description": "A Python packaging format."
},
"package-formats": {
"oneOf": [
{"$ref": "#/definitions/package-format"},
{"type": "array", "items": {"$ref": "#/definitions/package-format"}}
],
"description": "The format(s) for which the package must be included."
},
"dependencies": {
"type": "object",
"patternProperties": {
Expand Down
121 changes: 93 additions & 28 deletions poetry/core/masonry/builders/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from collections import defaultdict
from contextlib import contextmanager
from typing import Optional
from typing import Set
from typing import Union

Expand Down Expand Up @@ -60,12 +61,27 @@ def __init__(

packages.append(p)

includes = []
for include in self._package.include:
formats = include.get("format", [])

if (
formats
and self.format
and self.format not in formats
and not ignore_packages_formats
):
continue

includes.append(include)

self._module = Module(
self._package.name,
self._path.as_posix(),
packages=packages,
includes=self._package.include,
includes=includes,
)

self._meta = Metadata.from_package(self._package)

def build(self):
Expand Down Expand Up @@ -113,23 +129,49 @@ def is_excluded(self, filepath): # type: (Union[str, Path]) -> bool

return False

def find_files_to_add(self, exclude_build=True): # type: (bool) -> list
def find_files_to_add(
self, exclude_build=True
): # type: (bool) -> Set[BuildIncludeFile]
"""
Finds all files to add to the tarball
"""
to_add = []
to_add = set()

for include in self._module.includes:
include.refresh()
formats = include.formats or ["sdist"]
abn marked this conversation as resolved.
Show resolved Hide resolved

for file in include.elements:
if "__pycache__" in str(file):
continue

if file.is_dir():
if self.format in formats:
for current_file in file.glob("**/*"):
include_file = BuildIncludeFile(
path=current_file, source_root=self._path
)

if not current_file.is_dir() and not self.is_excluded(
include_file.relative_to_source_root()
):
to_add.add(include_file)
continue

file = file.relative_to(self._path)
if (
isinstance(include, PackageInclude)
and include.source
and self.format == "wheel"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dist specific logic should probably move to specific classes.

):
source_root = include.base
else:
source_root = self._path

include_file = BuildIncludeFile(path=file, source_root=source_root)

if self.is_excluded(file) and isinstance(include, PackageInclude):
if self.is_excluded(
include_file.relative_to_source_root()
) and isinstance(include, PackageInclude):
continue

if file.suffix == ".pyc":
Expand All @@ -140,31 +182,17 @@ def find_files_to_add(self, exclude_build=True): # type: (bool) -> list
continue

logger.debug(" - Adding: {}".format(str(file)))
to_add.append(file)

# Include project files
logger.debug(" - Adding: pyproject.toml")
to_add.append(Path("pyproject.toml"))

# If a license file exists, add it
for license_file in self._path.glob("LICENSE*"):
logger.debug(" - Adding: {}".format(license_file.relative_to(self._path)))
to_add.append(license_file.relative_to(self._path))

# If a README is specified we need to include it
# to avoid errors
if "readme" in self._poetry.local_config:
readme = self._path / self._poetry.local_config["readme"]
if readme.exists():
logger.debug(" - Adding: {}".format(readme.relative_to(self._path)))
to_add.append(readme.relative_to(self._path))

# If a build script is specified and explicitely required
# we add it to the list of files
to_add.add(include_file)

# add build script if it is specified and explicitly required
if self._package.build_script and not exclude_build:
to_add.append(Path(self._package.build_script))
to_add.add(
BuildIncludeFile(
path=self._package.build_script, source_root=self._path
)
)

return sorted(to_add)
return to_add

def get_metadata_content(self): # type: () -> bytes
content = METADATA_BASE.format(
Expand Down Expand Up @@ -268,3 +296,40 @@ def temporary_directory(cls, *args, **kwargs):
yield name

shutil.rmtree(name)


class BuildIncludeFile:
def __init__(
self,
path, # type: Path
source_root=None, # type: Optional[Path]
):
"""
:param path: a full path to the file to be included
:param source_root: the root path to resolve to
"""
self.path = Path(path)
self.source_root = None if not source_root else Path(source_root).resolve()
if not self.path.is_absolute() and self.source_root:
self.path = (self.source_root / self.path).resolve()
else:
self.path = self.path.resolve()

def __eq__(self, other): # type: (Union[BuildIncludeFile, Path]) -> bool
if hasattr(other, "path"):
return self.path == other.path
return self.path == other

def __ne__(self, other): # type: (Union[BuildIncludeFile, Path]) -> bool
kasteph marked this conversation as resolved.
Show resolved Hide resolved
return not self.__eq__(other)

def __hash__(self):
return hash(self.path)

def __repr__(self): # type: () -> str
return str(self.path)

def relative_to_source_root(self): # type(): -> Path
if self.source_root is not None:
return self.path.relative_to(self.source_root)
return self.path
36 changes: 31 additions & 5 deletions poetry/core/masonry/builders/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from posixpath import join as pjoin
from pprint import pformat
from typing import Iterator
from typing import Set

from poetry.core.utils._compat import Path
from poetry.core.utils._compat import decode
Expand All @@ -22,6 +23,7 @@
from ..utils.helpers import normalize_file_permissions
from ..utils.package_include import PackageInclude
from .builder import Builder
from .builder import BuildIncludeFile


SETUP = """\
Expand Down Expand Up @@ -74,15 +76,15 @@ def build(self, target_dir=None): # type: (Path) -> Path

files_to_add = self.find_files_to_add(exclude_build=False)

for relpath in files_to_add:
path = self._path / relpath
for file in sorted(files_to_add, key=lambda x: x.relative_to_source_root()):
tar_info = tar.gettarinfo(
str(path), arcname=pjoin(tar_dir, str(relpath))
str(file.path),
arcname=pjoin(tar_dir, str(file.relative_to_source_root())),
)
tar_info = self.clean_tarinfo(tar_info)

if tar_info.isreg():
with path.open("rb") as f:
with file.path.open("rb") as f:
tar.addfile(tar_info, f)
else:
tar.addfile(tar_info) # Symlinks & ?
Expand All @@ -105,7 +107,6 @@ def build(self, target_dir=None): # type: (Path) -> Path
gz.close()

logger.info(" - Built <comment>{}</comment>".format(target.name))

return target

def build_setup(self): # type: () -> bytes
Expand Down Expand Up @@ -302,6 +303,31 @@ def find_nearest_pkg(rel_path):

return pkgdir, sorted(packages), pkg_data

def find_files_to_add(
self, exclude_build=False
): # type: (bool) -> Set[BuildIncludeFile]
to_add = super(SdistBuilder, self).find_files_to_add(exclude_build)

# add any additional files, starting with all LICENSE files
additional_files = {
license_file for license_file in self._path.glob("LICENSE*")
}

# Include project files
additional_files.add("pyproject.toml")

# add readme if it is specified
if "readme" in self._poetry.local_config:
additional_files.add(self._poetry.local_config["readme"])

for file in additional_files:
file = BuildIncludeFile(path=file, source_root=self._path)
if file.path.exists():
logger.debug(" - Adding: {}".format(file.relative_to_source_root()))
to_add.add(file)

return to_add

@classmethod
def convert_dependencies(cls, package, dependencies):
main = []
Expand Down
Loading