@@ -986,12 +986,28 @@ def test_read_start_file_comments_and_blanks(self):
986986 fullname = os .path .join (self .sitedir , 'foo.start' )
987987 self .assertEqual (site ._pending_entrypoints [fullname ], ['os.path:join' ])
988988
989- def test_read_start_file_missing_colon_skipped (self ):
990- # Entry points without the mandatory colon are skipped.
991- self ._make_start ("os.path\n os.path:join\n " , name = 'foo' )
989+ def test_read_start_file_accepts_all_non_blank_lines (self ):
990+ # Syntax validation is deferred to entry-point execution time
991+ # (where pkgutil.resolve_name(strict=True) enforces the strict
992+ # pkg.mod:callable form), so parsing accepts every non-blank,
993+ # non-comment line, including syntactically invalid ones.
994+ content = (
995+ "os.path\n " # no colon
996+ "pkg.mod:\n " # empty callable
997+ ":callable\n " # empty module
998+ "pkg.mod:callable:extra\n " # multiple colons
999+ "os.path:join\n " # valid
1000+ )
1001+ self ._make_start (content , name = 'foo' )
9921002 site ._read_start_file (self .sitedir , 'foo.start' )
9931003 fullname = os .path .join (self .sitedir , 'foo.start' )
994- self .assertEqual (site ._pending_entrypoints [fullname ], ['os.path:join' ])
1004+ self .assertEqual (site ._pending_entrypoints [fullname ], [
1005+ 'os.path' ,
1006+ 'pkg.mod:' ,
1007+ ':callable' ,
1008+ 'pkg.mod:callable:extra' ,
1009+ 'os.path:join' ,
1010+ ])
9951011
9961012 def test_read_start_file_empty (self ):
9971013 # PEP 829: an empty .start file is still registered as present
@@ -1118,6 +1134,26 @@ def test_execute_entrypoints_import_error(self):
11181134 self .assertIn ('nosuchmodule_xyz' , err .getvalue ())
11191135 # os.path:join should still have been called (no exception for it)
11201136
1137+ def test_execute_entrypoints_strict_syntax_rejection (self ):
1138+ # PEP 829: only the strict pkg.mod:callable form is valid.
1139+ # At entry-point execution, pkgutil.resolve_name(strict=True)
1140+ # raises ValueError for invalid syntax; the invalid entry is
1141+ # reported and execution continues with the next one.
1142+ fullname = os .path .join (self .sitedir , 'bad.start' )
1143+ site ._pending_entrypoints [fullname ] = [
1144+ 'os.path' , # no colon
1145+ 'pkg.mod:' , # empty callable
1146+ ':callable' , # empty module
1147+ 'pkg.mod:callable:extra' , # multiple colons
1148+ ]
1149+ with captured_stderr () as err :
1150+ site ._execute_start_entrypoints ()
1151+ out = err .getvalue ()
1152+ self .assertIn ('Invalid entry point syntax' , out )
1153+ for bad in ('os.path' , 'pkg.mod:' , ':callable' ,
1154+ 'pkg.mod:callable:extra' ):
1155+ self .assertIn (bad , out )
1156+
11211157 def test_execute_entrypoints_callable_error (self ):
11221158 # Callable that raises prints traceback but continues.
11231159 mod_dir = os .path .join (self .sitedir , 'badmod' )
0 commit comments