@@ -393,15 +393,21 @@ def cmd_recheck(
393
393
t1 = time .time ()
394
394
manager = self .fine_grained_manager .manager
395
395
manager .log (f"fine-grained increment: cmd_recheck: { t1 - t0 :.3f} s" )
396
- self .options .export_types = export_types
396
+ old_export_types = self .options .export_types
397
+ self .options .export_types = self .options .export_types or export_types
397
398
if not self .following_imports ():
398
- messages = self .fine_grained_increment (sources , remove , update )
399
+ messages = self .fine_grained_increment (
400
+ sources , remove , update , explicit_export_types = export_types
401
+ )
399
402
else :
400
403
assert remove is None and update is None
401
- messages = self .fine_grained_increment_follow_imports (sources )
404
+ messages = self .fine_grained_increment_follow_imports (
405
+ sources , explicit_export_types = export_types
406
+ )
402
407
res = self .increment_output (messages , sources , is_tty , terminal_width )
403
408
self .flush_caches ()
404
409
self .update_stats (res )
410
+ self .options .export_types = old_export_types
405
411
return res
406
412
407
413
def check (
@@ -412,17 +418,21 @@ def check(
412
418
If is_tty is True format the output nicely with colors and summary line
413
419
(unless disabled in self.options). Also pass the terminal_width to formatter.
414
420
"""
415
- self .options .export_types = export_types
421
+ old_export_types = self .options .export_types
422
+ self .options .export_types = self .options .export_types or export_types
416
423
if not self .fine_grained_manager :
417
424
res = self .initialize_fine_grained (sources , is_tty , terminal_width )
418
425
else :
419
426
if not self .following_imports ():
420
- messages = self .fine_grained_increment (sources )
427
+ messages = self .fine_grained_increment (sources , explicit_export_types = export_types )
421
428
else :
422
- messages = self .fine_grained_increment_follow_imports (sources )
429
+ messages = self .fine_grained_increment_follow_imports (
430
+ sources , explicit_export_types = export_types
431
+ )
423
432
res = self .increment_output (messages , sources , is_tty , terminal_width )
424
433
self .flush_caches ()
425
434
self .update_stats (res )
435
+ self .options .export_types = old_export_types
426
436
return res
427
437
428
438
def flush_caches (self ) -> None :
@@ -535,6 +545,7 @@ def fine_grained_increment(
535
545
sources : list [BuildSource ],
536
546
remove : list [str ] | None = None ,
537
547
update : list [str ] | None = None ,
548
+ explicit_export_types : bool = False ,
538
549
) -> list [str ]:
539
550
"""Perform a fine-grained type checking increment.
540
551
@@ -545,6 +556,8 @@ def fine_grained_increment(
545
556
sources: sources passed on the command line
546
557
remove: paths of files that have been removed
547
558
update: paths of files that have been changed or created
559
+ explicit_export_types: --export-type was passed in a check command
560
+ (as opposite to being set in dmypy start)
548
561
"""
549
562
assert self .fine_grained_manager is not None
550
563
manager = self .fine_grained_manager .manager
@@ -559,6 +572,10 @@ def fine_grained_increment(
559
572
# Use the remove/update lists to update fswatcher.
560
573
# This avoids calling stat() for unchanged files.
561
574
changed , removed = self .update_changed (sources , remove or [], update or [])
575
+ if explicit_export_types :
576
+ # If --export-types is given, we need to force full re-checking of all
577
+ # explicitly passed files, since we need to visit each expression.
578
+ add_all_sources_to_changed (sources , changed )
562
579
changed += self .find_added_suppressed (
563
580
self .fine_grained_manager .graph , set (), manager .search_paths
564
581
)
@@ -577,7 +594,9 @@ def fine_grained_increment(
577
594
self .previous_sources = sources
578
595
return messages
579
596
580
- def fine_grained_increment_follow_imports (self , sources : list [BuildSource ]) -> list [str ]:
597
+ def fine_grained_increment_follow_imports (
598
+ self , sources : list [BuildSource ], explicit_export_types : bool = False
599
+ ) -> list [str ]:
581
600
"""Like fine_grained_increment, but follow imports."""
582
601
t0 = time .time ()
583
602
@@ -603,6 +622,9 @@ def fine_grained_increment_follow_imports(self, sources: list[BuildSource]) -> l
603
622
changed , new_files = self .find_reachable_changed_modules (
604
623
sources , graph , seen , changed_paths
605
624
)
625
+ if explicit_export_types :
626
+ # Same as in fine_grained_increment().
627
+ add_all_sources_to_changed (sources , changed )
606
628
sources .extend (new_files )
607
629
608
630
# Process changes directly reachable from roots.
@@ -1011,6 +1033,22 @@ def find_all_sources_in_build(
1011
1033
return result
1012
1034
1013
1035
1036
+ def add_all_sources_to_changed (sources : list [BuildSource ], changed : list [tuple [str , str ]]) -> None :
1037
+ """Add all (explicit) sources to the list changed files in place.
1038
+
1039
+ Use this when re-processing of unchanged files is needed (e.g. for
1040
+ the purpose of exporting types for inspections).
1041
+ """
1042
+ changed_set = set (changed )
1043
+ changed .extend (
1044
+ [
1045
+ (bs .module , bs .path )
1046
+ for bs in sources
1047
+ if bs .path and (bs .module , bs .path ) not in changed_set
1048
+ ]
1049
+ )
1050
+
1051
+
1014
1052
def fix_module_deps (graph : mypy .build .Graph ) -> None :
1015
1053
"""After an incremental update, update module dependencies to reflect the new state.
1016
1054
0 commit comments