@@ -313,22 +313,29 @@ def open(self) -> None:
313313 scientific = self .linter .config .strict_scientific_notation
314314 engineering = self .linter .config .strict_engineering_notation
315315 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 :
318318 raise ValueError (
319319 "Only one of strict-scientific-notation, "
320- "strict-engineering-notation, or strict-underscore-notation "
320+ "' strict-engineering-notation' , or ' strict-underscore-notation' "
321321 "can be set to True at a time."
322322 )
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+ )
332339
333340 def new_line (self , tokens : TokenWrapper , line_end : int , line_start : int ) -> None :
334341 """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]:
557564 """
558565 if number == 0 :
559566 return "0" , "0"
567+ if number == math .inf :
568+ return "math.inf" , "0"
569+ print (f"Converting { number } to standard or engineering base" )
560570 exponent = math .floor (math .log10 (abs (number )))
561571 if exponent == 0 :
562572 return str (number ), "0"
@@ -570,6 +580,8 @@ def to_standard_or_engineering_base(cls, number: float) -> tuple[str, str]:
570580 @classmethod
571581 def to_standard_scientific_notation (cls , number : float ) -> str :
572582 base , exp = cls .to_standard_or_engineering_base (number )
583+ if base == "math.inf" :
584+ return "math.inf"
573585 if exp != "0" :
574586 return f"{ base } e{ int (exp )} "
575587 if "." in base :
@@ -579,6 +591,8 @@ def to_standard_scientific_notation(cls, number: float) -> str:
579591 @classmethod
580592 def to_standard_engineering_notation (cls , number : float ) -> str :
581593 base , exp = cls .to_standard_or_engineering_base (number )
594+ if base == "math.inf" :
595+ return "math.inf"
582596 exp_value = int (exp )
583597 remainder = exp_value % 3
584598 # For negative exponents, the adjustment is different
@@ -623,91 +637,114 @@ def to_standard_underscore_grouping(cls, number: float) -> str:
623637 grouped_int_part = digit + grouped_int_part
624638 return f"{ grouped_int_part } .{ dec_part } "
625639
626- def _check_bad_float_notation (
640+ def _check_bad_float_notation ( # pylint: disable=too-many-locals
627641 self , line_num : int , start : tuple [int , int ], string : str
628642 ) -> 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+ )
629656
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 )
631666 return self .add_message (
632667 "bad-float-notation" ,
633- args = ("' or '" .join (suggested )),
668+ args = ("' or '" .join (sorted ( suggested ) )),
634669 line = line_num ,
670+ end_lineno = line_num ,
635671 col_offset = start [1 ],
672+ end_col_offset = start [1 ] + len (string ),
636673 confidence = HIGH ,
637674 )
638675
639- value = float (string )
640- threshold = self .linter .config .float_notation_threshold
641- abs_value = abs (value )
642676 has_underscore = "_" in string
643677 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+ )
644698 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 ,
654701 )
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 ()
655709 if has_exponent :
656710 if self .linter .config .strict_underscore_notation :
657711 # 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 :
694733 # 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 (
704741 r"^\d{0,3}(_\d{3})*\.?\d*([eE]-?\d{0,3}(_\d{3})*)?$" , string
705742 )
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 ()
711748 return None
712749
713750 def _check_line_ending (self , line_ending : str , line_num : int ) -> None :
0 commit comments