Giter VIP home page Giter VIP logo

py-openmath's People

Contributors

defeo avatar florian-rabe avatar nthiery avatar tkw1536 avatar videlec avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

py-openmath's Issues

the mechanism for registering converters didn't work for me

I tried the example at the bottom of page https://github.com/OpenMath/py-openmath: I tried to copy and paste each line, but it didn't work for me:

Finally, this class contains a mechanism for registering converters.
$ python3
Python 3.8.2 (default, Mar 13 2020, 10:14:16)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from fractions import Fraction
>>> from openmath import openmath as om
>>> from openmath.convert import DefaultConverter as converter
>>> def to_om_rat(obj):
...     return om.OMApplication(om.OMSymbol('rational', cd='nums1'),
...             list(map(converter.to_openmath, [obj.numerator, obj.denominator])))
...
>>> def to_py_rat(obj):
...     return Fraction(converter.to_python(obj.arguments[0]), converter.to_python(obj.arguments[1]))
...
>>> converter.register(Fraction, to_om_rat, 'nums1', 'rational', to_py_rat)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'BasicPythonConverter' object has no attribute 'register'
>>>

convert the empty set without using a special case

The empty set is converted from Python to OpenMath as
<OMS cdbase="http://www.openmath.org/cd" name="emptyset" cd="set1"/>
which is correct but not the best choice. It would be better to convert it as
<OMA><OMS cdbase=\"http://www.openmath.org/cd\" cd=\"set1\" name=\"set\"/></OMA>
it such way, the empty set is handled as a set and not as a special case.

About this, please consider what is said in
http://www.catb.org/~esr/writings/taoup/html/ch01s06.html , which is
especially relevant for OpenMath, which is intended to be used by
computers:

For robustness, designing in tolerance for unusual or extremely bulky
inputs is also important. Bearing in mind the Rule of Composition helps;
input generated by other programs is notorious for stress-testing software
(e.g., the original Unix C compiler
reportedly needed small upgrades to cope well with Yacc output). The forms
involved often seem useless to humans. For example, accepting empty
lists/strings/etc., even in places where a human would seldom or never
supply an empty string, avoids having to
special-case such situations when generating the input mechanically.
-- Henry Spencer
One very important tactic for being robust under odd inputs is to avoid
having special cases in your code. Bugs often lurk in the code for
handling special cases, and in the interactions among parts of the code
intended to handle different special cases.

CaseClass, not what we want

My attention was drawn today to a variation of this behaviour:

In [15]: import openmath.openmath as om

In [16]: a = om.OMObject(1, 2)

In [17]: b = om.OMObject(1, '2')

In [18]: a == b
Out[18]: False

In [19]: a
Out[19]: OMObject(1, version=2, id=None, cdbase=None)

In [20]: b
Out[20]: OMObject(1, version='2', id=None, cdbase=None)

In [21]: a.version
Out[21]: '2'

In [22]: b.version
Out[22]: '2'

which shows that we're not using CaseClass the way it is supposed to (we should not modify parameters in __init__, that is).

