packages feed

PyF 0.11.2.1 → 0.11.3.0

raw patch · 8 files changed

+61/−47 lines, 8 filesdep ~basedep ~template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, template-haskell

API changes (from Hackage documentation)

- PyF.Class: instance PyF.Class.PyFToString Data.ByteString.Internal.ByteString
+ PyF.Class: instance PyF.Class.PyFToString Data.ByteString.Internal.Type.ByteString

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for PyF +## 0.11.3.0 -- 2024-05-15++- Support for GHC 9.10.+ ## 0.11.2.1 -- 2023-10-25  - Final version for GHC 9.8
PyF.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                PyF-version:             0.11.2.1+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@@ -27,9 +27,9 @@                   PyF.Internal.ParserEx                   PyF.Internal.Parser -  build-depends:       base >= 4.12 && < 4.20+  build-depends:       base >= 4.12 && < 4.22                      , bytestring >= 0.10.8 && < 0.13-                     , template-haskell >= 2.14.0 && < 2.22+                     , 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
Readme.md view
@@ -2,11 +2,12 @@  *PyF* is a Haskell library for string interpolation and formatting. -*PyF* exposes a quasiquoter `f` which introduces string interpolation and formatting with a mini language inspired from printf and Python.+*PyF* exposes a quasiquoter `fmt` which introduces string interpolation and formatting with a mini language inspired by printf and Python.  # Quick Start  ```haskell+>>> :set -XQuasiQuotes >>> import PyF  >>> name = "Dave"@@ -27,7 +28,7 @@  You will need the extension `QuasiQuotes`, enable it with `{-# LANGUAGE QuasiQuotes #-}` in top of your source file or with `:set -XQuasiQuotes` in your `ghci` session. `ExtendedDefaultRules` and `OverloadedStrings` may be more convenient. -Expression to be formatted are referenced by `{expression:formattingOptions}` where `formattingOptions` follows the [Python format mini-language](https://docs.python.org/3/library/string.html#formatspec). It is recommended to read the python documentation, but the [Test file](https://github.com/guibou/PyF/blob/main/test/Spec.hs) as well as this readme contain many examples.+Expression to be formatted are referenced by `{expression:formattingOptions}` where `formattingOptions` follows the [Python format mini-language](https://docs.python.org/3/library/string.html#formatspec). It is recommended to read the Python documentation, but the [Test file](https://github.com/guibou/PyF/blob/main/test/Spec.hs) as well as this readme contain many examples.  # More Examples @@ -70,7 +71,7 @@ >>> [fmt|Octal (no prefix): {v:o}|] "Octal (no prefix): 37" >>> [fmt|Hexa (caps and prefix): {v:#X}|]-"Hexa (caps and prefix): 0x1F"+"Hexa (caps and prefix): 0X1F" ```  ## Grouping@@ -104,9 +105,9 @@ Preceding the width with a `0` enables sign-aware zero-padding, this is equivalent to inside `=` padding with a fill char of `0`.  ```haskell->>> [f{10:010}|]+>>> [fmt|{10:010}|] 0000000010->>> [f{-10:010}|]+>>> [fmt|{-10:010}|] -000000010 ``` @@ -143,7 +144,7 @@ |] ``` -Will returns `-a\n-b`. Note how the first and last line breaks are ignored.+Will returns `"- a\n- b"`. Note how the first and last line breaks are ignored.  ## Arbitrary value for precision and padding @@ -194,8 +195,8 @@  ## Error reporting -Template haskell is generally known to give developers a lot of-frustration when it comes to error message, dumping an unreadable+Template Haskell is generally known to give developers a lot of+frustration when it comes to error messages, dumping an unreadable piece of generated code.  However, in PyF, we took great care to provide clear error reporting, this means that:@@ -251,7 +252,7 @@ ... ``` -- Finally, if you make any type error inside the expression field, you are on your own, you'll get an awful error in the middle of the generated template Haskell splice.+- Finally, if you make any type error inside the expression field, you are on your own, you'll get an awful error in the middle of the generated Template Haskell splice.  ```haskell >>> [fmt|{3 + pi + "hello":10}|]@@ -263,7 +264,7 @@  ## Custom Delimiters -If `{` and `}` does not fit your needs, for example if you are formatting a lot of json, you can use custom delimiters. All quasi quoters have a parametric form which accepts custom delimiters. Due to template haskell stage restriction, you must define your custom quasi quoter in an other module.+If `{` and `}` do not fit your needs, for example if you are formatting a lot of JSON, you can use custom delimiters. All quasi quoters have a parametric form which accepts custom delimiters. Due to the Template Haskell stage restriction, you must define your custom quasi quoter in another module.  For example, in `MyCustomDelimiter.hs`: @@ -294,21 +295,21 @@  Have a look at `PyF.mkFormatter` for all the details about customization. -## Difference with the Python Syntax+## 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 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.  ### Not supported -- Number `n` formatter is not supported. In python this formatter can format a number and use current locale information for decimal part and thousand separator. There is no plan to support that because of the impure interface needed to read the locale.-- Python support sub variables in the formatting options in every places, such as `{expression:.{precision}}`. We only support it for `precision` and `width`. This is more complexe to setup for others fields.-- Python literal integers accepts binary/octal/hexa/decimal literals, PyF only accept decimal ones, I don't have a plan to support that, if you really need to format a float with a number of digit provided as a binary constant, open an issue.-- Python support adding custom formatters for new types, such as date. This may be really cool, for example `[fmt|{today:%Y-%M-%D}`. I don't know how to support that now.+- Number `n` formatter is not supported. In Python this formatter can format a number and use current locale information for decimal part and thousand separator. There is no plan to support that because of the impure interface needed to read the locale.+- Python supports sub variables in the formatting options in all places, such as `{expression:.{precision}}`. We only support it for `precision` and `width`. This is more complexe to setup for others fields.+- Python literal integers accept binary/octal/hexa/decimal literals, PyF only accept decimal ones, I don't have a plan to support that, if you really need to format a float with a number of digit provided as a binary constant, open an issue.+- Python supports adding custom formatters for new types, such as date. This may be really cool, for example `[fmt|{today:%Y-%M-%D}`. I don't know how to support that now. -### Difference+### Differences  - General formatters *g* and *G* behaves a bit differently. Precision influence the number of significant digits instead of the number of the magnitude at which the representation changes between fixed and exponential.-- Grouping options allows grouping with an `_` for floating point, python only allows `,`.+- Grouping options allows grouping with an `_` for floating point, Python only allows `,`. - Custom delimiters  # Build / test@@ -317,8 +318,8 @@  ```shell nix-shell # Optional, if you use nix-cabal new-build-cabal new-test+cabal build+cabal test ```  There are a few available shells for you.
src/PyF.hs view
@@ -3,7 +3,7 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE ViewPatterns #-} --- | A lot of quasiquoters to format and interpolate string expression+-- | A lot of quasiquoters to format and interpolate string expressions. module PyF   ( fmt,     fmtTrim,@@ -40,27 +40,27 @@ fmtTrim :: QuasiQuoter fmtTrim = mkFormatter "fmtTrim" (addTrim fmtConfig) --- | multiline string, no interpolation.+-- | Multiline string, no interpolation. str :: QuasiQuoter str = mkFormatter "str" strConfig --- | multiline string, no interpolation, but does indentation trimming.+-- | Multiline string, no interpolation, but does indentation trimming. strTrim :: QuasiQuoter strTrim = mkFormatter "strTrim" (addTrim strConfig) --- | Raw string, no interpolation neither escaping is performed.+-- | Raw string, neither interpolation nor escaping is performed. raw :: QuasiQuoter raw = expQQ "raw" (\s -> [|s|])  -- | Removes the trailing whitespace of a string. -- -- - First line is ignored if it only contains whitespaces--- - All other line common indentation is removed, ignoring line with only whitespaces.+-- - All other line common indentation is removed, ignoring lines with only whitespaces. -- -- >>> trimIndent "\n   hello\n   - a\n   - b\n   " -- "hello\n- a\n- b\n" ----- See 'fmtTrim' for a quasiquoter with this behavior+-- See 'fmtTrim' for a quasiquoter with this behavior. trimIndent :: String -> String trimIndent s =   case lines s of@@ -95,7 +95,7 @@       postProcess = id     } --- | Configuration for 'str' it just wrap the multiline string with 'fromString'.+-- | Configuration for 'str'. It just wraps the multiline string with 'fromString'. strConfig :: Config strConfig =   Config@@ -114,7 +114,7 @@     { postProcess = \q -> postProcess config [|PyF.trimIndent $(q)|]     } --- | Enable formatting+-- | Enable formatting. addFormatting :: (Char, Char) -> Config -> Config addFormatting delims c = c {delimiters = Just delims} 
src/PyF/Class.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE DataKinds #-}-{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}
src/PyF/Formatters.hs view
@@ -15,13 +15,13 @@ -- -- Formatters for integral / fractional and strings. ----- Is support:+-- The following is supported: -- -- For all types: -----   * Grouping of the integral part (i.e: adding a custom char to separate groups of digits)+--   * Grouping of the integral part (i.e. adding a custom char to separate groups of digits) --   * Padding (left, right, around, and between the sign and the number)---   * Sign handling (i.e: display the positive sign or not)+--   * Sign handling (i.e. display the positive sign or not) -- -- For floating: --@@ -30,7 +30,7 @@ -- -- For integrals: -----    * Binary / Hexa / Octal / Character representation+--    * Binary / Hexadecimal / Octal / Character representation module PyF.Formatters   ( -- * Generic formatting function     formatString,@@ -105,16 +105,16 @@ getAlignForString AlignCenter = Just AlignCenter getAlignForString AlignLeft = Just AlignLeft --- | This formatter support alternate version+-- | This formatter supports an alternate version. data AltStatus = CanAlt | NoAlt --- | This formatter support Upper case version+-- | This formatter support an uppercase version. data UpperStatus = CanUpper | NoUpper --- | This formatter formats an integral or a fractional+-- | This formatter formats an integral or a fractional. data FormatType = Fractional | Integral --- | All the Formatters+-- | All the Formatters. data Format (k :: AltStatus) (k' :: UpperStatus) (k'' :: FormatType) where   -- Integrals   Decimal :: Format 'NoAlt 'NoUpper 'Integral@@ -280,7 +280,7 @@  -- Final formatters --- | Format an integral number+-- | Format an integral number. formatIntegral ::   Integral paddingWidth =>   Integral i =>@@ -294,7 +294,7 @@   String formatIntegral f sign padding grouping i = padAndSign f (prefixIntegral f) sign padding (group (reprIntegral f i) grouping) --- | Format a fractional number+-- | Format a fractional number. formatFractional ::   (RealFloat f, Integral paddingWidth, Integral precision) =>   Format t t' 'Fractional ->@@ -309,7 +309,7 @@   String formatFractional f sign padding grouping precision i = padAndSign f "" sign padding (group (reprFractional f (fmap fromIntegral precision) i) grouping) --- | Format a string+-- | Format a string. formatString ::   forall paddingWidth precision.   (Integral paddingWidth, Integral precision) =>
src/PyF/Internal/Meta.hs view
@@ -161,7 +161,10 @@ toExp _ (Expr.HsLit _ l) = TH.LitE (toLit l) toExp _ (Expr.HsOverLit _ OverLit {ol_val}) = TH.LitE (toLit' ol_val) toExp d (Expr.HsApp _ e1 e2) = TH.AppE (toExp d . unLoc $ e1) (toExp d . unLoc $ e2)-#if MIN_VERSION_ghc(9,6,0)+#if MIN_VERSION_ghc(9,10,0)+toExp d (Expr.HsAppType _ e HsWC{hswc_body}) = TH.AppTypeE (toExp d . unLoc $ e) (toType . unLoc $ hswc_body)+toExp d (Expr.ExprWithTySig _ e HsWC{hswc_body=unLoc -> HsSig{sig_body}}) = TH.SigE (toExp d . unLoc $ e) (toType . unLoc $ sig_body)+#elif MIN_VERSION_ghc(9,6,0) toExp d (Expr.HsAppType _ e _ HsWC{hswc_body}) = TH.AppTypeE (toExp d . unLoc $ e) (toType . unLoc $ hswc_body) toExp d (Expr.ExprWithTySig _ e HsWC{hswc_body=unLoc -> HsSig{sig_body}}) = TH.SigE (toExp d . unLoc $ e) (toType . unLoc $ sig_body) #elif MIN_VERSION_ghc(9,2,0)@@ -177,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,6,0)+#if 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) #else 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)@@ -213,7 +218,9 @@ {- ORMOLU_ENABLE -}  -- toExp (Expr.List _ xs)                        = TH.ListE (fmap toExp xs)-#if MIN_VERSION_ghc(9,3,0)+#if MIN_VERSION_ghc(9,10,0)+toExp d (Expr.HsPar _ e) = TH.ParensE (toExp d . unLoc $ e)+#elif MIN_VERSION_ghc(9,3,0) toExp d (Expr.HsPar _ _ e _) = TH.ParensE (toExp d . unLoc $ e) #else toExp d (Expr.HsPar _ e) = TH.ParensE (toExp d . unLoc $ e)@@ -260,6 +267,7 @@ #endif #if 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) toExp _ (HsProjection _ fields) = TH.ProjectionE (fmap (unpackFS . unLoc . dfoLabel . unLoc) fields)
src/PyF/Internal/QQ.hs view
@@ -198,7 +198,9 @@       Just (HsVar _ l) -> [l] #endif -#if MIN_VERSION_ghc(9,6,0)+#if 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+#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 #else       Just (HsLam _ (MG _ (unLoc -> (map unLoc -> [Expr.Match _ _ (map unLoc -> ps) (GRHSs _ [unLoc -> GRHS _ _ (unLoc -> e)] _)])) _)) -> filter keepVar subVars