@@ -231,9 +231,14 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
231231	}
232232
233233	collisionErrors  :=  singlylinkedlist .New ()
234+ 	// Create a validFilesMap of mainModules to validate if python macros have valid srcs. 
235+ 	validFilesMap  :=  make (map [string ]struct {})
234236
235237	appendPyLibrary  :=  func (srcs  * treeset.Set , pyLibraryTargetName  string ) {
236238		allDeps , mainModules , annotations , err  :=  parser .parse (srcs )
239+ 		for  name  :=  range  mainModules  {
240+ 			validFilesMap [name ] =  struct {}{}
241+ 		}
237242		if  err  !=  nil  {
238243			log .Fatalf ("ERROR: %v\n " , err )
239244		}
@@ -363,6 +368,7 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
363368			setAnnotations (* annotations ).
364369			generateImportsAttribute ()
365370
371+ 
366372		pyBinary  :=  pyBinaryTarget .build ()
367373
368374		result .Gen  =  append (result .Gen , pyBinary )
@@ -490,7 +496,8 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
490496		result .Gen  =  append (result .Gen , pyTest )
491497		result .Imports  =  append (result .Imports , pyTest .PrivateAttr (config .GazelleImportsKey ))
492498	}
493- 
499+ 	emptyRules  :=  py .getRulesWithInvalidSrcs (args , validFilesMap )
500+ 	result .Empty  =  append (result .Empty , emptyRules ... )
494501	if  ! collisionErrors .Empty () {
495502		it  :=  collisionErrors .Iterator ()
496503		for  it .Next () {
@@ -502,6 +509,42 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
502509	return  result 
503510}
504511
512+ // getRulesWithInvalidSrcs checks existing Python rules in the BUILD file and return the rules with invalid source files. 
513+ // Invalid source files are files that do not exist or not a target. 
514+ func  (py  * Python ) getRulesWithInvalidSrcs (args  language.GenerateArgs , validFilesMap  map [string ]struct {}) (invalidRules  []* rule.Rule ) {
515+ 	if  args .File  ==  nil  {
516+ 		return 
517+ 	}
518+ 	for  _ , file  :=  range  args .GenFiles  {
519+ 		validFilesMap [file ] =  struct {}{}
520+ 	}
521+ 
522+ 	isTarget  :=  func (src  string ) bool  {
523+ 		return  strings .HasPrefix (src , "@" ) ||  strings .HasPrefix (src , "//" ) ||  strings .HasPrefix (src , ":" )
524+ 	}
525+ 	for  _ , existingRule  :=  range  args .File .Rules  {
526+ 		actualPyBinaryKind  :=  GetActualKindName (pyBinaryKind , args )
527+ 		if  existingRule .Kind () !=  actualPyBinaryKind  {
528+ 			continue 
529+ 		}
530+ 		var  hasValidSrcs  bool 
531+ 		for  _ , src  :=  range  existingRule .AttrStrings ("srcs" ) {
532+ 			if  isTarget (src ) {
533+ 				hasValidSrcs  =  true 
534+ 				break 
535+ 			}
536+ 			if  _ , ok  :=  validFilesMap [src ]; ok  {
537+ 				hasValidSrcs  =  true 
538+ 				break 
539+ 			}
540+ 		}
541+ 		if  ! hasValidSrcs  {
542+ 			invalidRules  =  append (invalidRules , newTargetBuilder (pyBinaryKind , existingRule .Name (), "" , "" , nil , false ).build ())
543+ 		}
544+ 	}
545+ 	return  invalidRules 
546+ }
547+ 
505548// isBazelPackage determines if the directory is a Bazel package by probing for 
506549// the existence of a known BUILD file name. 
507550func  isBazelPackage (dir  string ) bool  {
0 commit comments