@@ -122,12 +122,26 @@ _feature_flags = {}
122122
123123_requirement_attrs = {
124124 "extra_requires" : attr .string_list_dict (
125- doc = "List of optional requirements for this package" ,
125+ doc = ("A mapping of [extras](https://peps.python.org/pep-0508/#extras) options to lists of requirements (similar to `requires`). This attribute " +
126+ "is mutually exclusive with `extra_requires_file`." ),
127+ ),
128+ "extra_requires_files" : attr .label_keyed_string_dict (
129+ doc = ("A mapping of requirements files (similar to `requires_file`) to the name of an [extras](https://peps.python.org/pep-0508/#extras) option " +
130+ "This attribute is mutually exclusive with `extra_requires`." ),
131+ allow_files = True ,
126132 ),
127133 "requires" : attr .string_list (
128134 doc = ("List of requirements for this package. See the section on " +
129135 "[Declaring required dependency](https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#declaring-dependencies) " +
130- "for details and examples of the format of this argument." ),
136+ "for details and examples of the format of this argument. This " +
137+ "attribute is mutually exclusive with `requires_file`." ),
138+ ),
139+ "requires_file" : attr .label (
140+ doc = ("A file containing a list of requirements for this package. See the section on " +
141+ "[Declaring required dependency](https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#declaring-dependencies) " +
142+ "for details and examples of the format of this argument. This " +
143+ "attribute is mutually exclusive with `requires`." ),
144+ allow_single_file = True ,
131145 ),
132146}
133147
@@ -365,15 +379,50 @@ def _py_wheel_impl(ctx):
365379
366380 if ctx .attr .python_requires :
367381 metadata_contents .append ("Requires-Python: %s" % ctx .attr .python_requires )
368- for requirement in ctx .attr .requires :
369- metadata_contents .append ("Requires-Dist: %s" % requirement )
370382
383+ if ctx .attr .requires and ctx .attr .requires_file :
384+ fail ("`requires` and `requires_file` are mutually exclusive. Please update {}" .format (ctx .label ))
385+
386+ for requires in ctx .attr .requires :
387+ metadata_contents .append ("Requires-Dist: %s" % requires )
388+ if ctx .attr .requires_file :
389+ # The @ prefixed paths will be resolved by the PyWheel action.
390+ # Expanding each line containing a constraint in place of this
391+ # directive.
392+ metadata_contents .append ("Requires-Dist: @%s" % ctx .file .requires_file .path )
393+ other_inputs .append (ctx .file .requires_file )
394+
395+ if ctx .attr .extra_requires and ctx .attr .extra_requires_files :
396+ fail ("`extra_requires` and `extra_requires_files` are mutually exclusive. Please update {}" .format (ctx .label ))
371397 for option , option_requirements in sorted (ctx .attr .extra_requires .items ()):
372398 metadata_contents .append ("Provides-Extra: %s" % option )
373399 for requirement in option_requirements :
374400 metadata_contents .append (
375401 "Requires-Dist: %s; extra == '%s'" % (requirement , option ),
376402 )
403+ extra_requires_files = {}
404+ for option_requires_target , option in ctx .attr .extra_requires_files .items ():
405+ if option in extra_requires_files :
406+ fail ("Duplicate `extra_requires_files` option '{}' found on target {}" .format (option , ctx .label ))
407+ option_requires_files = option_requires_target [DefaultInfo ].files .to_list ()
408+ if len (option_requires_files ) != 1 :
409+ fail ("Labels in `extra_requires_files` must result in a single file, but {label} provides {files} from {owner}" .format (
410+ label = ctx .label ,
411+ files = option_requires_files ,
412+ owner = option_requires_target .label ,
413+ ))
414+ extra_requires_files .update ({option : option_requires_files [0 ]})
415+
416+ for option , option_requires_file in sorted (extra_requires_files .items ()):
417+ metadata_contents .append ("Provides-Extra: %s" % option )
418+ metadata_contents .append (
419+ # The @ prefixed paths will be resolved by the PyWheel action.
420+ # Expanding each line containing a constraint in place of this
421+ # directive and appending the extra option.
422+ "Requires-Dist: @%s; extra == '%s'" % (option_requires_file .path , option ),
423+ )
424+ other_inputs .append (option_requires_file )
425+
377426 ctx .actions .write (
378427 output = metadata_file ,
379428 content = "\n " .join (metadata_contents ) + "\n " ,
@@ -425,6 +474,7 @@ def _py_wheel_impl(ctx):
425474 )
426475
427476 ctx .actions .run (
477+ mnemonic = "PyWheel" ,
428478 inputs = depset (direct = other_inputs , transitive = [inputs_to_package ]),
429479 outputs = [outfile , name_file ],
430480 arguments = [args ],
0 commit comments