Skip to content

core: make _sympify reject Basic subclasses #20128

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

Merged
merged 2 commits into from
Sep 23, 2020

Conversation

oscarbenjamin
Copy link
Collaborator

Previously a Basic subclass could pass through _sympify e.g.:

  >>> _sympify(sin) is sin
  True

This was problemantic because _sympify is used to validate and prepare
args for many Basic subclasses which should only have Basic args. With
this change using _sympify with a Basic subclass will now raise an
error:

  >>> _sympify(sin)
  ...
  SympifyError: SympifyError: sin

This should mean that the output of _sympify is guaranteed to be of type
Basic.

References to other Issues or PRs

Fixes #20124

Release Notes

NO ENTRY

Previously a Basic subclass could pass through _sympify e.g.:

  >>> _sympify(sin) is sin
  True

This was problemantic because _sympify is used to validate and prepare
args for many Basic subclasses which should only have Basic args. With
this change using _sympify with a Basic subclass will now raise an
error:

  >>> _sympify(sin)
  ...
  SympifyError: SympifyError: sin

This should mean that the output of _sympify is guaranteed to be of type
Basic.
@sympy-bot
Copy link

Hi, I am the SymPy bot (v160). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

  • No release notes entry will be added for this pull request.

Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it.

Click here to see the pull request description that was parsed.

Previously a Basic subclass could pass through _sympify e.g.:
```
  >>> _sympify(sin) is sin
  True
```
This was problemantic because _sympify is used to validate and prepare
args for many Basic subclasses which should only have Basic args. With
this change using _sympify with a Basic subclass will now raise an
error:
```
  >>> _sympify(sin)
  ...
  SympifyError: SympifyError: sin
```
This should mean that the output of _sympify is guaranteed to be of type
Basic.

<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->

Fixes https://github.com/sympy/sympy/issues/20124

#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
NO ENTRY
<!-- END RELEASE NOTES -->

@codecov
Copy link

codecov bot commented Sep 22, 2020

Codecov Report

Merging #20128 into master will increase coverage by 31.359%.
The diff coverage is 87.846%.

@@              Coverage Diff               @@
##            master    #20128        +/-   ##
==============================================
+ Coverage   44.463%   75.822%   +31.359%     
==============================================
  Files          671       671                
  Lines       173608    173708       +100     
  Branches     41001     41020        +19     
==============================================
+ Hits         77192    131710     +54518     
+ Misses       90531     36245     -54286     
+ Partials      5885      5753       -132     

Comment on lines 1219 to 1221
if not (isinstance(pattern, type) and issubclass(pattern, Basic)):
pattern = _sympify(pattern)
if isinstance(pattern, BasicMeta):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This first if is essentially mutually exclusive with the second, isn't it? So perhaps it should be changed to an else

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good point. Actually I should have just swapped the order of these.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just moved the call to _sympify after the check for BasicMeta.

Simplify check for Basic subclasses in Basic.has
@oscarbenjamin
Copy link
Collaborator Author

I was expecting more failures from across the codebase due to this. Maybe there are few errors because the code that is buggy is more likely to be using sympify rather than _sympify.

If tests pass on this run I might push a temporary commit to test a stronger verification that _sympify is always producing Basic instances and that sympify can only produce instances of list, Basic, BasicMeta, and NoneType.

@oscarbenjamin
Copy link
Collaborator Author

So it looks like sympify with string input can return anything as it doesn't sympify the result of parse_expr:

In [1]: type(sympify('True'))                                                                                                                  
Out[1]: bool

In [2]: type(sympify(True))                                                                                                                    
Out[2]: sympy.logic.boolalg.BooleanTrue

In [3]: type(sympify('Matrix([[1]])'))                                                                                                         
Out[3]: sympy.matrices.dense.MutableDenseMatrix

In [4]: type(sympify(Matrix([[1]])))                                                                                                           
Out[4]: sympy.matrices.immutable.ImmutableDenseMatrix

I'm not sure if that should be considered a bug or not. It seems that _sympify only returns Basic (in the test suite).

@oscarbenjamin oscarbenjamin merged commit bd0778b into sympy:master Sep 23, 2020
@oscarbenjamin oscarbenjamin deleted the pr_basic_sympify branch October 1, 2020 22:56
oscarbenjamin added a commit to oscarbenjamin/sympy that referenced this pull request Oct 17, 2020
The behaviour of sympify was changed in

  sympy#20128

so that sympifying a Basic subclass would be an error when strict=True.
That change made the codepath for calling e.g. _sympify(Basic) slower as
more checks would be done before returning. This commit adds an early
raise for the case of calling _sympify(a) where a is a Basic subclass.
oscarbenjamin added a commit to oscarbenjamin/sympy that referenced this pull request Oct 17, 2020
The behaviour of sympify was changed in

  sympy#20128

so that sympifying a Basic subclass would be an error when strict=True.
That change made the codepath for calling e.g. _sympify(Basic) slower as
more checks would be done before returning. This commit adds an early
raise for the case of calling _sympify(a) where a is a Basic subclass.
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

Successfully merging this pull request may close these issues.

Sympify sometimes returns non-Basic
4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy