2121
2222class PackageClass (object ):
2323
24- def __init__ (self , * package_names_or_classes , ** filters ):
25- self .names = []
24+ def __init__ (self , * package_names_or_classes , exclude = (),
25+ include_dependencies = False , exclude_dependencies = False ,
26+ ** filters ):
27+ self .__names = set ()
2628 filenames = filters .pop ('has_files' , [])
2729 no_filenames = filters .pop ('no_files' , [])
28- excluded = filters .pop ('exclude' , [])
30+ excluded = []
31+ for package_names in exclude :
32+ excluded .extend (package_names )
2933 if filters :
3034 raise ValueError ('filter not supported' )
3135
3236 def included_in_filter (pkg ):
33- if pkg .name in excluded :
34- return False
3537 if not all (any (pkg .has_file (filename )
3638 for filename in filename_disjunction .split ('|' ))
3739 for filename_disjunction in filenames ):
@@ -55,19 +57,58 @@ def included_in_filter(pkg):
5557 'which must be one of '
5658 ':all:, :standard:, :optional:, or :experimental:'
5759 'got {}' .format (package_name_or_class ))
58- self .names .append (package_name_or_class )
60+ self .__names .add (package_name_or_class )
61+
62+ def include_recursive_dependencies (names , package_name ):
63+ if package_name in names :
64+ return
65+ try :
66+ pkg = Package (package_name )
67+ except FileNotFoundError :
68+ # Silently ignore unknown packages,
69+ # substitutions such as $(BLAS) $(PYTHON),
70+ # and optional dependencies of the form $(find-string ...).
71+ return
72+ names .add (package_name )
73+ for dependency in pkg .dependencies :
74+ include_recursive_dependencies (names , dependency )
75+
76+ if include_dependencies :
77+ package_names = set ()
78+ for name in self .__names :
79+ include_recursive_dependencies (package_names , name )
80+ self .__names = package_names
81+
82+ def exclude_recursive_dependencies (names , package_name ):
83+ try :
84+ pkg = Package (package_name )
85+ except FileNotFoundError :
86+ return
87+ for dependency in pkg .dependencies :
88+ names .discard (dependency )
89+ exclude_recursive_dependencies (names , dependency )
90+
91+ if exclude_dependencies :
92+ for name in list (self .__names ):
93+ exclude_recursive_dependencies (self .__names , name )
94+
95+ self .__names .difference_update (excluded )
96+
97+ @property
98+ def names (self ):
99+ return sorted (self .__names )
59100
60101 def _init_all (self , predicate ):
61- self .names . extend (pkg .name for pkg in Package .all () if predicate (pkg ))
102+ self .__names . update (pkg .name for pkg in Package .all () if predicate (pkg ))
62103
63104 def _init_standard (self , predicate ):
64- self .names . extend (pkg .name for pkg in Package .all () if pkg .type == 'standard' and predicate (pkg ))
105+ self .__names . update (pkg .name for pkg in Package .all () if pkg .type == 'standard' and predicate (pkg ))
65106
66107 def _init_optional (self , predicate ):
67- self .names . extend (pkg .name for pkg in Package .all () if pkg .type == 'optional' and predicate (pkg ))
108+ self .__names . update (pkg .name for pkg in Package .all () if pkg .type == 'optional' and predicate (pkg ))
68109
69110 def _init_experimental (self , predicate ):
70- self .names . extend (pkg .name for pkg in Package .all () if pkg .type == 'experimental' and predicate (pkg ))
111+ self .__names . update (pkg .name for pkg in Package .all () if pkg .type == 'experimental' and predicate (pkg ))
71112
72113 def apply (self , function , * args , ** kwds ):
73114 for package_name in self .names :
0 commit comments