It is unfortunate that Python has no decent way of implementing structs with inheritance (I won't go as far as calling them algebraic datatypes), but I think we should stick to something simpler and more pythonic.

I'm working on a few-lines-solution (ab)using named tuples, I'll link it shortly. That would also have the benefit of eliminating one dependency.

I'd be interested in hearing your opinion, @tkw1536.

Handle binding

The functions in convert do not cover OMBIND and OMV, which will be needed eventually.

This seems to be a low-priority issue for now, but I'm adding for future reference.

Move conversion into a class

The convert methods maintains global state, which is awkward.

The code should be wrapped into a class that encapsulates the state.

Allow customizing the treatment of literals in conversion

The treatment of the OpenMath literals (integer, float, string, byte array) is currently hard-coded in the convert methods.

The current treatment is a good defualt, but it should be possible to customize it.

One option, considering issue #12, is to simply use methods for this that can be overridden by other classes.

Consider dropping support for older versions of Python

When making a PR I noticed that tests for older python versions are broken. In particular in Python2 the following test fails:

File "/home/travis/build/OpenMath/py-openmath/openmath/convert_pickle.py", line 14, in openmath.convert_pickle
Failed example:
    to_openmath('coucou')
Expected:
    OMString(string='coucou', id=None)
Got:
    OMBytes(bytes='coucou', id=None)

(see https://travis-ci.org/github/OpenMath/py-openmath/jobs/689618027#L207

Furthermore the Python 3.3 and Python 3.4 tests are failing because the python binaries can not be installed on Travis anymore.

We should consider if we want to keep supporting or testing these old versions of Python, in particular as all of them have reached end of life.

Generalize the handling of symbol resolution

Currently one can register a callback for converting to Python an OpenMath symbol, based on cd and name.
A more general mechanism would be to support registering callbacks based on:

  • cdbase, cd, and name
  • cdbase and cd
  • cdbase
  • nothing (defining a default callback)

Taking the cdbase into account is required anyway by the OpenMath standard.
The others are practical in situations where all symbols in a given context (cd, cdbase) are handled identically, typically by loading the eponymous global Python object / functions.

Practical use case: in the pickle-based serialization, Florian recommends using a plain OMS symbol to represent a global Python objects; something like:

   <OMS cdbase=python cd=sagemath name=sage.foo.bar.baz/>

In that case, having to register all symbols would be unpractical.

please implement OpenMath integer_interval as Python range

>>> converter.to_python( decoder.decode_bytes( b"<OMA><OMS cdbase=\"http://www.openmath.org/cd\" cd=\"interval1\" name=\"integer_interval\"/><OMI>1</OMI><OMI>4</OMI></OMA>", snippet=True ) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 146, in to_python
    elem = self.to_python(omobj.elem)
  File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 143, in to_python
    return self._lookup_to_python(omobj.cdbase, omobj.cd, omobj.name)
  File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 133, in _lookup_to_python
    raise ValueError("no entry found")
ValueError: no entry found
>>> 

This should be converted to Python as range(1,5)
OpenMath integer_interval is already supported by the OpenMath implementations of Gap, Macaulay2, Ruby, Yacas, and range in the standard library of Python without importing anything

the empy string from OpenMath is not converted to Python

The expected output is in both cases the empty string ''

$ python3
Python 3.8.2 (default, Apr 27 2020, 15:53:34) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from openmath import encoder, decoder, openmath as om
>>> from openmath.convert import DefaultConverter as converter
>>> converter.to_python( decoder.decode_bytes( b"<OMSTR></OMSTR>", snippet=True ) )
>>> converter.to_python( decoder.decode_bytes( b"<OMSTR/>", snippet=True ) )
>>> 

announce the package on the (new) OM web site

We should really announce the availability of this via the OpenMath (Tom?) and and ODK (Luca?) channels (once it is sufficiently ready and tested).

Do good and talk about it.

For this we need

  • a better README
  • testing (e.g. in a nice SCSCP example)
  • ...

Please implement the conversion of full OpenMath objects with the OMOBJ tag

The OpenMath standard requires the OMOBJ tag, and hence, when converting from OpenMath to Python, py-openmath should accept also OpenMath objects with that tag, even if that tag is not generated when converting in the opposite direction.

Implementing the OMOBJ tag is easy, just take the child of the OMOBJ node, and call again converter.to_python applied to it.

>>> converter.to_python( decoder.decode_bytes( b'<OMOBJ xmlns="http://www.openmath.org/OpenMath" version="2.0" cdbase="http://www.openmath.org/cd"><OMI>3</OMI></OMOBJ>', snippet=True ) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/openmath/convert.py", line 149, in to_python
    raise ValueError('Cannot convert object of class %s to Python.' % omobj.__class__.__name__)
ValueError: Cannot convert object of class OMObject to Python.
>>> 

when converting big floats to OpenMath, remove the + of the exponent

the XML standard requires that the floats are without the + in the exponent, see https://docstore.mik.ua/orelly/xml/schema/ch04_04.htm
Hence 10.0**20 should be converted as <OMF dec="1e20"/>, not as <OMF dec="1e+20"/>

>>> encoder.encode_bytes(converter.to_openmath([10.0**20]))
b'<OMA xmlns="http://www.openmath.org/OpenMath"><OMS cdbase="http://www.openmath.org/cd" name="list" cd="list1"/><OMF dec="1e+20"/></OMA>'
>>> 

This output in fact doesn't validate, even if the OMOBJ tag is added, see
https://www.openmath.org/validation/omvalidate.html

To validate OpenMath, it can be used also the online validator
https://www.liquid-technologies.com/online-relaxng-validator
with the grammar copied from
https://www.openmath.org/standard/om20-2019-07-01/omstd20.html#app_openmath.rng

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.