@@ -41,6 +41,9 @@ def makedist(path, **attrs):
4141@pytest .mark .uses_network
4242def test_apply_pyproject_equivalent_to_setupcfg (url , monkeypatch , tmp_path ):
4343 monkeypatch .setattr (expand , "read_attr" , Mock (return_value = "0.0.1" ))
44+ monkeypatch .setattr (
45+ Distribution , "_validate_and_expand_pattern" , Mock (return_value = [])
46+ )
4447 setupcfg_example = retrieve_file (url )
4548 pyproject_example = Path (tmp_path , "pyproject.toml" )
4649 setupcfg_text = setupcfg_example .read_text (encoding = "utf-8" )
@@ -390,17 +393,21 @@ def base_pyproject(
390393 text ,
391394 count = 1 ,
392395 )
393- assert license_toml in text # sanity check
396+ if r"\\" not in license_toml :
397+ assert license_toml in text # sanity check
394398 text = f"{ text } \n { additional_text } \n "
395399 pyproject = _pep621_example_project (tmp_path , "README" , pyproject_text = text )
396400 return pyproject
397401
398- def base_pyproject_license_pep639 (self , tmp_path , additional_text = "" ):
402+ def base_pyproject_license_pep639 (
403+ self , tmp_path , additional_text = "" , * , license_files = None
404+ ):
405+ license_files = license_files or '["_FILE*"]'
399406 return self .base_pyproject (
400407 tmp_path ,
401408 additional_text = additional_text ,
402409 license_toml = 'license = "licenseref-Proprietary"'
403- '\n license-files = ["_FILE*"] \n ' ,
410+ f '\n license-files = { license_files } \n ' ,
404411 )
405412
406413 def test_both_license_and_license_files_defined (self , tmp_path ):
@@ -478,6 +485,58 @@ def test_deprecated_file_expands_to_text(self, tmp_path):
478485 assert dist .metadata .license == "--- LICENSE stub ---"
479486 assert set (dist .metadata .license_files ) == {"LICENSE.txt" } # auto-filled
480487
488+ def test_missing_patterns (self , tmp_path ):
489+ pyproject = self .base_pyproject_license_pep639 (tmp_path )
490+ assert list (tmp_path .glob ("_FILE*" )) == [] # sanity check
491+
492+ msg = r"License file pattern '_FILE\*' did not match any files."
493+ with pytest .raises (InvalidConfigError , match = msg ):
494+ pyprojecttoml .apply_configuration (makedist (tmp_path ), pyproject )
495+
496+ @pytest .mark .parametrize (
497+ ("license_files" , "msg" ),
498+ [
499+ pytest .param (
500+ '["../folder/LICENSE"]' ,
501+ "License file pattern '../folder/LICENSE' cannot contain '..'" ,
502+ id = ".." ,
503+ ),
504+ pytest .param (
505+ '["folder/../LICENSE"]' ,
506+ "License file pattern 'folder/../LICENSE' cannot contain '..'" ,
507+ id = "..2" ,
508+ ),
509+ pytest .param (
510+ '["/folder/LICENSE"]' ,
511+ "License file pattern '/folder/LICENSE' should be "
512+ "relative and must not start with '/'" ,
513+ id = "absolute-path" ,
514+ ),
515+ pytest .param (
516+ f'["C:{ r"\\" * 2 } folder{ r"\\" * 2 } LICENSE"]' ,
517+ r"License file pattern 'C:\\folder\\LICENSE' should be "
518+ "relative and must not start with '/'" ,
519+ id = "absolute-path2" ,
520+ ),
521+ pytest .param (
522+ '["~LICENSE"]' ,
523+ r"License file pattern '~LICENSE' contains invalid characters" ,
524+ id = "invalid_chars" ,
525+ ),
526+ pytest .param (
527+ '["LICENSE$"]' ,
528+ r"License file pattern 'LICENSE\$' contains invalid characters" ,
529+ id = "invalid_chars2" ,
530+ ),
531+ ],
532+ )
533+ def test_validate_patterns (self , tmp_path , license_files , msg ):
534+ pyproject = self .base_pyproject_license_pep639 (
535+ tmp_path , license_files = license_files
536+ )
537+ with pytest .raises (InvalidConfigError , match = msg ):
538+ pyprojecttoml .apply_configuration (makedist (tmp_path ), pyproject )
539+
481540
482541class TestPyModules :
483542 # https://github.com/pypa/setuptools/issues/4316
0 commit comments