33future to support ``tox.ini``, ``setup.cfg``, etc.
44"""
55import dataclasses
6+ import enum
67import os
8+ import sys
79from importlib .util import find_spec
8- import typing as t
10+
11+
12+ class EntrypointBuildMode (enum .Enum ):
13+ """
14+ The build mode for entrypoints. When ``build-hook`` is used, plux hooks into the build backend's build process using
15+ various extension points. Currently, we only support setuptools, where plux generates a plugin index and adds it to
16+ the .egg-info directory, which is later used to generate entry points.
17+
18+ The alternative is ``manual``, where build hooks are disabled and the user is responsible for generating and
19+ referencing entry points.
20+ """
21+ MANUAL = "manual"
22+ BUILD_HOOK = "build-hook"
923
1024
1125@dataclasses .dataclass
1226class PluxConfiguration :
1327 """
1428 Configuration object with sane default values.
1529 """
16- exclude : t .List [str ] = dataclasses .field (default_factory = list )
30+
31+ path : str = "."
32+ """The path to scan for plugins."""
33+
34+ exclude : list [str ] = dataclasses .field (default_factory = list )
35+ """A list of paths to exclude from scanning."""
36+
37+ entrypoint_build_mode : EntrypointBuildMode = EntrypointBuildMode .BUILD_HOOK
38+ """The point in the build process path plugins should be discovered and entrypoints generated."""
39+
40+ entrypoint_static_file : str = "plux.ini"
41+ """The name of the entrypoint ini file if entrypoint_build_mode is set to MANUAL."""
42+
43+ def merge (
44+ self ,
45+ path : str = None ,
46+ exclude : list [str ] = None ,
47+ entrypoint_build_mode : EntrypointBuildMode = None ,
48+ entrypoint_static_file : str = None ,
49+ ) -> "PluxConfiguration" :
50+ """
51+ Merges or overwrites the given values into the current configuration and returns a new configuration object.
52+ If the passed values are None, they are not changed.
53+ """
54+ return PluxConfiguration (
55+ path = path if path is not None else self .path ,
56+ exclude = list (set ((exclude if exclude is not None else []) + self .exclude )),
57+ entrypoint_build_mode = entrypoint_build_mode if entrypoint_build_mode is not None else self .entrypoint_build_mode ,
58+ entrypoint_static_file = entrypoint_static_file if entrypoint_static_file is not None else self .entrypoint_static_file ,
59+ )
60+
61+
62+ def read_plux_config_from_workdir (workdir : str = None ) -> PluxConfiguration :
63+ """
64+ Reads the plux configuration from the specified workdir. Currently, it only checks for a ``pyproject.toml`` to
65+ parse. If no pyproject.toml is found, a default configuration is returned.
66+
67+ :param workdir: The workdir which defaults to the current working directory.
68+ :return: A plux configuration object
69+ """
70+ try :
71+ pyproject_file = os .path .join (workdir or os .getcwd (), "pyproject.toml" )
72+ return parse_pyproject_toml (pyproject_file )
73+ except FileNotFoundError :
74+ return PluxConfiguration ()
1775
1876
1977def parse_pyproject_toml (path : str | os .PathLike [str ]) -> PluxConfiguration :
@@ -22,7 +80,7 @@ def parse_pyproject_toml(path: str | os.PathLike[str]) -> PluxConfiguration:
2280 object from the found values. Uses tomli or tomllib to parse the file.
2381
2482 :param path: Path to the pyproject.toml file.
25- :return: A ``Configuration`` object containing the parsed values.
83+ :return: A plux configuration object containing the parsed values.
2684 :raises FileNotFoundError: If the file does not exist.
2785 """
2886 if find_spec ("tomllib" ):
@@ -32,13 +90,28 @@ def parse_pyproject_toml(path: str | os.PathLike[str]) -> PluxConfiguration:
3290 else :
3391 raise ImportError ("Could not find a TOML parser. Please install either tomllib or tomli." )
3492
93+ # read the file
3594 if not os .path .exists (path ):
3695 raise FileNotFoundError (f"No pyproject.toml found at { path } " )
37-
3896 with open (path , "rb" ) as file :
3997 pyproject_config = load_toml (file )
4098
99+ # find the [tool.plux] section
41100 tool_table = pyproject_config .get ("tool" , {})
42101 tool_config = tool_table .get ("plux" , {})
43102
44- return PluxConfiguration (** tool_config )
103+ # filter out all keys that are not available in the config object
104+ kwargs = {}
105+ for key , value in tool_config .items ():
106+ if key not in PluxConfiguration .__annotations__ :
107+ print (f"Warning: ignoring unknown key { key } in [tool.plux] section of { path } " , file = sys .stderr )
108+ continue
109+
110+ kwargs [key ] = value
111+
112+ # parse entrypoint_build_mode enum
113+ if mode := kwargs .get ("entrypoint_build_mode" ):
114+ # will raise a ValueError exception if the mode is invalid
115+ kwargs ["entrypoint_build_mode" ] = EntrypointBuildMode (mode )
116+
117+ return PluxConfiguration (** kwargs )
0 commit comments