Skip to content

ENH: Developer CLI for SciPy#15959

Merged
rgommers merged 50 commits intoscipy:mainfrom
schettino72:cli-doit
Apr 15, 2022
Merged

ENH: Developer CLI for SciPy#15959
rgommers merged 50 commits intoscipy:mainfrom
schettino72:cli-doit

Conversation

@sayantikabanik
Copy link
Copy Markdown
Contributor

@sayantikabanik sayantikabanik commented Apr 8, 2022

Reference issue

What does this implement/fix?

  • Implements a developer CLI using doit, click along with a GUI implemented using rich-click.

Handy commands

  • Enabling the GUI: python do.py
  • Listing the args/options for a task: python do.py <task_name> --help

Additional information

Current list of implemented tasks:

  • Build & testing tasks

    • build (build & install package on path)
    • test (Run tests along with options to run tests for a given submodule)
  • Static checker tasks

    • pep8 ( Perform pep8 check with flake8)
    • mypy ( Run mypy on the codebase)
  • Environments

    • shell (Start Unix shell with PYTHONPATH set)
    • python (Start a Python shell with PYTHONPATH set)
    • ipython (Start IPython shell with PYTHONPATH set )
  • Documentation tasks

    • doc (Build documentation)
    • refguide-check (Run refguide check)
  • Release tasks

    • notes (Release notes and log generation)
    • authors (Task to generate list the authors who contributed within a given revision interval)
  • Benchmarking tasks

    • bench & bench compare

GUI look

Screenshot 2022-04-08 at 9 08 43 PM

cc @rgommers @schettino72

schettino72 and others added 30 commits March 17, 2022 02:41
Fix bench handling of CWD.
Do not rely on global value of installed path.
@rgommers rgommers added DX Everything related to making the experience of working on SciPy more pleasant enhancement A new feature or improvement labels Apr 8, 2022
@tupui
Copy link
Copy Markdown
Member

tupui commented Apr 8, 2022

The GUI looks awesome! Great work 👏

Copy link
Copy Markdown
Member

@rgommers rgommers left a comment

Choose a reason for hiding this comment

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

Thanks @sayantikabanik and @schettino72 for all the hard work to put together this developer interface - I think it will be a major upgrade to the experience of working on SciPy!

@scipy/maintainers this isn't 100% final but we've been using and tweaking it for a little while, and it's ready for merging now imho. Smaller things can be added/fixed in follow-ups. I'll add here the current plan for this CLI, and what I think are the main things to look at (aside from just trying the workflows you care about and playing around) for review.

The plan:

  1. Merge this PR in its current state (modulo review comments), with experimental status - so no docs yet, and reserve the freedom to make some changes over the next weeks.
  2. There's still a part of this in do.py (clearly marked) that @schettino72 wants to move into either doit or a separate package. That will simplify maintenance of this file, and make it reusable by other projects.
  3. Once we're happy with this CLI, remove dev.py and rename do.py to dev.py (better name, and do is a bash builtin).
  4. Update contributor docs for this (note that a lot of docs are in --help for each command, so we need fewer html docs).
  5. After 1.9.0, we can remove numpy.distutils build infra, and hence also runtests.py. At that point we have a single CLI again, this one.

To review:

  • The plan above
  • The added dependencies. They're not too heavy, but there are a few new ones. I think the screenshot in the PR description already shows that that's worth it.
  • The complexity of the logic, for build, test and bench tasks in particular. I think it's an improvement over the massive if-elif-else block in dev.py/runtests.py. But maybe there's room for further improvement.

Copy link
Copy Markdown
Member

@tupui tupui left a comment

Choose a reason for hiding this comment

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

I agree with the plan, we should not spend time on nitpicks there. Provided the added commands are working, I am fine with getting it in to iterate faster. If we start using this in CI, we will see rapidly what is working and what not.

On rich itself, I am neutral. It does look nicer, but it's not essential and rich is still moving very fast. But now that pip started to use it, it might be a sign of confidence/stability/guarantee.

Comment thread environment.yml
Comment on lines +43 to +44
- click
- pip:
Copy link
Copy Markdown
Member

