# \[ANN\] PyFormattedStrings.jl: Python-like formatted interpolation

**URL:** <https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224>\
**Category:** Package Announcements\
**Created:** [September 27, 2019, 10:50am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224 "2019-09-27T10:50:21Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 27, 2019, 10:50am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/1 "2019-09-27T10:50:21Z")

</div>

Several months ago I asked here ([Formatted string interpolation](https://discourse.julialang.org/t/formatted-string-interpolation/21350)) about string interpolation with formatting options, and didn’t find any solutions. So I developed a small package for this, which uses Python f-string syntax, e.g. `f"result = {1.23^5:.2f}"` gives `"result = 2.82"`. I’ve been using this package myself for quite a while already and didn’t have any issues - so decided to make it available: [https://github.com/aplavin/FormatInterp.jl](https://github.com/aplavin/FormatInterp.jl). I really don’t get how one can live (and generate strings) without such a thing 🙂  
Currently it has a single string macro, which parses a given string and generates an expression which uses `Formatting.jl` to format individual values, and concatenates them afterwards.

Bug reports are welcome! As for adding something new - I have no plans on that, but am open to PRs.

---

<div class="post-metadata">

**Author:** ![feanor12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/feanor12/32/8212_2.png) [@feanor12](https://discourse.julialang.org/u/feanor12)\
**Post date:** [September 27, 2019, 12:22pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/2 "2019-09-27T12:22:26Z")

</div>

A README.md file would be nice.

---

<div class="post-metadata">

**Author:** ![NiclasMattsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niclasmattsson/32/21988_2.png) [@NiclasMattsson](https://discourse.julialang.org/u/NiclasMattsson)\
**Post date:** [September 27, 2019, 2:00pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/3 "2019-09-27T14:00:00Z")

</div>

I’m sure people with a python background will appreciate your macro as it is, but would you consider extending it to also allow a more julian syntax for the rest of us? Something like this:

`f"result = $(1.23^5:.2f)"`

For me at least that would definitely be worth typing an extra character.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 27, 2019, 2:37pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/4 "2019-09-27T14:37:34Z")

</div>

I personally hate using `$` as the interpolation character, because it complicates generating latex strings (which I do quite often) more than `{` does. However, I’m open to PRs in this regard. Changing `{` to some other single character is almost trivial, but replacing it with a pair like `$(` requires some care.

---

<div class="post-metadata">

**Author:** ![kevbonham](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kevbonham/32/216165_2.png) [@kevbonham](https://discourse.julialang.org/u/kevbonham)\
**Post date:** [September 28, 2019, 1:15pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/5 "2019-09-28T13:15:30Z")

</div>

A trivial comment, but the package name doesn’t really conform to the [package naming guidelines](https://julialang.github.io/Pkg.jl/v1/creating-packages/#Package-naming-guidelines-1) (see especially #4)

Why not `FormattedInterpolation.jl` or `FStringInterpolation.jl`?

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [September 28, 2019, 3:49pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/6 "2019-09-28T15:49:38Z")

</div>

A related package is [StrLiterals.jl](https://github.com/JuliaString/StrLiterals.jl). For string-related issues, I recommend to watch [JuliaString](https://github.com/JuliaString) and @ScottPJones.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 30, 2019, 6:57am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/7 "2019-09-30T06:57:19Z")

</div>

Oh, indeed. I didn’t notice that section in the docs.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 30, 2019, 7:07am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/8 "2019-09-30T07:07:23Z")

</div>

Yes, I know about `StrLiterals`, but it’s not maintained at all - last commit and activity was 1.5 years ago, and now this package doesn’t work on reasonably recent Julia. Also `StrLiterals` doesn’t have python-like string syntax as I understand (cannot try because it doesn’t work). So for me it was easier to just roll out my own package to parse the input string and pass its parts to `Formatting.jl` than to fix and modify `StrLiterals`.

---

<div class="post-metadata">

**Author:** ![jbrea](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbrea/32/3879_2.png) [@jbrea](https://discourse.julialang.org/u/jbrea)\
**Post date:** [September 30, 2019, 7:15am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/9 "2019-09-30T07:15:45Z")

</div>

`StrLiterals` works for me on julia 1.2 (passes all tests) and `StrFormat` supports python-like string syntax. I don’t think these packages are unmaintained. What is not working for you?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [September 30, 2019, 7:35am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/10 "2019-09-30T07:35:06Z")

</div>

Ok, I stand corrected - the package itself works. And even formatting of expressions works after installing `StrFormat.jl`. I confused `StrLiterals` and `https://github.com/JuliaString/StringLiterals.jl` thinking they are the same package - and it is the latter one that does not work.  
So, taking this into account, `StrLiterals` + `StrFormat` have only one disadvantage I can see - what these packages call “python-like” syntax is not the syntax python or any other language actually uses, and this is done for no apparent reason.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [September 30, 2019, 7:55am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/11 "2019-09-30T07:55:09Z")

</div>

> So for me it was easier to just roll out my own package…

That is totally fine, and I did not want to disparage your work. The lack of format modifiers in `Base` julia string interpolation is an eternal gripe of mine, and I thought that you might not have been aware of the JuliaStrings “shadow ecosystem” for strings. This group of packages seems to be less well known than deserved.

Even when rolling my own, it is always nice to have working code and API design for related functionality to learn from.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [October 1, 2019, 2:10pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/12 "2019-10-01T14:10:14Z")

</div>

StringLiterals.jl was written back for Julia v0.4  
StrLiterals.jl is part of the whole set of string related packages (you can just do `using Strs` to get pretty much everything), and it most definitely is maintained for Julia v1.0 and above

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [October 1, 2019, 2:17pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/13 "2019-10-01T14:17:12Z")

</div>

I am not a python programmer, and most of the python-like formatting came from the `Format.jl` package I used under the hood.  
I documented in the README that I wanted to have it allow a truly python like syntax, however I only use the C printf style myself.  
If you wish to contribute to make it actually work more closely to the Python syntax (where the argument is part of the string, not positional), I would greatly appreciate it.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 1, 2019, 2:42pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/14 "2019-10-01T14:42:41Z")

</div>

Yes, now I see. It was just really confusing for me that there are two packages with almost exactly the same name (StrLiterals vs StringLiterals), and I didn’t notice they are in fact different.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 1, 2019, 2:44pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/15 "2019-10-01T14:44:11Z")

</div>

I also use Formatting.jl (almost the same as Format.jl, as I understand), my package just parses the string and generates a call to Formatting.jl for each interpolated argument.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [April 24, 2021, 5:04pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/16 "2021-04-24T17:04:48Z")

</div>

I have recently become familiar with registering in `General`, and decided to finally publish this formatting package in that registry. Following suggestions in this thread, I renamed the package and added a brief README. So, the package is now called `PyFormattedStrings` and registered: [JuliaHub](https://juliahub.com/ui/Packages/PyFormattedStrings/T968L).

It uses the built-in `Printf` stdlib under the hood: I switched to that from `Formatting.jl`. Arbitrary Julia syntax is supported within interpolated expressions, and formatting options syntax mirrors Python as closely as possible without reimplementing formatting from scratch. See [test/runtests.jl · master · Alexander Plavin / PyFormattedStrings.jl · GitLab](https://gitlab.com/aplavin/PyFormattedStrings.jl/-/blob/master/test/runtests.jl) for some more examples in addition to the README. Generally, there should be no additional runtime overhead compared to a manually-written corresponding `@printf` call.  
As far as I’m aware, there is no other package with the same interpolation capabilities and syntax yet.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [May 11, 2021, 11:30am UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/17 "2021-05-11T11:30:53Z")

</div>

Have you looked at the [Strs](https://github.com/JuliaString/Strs.jl) package yet?  
That has supported both Python-like and C-like formatted interpolated strings, for a number of years.  
As far as I am aware, it was the first to support formatted interpolated strings in Julia.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 11, 2021, 1:21pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/18 "2021-05-11T13:21:10Z")

</div>

> [@ScottPJones](#):
>
> That has supported both Python-like and C-like formatted interpolated strings, for a number of years.  
> As far as I am aware, it was the first to support formatted interpolated strings in Julia.

I agree that `Strs.jl` brought string interpolation to Julia earlier/first and never argued with this. Btw, my package is also quite old: it exists for about two years, and was published in this very thread more than 1.5 years ago.

> [@ScottPJones](#):
>
> Have you looked at the Strs package yet?

Yes, I did: you pointed me to that package earlier in this thread (:

Originally, I wrote `PyFormattedStrings` because I didn’t find any reasonable string interpolation in Julia at all - and I asked in this forum first, see link in the first post.  
Actually, I would probably just overlook `Strs.jl` if noone directly pointed towards it. Its README suggests that the package is, first and foremost, a kind of “alternative Strings” implementation - definitely not something I’m looking for.

In the past two years I mostly made small fixes/improvements to `PyFormattedStrings` that I stumbled across. Recently, I checked that there is still no other package with the same syntax, written a README, and finally registered `PyFormattedStrings` in `General`.

As for comparison to `Strs.jl` at the current state of both packages, I can immediately point the following differences - maybe there are others as well:

- Obvious: syntax is different. I definitely like `f"{123:5d}"` (Python or PyFormattedStrings) more than `f"\{5d}(123)"` (Strs.jl). Also, after multiple tries I couldn’t find how to generate literally the string `"\{5d}(123)"` in `Strs.jl` - that is, how to escape the control sequence. `PyFormattedStrings` follows the Python escaping rule: `f"{{123:5d}}" == "{123:5d}"`.
- `PyFormattedStrings` performance is better: my cursory testing with `@btime` shows that it is 2-10 times faster than `Strs.jl`. Loading time is also shorter.
- Support of (some) formatting options is better in `PyFormattedStrings`: e.g., `g` and `a` float modifiers work; `f"{123.45:.0f}" == "123"`, while `Strs.jl` gives `"123."`. Some others are probably better supported in `Strs.jl`, but I didn’t find any.
- `PyFormattedStrings` doesn’t reimplement formatting and relies on the `Printf` stdlib. So, any bugfixes and improvements to the latter would benefit the former, and the package itself is very lightweight.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [May 11, 2021, 3:12pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/19 "2021-05-11T15:12:59Z")

</div>

When I replied, I had forgotten about the earlier comments from a few years ago 🙂  
`Strs.jl` is really more of a convenience package, pulling together a number of other things, like the alternate strings (faster, and with validated UTF-8 format strings as well as UTF-16 & UTF-32 among others), but also incorporating the formatted interpolation support I’d done earlier.

PyFormattedStrings.jl does look nice, I was responding to the last line of your comment:

> As far as I’m aware, there is no other package with the same interpolation capabilities and syntax yet.

which sounded like you’d missed that `using StrLiterals, StrFormat` would provide the same capabilities (with some differences in syntax, as I wasn’t trying to recreate exactly a Python f-format string [which wasn’t even part of Python when I implemented this], but rather, something that allowed using keyword arguments and full Julia expressions in the interpolation). I was more going for having the formatting part be the same as Python instead (but depended on what Formatting.jl had implemented as far as parsing that), more to make it easier for people coming from Python, but not for direct copying of format strings.

I also prefer being able to have these in otherwise totally normal strings (i.e. without having to use special quoting syntax {{ and }} in the string, like Python).

I am interested in the performance gains you got by using the code in stdlib/Printf, but I’d rather change Format.jl to have that speedup, as well as write a formatting core that supports C style, Python style, and extra keywords for better format control. Right now, Formatting.jl (and Format.jl) have different code for different languages (and then there’s also the formatting code in Printf.jl, as well as the recent Fmt.jl.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 11, 2021, 10:05pm UTC](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224/20 "2021-05-11T22:05:22Z")

</div>

> [@ScottPJones](#):
>
> … something that allowed using keyword arguments and full Julia expressions in the interpolation …

I’m all for using arbitrary expressions in interpolation as well - otherwise it’s closer to just “formatting” than proper “interpolation”. Of course, PyFormattedStrings.jl also support any julia syntax within strings.  
Not completely sure what you mean by keyword arguments here, but I do see (from the docs) that Strs.jl is designed to be extensible.

> [@ScottPJones](#):
>
> I also prefer being able to have these in otherwise totally normal strings (i.e. without having to use special quoting syntax {{ and }} in the string, like Python).

“Normal strings” - that is, without the f-prefix? I personally don’t see the single-character prefix as any kind of inconvenience, just the opposite - it immediately tells the reader that there is some executable code within the string.

> [@ScottPJones](#):
>
> I am interested in the performance gains you got by using the code in stdlib/Printf

Well, I just convert the f-string to the corresponding printf format string, and then generate the same code as would be created by `@sprintf`:

```julia
# format_str - the resulting printf format string
format = Printf.Format(format_str)
# arguments - list of interpolated expressions, in their occurrence order
return :(Printf.format($format, $(esc.(arguments)...)))

```

Using `Printf` puts some limits on possible extensibility, but provides clear benefits in simplicity.

[Next page](https://discourse.julialang.org/t/ann-pyformattedstrings-jl-python-like-formatted-interpolation/29224.md?page=2)
