Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matching serialise/deserialise behaviours for units #391

Open
4 tasks
rafaqz opened this issue Oct 26, 2020 · 4 comments
Open
4 tasks

Matching serialise/deserialise behaviours for units #391

rafaqz opened this issue Oct 26, 2020 · 4 comments

Comments

@rafaqz
Copy link
Contributor

rafaqz commented Oct 26, 2020

Discussed from #214 (comment) onwards. Making a separate issue so this is easier to find and track.

We should be able to serialise and deserialise units to strings - so e.g. that a table with a units column can be save and loaded again.The way of doing this suggested by @c42f is to make show output the raw julia version that uparse can read back into units. We would then add print methods and some REPL show methods that keep the current behaviour in normal use.

A PR for this would involve:

  • swapping current show methods to work with print
  • define show(::IO, ::MIME"text/plain", unit) so the REPL still looks ok.
  • write new show methods that return the raw julia version
  • write some tests for print/string/show behaviours
@rafaqz rafaqz changed the title Matching serialise/deserialise behaviours Matching serialise/deserialise behaviours for units Oct 26, 2020
@c42f
Copy link
Contributor

c42f commented Oct 26, 2020

Just supporting julia syntax for round-tripping and the current syntax for pretty printing would be fine by me. It seems straightforward and explicit.


Continuing some conversation from #214

Solutions I can think of for this are to just parse whitespace as * in uparse leaving show as-is

Currently uparse just uses the Julia parser itself so somebody would have to implement a small parser. That might be fine though.

If we wanted to support a more general syntax, some research I did a while ago in #214 (comment), seems relevant. Here's some links to existing prior art for unit string representations:

  • The NIST SP811 is influential but doesn't specify a precise grammar for unit strings.
  • The FITS standard is well developed but "overcomplete" allowing flexible parsing of various non-unique representations of a unit string. It's the standard followed in the astropy.units library and seems to have inspired various other standards and proto-standards such as ASDF which defers to FITS.
  • The MIXF standard seems to be an elaborated version of SP811 for plain text unit strings provides a formal grammar. This seems promising but is rather opinionated about using . as multiplication which means incompatibility with julia syntax.
  • The NetCDF format appears to use the udunits package which has a unit parser with a grammar also derived from SP811 with an extension for affine units.
  • The python pint library seems to use python syntax for unit string constructions

@singularitti
Copy link
Contributor

This feature is badly wanted! See my comment in #412 (comment).

@rafaqz
Copy link
Contributor Author

rafaqz commented Feb 1, 2021

It shouldn't be too hard to write if you want to have a go at it. I haven't had time yet as this is more something I want to work theoretically than something I need immediately.

@michikawa07
Copy link
Contributor

michikawa07 commented Mar 20, 2023

@sostock @rafaqz @c42f
I am working on this problem (cf. #412, #569).
My implementation is based on this proposal, #214 (comment)
One example is here. Is my approach correct?

function print(io::IO, x::Units) # swaped old show(io::IO, x::Unitlike)
    is_first =true
    sep = " "
    foreach(sortexp(x)) do y
        is_first || print(io, sep)
        showrep(io,y)
        is_first = false
    end
end

show(io::IO, mime::MIME"text/plain", x::Units) = print(io, x) # for REPL

function show(io::IO, x::Units) # for default, parsable
    sep = "*"
    is_first = true
    foreach(sortexp(x)) do y
        p = power(y) 
        pow = p == 1//1        ? ""  :
              p.den == 1       ? string("^", p.num) : 
              p == p.num/p.den ? string("^", "(", p.num, "/" , p.den, ")") :
                                 string("^", "(", p.num, "//", p.den, ")")
        is_first || print(io, sep)
        print(io, prefix(y))
        print(io, usym(y))
        print(io, pow)
        is_first = false
    end    
end

(The content of show(io::IO, x::Units) method is the same as the one in UnitfulParsableString.jl)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants