yaml.load
loads numbers as Python floats. I cannot find a straightforward way to override this.
Compare json.load
, which allows parse_float=Decimal
if you want to parse floating point numbers as decimal.Decimal
s.
Is there any way to accomplish this with PyYAML? Or is this inadvisable by some property of the YAML spec?
You can do something like:
def decimal_constructor(loader, node):
value = loader.construct_scalar(node)
return Decimal(value)
yaml.add_constructor(u'!decimal', decimal_constructor)
This allows you to load decimals, but only if they are prefixed with the !decimal
tag in the YAML document. However, you can use a custom Resolver
to resolve all numbers to !decimal
:
class MyResolver(BaseResolver):
pass
MyResolver.add_implicit_resolver(
'!decimal',
re.compile(r'''^(?:[-+]?(?:[0-9][0-9_]*)\.[0-9_]*(?:[eE][-+][0-9]+)?
|\.[0-9_]+(?:[eE][-+][0-9]+)?
|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\.[0-9_]*
|[-+]?\.(?:inf|Inf|INF)
|\.(?:nan|NaN|NAN))$''', re.X),
list('-+0123456789.'))
You should copy the other implicit resolvers over from the default resolver. Then, you need to define a Loader
that uses your resolver.
class MyLoader(Reader, Scanner, Parser, Composer, SafeConstructor, MyResolver):
def __init__(self, stream):
Reader.__init__(self, stream)
Scanner.__init__(self)
Parser.__init__(self)
Composer.__init__(self)
SafeConstructor.__init__(self)
MyResolver.__init__(self)
Above, we added your constructor to the default loader. Change that line to:
yaml.add_constructor(u'!decimal', decimal_constructor, MyLoader)
Finally, load the YAML using
yaml.load(stream, MyLoader)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With