Skip to content

Commit

Permalink
feat: make it possible to build subprojects from python packages
Browse files Browse the repository at this point in the history
  • Loading branch information
vberlier committed Apr 20, 2022
1 parent 910d714 commit 8e54ffb
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 4 deletions.
59 changes: 55 additions & 4 deletions beet/toolchain/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,56 @@
"sandbox",
"run_beet",
"JinjaExtension",
"SubprojectError",
]


from contextlib import ExitStack, contextmanager
from functools import wraps
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Iterator, Optional, Union
from typing import Iterator, Optional, Union, overload

from jinja2 import Environment
from jinja2.ext import Extension

from beet.core.utils import FileSystemPath, JsonDict
from beet.core.utils import FileSystemPath, JsonDict, import_from_string
from beet.toolchain.pipeline import FormattedPipelineException

from .config import ProjectConfig, config_error_handler
from .context import Context, Plugin, PluginSpec, ProjectCache
from .context import Context, Pipeline, Plugin, PluginSpec, ProjectCache
from .project import Project, ProjectBuilder
from .template import TemplateManager
from .worker import WorkerPool


class SubprojectError(FormattedPipelineException):
"""Raised when a subproject fails to build."""

def __init__(self, message: str):
super().__init__(message)
self.message = message
self.format_cause = True


@overload
def subproject(config: Union[ProjectConfig, JsonDict, FileSystemPath]) -> Plugin:
...


@overload
def subproject(config: Optional[str] = None, *, package: str) -> Plugin:
...


def subproject(
config: Optional[Union[ProjectConfig, JsonDict, FileSystemPath]] = None,
*,
package: Optional[str] = None,
) -> Plugin:
"""Return a plugin that runs a subproject."""

@wraps(subproject)
def plugin(ctx: Context):
project = Project(
resolved_cache=ctx.cache,
Expand All @@ -38,7 +65,31 @@ def plugin(ctx: Context):
with config_error_handler("<subproject>"):
project.resolved_config = ProjectConfig(**config).resolve(ctx.directory)
else:
path = Path(config)
if package:
whitelist = ctx.inject(Pipeline).whitelist

try:
imported_package = import_from_string(package, whitelist=whitelist)
except Exception as exc:
msg = (
f'Couldn\'t import package "{package}" for building subproject.'
)
raise SubprojectError(msg) from exc

if filename := getattr(imported_package, "__file__", None):
path = Path(filename).parent
else:
msg = f'Missing "__file__" attribute on package "{package}" for building subproject.'
raise SubprojectError(msg)

if config:
path /= config

elif config:
path = Path(config)

else:
raise SubprojectError("No config provided for building subproject.")

if path.is_dir():
project.config_directory = path
Expand Down
1 change: 1 addition & 0 deletions examples/load_subproject_package/beet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
require: [demo]
5 changes: 5 additions & 0 deletions examples/load_subproject_package/demo/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from beet import Context, subproject


def beet_default(ctx: Context):
ctx.require(subproject(package="demo"))
2 changes: 2 additions & 0 deletions examples/load_subproject_package/demo/beet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
data_pack:
load: [src]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
say hello
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
say hello
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 9,
"description": ""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 8,
"description": ""
}
}

0 comments on commit 8e54ffb

Please sign in to comment.