@@ -490,7 +490,10 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
490490 result .Gen = append (result .Gen , pyTest )
491491 result .Imports = append (result .Imports , pyTest .PrivateAttr (config .GazelleImportsKey ))
492492 }
493-
493+ if ! cfg .CoarseGrainedGeneration () {
494+ emptyRules := py .getRulesWithInvalidSrcs (cfg , args )
495+ result .Empty = append (result .Empty , emptyRules ... )
496+ }
494497 if ! collisionErrors .Empty () {
495498 it := collisionErrors .Iterator ()
496499 for it .Next () {
@@ -502,6 +505,48 @@ func (py *Python) GenerateRules(args language.GenerateArgs) language.GenerateRes
502505 return result
503506}
504507
508+ // getRulesWithInvalidSrcs checks existing Python rules in the BUILD file and return the rules with invalid source files.
509+ // Invalid source files are files that do not exist or not a target.
510+ func (py * Python ) getRulesWithInvalidSrcs (cfg * pythonconfig.Config , args language.GenerateArgs ) (invalidRules []* rule.Rule ) {
511+ if args .File == nil {
512+ return
513+ }
514+ filesMap := make (map [string ]struct {})
515+ for _ , file := range args .RegularFiles {
516+ if cfg .IgnoresFile (filepath .Base (file )) {
517+ continue
518+ }
519+ filesMap [file ] = struct {}{}
520+ }
521+ for _ , file := range args .GenFiles {
522+ filesMap [file ] = struct {}{}
523+ }
524+
525+ isTarget := func (src string ) bool {
526+ return strings .HasPrefix (src , "@" ) || strings .HasPrefix (src , "//" ) || strings .HasPrefix (src , ":" )
527+ }
528+ for _ , existingRule := range args .File .Rules {
529+ if existingRule .Kind () != pyBinaryKind {
530+ continue
531+ }
532+ var hasValidSrcs bool
533+ for _ , src := range existingRule .AttrStrings ("srcs" ) {
534+ if isTarget (src ) {
535+ hasValidSrcs = true
536+ break
537+ }
538+ if _ , ok := filesMap [src ]; ok {
539+ hasValidSrcs = true
540+ break
541+ }
542+ }
543+ if ! hasValidSrcs {
544+ invalidRules = append (invalidRules , newTargetBuilder (existingRule .Kind (), existingRule .Name (), args .Config .RepoRoot , args .Rel , nil ).build ())
545+ }
546+ }
547+ return invalidRules
548+ }
549+
505550// isBazelPackage determines if the directory is a Bazel package by probing for
506551// the existence of a known BUILD file name.
507552func isBazelPackage (dir string ) bool {
0 commit comments