packages feed

PyF 0.11.3.0 → 0.11.4.0

raw patch · 58 files changed

+347/−392 lines, 58 filesdep ~timePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: time

API changes (from Hackage documentation)

Files

ChangeLog.md view
@@ -1,5 +1,15 @@ # Revision history for PyF +## 0.11.4.0 -- 2025-01-03++- Fix indentation in `fmtTrim` when line break was escaped (bug https://github.com/guibou/PyF/issues/141).+- Support for GHC 9.12.+- Fix for tests in GHC 9.10.+- No more "python" reference check in the test phase. I'm removing complexity,+  and if it does not match the python implementation, we can just introduce a+  new test case. Note that python checking can be reimplemented easilly by+  parsing the AST.+ ## 0.11.3.0 -- 2024-05-15  - Support for GHC 9.10.@@ -27,8 +37,8 @@  - Support for GHC 9.4. (Written with a pre-release of GHC 9.4, hopefully it won't change too much before the release). - Error reporting now uses the native GHC API. In summary, it means that- haskell-language-server will point to the correct location of the error, not- the beginning of the quasi quotes.+  haskell-language-server will point to the correct location of the error, not+  the beginning of the quasi quotes. - PyF will now correctly locate the error for variable not found in expression, even if the expression is complicated. The support for complex expression is limited, and PyF may return a false positive if you try to format a complex lambda / case expression. Please open a ticket if you need that. - Add support for literal `[]` and `()` in haskell expression. - Add support for overloaded labels, thank you Shimuuar.@@ -48,21 +58,30 @@ ## 0.10.0.1 -- 2021-10-30  - Due to the dependencies refactor, `PyF` no have no dependencies other than the one packaged with GHC. The direct result is that `PyF` build time is reduced to 6s versus 4 minutes and 20s before.+ - Remove the dependency to `megaparsec` and replaces it by `parsec`. This should have minor impact on the error messages.+ - *Huge Change*. The parsing of embeded expression does not depend anymore on `haskell-src-ext` and `haskell-src-meta` and instead depends on the built-in `ghc` lib.+ - Added instances for `(Lazy)ByteString` to `PyFClassify` and `PyFToString`. `ByteString` can now be integrated into format string, and will be decoded as ascii.+ - Relax the constraint for floating point formatting from `RealFrac` to `Real`. As a result, a few new type can be formatted as floating point number. One drawback is that some `Integral` are `Real` too and hence it is not an error anymore to format an integral as floating point, but you still need to explicitly select a floating point formatter.+ - Added instance for `(Nominal)DiffTime` to `PyFClassify`, so you can now format them without conversion.+ - Introducing of the new typeclass `PyfFormatIntegral` and `PyfFormatFractional` in order to customize the formatting for numbers. An instance is derived for respectively any `Integral` and `Real` types.+ - Support for `Char` formatting, as string (showing the `Char` value) or as integral, showing the `ord`.+ - `Data.Ratio`.  - Introducing `fmtTrim` module. It offers the same behavior as `fmt`, but trims common indentation. Se `PyF.trimIndent` for documentation.+ - Introducing `raw` for convenience. It is a multiline string without any escaping, formatting neither leading whitespace handling.-- Introducing `str` and `strTrim`. They are similar to `fmt` and `fmtTrim` but without formatting. You can see them as multiline haskell string, with special character escaping, but without formatting. For convenience, the `strTrim` version also removes indentation. +- Introducing `str` and `strTrim`. They are similar to `fmt` and `fmtTrim` but without formatting. You can see them as multiline haskell string, with special character escaping, but without formatting. For convenience, the `strTrim` version also removes indentation. -- `fmtWithDelimiters` is gone and replaced by `mkFormatter` in `PyF` which is "more" generic. +- `fmtWithDelimiters` is gone and replaced by `mkFormatter` in `PyF` which is "more" generic.  ## 0.9.0.3 -- 2021-02-06 @@ -115,7 +134,6 @@ - Template haskell splices are simpler. This leads to more efficient / small generated code and in the event of this code appears in a GHC error message, it is more readable. - PyF now longer emit unnecessary default typing. - ## 0.7.3.0 -- 2019-02-28  - Tests: fix non reproducible tests@@ -127,7 +145,7 @@ ## 0.7.1.0 -- 2019-02-11  - Fixed: PyF was wrongly ignoring everything located after a non-doubled closing delimiter.-- New Feature: line break can be escaped with \, thus allowing string to start on a new line ignoring the initial backspace+- New Feature: line break can be escaped with , thus allowing string to start on a new line ignoring the initial backspace  ## 0.7.0.0 -- 2019-02-04 @@ -169,15 +187,14 @@ - Introduce `PyF.Formatters`, type safe generic number formatter solution - Remove dependency to `scientific` - ## 0.3.0.0 -- 2018-04-01 -* Support for haskell subexpression+- Support for haskell subexpression  ## 0.1.1.0  -- 2018-01-07 -* Add support for the `sign` field.+- Add support for the `sign` field.  ## 0.1.0.0  -- 2018-01-03 -* First version. Released on an unsuspecting world.+- First version. Released on an unsuspecting world.
PyF.cabal view
@@ -1,75 +1,107 @@-cabal-version:       2.4-name:                PyF-version:             0.11.3.0-synopsis:            Quasiquotations for a python like interpolated string formatter-description:         Quasiquotations for a python like interpolated string formatter.-license:             BSD-3-Clause-license-file:        LICENSE-author:              Guillaume Bouchard-maintainer:          guillaum.bouchard@gmail.com-category:            Text-build-type:          Simple-extra-source-files:  ChangeLog.md Readme.md test/golden/*.golden test/golden96/*.golden+cabal-version:      2.4+name:               PyF+version:            0.11.4.0+synopsis:+  Quasiquotations for a python like interpolated string formatter -Flag python_test-    Description: Enable extensive python testing-    Manual: True-    Default: False+description:+  Quasiquotations for a python like interpolated string formatter. +license:            BSD-3-Clause+license-file:       LICENSE+author:             Guillaume Bouchard+maintainer:         guillaum.bouchard@gmail.com+category:           Text+build-type:         Simple+extra-source-files:+  ChangeLog.md+  Readme.md+  test/golden/*.golden+  test/golden96/*.golden+ library   exposed-modules:-                  PyF-                  PyF.Class-                  PyF.Internal.PythonSyntax-                  PyF.Internal.Meta-                  PyF.Internal.QQ-                  PyF.Formatters-                  PyF.Internal.ParserEx-                  PyF.Internal.Parser+    PyF+    PyF.Class+    PyF.Formatters+    PyF.Internal.Meta+    PyF.Internal.Parser+    PyF.Internal.ParserEx+    PyF.Internal.PythonSyntax+    PyF.Internal.QQ -  build-depends:       base >= 4.12 && < 4.22-                     , bytestring >= 0.10.8 && < 0.13-                     , template-haskell >= 2.14.0 && < 2.24-                     , text >= 1.2.3 && < 2.2-                     , time >= 1.8.0 && < 1.14-                     , parsec >= 3.1.13 && < 3.2-                     , mtl >= 2.2.2 && < 2.4-                     , ghc >= 8.6.1-  if impl(ghc < 9.2.1)-    build-depends:-                       ghc-boot >= 8.6.1 && < 9.7-  hs-source-dirs: src-  ghc-options: -Wall -Wunused-packages -Wincomplete-uni-patterns-  default-language:    Haskell2010+  build-depends:+    , base              >=4.12   && <4.22+    , bytestring        >=0.10.8 && <0.13+    , ghc               >=8.6.1+    , mtl               >=2.2.2  && <2.4+    , parsec            >=3.1.13 && <3.2+    , template-haskell  >=2.14.0 && <2.24+    , text              >=1.2.3  && <2.2+    , time              >=1.8.0  && <1.15++  if impl(ghc <9.2.1)+    build-depends: ghc-boot >=8.6.1 && <9.7++  hs-source-dirs:     src+  ghc-options:        -Wall -Wunused-packages -Wincomplete-uni-patterns+  default-language:   Haskell2010   default-extensions: QuasiQuotes  test-suite pyf-test-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             Spec.hs-  other-modules: SpecUtils SpecCustomDelimiters-  build-depends:       base, PyF, hspec, template-haskell, text, bytestring, time-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages-  default-language:    Haskell2010-  if flag(python_test)-    cpp-options: -DPYTHON_TEST-    build-depends:       process+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test+  main-is:          Spec.hs+  other-modules:    SpecCustomDelimiters+  build-depends:+    , base+    , bytestring+    , hspec+    , PyF+    , template-haskell+    , text+    , time +  ghc-options:+    -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages++  default-language: Haskell2010+ test-suite pyf-overloaded-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             SpecOverloaded.hs-  build-depends:       base, PyF, hspec, text, bytestring-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages-  default-language:    Haskell2010+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test+  main-is:          SpecOverloaded.hs+  build-depends:+    , base+    , bytestring+    , hspec+    , PyF+    , text +  ghc-options:+    -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages++  default-language: Haskell2010+ test-suite pyf-failure-  type:                exitcode-stdio-1.0-  hs-source-dirs:      test-  main-is:             SpecFail.hs-  build-depends:       base, hspec, text, process, hspec, temporary, filepath, deepseq, HUnit, PyF-  ghc-options:         -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages-  default-language:    Haskell2010+  type:             exitcode-stdio-1.0+  hs-source-dirs:   test+  main-is:          SpecFail.hs+  build-depends:+    , base+    , deepseq+    , filepath+    , hspec+    , HUnit+    , process+    , PyF+    , temporary+    , text++  ghc-options:+    -Wall -threaded -rtsopts -with-rtsopts=-N -Wunused-packages++  default-language: Haskell2010  source-repository head   type:     git
Readme.md view
@@ -217,7 +217,7 @@  Note: error reporting uses the native GHC error infrastructure, so they will correctly appear in your editor (using [HLS](https://github.com/haskell/haskell-language-server)), for example: -  ![Error reported in editor](error_example.png)+![Error reported in editor](error_example.png)  - Error in variable name are also readable: @@ -297,7 +297,7 @@  ## Differences with the Python Syntax -The implementation is unit-tested against the reference Python implementation (Python 3.6.4) and should match its result. However some formatters are not supported or some (minor) differences can be observed.+The implementation *was* unit-tested against the reference Python implementation (Python 3.6.4) and should match its result. Since 2025, the standalone test suite is not cross checked with the standard python implementation. However some formatters are not supported or some (minor) differences can be observed.  ### Not supported @@ -344,7 +344,7 @@  # GHC compatibility -This library is tested in CI with ghc 8.6 to 9.2.+This library is tested in CI with ghc 8.6 to 9.12.  # Conclusion @@ -355,7 +355,7 @@ Everything works with nix and flakes. But you can also try with manual cabal / stack if you wish.  - `nix develop` will open a shell with everything you need to work on PyF, including haskell-language-server. It may be a bit too much, so you can instead:-- `nix develop .#pyf_XY` opens a shell with a specific GHC version and without haskell-language-server. That's mostly to test compatibility with different GHC version or open a shell without HLS if you are in a hurry. Replace `pyf_XY` by `pyf_86`, `pyf_88`, `pyf_810`, `pyf_90` or `pyf_92`.+- `nix develop .#pyf_XY` opens a shell with a specific GHC version and without haskell-language-server. That's mostly to test compatibility with different GHC version or open a shell without HLS if you are in a hurry. Replace `pyf_XY` by a GHC version, e.g. `pyf_912`.  Once in the shell, use `cabal build`, `cabal test`, `cabal repl`. @@ -363,15 +363,15 @@  You can locally build and test everything using: -- `nix build .#pyf_all`.+- `nix flake check`  Don't hesitate to submit a PR not tested on all GHC versions.  ## Formatting -The codebase is formatted with `ormolu`. Please run:+Please run: -- `nix run .\#run-ormolu`+- `nix run fmt`  Before submitting. 
src/PyF.hs view
@@ -38,7 +38,9 @@  -- | Format with whitespace trimming. fmtTrim :: QuasiQuoter-fmtTrim = mkFormatter "fmtTrim" (addTrim fmtConfig)+fmtTrim = let+  qq = mkFormatter "fmtTrim" fmtConfig+  in qq { quoteExp = \s -> quoteExp qq (trimIndent  s) }  -- | Multiline string, no interpolation. str :: QuasiQuoter@@ -46,7 +48,8 @@  -- | Multiline string, no interpolation, but does indentation trimming. strTrim :: QuasiQuoter-strTrim = mkFormatter "strTrim" (addTrim strConfig)+strTrim = let qq = mkFormatter "strTrim" strConfig+  in qq { quoteExp = \s -> quoteExp qq (trimIndent  s) }  -- | Raw string, neither interpolation nor escaping is performed. raw :: QuasiQuoter
src/PyF/Class.hs view
@@ -135,7 +135,7 @@ instance PyFToString Char where pyfToString c = [c]  -- | Default instance. Convert any type with a 'Show instance.-instance {-# OVERLAPPABLE #-} Show t => PyFToString t where pyfToString = show+instance {-# OVERLAPPABLE #-} (Show t) => PyFToString t where pyfToString = show  -- * Real formatting (with optional fractional part) @@ -163,7 +163,7 @@     String  -- | Default instance working for any 'Real'. Internally it converts the type to 'Double'.-instance {-# OVERLAPPABLE #-} Real t => PyfFormatFractional t where+instance {-# OVERLAPPABLE #-} (Real t) => PyfFormatFractional t where   pyfFormatFractional f s p g prec v = formatFractional f s p g prec (realToFrac @t @Double v)  -- | This instance does not do any conversion.@@ -183,7 +183,7 @@ -- 'Integral' constraint. class PyfFormatIntegral i where   pyfFormatIntegral ::-    Integral paddingWidth =>+    (Integral paddingWidth) =>     Format t t' 'Integral ->     -- | Sign formatting     SignMode ->@@ -195,7 +195,7 @@     String  -- | Default instance for any 'Integral'.-instance {-# OVERLAPPABLE #-} Integral t => PyfFormatIntegral t where+instance {-# OVERLAPPABLE #-} (Integral t) => PyfFormatIntegral t where   pyfFormatIntegral f s p g v = formatIntegral f s p g v  -- | Returns the numerical value of a 'Char'
src/PyF/Formatters.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveLift #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -9,7 +10,6 @@ {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}  -- | --@@ -53,10 +53,10 @@ where  import Data.Char (chr, toUpper)+import Data.Data (Data) import Data.List (intercalate) import Language.Haskell.TH.Syntax import qualified Numeric-import Data.Data (Data)  -- ADT for API @@ -84,7 +84,6 @@   -- | Padding will be added around the value   AlignCenter :: AlignMode 'AlignAll - deriving instance Show (AlignMode k)  -- The generic version@@ -174,8 +173,8 @@   | isInfinite f = Infinite sign (upperIt "inf")   | isNaN f = NaN (upperIt "nan")   | isNegativeZero f = case reprFractional fmt precision (abs f) of-       FractionalRepr Positive aa bb cc -> FractionalRepr Negative aa bb cc-       other -> error $ "reprFractional (isNegativeZero f): The impossible happened : " ++ show other ++ ". Please open an issue at https://github.com/guibou/PyF/issues/"+      FractionalRepr Positive aa bb cc -> FractionalRepr Negative aa bb cc+      other -> error $ "reprFractional (isNegativeZero f): The impossible happened : " ++ show other ++ ". Please open an issue at https://github.com/guibou/PyF/issues/"   | otherwise = FractionalRepr sign decimalPart fractionalPart suffixPart   where     upperIt s = case fmt of@@ -189,8 +188,8 @@       Exponent -> overrideExponent precision $ splitFractionalExp (Numeric.showEFloat precision iAbs "")       Generic -> splitFractionalExp (Numeric.showGFloatAlt precision iAbs "")       Percent -> case splitFractional (Numeric.showFFloatAlt precision (iAbs * 100) "") of-                  (a, b, "") -> (a, b, "%")-                  other -> error $ "reprFractional (format): The impossible happened : " ++ show other ++ ". Please open an issue at https://github.com/guibou/PyF/issues/"+        (a, b, "") -> (a, b, "%")+        other -> error $ "reprFractional (format): The impossible happened : " ++ show other ++ ". Please open an issue at https://github.com/guibou/PyF/issues/"       Alternate fmt' -> format fmt'       Upper fmt' ->         let (a, b, c) = format fmt'@@ -229,7 +228,7 @@ group (FractionalRepr s a b d) (Just (size, c)) = FractionalRepr s (groupIntercalate c size a) b d group i _ = i -padAndSign :: Integral paddingWidth => Format t t' t'' -> String -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Repr -> String+padAndSign :: (Integral paddingWidth) => Format t t' t'' -> String -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Repr -> String padAndSign format prefix sign padding repr = leftAlignMode <> prefixStr <> middleAlignMode <> content <> rightAlignMode   where     (signStr, content) = case repr of@@ -282,8 +281,8 @@  -- | Format an integral number. formatIntegral ::-  Integral paddingWidth =>-  Integral i =>+  (Integral paddingWidth) =>+  (Integral i) =>   Format t t' 'Integral ->   SignMode ->   -- | Padding
src/PyF/Internal/Meta.hs view
@@ -180,7 +180,9 @@ toExp d (Expr.OpApp _ e1 o e2) = TH.UInfixE (toExp d . unLoc $ e1) (toExp d . unLoc $ o) (toExp d . unLoc $ e2) toExp d (Expr.NegApp _ e _) = TH.AppE (TH.VarE 'negate) (toExp d . unLoc $ e) -- NOTE: for lambda, there is only one match-#if MIN_VERSION_ghc(9,10,0)+#if MIN_VERSION_ghc(9,12,0)+toExp d (Expr.HsLam _ _ (Expr.MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (unLoc -> map unLoc -> ps) (Expr.GRHSs _ [unLoc -> Expr.GRHS _ _ (unLoc -> e)] _)])))) = TH.LamE (fmap (toPat d) ps) (toExp d e)+#elif MIN_VERSION_ghc(9,10,0) toExp d (Expr.HsLam _ _ (Expr.MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (Expr.GRHSs _ [unLoc -> Expr.GRHS _ _ (unLoc -> e)] _)])))) = TH.LamE (fmap (toPat d) ps) (toExp d e) #elif MIN_VERSION_ghc(9,6,0) toExp d (Expr.HsLam _ (Expr.MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (Expr.GRHSs _ [unLoc -> Expr.GRHS _ _ (unLoc -> e)] _)])))) = TH.LamE (fmap (toPat d) ps) (toExp d e)@@ -246,7 +248,9 @@   (FromThen a b) -> TH.FromThenR (toExp d $ unLoc a) (toExp d $ unLoc b)   (FromTo a b) -> TH.FromToR (toExp d $ unLoc a) (toExp d $ unLoc b)   (FromThenTo a b c) -> TH.FromThenToR (toExp d $ unLoc a) (toExp d $ unLoc b) (toExp d $ unLoc c)-#if MIN_VERSION_ghc(9,7,0)+#if MIN_VERSION_ghc(9,12,0)+toExp _ (HsOverLabel _ fs) = TH.LabelE (unpackFS fs)+#elif MIN_VERSION_ghc(9,7,0) toExp _ (HsOverLabel _ lbl _) = TH.LabelE (fromSourceText lbl)    where      fromSourceText :: SourceText -> String@@ -265,8 +269,11 @@ -- enabled thus match on Nothing toExp _ (HsOverLabel _ Nothing lbl) = TH.LabelE (unpackFS lbl) #endif-#if MIN_VERSION_ghc(9,6,0)+#if MIN_VERSION_ghc(9,12,0) toExp dynFlags (HsGetField _ expr field) = TH.GetFieldE (toExp dynFlags (unLoc expr)) (unpackFS . field_label . unLoc . dfoLabel . unLoc $ field)+toExp _ (HsProjection _ fields) = TH.ProjectionE (fmap (unpackFS . unLoc . fmap field_label . dfoLabel) fields)+#elif MIN_VERSION_ghc(9,6,0)+toExp dynFlags (HsGetField _ expr field) = TH.GetFieldE (toExp dynFlags (unLoc expr)) (unpackFS . field_label . unLoc . dfoLabel . unLoc $ field) toExp _ (HsProjection _ fields) = TH.ProjectionE (fmap (unpackFS . unLoc . fmap field_label . dfoLabel . unLoc) fields) #elif MIN_VERSION_ghc(9, 4, 0) toExp dynFlags (HsGetField _ expr field) = TH.GetFieldE (toExp dynFlags (unLoc expr)) (unpackFS . unLoc . dfoLabel . unLoc $ field)@@ -295,4 +302,3 @@ #else     dynFlags = defaultDynFlags fakeSettings fakeLlvmConfig #endif-
src/PyF/Internal/Parser.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-}+{-# LANGUAGE ViewPatterns #-}  -- | This module is here to parse Haskell expression using the GHC Api module PyF.Internal.Parser (parseExpression) where
src/PyF/Internal/PythonSyntax.hs view
@@ -1,11 +1,11 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE CPP #-}  -- | -- This module provides a parser for <https://docs.python.org/3.4/library/string.html#formatspec python format string mini language>.@@ -28,6 +28,7 @@ import Control.Monad (replicateM_, void) import Control.Monad.Reader (Reader, asks) import qualified Data.Char+import Data.Data (Data) import Data.Maybe (fromMaybe) import GHC (GhcPs, HsExpr) import Language.Haskell.TH.LanguageExtensions (Extension (..))@@ -36,7 +37,6 @@ import PyF.Internal.Meta import qualified PyF.Internal.Parser as ParseExp import Text.Parsec-import Data.Data (Data)  #if MIN_VERSION_ghc(9,7,0) @@ -332,7 +332,7 @@  -- | Similar to 'manyTill' but always parse one element. -- Be careful, @someTill p e@ may parse @e@ as first element if @e@ is a subset of @p@.-someTill :: Stream s m t => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]+someTill :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a] someTill p e = (:) <$> p <*> manyTill p e  evalFlag :: TypeFlag -> Padding -> Maybe Char -> Precision -> AlternateForm -> Maybe SignMode -> Either String TypeFormat
src/PyF/Internal/QQ.hs view
@@ -35,7 +35,6 @@ import Data.Proxy import Data.String (fromString) - #if MIN_VERSION_ghc(9,0,0) import GHC.Tc.Utils.Monad (addErrAt) import GHC.Tc.Types (TcM)@@ -63,8 +62,6 @@ #endif #endif -- #if MIN_VERSION_ghc(9,0,0) import GHC.Types.Name.Reader #else@@ -170,9 +167,10 @@  findFreeVariablesInFormatMode :: Maybe FormatMode -> [(SrcSpan, RdrName)] findFreeVariablesInFormatMode Nothing = []-findFreeVariablesInFormatMode (Just (FormatMode padding tf _ )) = findFreeVariables tf <> case padding of-  PaddingDefault -> []-  Padding eoi _ -> findFreeVariables eoi+findFreeVariablesInFormatMode (Just (FormatMode padding tf _)) =+  findFreeVariables tf <> case padding of+    PaddingDefault -> []+    Padding eoi _ -> findFreeVariables eoi  checkOneItem :: Item -> Q (Maybe (SrcSpan, String)) checkOneItem (Raw _) = pure Nothing@@ -185,7 +183,7 @@     [] -> pure Nothing     ((err, span) : _) -> pure $ Just (span, err) -+{- ORMOLU_DISABLE -} findFreeVariables :: Data a => a -> [(SrcSpan, RdrName)] findFreeVariables item = allNames   where@@ -198,17 +196,31 @@       Just (HsVar _ l) -> [l] #endif -#if MIN_VERSION_ghc(9,10,0)+#if MIN_VERSION_ghc(9,12,0)+      Just (HsLam _ _ (MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (unLoc -> map unLoc -> ps) (GRHSs _ [unLoc -> GRHS _ _ (unLoc -> e)] _)])))) -> filter keepVar subVars+        where+          keepVar (L _ n) = n `notElem` subPats+          subVars = concat $ gmapQ f [e]+          subPats = concat $ gmapQ findPats ps+#elif MIN_VERSION_ghc(9,10,0)       Just (HsLam _ _ (MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (GRHSs _ [unLoc -> GRHS _ _ (unLoc -> e)] _)])))) -> filter keepVar subVars+        where+          keepVar (L _ n) = n `notElem` subPats+          subVars = concat $ gmapQ f [e]+          subPats = concat $ gmapQ findPats ps #elif MIN_VERSION_ghc(9,6,0)       Just (HsLam _ (MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (GRHSs _ [unLoc -> GRHS _ _ (unLoc -> e)] _)])))) -> filter keepVar subVars+        where+          keepVar (L _ n) = n `notElem` subPats+          subVars = concat $ gmapQ f [e]+          subPats = concat $ gmapQ findPats ps #else       Just (HsLam _ (MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (GRHSs _ [unLoc -> GRHS _ _ (unLoc -> e)] _)])) _)) -> filter keepVar subVars-#endif         where           keepVar (L _ n) = n `notElem` subPats           subVars = concat $ gmapQ f [e]           subPats = concat $ gmapQ findPats ps+#endif       _ -> concat $ gmapQ f e      -- Find all Variables bindings (i.e. patterns) in an HsExpr@@ -221,6 +233,7 @@     -- level expression: gmapQ only checks sub constructors.     allVars = concat $ gmapQ f [item]     allNames = map (\(L l e) -> (l, e)) allVars+{- ORMOLU_ENABLE -}  lookupName :: RdrName -> Q Bool lookupName n = case n of@@ -302,6 +315,7 @@     (_sysUnExpect, msgs1) = span (SysUnExpect "" ==) (errorMessages err)     (_unExpect, msgs2) = span (UnExpect "" ==) msgs1     (_expect, messages) = span (Expect "" ==) msgs2+ {- Note: Empty String Lifting @@ -321,7 +335,7 @@  toFormat :: Item -> Q Exp toFormat (Raw x) = pure $ LitE (StringL x) -- see [Empty String Lifting]-toFormat (Replacement ( _, expr) y) = do+toFormat (Replacement (_, expr) y) = do   formatExpr <- padAndFormat (fromMaybe DefaultFormatMode y)   pure (formatExpr `AppE` expr) @@ -395,7 +409,7 @@     Just (Nothing, a) -> Just (i, AnyAlign a, ' ')     Just (Just c, a) -> Just (i, AnyAlign a, c) -formatAnyIntegral :: forall i paddingWidth t t'. Integral paddingWidth => PyfFormatIntegral i => Formatters.Format t t' 'Formatters.Integral -> Formatters.SignMode -> Maybe (paddingWidth, AnyAlign, Char) -> Maybe (Int, Char) -> i -> String+formatAnyIntegral :: forall i paddingWidth t t'. (Integral paddingWidth) => (PyfFormatIntegral i) => Formatters.Format t t' 'Formatters.Integral -> Formatters.SignMode -> Maybe (paddingWidth, AnyAlign, Char) -> Maybe (Int, Char) -> i -> String formatAnyIntegral f s Nothing grouping i = pyfFormatIntegral @i @paddingWidth f s Nothing grouping i formatAnyIntegral f s (Just (padSize, AnyAlign alignMode, c)) grouping i = pyfFormatIntegral f s (Just (padSize, alignMode, c)) grouping i @@ -418,7 +432,7 @@ instance (PyfFormatFractional t) => FormatAny2 'PyFFractional t k where   formatAny2 _ s a = formatAnyFractional Formatters.Generic s (paddingKToPadding a) -newPaddingKForString :: Integral i => PaddingK 'Formatters.AlignAll i -> Maybe (Int, Formatters.AlignMode 'Formatters.AlignAll, Char)+newPaddingKForString :: (Integral i) => PaddingK 'Formatters.AlignAll i -> Maybe (Int, Formatters.AlignMode 'Formatters.AlignAll, Char) newPaddingKForString padding = case padding of   PaddingDefaultK -> Nothing   PaddingK i Nothing -> Just (fromIntegral i, Formatters.AlignLeft, ' ') -- default align left and fill with space for string@@ -428,5 +442,5 @@ instance (PyFToString t) => FormatAny2 'PyFString t 'Formatters.AlignAll where   formatAny2 _ _s a _grouping precision t = Formatters.formatString (newPaddingKForString a) precision (pyfToString t) -instance TypeError ('Text "String type is incompatible with inside padding (=).") => FormatAny2 'PyFString t 'Formatters.AlignNumber where+instance (TypeError ('Text "String type is incompatible with inside padding (=).")) => FormatAny2 'PyFString t 'Formatters.AlignNumber where   formatAny2 = error "Unreachable"
test/Spec.hs view
@@ -27,25 +27,17 @@ import Data.Proxy (Proxy (..)) import qualified Data.Ratio import qualified Data.Text+import qualified Data.Text as Text import qualified Data.Text.Lazy import qualified Data.Time import GHC.OverloadedLabels import GHC.TypeLits (KnownSymbol, Symbol, symbolVal) import PyF import SpecCustomDelimiters-import SpecUtils import Test.Hspec-import qualified Data.Text as Text -{--   - Normal tests are done using the recommanded API: [fmt|.....|]-   - Test with $(checkExample formatString result) are checked against the python reference implementation. Result is provided as documentation.-   - Test with $(checkExampleDiff formatString result) are not checked against the python reference implementation. This is known (and documented) differences.-   - Test with $(check formatString) are only tested against the python reference implementation.--}- main :: IO ()-main = hspec spec+main = hspec $ parallel spec  newtype FooFloating t = FooFloating t   deriving newtype (Show, RealFloat, RealFrac, Floating, Fractional, Real, Enum, Num, Ord, Eq, PyfFormatFractional)@@ -72,13 +64,13 @@ -- Data type to test overloaded labels data V (a :: Symbol) = V -instance KnownSymbol a => Show (V a) where+instance (KnownSymbol a) => Show (V a) where   show V = "V=" ++ symbolVal (Proxy @a)  instance (a ~ a') => IsLabel a (V a') where   fromLabel = V -showV :: KnownSymbol a => V a -> String+showV :: (KnownSymbol a) => V a -> String showV = show  globalName :: String@@ -95,159 +87,161 @@     it "string" $ [fmt|{aString}|] `shouldBe` "hello"   describe "only expression" $ do     describe "default" $ do-      it "int" $(checkExample "{123}" "123")-      it "float" $(checkExample "{0.234}" "0.234")-      it "string" $(checkExample "{\"hello\"}" "hello")-      it "float precision" $(checkExample "{0.234:.1}" "0.2")-      it "string precision" $(checkExample "{\"hello\":.1}" "h")-      it "sign +" $(checkExample "{0.234:+}" "+0.234")-      it "sign space" $(checkExample "{0.234: }" " 0.234")-      it "sign neg" $(checkExample "{-123:+}" "-123")+      it "int" $ [fmt|{123}|] `shouldBe` "123"+      it "float" $ [fmt|{0.234}|] `shouldBe` "0.234"+      it "string" $ [fmt|{"hello"}|] `shouldBe` "hello"+      it "float precision" $ [fmt|{0.234:.1}|] `shouldBe` "0.2"+      it "string precision" $ [fmt|{"hello":.1}|] `shouldBe` "h"+      it "sign +" $ [fmt|{0.234:+}|] `shouldBe` "+0.234"+      it "sign space" $ [fmt|{0.234: }|] `shouldBe` " 0.234"+      it "sign neg" $ [fmt|{-123:+}|] `shouldBe` "-123"     describe "binary" $ do-      it "simple" $(checkExample "{123:b}" "1111011")-      it "alt" $(checkExample "{123:#b}" "0b1111011")-      it "sign" $(checkExample "{123:+#b}" "+0b1111011")+      it "simple" $ [fmt|{123:b}|] `shouldBe` "1111011"+      it "alt" $ [fmt|{123:#b}|] `shouldBe` "0b1111011"+      it "sign" $ [fmt|{123:+#b}|] `shouldBe` "+0b1111011"     describe "character" $-      it "simple" $(checkExample "{123:c}" "{")+      it "simple" $+        [fmt|{123:c}|] `shouldBe` "{"     describe "decimal" $ do-      it "simple" $(checkExample "{123:d}" "123")-      it "sign" $(checkExample "{123:+d}" "+123")+      it "simple" $ [fmt|{123:d}|] `shouldBe` "123"+      it "sign" $ [fmt|{123:+d}|] `shouldBe` "+123"     describe "exponentiel" $ do-      it "simple > 1" $(checkExample "{234.0:e}" "2.340000e+02")-      it "precision > 1" $(checkExample "{234.0:.1e}" "2.3e+02")-      it "simple < 1" $(checkExample "{0.234:e}" "2.340000e-01")-      it "precision < 1 " $(checkExample "{0.234:.1e}" "2.3e-01")+      it "simple > 1" $ [fmt|{234.0:e}|] `shouldBe` "2.340000e+02"+      it "precision > 1" $ [fmt|{234.0:.1e}|] `shouldBe` "2.3e+02"+      it "simple < 1" $ [fmt|{0.234:e}|] `shouldBe` "2.340000e-01"+      it "precision < 1 " $ [fmt|{0.234:.1e}|] `shouldBe` "2.3e-01"     describe "exponentiel caps" $ do-      it "simple > 1" $(checkExample "{234.0:E}" "2.340000E+02")-      it "precision > 1" $(checkExample "{234.0:.1E}" "2.3E+02")-      it "simple < 1" $(checkExample "{0.234:E}" "2.340000E-01")-      it "precision < 1 " $(checkExample "{0.234:.1E}" "2.3E-01")+      it "simple > 1" $ [fmt|{234.0:E}|] `shouldBe` "2.340000E+02"+      it "precision > 1" $ [fmt|{234.0:.1E}|] `shouldBe` "2.3E+02"+      it "simple < 1" $ [fmt|{0.234:E}|] `shouldBe` "2.340000E-01"+      it "precision < 1 " $ [fmt|{0.234:.1E}|] `shouldBe` "2.3E-01"     describe "general" $ do-      it "simple small" $(checkExampleDiff "{123.02:g}" "123.020000")-      it "precision small" $(checkExampleDiff "{123.02:.1g}" "123.0")-      it "simple big" $(checkExampleDiff "{1234567890.23:g}" "1.234568e+09")-      it "precision big" $(checkExampleDiff "{1234567890.23:.1g}" "1.2e+09")+      it "simple small" $ [fmt|{123.02:g}|] `shouldBe` "123.020000"+      it "precision small" $ [fmt|{123.02:.1g}|] `shouldBe` "123.0"+      it "simple big" $ [fmt|{1234567890.23:g}|] `shouldBe` "1.234568e+09"+      it "precision big" $ [fmt|{1234567890.23:.1g}|] `shouldBe` "1.2e+09"     describe "general caps" $ do-      it "simple small" $(checkExampleDiff "{123.02:G}" "123.020000")-      it "precision small" $(checkExampleDiff "{123.02:.1G}" "123.0")-      it "simple big" $(checkExampleDiff "{1234567890.23:G}" "1.234568E+09")-      it "precision big" $(checkExampleDiff "{1234567890.23:.1G}" "1.2E+09")+      it "simple small" $ [fmt|{123.02:G}|] `shouldBe` "123.020000"+      it "precision small" $ [fmt|{123.02:.1G}|] `shouldBe` "123.0"+      it "simple big" $ [fmt|{1234567890.23:G}|] `shouldBe` "1.234568E+09"+      it "precision big" $ [fmt|{1234567890.23:.1G}|] `shouldBe` "1.2E+09"     describe "fixed" $ do-      it "simple" $(checkExample "{0.234:f}" "0.234000")-      it "precision" $(checkExample "{0.234:.1f}" "0.2")+      it "simple" $ [fmt|{0.234:f}|] `shouldBe` "0.234000"+      it "precision" $ [fmt|{0.234:.1f}|] `shouldBe` "0.2"     describe "fixed caps" $ do-      it "simple" $(checkExample "{0.234:F}" "0.234000")-      it "precision" $(checkExample "{0.234:.1F}" "0.2")+      it "simple" $ [fmt|{0.234:F}|] `shouldBe` "0.234000"+      it "precision" $ [fmt|{0.234:.1F}|] `shouldBe` "0.2"     describe "octal" $ do-      it "simple" $(checkExample "{123:o}" "173")-      it "alt" $(checkExample "{123:#o}" "0o173")+      it "simple" $ [fmt|{123:o}|] `shouldBe` "173"+      it "alt" $ [fmt|{123:#o}|] `shouldBe` "0o173"     describe "string" $ do-      it "string" $(checkExample "{\"hello\":s}" "hello")-      it "precision" $(checkExample "{\"hello\":.2s}" "he")+      it "string" $ [fmt|{"hello":s}|] `shouldBe` "hello"+      it "precision" $ [fmt|{"hello":.2s}|] `shouldBe` "he"     describe "hex" $ do-      it "simple" $(checkExample "{123:x}" "7b")-      it "alt" $(checkExample "{123:#x}" "0x7b")+      it "simple" $ [fmt|{123:x}|] `shouldBe` "7b"+      it "alt" $ [fmt|{123:#x}|] `shouldBe` "0x7b"     describe "hex caps" $ do-      it "simple" $(checkExample "{123:X}" "7B")-      it "alt" $(checkExample "{123:#X}" "0X7B")+      it "simple" $ [fmt|{123:X}|] `shouldBe` "7B"+      it "alt" $ [fmt|{123:#X}|] `shouldBe` "0X7B"     describe "percent" $ do-      it "simple" $(checkExample "{0.234:%}" "23.400000%")-      it "precision" $(checkExample "{0.234:.2%}" "23.40%")+      it "simple" $ [fmt|{0.234:%}|] `shouldBe` "23.400000%"+      it "precision" $ [fmt|{0.234:.2%}|] `shouldBe` "23.40%"     describe "string truncating" $-      it "works" $(checkExample "{\"hello\":.3}" "hel")+      it "works" $+        [fmt|{"hello":.3}|] `shouldBe` "hel"     describe "padding" $ do       describe "default char" $ do-        it "left" $(checkExample "{\"hello\":<10}" "hello     ")-        it "right" $(checkExample "{\"hello\":>10}" "     hello")-        it "center" $(checkExample "{\"hello\":^10}" "  hello   ")+        it "left" $ [fmt|{"hello":<10}|] `shouldBe` "hello     "+        it "right" $ [fmt|{"hello":>10}|] `shouldBe` "     hello"+        it "center" $ [fmt|{"hello":^10}|] `shouldBe` "  hello   "       describe "a char" $ do-        it "left" $(checkExample "{\"hello\":-<10}" "hello-----")-        it "right" $(checkExample "{\"hello\":->10}" "-----hello")-        it "center" $(checkExample "{\"hello\":-^10}" "--hello---")+        it "left" $ [fmt|{"hello":-<10}|] `shouldBe` "hello-----"+        it "right" $ [fmt|{"hello":->10}|] `shouldBe` "-----hello"+        it "center" $ [fmt|{"hello":-^10}|] `shouldBe` "--hello---"       describe "inside" $ do-        it "inside" $(checkExample "{123:=+10}" "+      123")-        it "inside" $(checkExample "{123:=10}" "       123")-        it "inside" $(checkExample "{- 123:=10}" "-      123")-        it "inside" $(checkExample "{- 123:|= 10}" "-||||||123")-        it "inside" $(checkExample "{123:|= 10}" " ||||||123")+        it "inside" $ [fmt|{123:=+10}|] `shouldBe` "+      123"+        it "inside" $ [fmt|{123:=10}|] `shouldBe` "       123"+        it "inside" $ [fmt|{- 123:=10}|] `shouldBe` "-      123"+        it "inside" $ [fmt|{- 123:|= 10}|] `shouldBe` "-||||||123"+        it "inside" $ [fmt|{123:|= 10}|] `shouldBe` " ||||||123"       describe "default padding" $ do-        it "floating" $(checkExample "{1:10f}" "  1.000000")-        it "integral" $(checkExample "{1:10d}" "         1")-        it "string" $(checkExample "{\"h\":10s}" "h         ")-        it "default" $(checkExample "{1:10}" "         1")-        it "default" $(checkExample "{1.0:10}" "       1.0")-        it "default" $(checkExample "{\"h\":10}" "h         ")+        it "floating" $ [fmt|{1:10f}|] `shouldBe` "  1.000000"+        it "integral" $ [fmt|{1:10d}|] `shouldBe` "         1"+        it "string" $ [fmt|{"h":10s}|] `shouldBe` "h         "+        it "default" $ [fmt|{1:10}|] `shouldBe` "         1"+        it "default" $ [fmt|{1.0:10}|] `shouldBe` "       1.0"+        it "default" $ [fmt|{"h":10}|] `shouldBe` "h         "     describe "NaN" $ do       describe "float" $ do         let nan = 0.0 / 0 :: Float-        it "nan" $(checkExample "{nan}" "nan")-        it "nan f" $(checkExample "{nan:f}" "nan")-        it "nan e" $(checkExample "{nan:e}" "nan")-        it "nan g" $(checkExample "{nan:g}" "nan")-        it "nan F" $(checkExample "{nan:F}" "NAN")-        it "nan G" $(checkExample "{nan:G}" "NAN")-        it "nan E" $(checkExample "{nan:E}" "NAN")+        it "nan" $ [fmt|{nan}|] `shouldBe` "nan"+        it "nan f" $ [fmt|{nan:f}|] `shouldBe` "nan"+        it "nan e" $ [fmt|{nan:e}|] `shouldBe` "nan"+        it "nan g" $ [fmt|{nan:g}|] `shouldBe` "nan"+        it "nan F" $ [fmt|{nan:F}|] `shouldBe` "NAN"+        it "nan G" $ [fmt|{nan:G}|] `shouldBe` "NAN"+        it "nan E" $ [fmt|{nan:E}|] `shouldBe` "NAN"       describe "double" $ do         let nan = 0.0 / 0 :: Double-        it "nan" $(checkExample "{nan}" "nan")-        it "nan f" $(checkExample "{nan:f}" "nan")-        it "nan e" $(checkExample "{nan:e}" "nan")-        it "nan g" $(checkExample "{nan:g}" "nan")-        it "nan F" $(checkExample "{nan:F}" "NAN")-        it "nan G" $(checkExample "{nan:G}" "NAN")-        it "nan E" $(checkExample "{nan:E}" "NAN")+        it "nan" $ [fmt|{nan}|] `shouldBe` "nan"+        it "nan f" $ [fmt|{nan:f}|] `shouldBe` "nan"+        it "nan e" $ [fmt|{nan:e}|] `shouldBe` "nan"+        it "nan g" $ [fmt|{nan:g}|] `shouldBe` "nan"+        it "nan F" $ [fmt|{nan:F}|] `shouldBe` "NAN"+        it "nan G" $ [fmt|{nan:G}|] `shouldBe` "NAN"+        it "nan E" $ [fmt|{nan:E}|] `shouldBe` "NAN"     describe "Infinite" $ do       describe "float" $ do         let inf = 1.0 / 0 :: Float-        it "infinite" $(checkExample "{inf}" "inf")-        it "infinite f" $(checkExample "{inf:f}" "inf")-        it "infinite e" $(checkExample "{inf:e}" "inf")-        it "infinite g" $(checkExample "{inf:g}" "inf")-        it "infinite F" $(checkExample "{inf:F}" "INF")-        it "infinite G" $(checkExample "{inf:G}" "INF")-        it "infinite E" $(checkExample "{inf:E}" "INF")+        it "infinite" $ [fmt|{inf}|] `shouldBe` "inf"+        it "infinite f" $ [fmt|{inf:f}|] `shouldBe` "inf"+        it "infinite e" $ [fmt|{inf:e}|] `shouldBe` "inf"+        it "infinite g" $ [fmt|{inf:g}|] `shouldBe` "inf"+        it "infinite F" $ [fmt|{inf:F}|] `shouldBe` "INF"+        it "infinite G" $ [fmt|{inf:G}|] `shouldBe` "INF"+        it "infinite E" $ [fmt|{inf:E}|] `shouldBe` "INF"       describe "double" $ do         let inf = 1.0 / 0 :: Double-        it "infinite" $(checkExample "{inf}" "inf")-        it "infinite f" $(checkExample "{inf:f}" "inf")-        it "infinite e" $(checkExample "{inf:e}" "inf")-        it "infinite g" $(checkExample "{inf:g}" "inf")-        it "infinite F" $(checkExample "{inf:F}" "INF")-        it "infinite G" $(checkExample "{inf:G}" "INF")-        it "infinite E" $(checkExample "{inf:E}" "INF")+        it "infinite" $ [fmt|{inf}|] `shouldBe` "inf"+        it "infinite f" $ [fmt|{inf:f}|] `shouldBe` "inf"+        it "infinite e" $ [fmt|{inf:e}|] `shouldBe` "inf"+        it "infinite g" $ [fmt|{inf:g}|] `shouldBe` "inf"+        it "infinite F" $ [fmt|{inf:F}|] `shouldBe` "INF"+        it "infinite G" $ [fmt|{inf:G}|] `shouldBe` "INF"+        it "infinite E" $ [fmt|{inf:E}|] `shouldBe` "INF"     describe "Grouping" $ do-      it "groups int" $(checkExample "{123456789:,d}" "123,456,789")-      it "groups int with _" $(checkExample "{123456789:_d}" "123_456_789")-      it "groups float" $(checkExample "{123456789.234:,f}" "123,456,789.234000")-      it "groups bin" $(checkExample "{123456789:_b}" "111_0101_1011_1100_1101_0001_0101")-      it "groups hex" $(checkExample "{123456789:_x}" "75b_cd15")-      it "groups oct" $(checkExample "{123456789:_o}" "7_2674_6425")+      it "groups int" $ [fmt|{123456789:,d}|] `shouldBe` "123,456,789"+      it "groups int with _" $ [fmt|{123456789:_d}|] `shouldBe` "123_456_789"+      it "groups float" $ [fmt|{123456789.234:,f}|] `shouldBe` "123,456,789.234000"+      it "groups bin" $ [fmt|{123456789:_b}|] `shouldBe` "111_0101_1011_1100_1101_0001_0101"+      it "groups hex" $ [fmt|{123456789:_x}|] `shouldBe` "75b_cd15"+      it "groups oct" $ [fmt|{123456789:_o}|] `shouldBe` "7_2674_6425"     describe "negative zero" $ do-      it "f" $(checkExample "{-0.0:f}" "-0.000000")-      it "e" $(checkExample "{-0.0:e}" "-0.000000e+00")-      it "g" $(checkExampleDiff "{-0.0:g}" "-0.000000")-      it "F" $(checkExample "{-0.0:F}" "-0.000000")-      it "G" $(checkExampleDiff "{-0.0:G}" "-0.000000")-      it "E" $(checkExample "{-0.0:E}" "-0.000000E+00")+      it "f" $ [fmt|{-0.0:f}|] `shouldBe` "-0.000000"+      it "e" $ [fmt|{-0.0:e}|] `shouldBe` "-0.000000e+00"+      it "g" $ [fmt|{-0.0:g}|] `shouldBe` "-0.000000"+      it "F" $ [fmt|{-0.0:F}|] `shouldBe` "-0.000000"+      it "G" $ [fmt|{-0.0:G}|] `shouldBe` "-0.000000"+      it "E" $ [fmt|{-0.0:E}|] `shouldBe` "-0.000000E+00"     describe "0" $ do-      it "works" $(checkExample "{123:010}" "0000000123")-      it "works with sign" $(checkExample "{-123:010}" "-000000123")-      it "accept mode override" $(checkExample "{-123:<010}" "-123000000")-      it "accept mode and char override" $(checkExample "{-123:.<010}" "-123......")+      it "works" $ [fmt|{123:010}|] `shouldBe` "0000000123"+      it "works with sign" $ [fmt|{-123:010}|] `shouldBe` "-000000123"+      it "accept mode override" $ [fmt|{-123:<010}|] `shouldBe` "-123000000"+      it "accept mode and char override" $ [fmt|{-123:.<010}|] `shouldBe` "-123......"     describe "no digit no dot" $ do-      it "f" $(checkExample "{1.0:.0f}" "1")-      it "e" $(checkExample "{1.0:.0e}" "1e+00")-      it "g" $(checkExample "{1.0:.0g}" "1")-      it "E" $(checkExample "{1.0:.0E}" "1E+00")-      it "G" $(checkExample "{1.0:.0G}" "1")-      it "percent" $(checkExample "{1.0:.0%}" "100%")+      it "f" $ [fmt|{1.0:.0f}|] `shouldBe` "1"+      it "e" $ [fmt|{1.0:.0e}|] `shouldBe` "1e+00"+      it "g" $ [fmt|{1.0:.0g}|] `shouldBe` "1"+      it "E" $ [fmt|{1.0:.0E}|] `shouldBe` "1E+00"+      it "G" $ [fmt|{1.0:.0G}|] `shouldBe` "1"+      it "percent" $ [fmt|{1.0:.0%}|] `shouldBe` "100%"     describe "no digit alt -> dot" $ do-      it "f" $(checkExample "{1.0:#.0f}" "1.")-      it "e" $(checkExample "{1.0:#.0e}" "1.e+00")-      it "g" $(checkExample "{1.0:#.0g}" "1.")-      it "E" $(checkExample "{1.0:#.0E}" "1.E+00")-      it "G" $(checkExample "{1.0:#.0G}" "1.")-      it "percent" $(checkExample "{1.0:#.0%}" "100.%")+      it "f" $ [fmt|{1.0:#.0f}|] `shouldBe` "1."+      it "e" $ [fmt|{1.0:#.0e}|] `shouldBe` "1.e+00"+      it "g" $ [fmt|{1.0:#.0g}|] `shouldBe` "1."+      it "E" $ [fmt|{1.0:#.0E}|] `shouldBe` "1.E+00"+      it "G" $ [fmt|{1.0:#.0G}|] `shouldBe` "1."+      it "percent" $ [fmt|{1.0:#.0%}|] `shouldBe` "100.%"   describe "complex" $     it "works with many things at once" $       let name = "Guillaume"@@ -488,18 +482,18 @@                   hello                   - a                    - {-                2 + 2+                      2 + 2                    :d}|]         `shouldBe` "hello\n- a\n - 4" -    it "behaves well with escaped first line" $ do-      [fmtTrim|\-                  - a-                  - b-                  |]-        `shouldBe` "- a\n- b\n"     it "Do not touch single lines" $ do       [fmtTrim|  hello|] `shouldBe` "  hello"+    it "trim when there is a linebreak" $ do+      -- https://github.com/guibou/PyF/issues/141+      [fmtTrim|+          Cannot convert formula 2.0 * exponent(unit=s, value=1.0) which has unit dimensionless to\+           unit dimensionless for they have different dimensions|]+          `shouldBe` "Cannot convert formula 2.0 * exponent(unit=s, value=1.0) which has unit dimensionless to unit dimensionless for they have different dimensions"   describe "raw" $ do     it "does not escape anything" $       [raw|hello
test/SpecFail.hs view
@@ -1,24 +1,22 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExtendedDefaultRules #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE ScopedTypeVariables #-}  import Control.DeepSeq import Control.Exception import Data.Bits (Bits (..)) import Data.Char (ord) import qualified Data.Text as Text+import PyF import System.Exit import System.FilePath-import qualified System.IO as IO import System.IO.Temp import System.Process (readProcessWithExitCode) import Test.HUnit.Lang import Test.Hspec -import PyF- -- * Check compilation with external GHC (this is usefull to test compilation failure)  data CompilationStatus@@ -28,24 +26,25 @@   | Ok String   deriving (Show, Eq) - makeTemplate :: String -> String-makeTemplate s = [fmt|{{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules, TypeApplications #-}}+makeTemplate s =+  [fmt|{{-# LANGUAGE QuasiQuotes, ExtendedDefaultRules, TypeApplications #-}} import PyF truncate' = truncate @Float @Int hello = "hello" number = 3.14 :: Float main :: IO ()-main = putStrLn [fmt|{s}|] <> "|]\n"+main = putStrLn [fmt|{s}|]+    <> "|]\n"  -- | Compile a formatting string -- -- >>> checkCompile fileContent -- CompileError "Bla bla bla, Floating cannot be formatted as hexa (`x`)-checkCompile :: HasCallStack => String -> IO CompilationStatus-checkCompile content = withSystemTempFile "PyFTest.hs" $ \path fd -> do-  IO.hPutStr fd content-  IO.hFlush fd+checkCompile :: (HasCallStack) => String -> IO CompilationStatus+checkCompile content = withSystemTempDirectory "PyF" $ \dirPath -> do+  let path = dirPath </> "PyFTest.hs"+  writeFile path content   (ecode, _stdout, stderr) <-     readProcessWithExitCode       "ghc"@@ -55,6 +54,11 @@         -- Disable the usage of the annoying .ghc environment file         "-package-env",         "-",+        -- Move the ".o" in the temporary dir+        "-odir",+        dirPath,+        "-hidir",+        dirPath,         -- Tests use a filename in a temporary directory which may have a long filename which triggers         -- line wrapping, reducing the reproducibility of error message         -- By setting the column size to a high value, we ensure reproducible error messages@@ -92,6 +96,7 @@     . Text.replace (Text.pack "[Char]") (Text.pack "String")     . Text.pack +{- ORMOLU_DISABLE -} golden :: HasCallStack => String -> String -> IO () golden name output = do   let@@ -109,20 +114,27 @@         Left _ -> output   -- Flush lazy IO   _ <- evaluate (force goldenContent)-  if output /= goldenContent+  -- Apparently the whitespaces in GHC 9.10 changed+  -- By stripping, we just keep the test working as expected, but we are+  -- compatible with different version of GHC.+  --+  -- TODO: use GHC API to build directly the example and gather errors in a+  -- more reproducible way.+  if Text.strip (Text.pack output) /= Text.strip (Text.pack goldenContent)     then do       writeFile actualFile output-      (_, diffOutput, _) <- readProcessWithExitCode "diff" [goldenFile, actualFile] ""+      (_, diffOutput, _) <- readProcessWithExitCode "diff" ["-b", goldenFile, actualFile] ""       putStrLn diffOutput       -- Update golden file-      writeFile goldenFile output+      writeFile goldenFile (Text.unpack $ Text.strip (Text.pack output))       assertFailure diffOutput-    else writeFile goldenFile output+    else writeFile goldenFile (Text.unpack $ Text.strip (Text.pack output))+{- ORMOLU_ENABLE -} -failCompile :: HasCallStack => String -> Spec+failCompile :: (HasCallStack) => String -> Spec failCompile s = failCompileContent s s (makeTemplate s) -failCompileContent :: HasCallStack => String -> String -> String -> Spec+failCompileContent :: (HasCallStack) => String -> String -> String -> Spec failCompileContent h caption fileContent =   before (checkCompile fileContent) $ do     let goldenName = concatMap cleanSpecialChars h@@ -150,7 +162,7 @@ cleanSpecialChars e = pure e  main :: IO ()-main = hspec spec+main = hspec $ parallel spec  spec :: Spec spec =
− test/SpecUtils.hs
@@ -1,77 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE TemplateHaskell #-}--module SpecUtils-  ( checkExample,-    checkExampleDiff,-  )-where--import Language.Haskell.TH-#ifdef PYTHON_TEST-import Language.Haskell.TH.Syntax-import System.Exit-import System.Process-#endif--import PyF (fmtConfig)-import PyF.Internal.QQ-import Test.Hspec---- * Utils--#ifdef PYTHON_TEST--- | Runs a python formatter example------ For conveniance, it exports a few python symbols, `inf`, `nan` and pi.------ >>> runPythonExample "{3.14159:.1f}--- "3.1-runPythonExample :: String -> IO (Maybe String)-runPythonExample s = do-  let pythonPath = "python3"-      args = ["-c", "from math import pi;nan = float('NaN');inf = float('inf');print(f\'''" ++ s ++ "''', end='')"]-  (ecode, stdout, _stderr) <- readProcessWithExitCode pythonPath args ""-  pure $ case ecode of-    ExitSuccess -> Just stdout-    ExitFailure _ -> Nothing---- | `pyCheck formatString reference` compares a format string against--- a reference (if `Just`) and against the python implementation------ This TH expression will return an expression compatible with `Hspec` `SpecM`.------ This expression is a failure if python cannot format this formatString--- or if the python result does not match the (provided) reference.-pyCheck :: String -> Maybe String -> Q Exp-pyCheck s exampleStr = do-  pythonRes <- Language.Haskell.TH.Syntax.runIO (runPythonExample s)-  case pythonRes of-    Nothing -> [|expectationFailure $ "Expression: `" ++ s ++ "` fails in python"|]-    Just res -> do-      let qexp = [|$(toExp fmtConfig s) `shouldBe` res|]-      case exampleStr of-        Nothing -> qexp-        Just e ->-          if res == e-            then qexp-            else [|expectationFailure $ "Provided result `" ++ e ++ "` does not match the python result `" ++ res ++ "`"|]---- * Exported---- | `checkExample formatString result` checks if, once formated,---     `formatString` is equal to result. It also checks that the result is---     the same as the one provided by python.-checkExample :: String -> String -> Q Exp-checkExample s res = pyCheck s (Just res)-#else--- | Alias for checkExampleDiff-checkExample :: String -> String -> Q Exp-checkExample = checkExampleDiff-#endif---- | `checkExampleDiff formatString result` checks if, once formated,---     `formatString` is equal to result. It does not check the result---     against the python implementation-checkExampleDiff :: String -> String -> Q Exp-checkExampleDiff s res = [|$(toExp fmtConfig s) `shouldBe` res|]
test/golden96/Hello {length name}.16675806454852491955.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:36: error:     • Variable not in scope: name     • In the quasi-quotation: [fmt|Hello {length name}|]
test/golden96/Hello {name}.16618004304593959603.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:29: error:     • Variable not in scope: name     • In the quasi-quotation: [fmt|Hello {name}|]
test/golden96/Hello {piCL.{precision}}.9628757040831863475.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:34: error:     • Variable not in scope: precision     • In the quasi-quotation: [fmt|Hello {pi:.{precision}}|]
test/golden96/Hello {piCL.{truncate number + precision}}.18094049741103110835.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:52: error:     • Variable not in scope: precision     • In the quasi-quotation: [fmt|Hello {pi:.{truncate number + precision}}|]
test/golden96/Hello {piCL{width}}.15463239215289408179.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:33: error:     • Variable not in scope: width     • In the quasi-quotation: [fmt|Hello {pi:{width}}|]
test/golden96/fooBSPbar.17645057532673886893.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:25: error:     • Lexical error in literal section     • In the quasi-quotation: [fmt|foo\Pbar|]
test/golden96/fooNLbliBSPbar.16759496276764189145.golden view
@@ -1,4 +1,3 @@- INITIALPATH:8:4: error:     • Lexical error in literal section     • In the quasi-quotation: [fmt|foo
test/golden96/hello { world.10778336899993839283.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:35: error: unexpected end of input
test/golden96/hello } world.5295037443422799539.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:28: error: unexpected '}'
test/golden96/helloNL {NLlet a = 5NL b = 10NLin 1 + - SL lalalal}.3018767237106994099.golden view
@@ -1,4 +1,3 @@- INITIALPATH:11:10: error:     • parse error on input `/' in haskell expression     • In the quasi-quotation: [fmt|hello
test/golden96/helloNLNLNL{piCLl}.13123157148160021427.golden view
@@ -1,4 +1,3 @@- INITIALPATH:10:6: error: unexpected "}"
test/golden96/{1 + - SL lalalal}.14923086665437293731.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:29: error:     • parse error on input `/' in haskell expression     • In the quasi-quotation: [fmt|{1 + - / lalalal}|]
test/golden96/{TrueCLd}.12627313193367841398.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Bool’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Decimal PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing True)’
test/golden96/{TrueCLf}.18281408089045870326.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real Bool’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional PyF.Formatters.Fixed PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) True)’
test/golden96/{True}.16254223077612353942.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘PyF.Internal.QQ.FormatAny2 (PyFClassify Bool) Bool PyF.Formatters.AlignAll’ arising from a use of ‘PyF.Internal.QQ.formatAny’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAny PyF.Formatters.Minus PyF.Internal.QQ.PaddingDefaultK Nothing (Nothing :: Maybe Int) True)’
test/golden96/{helloCL s}.13047921915648718386.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:30: error:     • Type incompatible with sign field ( ), use any of {'b', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 'x', 'X', '%'} or remove the sign field.     • In the quasi-quotation: [fmt|{hello: s}|]
test/golden96/{helloCL%}.1257653362598537778.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional PyF.Formatters.Percent PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCL+s}.1657517030647448626.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:30: error:     • Type incompatible with sign field (+), use any of {'b', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 'x', 'X', '%'} or remove the sign field.     • In the quasi-quotation: [fmt|{hello:+s}|]
test/golden96/{helloCL,s}.14139635988852178482.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:30: error:     • String type is incompatible with grouping (_ or ,).     • In the quasi-quotation: [fmt|{hello:,s}|]
test/golden96/{helloCL-s}.12627805606214404146.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:30: error:     • Type incompatible with sign field (-), use any of {'b', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 'x', 'X', '%'} or remove the sign field.     • In the quasi-quotation: [fmt|{hello:-s}|]
test/golden96/{helloCL=100s}.14374776122070431282.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:33: error:     • String type is incompatible with inside padding (=).     • In the quasi-quotation: [fmt|{hello:=100s}|]
test/golden96/{helloCL=100}.9444838110946424370.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-64725]     • String type is incompatible with inside padding (=).     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAny PyF.Formatters.Minus (PyF.Internal.QQ.PaddingK (100 :: Int) (Just (Nothing, PyF.Formatters.AlignInside))) Nothing (Nothing :: Maybe Int) hello)’
test/golden96/{helloCLE}.15676531368138664498.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional (PyF.Formatters.Upper PyF.Formatters.Exponent) PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCLG}.17442699390234010162.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional (PyF.Formatters.Upper PyF.Formatters.Generic) PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCLX}.8447528333473699378.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral String’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral (PyF.Formatters.Upper PyF.Formatters.Hexa) PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing hello)’
test/golden96/{helloCL_s}.1094067961907256370.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:30: error:     • String type is incompatible with grouping (_ or ,).     • In the quasi-quotation: [fmt|{hello:_s}|]
test/golden96/{helloCLb}.14869862508711808562.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral String’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Binary PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing hello)’
test/golden96/{helloCLd}.1892681375540151858.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral String’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Decimal PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing hello)’
test/golden96/{helloCLe}.13933826712837941810.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional PyF.Formatters.Exponent PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCLf}.14332487603622862386.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional PyF.Formatters.Fixed PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCLg}.9607247906229690930.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Real String’ arising from a use of ‘PyF.Internal.QQ.formatAnyFractional’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyFractional PyF.Formatters.Generic PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing (Just 6 :: Maybe Int) hello)’
test/golden96/{helloCLo}.9389880575827657266.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral String’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Octal PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing hello)’
test/golden96/{helloCLx}.14710080644372944434.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral String’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Hexa PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing hello)’
test/golden96/{numberCLX}.4609648040604121432.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Float’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral (PyF.Formatters.Upper PyF.Formatters.Hexa) PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing number)’
test/golden96/{numberCLb}.8801685868342243288.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Float’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Binary PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing number)’
test/golden96/{numberCLd}.13336740346716692056.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Float’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Decimal PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing number)’
test/golden96/{numberCLo}.12467189151987896600.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Float’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Octal PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing number)’
test/golden96/{numberCLx}.14457861675063419224.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:22: error: [GHC-39999]     • No instance for ‘Integral Float’ arising from a use of ‘PyF.Internal.QQ.formatAnyIntegral’     • In the first argument of ‘putStrLn’, namely ‘(PyF.Internal.QQ.formatAnyIntegral PyF.Formatters.Hexa PyF.Formatters.Minus (Nothing :: Maybe (Int, PyF.Formatters.AnyAlign, Char)) Nothing number)’
test/golden96/{piCL.{SL}}.6840925804160914882.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:28: error:     • parse error on input `/' in haskell expression     • In the quasi-quotation: [fmt|{pi:.{/}}|]
test/golden96/{piCL.{}}.9894464503607709506.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:28: error: unexpected "}"
test/golden96/{truncate numberCL.3b}.11608798523190422838.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:41: error:     • Type incompatible with precision (.3), use any of {'e', 'E', 'f', 'F', 'g', 'G', 'n', 's', '%'} or remove the precision field.     • In the quasi-quotation: [fmt|{truncate number:.3b}|]
test/golden96/{truncate numberCL.3d}.9142976352287206710.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:41: error:     • Type incompatible with precision (.3), use any of {'e', 'E', 'f', 'F', 'g', 'G', 'n', 's', '%'} or remove the precision field.     • In the quasi-quotation: [fmt|{truncate number:.3d}|]
test/golden96/{truncate numberCL.3o}.1443712191031422262.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:41: error:     • Type incompatible with precision (.3), use any of {'e', 'E', 'f', 'F', 'g', 'G', 'n', 's', '%'} or remove the precision field.     • In the quasi-quotation: [fmt|{truncate number:.3o}|]
test/golden96/{truncate numberCL.3x}.12613302271643495734.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:41: error:     • Type incompatible with precision (.3), use any of {'e', 'E', 'f', 'F', 'g', 'G', 'n', 's', '%'} or remove the precision field.     • In the quasi-quotation: [fmt|{truncate number:.3x}|]
test/golden96/{}.14986928820806517861.golden view
@@ -1,4 +1,3 @@- INITIALPATH:7:23: error: unexpected "}"