@tupui tupui Apr 8, 2022

Choose a reason for hiding this comment

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

We can already remove this I think since the release on conda is in progress.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated, though for arm64 it failed with PackagesNotFoundError:. It's not yet available under conda-forge/osx-arm64 or conda-forge/noarch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Opened an issue for that at conda-forge/doit-feedstock#16

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks like we won't get that arm64 package, so let's revert back to pip until there's a new doit release which is noarch.

Comment thread do.py

BUG:
- [ ] python dev.py -t scipy.optimize.tests.test_minimize_constrained.py::TestTrustRegionConstr::test_args
unknown marker "slow". seems conftest is not being loaded
Copy link
Copy Markdown
Member

@tupui tupui Apr 8, 2022

Choose a reason for hiding this comment

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

I thought this was solved with latest pytest. They had a regression on 7.1 and 7.1.1 should fix it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It still fails for me on pytest 7.1.1
Note the command line above reproduces an error on existing dev.py, not on the code in this PR.

Copy link
Copy Markdown
Contributor Author

@sayantikabanik sayantikabanik Apr 14, 2022

Choose a reason for hiding this comment

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

Failed for me as well using pytest 7.1.1

pytest.PytestUnknownMarkWarning: Unknown pytest.mark.slow 

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@sayantikabanik feel free to look into this. I am busy with other stuff...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I made an attempt to fix the above (using custom marks), though wasn't able to arrive at the expected outcome.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🤦 The problem is the example is using python module notation (separated by dot), but also includes .py.
A pytest bug is responsible for the misleading error message...

WRONG:

python dev.py -t scipy.optimize.tests.test_minimize_constrained.py::TestTrustRegionConstr::test_args

CORRECT:

python dev.py -t scipy.optimize.tests.test_minimize_constrained::TestTrustRegionConstr::test_args
python dev.py -t scipy/optimize/tests/test_minimize_constrained.py::TestTrustRegionConstr::test_args

Comment thread do.py Outdated
# TODO:
First milestone replace dev.py

- [ ] doc: it would make sense to expose MAKE targets as sub-commands or options
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Note that I plan to seriously cull what's in that Makefile. We really only need html, show, upload, dist. That's for another time though, for now what's in the CLI is enough.

@schettino72
Copy link
Copy Markdown
Contributor

Thanks @rgommers and @sayantikabanik for support and collaboration.

I would just like to add to the plan (at least from my side and if you guys agree).
This PR has improvements for the CLI itself...

But now since commands tasks are based on doit, there is room for improvements on individual tasks.
Mostly speed up by taking advantage of up-to-date checks and incremental execution.

@rgommers
Copy link
Copy Markdown
Member

rgommers commented Apr 8, 2022

But now since commands tasks are based on doit, there is room for improvements on individual tasks.
Mostly speed up by taking advantage of up-to-date checks and incremental execution.

This would be interesting in principle, anything where we can improve the lag on the development cycle will be quite helpful. The question is which commands though. Right now, every tool has its own cache, at least these ones:

  • Meson (build)
  • Sphinx (doc build)
  • ASV (benchmarks, and build envs for --compare)
  • Mypy (type annotations, a bit flaky IIRC)

The Meson cache is reliable and fast, and doit doesn't have enough info to skip invoking Meson. For ASV there may be an opportunity to skip the "environment up to date" checks, not sure. Sphinx is glacially slow, but it's all a single step, so not sure what doit can do about that. Mypy the same I think.

Perhaps the bigger gain here would be for composite commands, like "run through the whole release workflow for tag v1.8.0". Thinking about that some more, it's the composability of tasks more than skipping tasks that will be helpful. The dev.py style if-else logic make it quite hard to extend. Now we can more easily define new tasks that depend on other tasks. Those multi-task jobs where doit is in control are then in turn much easier to ensure "task is up-to-date and hence can be skipped" is feasible, because there's no environment activation, change in build configuration, etc. that can mess things up in between two tasks.

@rgommers
Copy link
Copy Markdown
Member

Hi all, I plan to merge this by Friday unless there's blocking concerns. That will help get people to use it and find possible parts that aren't working smoothly just yet. We'll keep dev.py around until we're sure this is all good to go.

