@@ -313,22 +313,29 @@ def open(self) -> None:
313
313
scientific = self .linter .config .strict_scientific_notation
314
314
engineering = self .linter .config .strict_engineering_notation
315
315
underscore = self .linter .config .strict_underscore_notation
316
- float_config = sum ([scientific , engineering , underscore ])
317
- if float_config > 1 :
316
+ number_of_strict_float_notation = sum ([scientific , engineering , underscore ])
317
+ if number_of_strict_float_notation > 1 :
318
318
raise ValueError (
319
319
"Only one of strict-scientific-notation, "
320
- "strict-engineering-notation, or strict-underscore-notation "
320
+ "' strict-engineering-notation' , or ' strict-underscore-notation' "
321
321
"can be set to True at a time."
322
322
)
323
- if float_config == 0 :
324
- # i.e. nothing is strict so we should check all
325
- self .should_check_scientific_notation = True
326
- self .should_check_engineering_notation = True
327
- self .should_check_underscore_notation = True
328
- else :
329
- self .should_check_scientific_notation = scientific
330
- self .should_check_engineering_notation = engineering
331
- self .should_check_underscore_notation = underscore
323
+ self .all_float_notation_allowed = number_of_strict_float_notation == 0
324
+ if (
325
+ self .linter .config .float_notation_threshold < 10
326
+ and self .linter .config .strict_scientific_notation
327
+ ):
328
+ raise ValueError (
329
+ "'float-notation-threshold' must be at least 10 "
330
+ "when 'strict-scientific-notation' is enabled, got "
331
+ f"{ self .linter .config .float_notation_threshold } ."
332
+ )
333
+ if self .linter .config .float_notation_threshold < 1000 :
334
+ raise ValueError (
335
+ "'float-notation-threshold' must be at least 1000 "
336
+ f"when 'strict-scientific-notation' is disabled, got "
337
+ f"{ self .linter .config .float_notation_threshold } ."
338
+ )
332
339
333
340
def new_line (self , tokens : TokenWrapper , line_end : int , line_start : int ) -> None :
334
341
"""A new line has been encountered, process it if necessary."""
@@ -557,6 +564,9 @@ def to_standard_or_engineering_base(cls, number: float) -> tuple[str, str]:
557
564
"""
558
565
if number == 0 :
559
566
return "0" , "0"
567
+ if number == math .inf :
568
+ return "math.inf" , "0"
569
+ print (f"Converting { number } to standard or engineering base" )
560
570
exponent = math .floor (math .log10 (abs (number )))
561
571
if exponent == 0 :
562
572
return str (number ), "0"
@@ -570,6 +580,8 @@ def to_standard_or_engineering_base(cls, number: float) -> tuple[str, str]:
570
580
@classmethod
571
581
def to_standard_scientific_notation (cls , number : float ) -> str :
572
582
base , exp = cls .to_standard_or_engineering_base (number )
583
+ if base == "math.inf" :
584
+ return "math.inf"
573
585
if exp != "0" :
574
586
return f"{ base } e{ int (exp )} "
575
587
if "." in base :
@@ -579,6 +591,8 @@ def to_standard_scientific_notation(cls, number: float) -> str:
579
591
@classmethod
580
592
def to_standard_engineering_notation (cls , number : float ) -> str :
581
593
base , exp = cls .to_standard_or_engineering_base (number )
594
+ if base == "math.inf" :
595
+ return "math.inf"
582
596
exp_value = int (exp )
583
597
remainder = exp_value % 3
584
598
# For negative exponents, the adjustment is different
@@ -623,91 +637,114 @@ def to_standard_underscore_grouping(cls, number: float) -> str:
623
637
grouped_int_part = digit + grouped_int_part
624
638
return f"{ grouped_int_part } .{ dec_part } "
625
639
626
- def _check_bad_float_notation (
640
+ def _check_bad_float_notation ( # pylint: disable=too-many-locals
627
641
self , line_num : int , start : tuple [int , int ], string : str
628
642
) -> None :
643
+ value = float (string )
644
+ engineering = (
645
+ self .all_float_notation_allowed
646
+ or self .linter .config .strict_engineering_notation
647
+ )
648
+ scientific = (
649
+ self .all_float_notation_allowed
650
+ or self .linter .config .strict_scientific_notation
651
+ )
652
+ pep515 = (
653
+ self .all_float_notation_allowed
654
+ or self .linter .config .strict_underscore_notation
655
+ )
629
656
630
- def raise_bad_float_notation (suggested : set [str ]) -> None :
657
+ def raise_bad_float_notation () -> None :
658
+ suggested = set ()
659
+ if scientific :
660
+ suggested .add (self .to_standard_scientific_notation (value ))
661
+ if engineering :
662
+ suggested .add (self .to_standard_engineering_notation (value ))
663
+ if pep515 :
664
+ suggested .add (self .to_standard_underscore_grouping (value ))
665
+ print ("\t Bad float notation, suggesting:" , suggested )
631
666
return self .add_message (
632
667
"bad-float-notation" ,
633
- args = ("' or '" .join (suggested )),
668
+ args = ("' or '" .join (sorted ( suggested ) )),
634
669
line = line_num ,
670
+ end_lineno = line_num ,
635
671
col_offset = start [1 ],
672
+ end_col_offset = start [1 ] + len (string ),
636
673
confidence = HIGH ,
637
674
)
638
675
639
- value = float (string )
640
- threshold = self .linter .config .float_notation_threshold
641
- abs_value = abs (value )
642
676
has_underscore = "_" in string
643
677
has_exponent = "e" in string or "E" in string
678
+ should_be_written_simply = (
679
+ 1 <= value < 10 and self .linter .config .strict_scientific_notation
680
+ ) or 1 <= value < 1000
681
+ is_written_complexly = has_underscore or has_exponent
682
+ print (f"Checking { string } line { line_num } " )
683
+ if should_be_written_simply and is_written_complexly :
684
+ print (f"\t { value } is a simple number" )
685
+ # If the value does not deserve a complex notation then write it in a simple way.
686
+ # The threshold is guaranteed to be higher than those value.
687
+ # When 1 <= value < 10 the engineering notation is equivalent to the scientific notation
688
+ return raise_bad_float_notation ()
689
+
690
+ abs_value = abs (value )
691
+ should_not_be_checked_because_of_threshold = (
692
+ abs_value < self .linter .config .float_notation_threshold # under threshold
693
+ and ( # use scientific or engineering notation and under 1/threshold
694
+ self .linter .config .strict_underscore_notation
695
+ or abs_value > 1 / self .linter .config .float_notation_threshold
696
+ )
697
+ )
644
698
print (
645
- f"Checking { string } { line_num } : "
646
- f"s:{ self .should_check_scientific_notation } "
647
- f"e:{ self .should_check_engineering_notation } "
648
- f"u;{ self .should_check_underscore_notation } "
649
- f"has_underscore: { has_underscore } "
650
- f"has_exponent: { has_exponent } "
651
- f"abs_value: { abs_value } "
652
- f"threshold: { threshold } "
653
- f"strict_scientific_notation: { self .linter .config .strict_scientific_notation } "
699
+ "\t should_not_be_checked_because_of_threshold=" ,
700
+ should_not_be_checked_because_of_threshold ,
654
701
)
702
+ if not is_written_complexly :
703
+ if should_not_be_checked_because_of_threshold :
704
+ # This number is free style, we do not have to check it, unless it's
705
+ # written complexly, then it could be badly written
706
+ print ("\t Free style number, no need to check" )
707
+ return None
708
+ return raise_bad_float_notation ()
655
709
if has_exponent :
656
710
if self .linter .config .strict_underscore_notation :
657
711
# If we have exponent it means it's not proper underscore
658
- return raise_bad_float_notation (
659
- {self .to_standard_underscore_grouping (value )}
660
- )
661
- if abs_value > threshold or abs_value < 1 / threshold :
662
- value_as_str , exponent_as_str = string .lower ().split ("e" )
663
- value = float (value_as_str )
664
- wrong_scientific_notation = (
665
- self .should_check_scientific_notation and not (1 <= value < 10 )
666
- )
667
- if (
668
- self .linter .config .strict_scientific_notation
669
- and wrong_scientific_notation
670
- ):
671
- return raise_bad_float_notation (
672
- {self .to_standard_scientific_notation (value )}
673
- )
674
- wrong_engineering_notation = (
675
- self .should_check_engineering_notation
676
- and not (1 <= value < 1000 and int (exponent_as_str ) % 3 == 0 )
677
- )
678
- if (
679
- self .linter .config .strict_engineering_notation
680
- and wrong_engineering_notation
681
- ):
682
- return raise_bad_float_notation (
683
- {self .to_standard_engineering_notation (value )}
684
- )
685
- if wrong_scientific_notation and wrong_engineering_notation :
686
- return raise_bad_float_notation (
687
- {
688
- self .to_standard_scientific_notation (value ),
689
- self .to_standard_engineering_notation (value ),
690
- self .to_standard_underscore_grouping (value ),
691
- }
692
- )
693
- if has_underscore :
712
+ return raise_bad_float_notation ()
713
+ base_as_str , exponent_as_str = string .lower ().split ("e" )
714
+ base = float (base_as_str )
715
+ print ("\t Base:" , base , "Exponent:" , exponent_as_str )
716
+ wrong_scientific_notation = not (1 <= base < 10 )
717
+ print (f"\t wrong_scientific_notation:{ wrong_scientific_notation } " )
718
+ if (
719
+ self .linter .config .strict_scientific_notation
720
+ and wrong_scientific_notation
721
+ ):
722
+ return raise_bad_float_notation ()
723
+ wrong_engineering_notation = not (
724
+ 1 <= base < 1000 and int (exponent_as_str ) % 3 == 0
725
+ )
726
+ print (f"\t wrong_engineering_notation:{ wrong_engineering_notation } " )
727
+ if (
728
+ self .linter .config .strict_engineering_notation
729
+ and wrong_engineering_notation
730
+ ) or (wrong_scientific_notation and wrong_engineering_notation ):
731
+ return raise_bad_float_notation ()
732
+ elif has_underscore :
694
733
# If we have underscore and exponent, we suggest exponent by default
695
- if self .linter .config .strict_scientific_notation :
696
- return raise_bad_float_notation (
697
- {self .to_standard_scientific_notation (value )}
698
- )
699
- if self .linter .config .strict_engineering_notation :
700
- return raise_bad_float_notation (
701
- {self .to_standard_engineering_notation (value )}
702
- )
703
- underscore_notation = has_underscore and re .match (
734
+ print ("\t Has underscore, checking underscore grouping" )
735
+ if (
736
+ self .linter .config .strict_scientific_notation
737
+ or self .linter .config .strict_engineering_notation
738
+ ):
739
+ return raise_bad_float_notation ()
740
+ wrong_underscore_notation = not re .match (
704
741
r"^\d{0,3}(_\d{3})*\.?\d*([eE]-?\d{0,3}(_\d{3})*)?$" , string
705
742
)
706
- if not underscore_notation :
707
- return raise_bad_float_notation (
708
- { self . to_standard_underscore_grouping ( value )}
709
- )
710
- return None
743
+ print ( f" \t wrong_underscore_notation: { wrong_underscore_notation } " )
744
+ if pep515 and wrong_underscore_notation :
745
+ return raise_bad_float_notation ()
746
+ else :
747
+ return raise_bad_float_notation ()
711
748
return None
712
749
713
750
def _check_line_ending (self , line_ending : str , line_num : int ) -> None :
0 commit comments