Package: pvl
pvlPython implementation of a PVL (Parameter Value Language) library.Free software: BSD licenseDocumentation:http://pvl.readthedocs.org.Support for Python 3.6 and higher (avaiable via pypi and conda).PlanetaryPyAffiliate Package.PVL is a markup language, like JSON or YAML, commonly employed for
entries in the Planetary Data System used by NASA to archive
mission data, among other uses.  This package supports both encoding
and decoding a variety of PVL ‘flavors’ including PVL itself, ODL,NASA PDS 3 Labels, andUSGS ISIS Cube Labels.InstallationCan either install with pip or with conda.To install with pip, at the command line:$ pip install pvlDirections for installing with conda-forge:Installingpvlfrom the conda-forge channel can be achieved by adding
conda-forge to your channels with:conda config --add channels conda-forgeOnce the conda-forge channel has been enabled,pvlcan be installed with:conda install pvlIt is possible to list all of the versions ofpvlavailable on your platform
with:conda search pvl --channel conda-forgeBasic Usagepvlexposes an API familiar to users of the standard libraryjsonmodule.Decoding is primarily done throughpvl.load()for file-like objects andpvl.loads()for strings:>>> import pvl
>>> module = pvl.loads("""
...     foo = bar
...     items = (1, 2, 3)
...     END
... """)
>>> print(module)
PVLModule([
  ('foo', 'bar')
  ('items', [1, 2, 3])
])
>>> print(module['foo'])
barThere is also apvl.loadu()to which you can provide the URL of a file that you would normally provide topvl.load().You may also usepvl.load()to read PVL text directly from animagethat begins with PVL text:>>> import pvl
>>> label = pvl.load('tests/data/pattern.cub')
>>> print(label)
PVLModule([
  ('IsisCube',
   {'Core': {'Dimensions': {'Bands': 1,
                            'Lines': 90,
                            'Samples': 90},
             'Format': 'Tile',
             'Pixels': {'Base': 0.0,
                        'ByteOrder': 'Lsb',
                        'Multiplier': 1.0,
                        'Type': 'Real'},
             'StartByte': 65537,
             'TileLines': 128,
             'TileSamples': 128}})
  ('Label', PVLObject([
    ('Bytes', 65536)
  ]))
])
>>> print(label['IsisCube']['Core']['StartByte'])
65537Similarly, encoding Python objects as PVL text is done throughpvl.dump()andpvl.dumps():>>> import pvl
>>> print(pvl.dumps({
...     'foo': 'bar',
...     'items': [1, 2, 3]
... }))
FOO   = bar
ITEMS = (1, 2, 3)
END
<BLANKLINE>pvl.PVLModuleobjects may also be pragmatically built up
to control the order of parameters as well as duplicate keys:>>> import pvl
>>> module = pvl.PVLModule({'foo': 'bar'})
>>> module.append('items', [1, 2, 3])
>>> print(pvl.dumps(module))
FOO   = bar
ITEMS = (1, 2, 3)
END
<BLANKLINE>Apvl.PVLModuleis adict-like container that preserves
ordering as well as allows multiple values for the same key. It provides
similar semantics to alistof key/valuetuplesbut
withdict-style access:>>> import pvl
>>> module = pvl.PVLModule([
...     ('foo', 'bar'),
...     ('items', [1, 2, 3]),
...     ('foo', 'remember me?'),
... ])
>>> print(module['foo'])
bar
>>> print(module.getall('foo'))
['bar', 'remember me?']
>>> print(module.items())
ItemsView(PVLModule([
  ('foo', 'bar')
  ('items', [1, 2, 3])
  ('foo', 'remember me?')
]))
>>> print(pvl.dumps(module))
FOO   = bar
ITEMS = (1, 2, 3)
FOO   = 'remember me?'
END
<BLANKLINE>However, there are some aspects to the defaultpvl.PVLModulethat are not entirely
aligned with the modern Python 3 expectations of a Mapping object.  If you would like
to experiment with a more Python-3-ic object, you could instantiate apvl.collections.PVLMultiDictobject, orimport pvl.new as pvlin your code
to have the loaders return objects of this type (and then easily switch back by just
changing the import statement).  To learn more about how PVLMultiDict is different
from the existing OrderedMultiDict that PVLModule is derived from, please read the
new PVLMultiDict documentation.The intent is for the loaders (pvl.load(),pvl.loads(), andpvl.loadu())
to be permissive, and attempt to parse as wide a variety of PVL text as
possible, including some kinds of ‘broken’ PVL text.On the flip side, when dumping a Python object to PVL text (viapvl.dumps()andpvl.dump()), the library will default
to writing PDS3-Standards-compliant PVL text, which in some ways
is the most restrictive, but the most likely version of PVL text
that you need if you’re writing it out (this is different from
pre-1.0 versions ofpvl).You can change this behavior by giving different parameters to the
loaders and dumpers that define the grammar of the PVL text that
you’re interested in, as well as custom parsers, decoders, and
encoders.For more information on custom serilization and deseralization see thefull documentation.ContributingFeedback, issues, and contributions are always gratefully welcomed. See thecontributing guidefor details on how to help and setup a development
environment.HistoryAll notable changes to this project will be documented in this file.The format is based onKeep a Changelog,
and this project adheres toSemantic Versioning.When updating this file, please add an entry for your change underNot Yet Releasedand one of the following headings:Added - for new features.Changed - for changes in existing functionality.Deprecated - for soon-to-be removed features.Removed - for now removed features.Fixed - for any bug fixes.Security - in case of vulnerabilities.If the heading does not yet exist underNot Yet Released, then add it
as a 3rd level heading, underlined with pluses (see examples below).When preparing for a public release add a new 2nd level heading,
underlined with dashes underNot Yet Releasedwith the version number
and the release date, in year-month-day format (see examples below).Not Yet Released1.3.2 (2022-02-05)FixedThe parser was requesting the next token after an end-statement, even
though nothing was done with this token (in the future it could
be a comment that should be processed).  In the very rare case
where all of the “data” bytes in a file with an attached PVL label
(like a .IMG or .cub file) actually convert to UTF with no
whitespace characters, that next token will take an unacceptable
amount of time to return, if it does at all.  The parser now does
not request additional tokens once an end-statement is identified
(Issue 104).1.3.1 (2022-02-05)FixedDeeply nested Aggregation Blocks (Object or Group) which had mis-matched
Block Names should now properly result in LexerErrors instead of
resulting in StopIteration Exceptions (Issue 100).The default “Omni” parsing strategy, now considers the ASCII NULL character
(”0”) a “reserved character.” The practical effect is that the
ASCII NULL can not be in parameter names or unquoted strings (but
would still be successfully parsed in quoted strings). This means
that PVL-text that might have incorrectly used ASCII NULLs as
delimiters will once again be consumed by our omnivorous parser
(Issue 98).1.3.0 (2021-09-10)Addedpvl.collections.Quantity objects now have __int__() and __float__()
functions that will return the int and float versions of their
.value parameter to facilitate numeric operations with Quantity
objects (Issue 91).pvl.load() now has anencoding=parameter that is identical in usage
to the parameter passed toopen(), and will attempt to decode the whole
file as if it had been encoded thusly.  If it encounters a decoding error,
it will fall back to decoding the bytes one at a time as ASCII text (Issue 93).FixedIf the PVL-text contained characters beyond the set allowed by the
PVL specification, the OmniGrammar would refuse to parse them.
This has been fixed to allow any valid character to be parsed,
so that if there are weird UTF characters in the PVL-text, you’ll get
those weird UTF characters in the returned dict-like.  When the
stricter PVL, ODL, or PDS3 dialects are used to “load” PVL-text,
they will properly fail to parse this text (Issue 93).Empty parameters inside groups or objects (but not at the end), would
cause the default “Omni” parsing strategy to go into an infinite
loop.  Empty parameters in PVL, ODL, and PDS3 continue to not be
allowed (Issue 95).1.2.1 (2021-05-31)AddedSo many tests, increased coverage by about 10%.FixedAttempting to importpvl.newwithoutmultidictbeing available,
will now properly yield an ImportError.Thedump()anddumps()functions now properly overwritten inpvl.new.All encoders that descended from PVLEncoder didn’t properly have group_class and
object_class arguments to their constructors, now they do.Thechar_allowed()function in grammar objects now raises a more useful ValueError
than just a generic Exception.The newcollections.PVLMultiDictwasn’t correctly inserting Mapping objects with
theinsert_before()andinsert_after()methods.Thetoken.Tokenclass’s__index__()function didn’t always properly return an
index.Thetoken.Tokenclass’s__float__()function would return int objects if the
token could be converted to int.  Now always returns floats.1.2.0 (2021-03-27)AddedAdded a default_timezone parameter to grammar objects so that they could
both communicate whether they had a default timezone (if not None),
and what it was.Added a pvl.grammar.PDSGrammar class that specifies the default UTC
time offset.Added a pvl.decoder.PDSLabelDecoder class that properly enforces only
milisecond time precision (not microsecond as ODL allows), and does
not allow times with a +HH:MM timezone specifier.  It does assume
any time without a timezone specifier is a UTC time.Added areal_clsparameter to the decoder classes, so that users can specify
an arbitrary type with which real numbers in the PVL-text could be returned in
the dict-like from the loaders (defaults tofloatas you’d expect).The encoders now support a broader range of real types to complement the decoders.ChangedImproved some build and test functionality.Moved the is_identifier() static function from the ODLEncoder to the ODLDecoder
where it probably should have always been.FixedVery long Pythonstrobjects that otherwise qualified as ODL/PDS3 Symbol Strings,
would get written out with single-quotes, but they would then be split across lines
via the formatter, so they should be written as Text Strings with double-quotes.
Better protections have been put in place.pvl.decoder.ODLDecoder now will return both “aware” and “naive”
datetime objects (as appropriate) since “local” times without a
timezone are allowed under ODL.pvl.decoder.ODLDecoder will now properly reject any unquoted string
that does not parse as an ODL Identifier.pvl.decoder.ODLDecoder will raise an exception if there is a seconds value
of 60 (which the PVLDecoder allows)pvl.encoder.ODLEncoder will raise an exception if given a “naive” time
object.pvl.encoder.PDSLabelEncoder will now properly raise an exception if
a time or datetime object cannot be represented with only milisecond
precision.1.1.0 (2020-12-04)AddedModifiedpvl_validateto more robustly deal with errors, and also provide
more error-reporting via-vand-vv.Modified ISISGrammar so that it can parse comments that begin with an octothorpe (#).FixedAltered documentation in grammar.py that was incorrectly indicating that
there were parameters that could be passed on object initiation that would
alter how those objects behaved.1.0.1 (2020-09-21)FixedThe PDSLabelEncoder was improperly raising an exception if the Python datetime
object to encode had a tzinfo component that had zero offset from UTC.1.0.0 (2020-08-23)This production version of the pvl library consists of significant
API and functionality changes from the 0.x version that has been
in use for 5 years (a credit to Trevor Olson’s skills).  The
documentation has been significantly upgraded, and various granular
changes over the 10 alpha versions of 1.0.0 over the last 8 months
are detailed in their entries below.  However, here is a high-level
overview of what changed from the 0.x version:Addedpvl.load()andpvl.dump()take all of the arguments that they could take
before (string containing a filename, byte streams, etc.), but now also accept anyos.PathLikeobject, or even an already-opened file object.pvl.loadu()function will load PVL text from URLs.Utility programspvl_validateandpvl_translatewere added, please see
the “Utility Programs” section of the documentation for more information.The library can now parse and encode PVL Values with Units expressions
with third-party quantity objects likeastropy.units.Quantityandpint.Quantity.
Please see the “Quantities: Values and Units” section of the documentation.Implemented a new PVLMultiDict (optional, needs 3rd party multidict library) which
which has more pythonic behaviors than the existing OrderedMultiDict.  Experiment
with getting it returned by the loaders by altering your import statement toimport pvl.new as pvland then using the loaders as usual to get the new object
returned to you.ChangedOnly guaranteed to work with Python 3.6 and above.Rigorously implemented the three dialects of PVL text: PVL itself,
ODL, and the PDS3 Label Standard.  There is a fourth de-facto
dialect, that of ISIS cube labels that is also handled.  Please see
the “Standards & Specifications” section of the documentation.There is now a default dialect for the dump functions: the PDS3 Label Standard.
This is different and more strict than before, but other output dialects are
possible.  Please see the “Writing out PVL text” section in the documentation
for more information, and how to enable an output similar to the 0.x output.There are nowpvl.collectionsandpvl.exceptionsmodules.  There was previously
an internalpvl._collectionsmodule, and the exception classes were scattered through
the other modules.FixedAlldatetime.timeanddatetime.datetimeobjects returned from the loaders
are now timezone “aware.” Previously some were and some were not.Functionality to correctly parse dash (-) continuation lines in ISIS output is
now supported.The library now properly parses quoted strings that include backslashes.DeprecatedThepvl.collections.Unitsobject is deprecated in favor of
the newpvl.collections.Quantityobject (really a name-only change, no functionality
difference).1.0.0-alpha.9 (2020-08-18)Minor addition to pvl.collections.MutableMappingSequence.Implemented PVLMultiDict which is based on the 3rd Partymultidict.MultiDictobject as an option to use instead
of the default OrderedMultiDict.  The new PVLMultiDict
is better aligned with the Python 3 way that Mapping
objects behave.Enhanced the existing OrderedMultiDict with some functionality
that extends its behavior closer to the Python 3 ideal, and
inserted warnings about how the retained non-Python-3
behaviors might be removed at the next major patch.Implemented pvl.new that can be included for those that wish
to try out what getting the new PVLMultiDict returned from
the loaders might be like by just changing an import statement.1.0.0-alpha.8 (2020-08-01)Renamed the _collections module to just collections.Renamed the Units class to Quantity (Units remains, but has a deprecation warning).Defined a new ABC: pvl.collections.MutableMappingSequenceMore detail for these changes can be found in Issue #62.1.0.0-alpha.7 (2020-07-29)Created a new exceptions.py module and grouped all pvl Exceptions
there.  Addresses #58Altered the message that LexerError emits to provide context
around the character that caused the error.Added bump2version configuration file.1.0.0-alpha.6 (2020-07-27)Enforced that all datetime.time and datetime.datetime objects
returned should be timezone “aware.”  This breaks 0.x functionality
where some were and some weren’t.  Addresses #57.1.0.0-alpha.5 (2020-05-30)ISIS creates PVL text with unquoted plus signs (“+”), needed to adjust
the ISISGrammar and OmniGrammar objects to parse this properly (#59).In the process of doing so, realized that we have some classes that
optionally take a grammar and a decoder, and if they aren’t given, to default.
However, a decoderhasa grammar object, so if a grammar isn’t provided, but
a decoder is, the grammar should be taken from the decoder, otherwise you
could get confusing behavior.Updated pvl_validate to be explicit about these arguments.Added a –version argument to both pvl_translate and pvl_validate.1.0.0.-alpha.4 (2020-05-29)Added the pvl.loadu() function as a convenience function to load PVL text from
URLs.1.0.0-alpha.3 (2020-05-28)Implemented tests in tox and Travis for Python 3.8, and discovered a bug
that we fixed (#54).1.0.0-alpha.2 (2020-04-18)The ability to deal with 3rd-party ‘quantity’ objects like astropy.units.Quantity
and pint.Quantity was added and documented, addresses #22.1.0.0-alpha.1 (2020-04-17)This is a bugfix on 1.0.0-alpha to properly parse scientific notation
and deal with properly catching an error.1.0.0-alpha (winter 2019-2020)This is the alpha version of release 1.0.0 for pvl, and the items
here and in other ‘alpha’ entries may be consolidated when 1.0.0
is released.  This work is categorized as 1.0.0-alpha because
backwards-incompatible changes are being introduced to the codebase.Refactored code so that it will no longer support Python 2,
and is only guaranteed to work with Python 3.6 and above.Rigorously implemented the three dialects of PVL text: PVL itself,
ODL, and the PDS3 Label Standard.  There is a fourth de-facto
dialect, that of ISIS cube labels that is also handled.  These
dialects each have their own grammars, parsers, decoders, and
encoders, and there are also some ‘Omni’ versions of same that
handle the widest possible range of PVL text.When parsing via the loaders,pvlcontinues to consume as
wide a variety of PVL text as is reasonably possible, just like
always.  However, now when encoding via the dumpers,pvlwill
default to writing out PDS3 Label Standard format PVL text, one
of the strictest dialects, but other options are available.  This
behavior is different from the pre-1.0 version, which wrote out
more generic PVL text.Removed the dependency on thesixlibrary that provided Python 2
compatibility.Removed the dependency on thepytzlibrary that provided ‘timezone’
support, as that functionality is replaced with the Standard Library’sdatetimemodule.The privatepvl/_numbers.pyfile was removed, as its capability is now
accomplished with the Python Standard Library.The privatepvl/_datetimes.pyfile was removed, as its capability is now
accomplished with the Standard Library’sdatetimemodule.the privatepvl/_strings.pyfile was removed, as its capabilities are now
mostly replaced with the new grammar module and some functions in other new
modules.Internally, the library is now working with string objects, not byte literals,
so thepvl/stream.pymodule is no longer needed.Added an optional dependency on the 3rd partydateutillibrary, to parse
more exotic date and time formats.  If this library is not present, thepvllibrary will gracefully fall back to not parsing more exotic
formats.Implmented a more formal approach to parsing PVL text:  The properties
of the PVL language are represented by a grammar object.  A string is
broken into tokens by the lexer function.  Those tokens are parsed by a
parser object, and when a token needs to be converted to a Python object,
a decoder object does that job.  When a Python object must be converted to
PVL text, an encoder object does that job.Since the tests intests/test_decoder.pyandtests/test_encoder.pywere really just exercising the loader and dumper functions, those tests were
moved totests/test_pvl.py, but all still work (with light modifications for
the new defaults).  Unit tests were added for most of the new classes and
functions.  All docstring tests now also pass doctest testing and are now
included in themake testtarget.Functionality to correctly parse dash (-) continuation lines written by ISIS
as detailed in #34 is implemented and tested.Functionality to usepathlib.Pathobjects forpvl.load()andpvl.dump()as requested in #20 and #31 is implemented and tested.Functionality to accept already-opened file objects that were opened in
‘r’ mode or ‘rb’ mode as alluded to in #6 is implemented and tested.The library now properly parses quoted strings that include backslashes
as detailed in #33.Utility programs pvl_validate and pvl_translate were added.Documentation was updated and expanded.0.3.0 (2017-06-28)Create methods to add items to the labelGive user option to allow the parser to succeed in parsing broken labels0.2.0 (2015-08-13)Drastically increase test coverage.Lots of bug fixes.Add Cube and PDS encoders.Cleanup README.Use pvl specification terminology.Added element access by index and slice.0.1.1 (2015-06-01)Fixed issue with reading Pancam PDS Products.0.1.0 (2015-05-30)First release on PyPI.