@grlee77
Copy link
Copy Markdown
Contributor

grlee77 commented Apr 14, 2022

This looks great! I tried the test, doc and pep8 commands and they ran as expected. The only issue I noticed is that python do.py pep8 does result in a lot of flake8 warnings about the new do.py itself.

@schettino72
Copy link
Copy Markdown
Contributor

@grlee77 I have just started to work on fixing flake8 issues. I should be able to push an update today.

@schettino72
Copy link
Copy Markdown
Contributor

I fixed the pep8 issues in do.py.

Minor issue: I guess we should take this opportunity to rename the command pep8.
pep8 package was renamed to pycodestyle...
And tool used is actually flake8 which uses executes pycodestyle and pyflakes internally.

@rgommers rgommers added this to the 1.9.0 milestone Apr 15, 2022
@rgommers
Copy link
Copy Markdown
Member

Minor issue: I guess we should take this opportunity to rename the command pep8.

Yes you're right, I'd suggest we call it lint because what it does is linting in the same way as we do in CI (where it's also called lint). It actually does two separate things:

  1. Run flake8 over the whole code base
  2. Check for PEP 8 compliance on the diff between the branch and main by running the tools/lint_diff.py script.

I'll push a change.

Wrench emoji means "depends on build", so invent a new emoji for
"runs fast, no build required".

[ci skip]
@rgommers
Copy link
Copy Markdown
Member

I added a new emoji for "doesn't depend on the build task" to make sure things line up.

Copy link
Copy Markdown
Member

@rgommers rgommers left a comment

Choose a reason for hiding this comment

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

Hi all, I plan to merge this by Friday unless there's blocking concerns. That will help get people to use it and find possible parts that aren't working smoothly just yet. We'll keep dev.py around until we're sure this is all good to go.

It is now Friday, and this has been tested by a fair number of people. So let's merge this as is. A huge thank you to @schettino72 and @sayantikabanik for doing the heavy lifting. And of course to everyone else who contributed ideas/testing/review.

There are a few follow-ups listed in the file itself. Others I'm aware of:

  • clean up docs Makefile
  • add support for act in do.py (@sayantikabanik has changes ready for that)
  • once the doit conda package is installable as noarch, update the environment yml files
  • look at new opportunities provided by the new structure (caching w doit, more complex workflows, ...?)

And one that just occurred to me and may make sense:

  • make the --help output paging, because it's too long to fit on the average terminal.

@sayantikabanik
Copy link
Copy Markdown
Contributor Author

sayantikabanik commented Apr 20, 2022

  • add support for act in do.py (@sayantikabanik has changes ready for that)

Currently facing an issue which is also reported under #16009
Post the fix, I can run a few tests.

[macOS tests (meson)/Meson build] Skipping job 'Meson build' due to 'github.repository == 'scipy/scipy' || github.repository == '''

@AnirudhDagar
Copy link
Copy Markdown
Member

When there is any kind of error, it is not logged on the terminal. Instead, the script just exits without telling anything.

How to reproduce

Just add any random erroneous line to do.py file task.

scipy/do.py

Lines 545 to 551 in 9137ef1

@classmethod
def build_project(cls, dirs, args, env):
"""
Build a dev version of the project.
"""
cmd = ["ninja", "-C", str(dirs.build)]
if args.parallel > 1:

Here I'm adding the following before line 550.

     @classmethod 
     def build_project(cls, dirs, args, env): 
         """ 
         Build a dev version of the project. 
         """ 
         import thisdoesnotexist  #obviously this should error out
         cmd = ["ninja", "-C", str(dirs.build)] 
         if args.parallel > 1:

But when I run python do.py build, the script just runs and exits at this line without any error or traceback output.
Is this issue already known since do.py is under development atm? Asking here quickly, otherwise, I'll open up an issue.

cc @sayantikabanik @schettino72 @rgommers

@AnirudhDagar
Copy link
Copy Markdown
Member

nevermind, just found this comment rgommers#133 (comment)

Apologies for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DX Everything related to making the experience of working on SciPy more pleasant enhancement A new feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants