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

Meta-PR: More # optional doctest tags #34998

Closed

Conversation

mkoeppe
Copy link
Contributor

@mkoeppe mkoeppe commented Feb 7, 2023

We add # optional tags for various doctests, depending on

There is no change when doctesting the monolithic sage library, but it eliminates numerous failures when testing modularized distributions such as sagemath-standard-no-symbolics (#35150) and sagemath-polyhedra (#35095).

In short:

  • Everything that uses factorization needs to be marked sage.libs.pari
  • Everything that uses linear algebra (including CombinatorialFreeModule) needs to be marked sage.modules
  • Other annotations are self-explanatory

Depends on:

@codecov-commenter
Copy link

codecov-commenter commented Feb 7, 2023

Codecov Report

Patch coverage has no change and project coverage change: -0.70 ⚠️

Comparison is base (f449b14) 88.62% compared to head (fa9d589) 87.93%.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #34998      +/-   ##
===========================================
- Coverage    88.62%   87.93%   -0.70%     
===========================================
  Files         2148     2148              
  Lines       398653   398686      +33     
===========================================
- Hits        353308   350571    -2737     
- Misses       45345    48115    +2770     
Impacted Files Coverage Δ
src/sage/arith/misc.py 90.99% <ø> (ø)
src/sage/calculus/test_sympy.py 0.00% <ø> (ø)
src/sage/categories/additive_magmas.py 97.77% <ø> (ø)
src/sage/categories/additive_semigroups.py 100.00% <ø> (ø)
src/sage/categories/affine_weyl_groups.py 100.00% <ø> (ø)
src/sage/categories/algebra_functor.py 80.00% <ø> (-20.00%) ⬇️
src/sage/categories/algebra_ideals.py 88.88% <ø> (ø)
src/sage/categories/algebra_modules.py 100.00% <ø> (ø)
src/sage/categories/algebras.py 100.00% <ø> (ø)
src/sage/categories/algebras_with_basis.py 96.22% <ø> (ø)
... and 247 more

... and 83 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@mkoeppe mkoeppe force-pushed the sd117_more_optional_doctest_tags branch from 5e7fa7d to 7f37354 Compare February 10, 2023 02:21
@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 10, 2023

Tests pass, ready for review

@mkoeppe mkoeppe force-pushed the sd117_more_optional_doctest_tags branch from ad237b3 to ceecd88 Compare February 19, 2023 23:38
@mkoeppe mkoeppe requested a review from kliem February 20, 2023 05:28
@mkoeppe mkoeppe self-assigned this Feb 21, 2023
@kwankyu
Copy link
Collaborator

kwankyu commented Feb 21, 2023

Tests pass, ready for review

Yes. But to check that # optional - sage.module.... tags are added where necessary, (and remind me this modularization stuff) let me ask some questions:

For instance,

sage: CyclotomicField.__module__
'sage.rings.number_field.number_field'

Then how can I see which is the minimal distribution package that installs the module sage.rings.number_field.number_field?

The minimal distribution package should be unique. Right?

If the smallest distribution package that installs the module containing the doctest using CyclotomicField is not, in the distribution packages hierarchy, above (or the same as) the smallest distribution package that installs the module sage.rings.number_field.number_field, then the doctest should have # optional - sage.rings.number_field tag. Am I right?

Which of sage.rings.number_field and sage.rings.number_field.number_field should be added to # optional - tag?

Is this the only scenario that # optional - sage.module.... needs to be added?

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 21, 2023

Then how can I see which is the minimal distribution package that installs the module sage.rings.number_field.number_field?

Which of sage.rings.number_field and sage.rings.number_field.number_field should be added to # optional - tag?

In src/sage/features/sagemath.py you can see that the actual Python module whose presence is tested for the feature "sage.rings.number_field" is sage.rings.number_field.number_field_element. Often, it is the case that:

  • the element implementations have a compile-time dependency on a library (in this case, NTL), whereas
  • the parent implementation may not have such a dependency at compile time or module load time; but
  • the parent cannot be instantiated if the element implementation module is not present because that involves creating some elements.

"sage.rings.number_field" is the name for the full functionality (not just loading some modules) of the classes defined in sage.rings.number_field.number_field etc.

The minimal distribution package should be unique. Right?

When the modularization takes its final form, every module will be distributed by exactly one distribution package, so uniqueness holds trivially.

However, during the modularization effort, there still exist some distribution packages that are subsets of other distribution packages: Currently, all of sagemath-{environment,repl,objects,categories} are subsets of sagemath-standard. Some PRs introduce additional such cases:

Another PR corrects such subset relations by making the subset distributions dependencies (install-requires) instead:

During the modularization effort, it may also be convenient to temporarily introduce some nontrivial antichains of distribution packages; in that case, the uniqueness will not necessarily hold. (Such antichains may also be introduced inadvertently by mistakes in writing the MANIFEST.in files.)

If the smallest distribution package that installs the module containing the doctest using CyclotomicField is not, in the distribution packages hierarchy, above (or the same as) the smallest distribution package that installs the module sage.rings.number_field.number_field, then the doctest should have # optional - sage.rings.number_field tag. Am I right?

I think here you are asking about the modules shipped by distribution packages together with their declared runtime dependencies (install-requires).

So the doctest should have # optional - sage.rings.number_field tag whenever the module in which it appears is shipped in a distribution package that does not include the modules that provide the feature "sage.rings.number_field".

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 21, 2023

When the modularization takes its final form, every module will be distributed by exactly one distribution package, so uniqueness holds trivially.

There won't be sagemath-standard? There won't be a distribution package that requires a set of smaller distribution packages and includes some individual modules? The hierarchy will disappear?

Or do you mean that every module will be included in exactly one minimal (in subset relations) distribution package?

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 21, 2023

sagemath-standard will continue to exist but most likely will not ship any module. Instead it will declare a bunch of runtime dependencies so that installing it will install all modules.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 21, 2023

The hierarchy will disappear?

This hierarchy diagram is not intended to visualize inclusion; it visualizes runtime dependencies.

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

The hierarchy will disappear?

This hierarchy diagram is not intended to visualize inclusion; it visualizes runtime dependencies.

Suppose there are only three modules A, B, and C.

(1) If distribution package P1 installs modules A and B and distribution package P2 depends on P1 but also installs a module C, then a doctest in C would not need "#optional - A"

(2) If distribution package P1 installs modules A and B and distribution P3 installs the module C and P2 depends on P1 and P3, then the same doctest in C would need "# optional - A"

The modularization in final form would look like (2). Am I right?

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Suppose there are only three modules A, B, and C.

(1) If distribution package P1 installs modules A and B and distribution package P2 depends on P1 but also installs a module C, then a doctest in C would not need "#optional - A"

That's right. When C is doctested, its unique containing distribution P2 is installed, hence by declared dependencies also P1 is installed, so A is available.

(2) If distribution package P1 installs modules A and B and distribution P3 installs the module C and P2 depends on P1 and P3, then the same doctest in C would need "# optional - A"

Right.

The modularization in final form would look like (2). Am I right?

Both cases can appear in the modularization in final form.

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

In the example, the distribution package that installs A is P1. (I added adjective minimal for this above)

In (1), the distribution package that installs C is P2. As P2 is above P1 in the hierarchy, the doctest does not need the tag

In (2), the distribution package that installs C is P3. Here P3 is not above P1, and hence the doctest needs the tag.

So to decide whether the tag is necessary for a doctest, we need to know the distribution that installs a module. This is my first question above.

Is there a command that reports the distribution that installs module M, for input M? Or should we search through the source code of distribution packages?

Is there a command that reports the relationship between two distributions in the hierarchy? Or should we rely on the hierarchy diagram in the developer manual?

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

I guess that the hierarchy diagram can be outdated anytime. Then we still need to look through the source code of distribution packages if the command does not exist.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

So to decide whether the tag is necessary for a doctest, we need to know the distribution that installs a module. [...]
Is there a command that reports the distribution that installs module M, for input M? Or should we search through the source code of distribution packages?

When M is already installed, we can get this information using importlib.metadata.packages_distributions and importlib.metadata.files.
I don't know if there is a more convenient function that gives this information directly.

On the source code level, I hope to add a comment line to the top of each file that indicates the distribution; see #30666, which adds a number of these comments. This will replace the current method of defining the distributions via MANIFEST.in files, which is error-prone (there's no control that we ship every module exactly once).

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Is there a command that reports the relationship between two distributions in the hierarchy? Or should we rely on the hierarchy diagram in the developer manual?

For installed distributions, importlib.metadata.requires provides this information.

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

I wrote quickly this:

from importlib.metadata import packages_distributions, distribution, requires

def sage_distribution_packages():
    sage_dists = []
    for dist_list in packages_distributions().values():
        for dist in dist_list:
            if dist.startswith('sage-') or dist.startswith('sagemath-'):
                sage_dists.append(dist)
    return list(set(sage_dists))

def find_sage_distribution_package(mod):
    dists = []
    for dist_pack in sage_distribution_packages():
        for pack in distribution(dist_pack).files:
            if pack.name.endswith('.py'):
                parts = pack.parts
                mod2 = '.'.join(list(parts[:-1]) + [pack.name[:-3]])
            elif pack.name.endswith('.pyx'):
                parts = pack.parts
                mod2 = '.'.join(list(parts[:-1]) + [pack.name[:-4]])  
            else:
                continue
            if mod2 == mod:
                dists.append(dist_pack)
                break
    return dists  

The I get

sage: sage_distribution_packages()
['sagemath-standard', 'sage-docbuild', 'sage-conf']
sage: m = CyclotomicField.__module__; m
'sage.rings.number_field.number_field'
sage: find_sage_distribution_package(m)
['sagemath-standard']
sage: find_sage_distribution_package('sage.structure.coerce')
['sagemath-standard']

So there is no need to add # optional - sage.rings.number_field to the doctest I am looking at in sage.structure.coerce, right now.

But this PR is provisional to modularized distributions sagemath-standard-no-symbolics and sagemath-polyhedra. So this PR depends on other PRs providing the distributions. Right?

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Thanks for writing this! It would be a useful addition to sage.misc.dev_tools, providing something of the same kind as import_statements

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Here you ran your code in a non-modularized installation: sagemath-standard ships everything, so your code will tell you that nothing needs a # optional - sage....

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

So this PR depends on other PRs providing the distributions.

No, this PR does not have any dependencies because the added annotations do nothing in the monolithic installation.

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

I meant rather that to see the necessity of those tags you added in this PR through the commands, I should run the commands in sage where the new modularized distribution packages are installed.

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Yes, testing with the subset distributions, for example using make SAGE_CHECK=yes sagemath_categories or (with #32432) make SAGE_CHECK=yes sagemath_polyhedra is the strategy that I used for finding the necessary tags; and it would also be a meaningful strategy for reviewing.

@kwankyu
Copy link
Collaborator

kwankyu commented Feb 22, 2023

This merge-conflicts with #35095. Would you make either of them dependent on the other so that they can be reviewed together?

@mkoeppe
Copy link
Contributor Author

mkoeppe commented Feb 22, 2023

Thanks, I've merged it into #35095.

@mkoeppe mkoeppe force-pushed the sd117_more_optional_doctest_tags branch from b55ba8f to 4b6a8df Compare April 9, 2023 20:40
@mkoeppe mkoeppe changed the title More # optional doctest tags Meta-PR: More # optional doctest tags Apr 15, 2023
SageMath version 10.0.rc0, Release Date: 2023-04-23
@github-actions
Copy link

Documentation preview for this PR is ready! 🎉
Built with commit: ab44e66

@mkoeppe mkoeppe modified the milestones: sage-10.0, sage-10.1 Apr 30, 2023
vbraun pushed a commit that referenced this pull request May 22, 2023
…mat doctests

    
<!-- Please provide a concise, informative and self-explanatory title.
-->
<!-- Don't put issue numbers in the title. Put it in the Description
below. -->
<!-- For example, instead of "Fixes #12345", use "Add a new method to
multiply two integers" -->

### 📚 Description

<!-- Describe your changes here in detail. -->
Adding doctest tags `# optional - sage.rings.finite_rings`,
`...number_field`, `...padics` etc. for modularization purposes.

Also:
- some coding style fixes in the doctests (such as adding spaces around
some operators and after commas, following PEP 8)
- improved the readability of doctests in the HTML format by breaking
long lines to avoid having to scroll horizontally
<!-- Why is this change required? What problem does it solve? -->
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
<!-- If your change requires a documentation PR, please link it
appropriately. -->

This is:
- Part of #29705
- Split out & squashed from #34998

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. It should be `[x]` not `[x
]`. -->

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #35422
Reported by: Matthias Köppe
Reviewer(s): Gonzalo Tornaría, Kwankyu Lee, Matthias Köppe
@mkoeppe
Copy link
Contributor Author

mkoeppe commented Jul 7, 2023

Outdated.

@mkoeppe mkoeppe closed this Jul 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants