88import re
99import shutil
1010import sys
11+ import tomllib
1112import typing as t
13+ from fnmatch import fnmatchcase
1214from pathlib import Path
1315
1416import setuptools
@@ -39,20 +41,31 @@ def _ensure_dist_info(self, *args, **kwargs):
3941class plugins (InfoCommon , setuptools .Command ):
4042 description = "Discover plux plugins and store them in .egg_info"
4143
42- user_options = [
43- # TODO
44+ user_options : t .ClassVar [list [tuple [str , str , str ]]] = [
45+ ('exclude=' , 'e' , "exclude those files when discovering plugins" ),
46+ # TODO: add more
4447 ]
4548
4649 egg_info : str
4750
4851 def initialize_options (self ) -> None :
4952 self .plux_json_path = None
53+ self .exclude = None
5054
5155 def finalize_options (self ) -> None :
5256 self .plux_json_path = get_plux_json_path (self .distribution )
57+ self .ensure_string_list ('exclude' )
58+ if self .exclude is None :
59+ self .exclude = []
60+
61+ project_config = read_configuration (self .distribution )
62+ file_exclude = project_config .get ("exclude" )
63+ if file_exclude :
64+ self .exclude = set (self .exclude ) | set (file_exclude )
65+ self .exclude = [_path_to_module (item ) for item in self .exclude ]
5366
5467 def run (self ) -> None :
55- plugin_finder = PluginFromPackageFinder (DistributionPackageFinder (self .distribution ))
68+ plugin_finder = PluginFromPackageFinder (DistributionPackageFinder (self .distribution , exclude = self . exclude ))
5669 ep = discover_entry_points (plugin_finder )
5770
5871 self .debug_print (f"writing discovered plugins into { self .plux_json_path } " )
@@ -191,6 +204,20 @@ def get_plux_json_path(distribution):
191204 return os .path .join (egg_info_dir , "plux.json" )
192205
193206
207+ def read_configuration (distribution ) -> dict :
208+ dirs = distribution .package_dir
209+ pyproject_base = (dirs or {}).get ("" , os .curdir )
210+ pyproject_file = os .path .join (pyproject_base , "pyproject.toml" )
211+ if not os .path .exists (pyproject_file ):
212+ return {}
213+
214+ with open (pyproject_file , "rb" ) as file :
215+ pyproject_config = tomllib .load (file )
216+
217+ tool_table = pyproject_config .get ("tool" , {})
218+ return tool_table .get ("plux" , {})
219+
220+
194221def update_entrypoints (distribution , ep : EntryPointDict ):
195222 if distribution .entry_points is None :
196223 distribution .entry_points = {}
@@ -375,6 +402,27 @@ def _to_filename(name):
375402 return name .replace ("-" , "_" )
376403
377404
405+ def _path_to_module (path ):
406+ """
407+ Convert a path to a Python module to its module representation
408+ Example: plux/core/test -> plux.core.test
409+ """
410+ return path .strip ("/" ).replace ("/" , "." )
411+
412+
413+ class _Filter :
414+ """
415+ Given a list of patterns, create a callable that will be true only if
416+ the input matches at least one of the patterns.
417+ This is from `setuptools.discovery._Filter`
418+ """
419+ def __init__ (self , patterns : t .Iterable [str ]):
420+ self ._patterns = patterns
421+
422+ def __call__ (self , item : str ):
423+ return any (fnmatchcase (item , pat ) for pat in self ._patterns )
424+
425+
378426class _PackageFinder :
379427 """
380428 Generate a list of Python packages. How these are generated depends on the implementation.
@@ -397,11 +445,12 @@ class DistributionPackageFinder(_PackageFinder):
397445 correctly if configured.
398446 """
399447
400- def __init__ (self , distribution : Distribution ):
448+ def __init__ (self , distribution : Distribution , exclude : t . Optional [ t . Iterable [ str ]] = None ):
401449 self .distribution = distribution
450+ self .exclude = _Filter (exclude or [])
402451
403452 def find_packages (self ) -> t .Iterable [str ]:
404- return self .distribution .packages
453+ return self .filter_packages ( self . distribution .packages )
405454
406455 @property
407456 def path (self ) -> str :
@@ -415,6 +464,9 @@ def path(self) -> str:
415464 where = "."
416465 return where
417466
467+ def filter_packages (self , packages : t .Iterable [str ]) -> t .Iterable [str ]:
468+ return [item for item in packages if not self .exclude (item )]
469+
418470
419471class DefaultPackageFinder (_PackageFinder ):
420472 def __init__ (self , where = "." , exclude = (), include = ("*" ,), namespace = True ) -> None :
0 commit comments