Repository: benchopt/benchopt (python)

Issue:
ENH support run command without `.` by default
Reading the doc, it is not always clear that one should run the command as follows:

```
benchopt run . --config pathological.yml
```

One would rather like a command like 

```
benchopt run --config pathological.yml
```
to work out of the box.



Pull request:
ENH use current working directory as default in CLI
Fixes #382
Not exactly sure how to test this though....

Patch:
diff --git a/README.rst b/README.rst
index bd85db0..16e98d5 100644
--- a/README.rst
+++ b/README.rst
@@ -75,9 +75,10 @@ For instance, the benchmark for Lasso can be retrieved with:
     git clone https://github.com/benchopt/benchmark_lasso
 
 
-Command line usage
-------------------
+Command line interface
+----------------------
 
+The preferred way to run the benchmarks is through the command line interface.
 To run the Lasso benchmark on all datasets and with all solvers, run:
 
 .. code-block::
@@ -90,7 +91,10 @@ To get more details about the different options, run:
 
     benchopt run -h
 
-or read the `API Documentation <https://benchopt.github.io/api.html>`_.
+or read the `CLI documentation <https://benchopt.github.io/cli.html>`_.
+
+Benchopt also provides a Python API described in the
+`API documentation <https://benchopt.github.io/api.html>`_.
 
 List of optimization problems available
 ---------------------------------------
diff --git a/benchopt/cli/completion.py b/benchopt/cli/completion.py
index 8c111bd..5f416cf 100644
--- a/benchopt/cli/completion.py
+++ b/benchopt/cli/completion.py
@@ -46,6 +46,7 @@ def complete_benchmarks(ctx, param, incomplete):
 
 def find_benchmark_in_args(args):
     "Find the benchmark in preceeding args for benchmark dependent completion."
+    args.extend([Path.cwd()])  # default path is current working directory
     for b in args:
         if (Path(b) / "objective.py").exists():
             return Benchmark(b)
diff --git a/benchopt/cli/helpers.py b/benchopt/cli/helpers.py
index e9b0950..780505b 100644
--- a/benchopt/cli/helpers.py
+++ b/benchopt/cli/helpers.py
@@ -31,7 +31,7 @@ helpers = click.Group(
     help="Clean the cache and the outputs from a benchmark.",
     options_metavar=''
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 def clean(benchmark, token=None, filename=None):
 
@@ -185,7 +185,7 @@ def print_info(cls_name_list, cls_list, env_name=None, verbose=False):
     help="List information (solvers/datasets) and corresponding requirements "
     "for a given benchmark."
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--solver', '-s', 'solver_names',
               metavar="<solver_name>", multiple=True, type=str,
@@ -378,7 +378,7 @@ def get(ctx, name):
     "class BASE_CLASS_NAME.",
     hidden=True
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.argument('module_filename', nargs=1, type=Path)
 @click.argument('base_class_name', nargs=1, type=str)
diff --git a/benchopt/cli/main.py b/benchopt/cli/main.py
index 2f2491e..6cfc591 100644
--- a/benchopt/cli/main.py
+++ b/benchopt/cli/main.py
@@ -17,8 +17,8 @@ from benchopt.utils.profiling import print_stats
 
 
 main = click.Group(
-    name='Principal Commands',
-    help="Principal commands that are used in ``benchopt``."
+    name='Main commands',
+    help="Main commands that are used in ``benchopt``."
 )
 
 
@@ -67,7 +67,7 @@ def _get_run_args(cli_kwargs, config_file_kwargs):
     "in a benchmark-dedicated conda environment or in your own "
     "conda environment, see the command `benchopt install`."
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--objective-filter',
               metavar='<objective_filter>', multiple=True, type=str,
@@ -267,7 +267,7 @@ def run(config_file=None, **kwargs):
 @main.command(
     help="Install the requirements (solvers/datasets) for a benchmark."
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--force', '-f',
               is_flag=True,
@@ -402,7 +402,7 @@ def install(
     "benchopt.github.io/how.html#example-of-parametrized-simulated-dataset",
     context_settings=dict(ignore_unknown_options=True)
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--env-name', type=str, default=None, metavar='NAME',
               shell_complete=complete_conda_envs,
diff --git a/benchopt/cli/process_results.py b/benchopt/cli/process_results.py
index 19bc90b..a15b257 100644
--- a/benchopt/cli/process_results.py
+++ b/benchopt/cli/process_results.py
@@ -1,4 +1,5 @@
 import click
+from pathlib import Path
 
 from benchopt.config import get_setting
 from benchopt.benchmark import Benchmark
@@ -7,7 +8,7 @@ from benchopt.cli.completion import complete_benchmarks
 from benchopt.cli.completion import complete_output_files
 
 process_results = click.Group(
-    name='Process Results',
+    name='Process results',
     help="Utilities to process benchmark outputs produced by benchopt."
 )
 
@@ -20,7 +21,7 @@ def get_plot_kinds(ctx, args, incomplete):
 @process_results.command(
     help="Plot the result from a previously run benchmark."
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--filename', '-f', type=str, default=None,
               shell_complete=complete_output_files,
@@ -70,7 +71,7 @@ def plot(benchmark, filename=None, kinds=('suboptimality_curve',),
     "See the :ref:`publish_doc` documentation for more info on how to use "
     "this command."
 )
-@click.argument('benchmark', type=click.Path(exists=True),
+@click.argument('benchmark', default=Path.cwd(), type=click.Path(exists=True),
                 shell_complete=complete_benchmarks)
 @click.option('--token', '-t', type=str, default=None,
               help="Github token to access the result repo.")
@@ -105,7 +106,8 @@ def publish(benchmark, token=None, filename=None):
     help="Generate result website from list of benchmarks."
 )
 @click.option('--benchmark', '-b', 'benchmarks', metavar="<bench>",
-              multiple=True, type=click.Path(exists=True),
+              multiple=True, default=[Path.cwd()],
+              type=click.Path(exists=True),
               shell_complete=complete_benchmarks,
               help="Folders containing benchmarks to include.")
 @click.option('--pattern', '-k', 'patterns',
diff --git a/doc/_static/style.css b/doc/_static/style.css
index 947d0ef..d440b91 100644
--- a/doc/_static/style.css
+++ b/doc/_static/style.css
@@ -56,5 +56,30 @@ code {
 
 #sidebar {
     text-overflow: ellipsis;
-    overflow: hidden;
+    max-height: 80%;
+    overflow-y: auto;
 }
+
+/* Make the sidebar table of content more compact and with larger indent */
+.bs-sidenav .nav .nav > li > a {
+    padding-left: 30px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+}
+.bs-sidenav .nav .nav .nav > li > a {
+    padding-left: 50px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+}
+.bs-sidenav .nav .nav .nav .nav > li > a {
+    padding-left: 70px;
+    padding-top: 1px;
+    padding-bottom: 1px;
+}
+
+/* Hide the search box for medium size screen */
+@media (min-width: 768px) and (max-width: 1000px) {
+    .navbar-form {
+        display: none;
+    }
+ }
\ No newline at end of file
diff --git a/doc/advanced.rst b/doc/advanced.rst
index 6c9d046..6a70276 100644
--- a/doc/advanced.rst
+++ b/doc/advanced.rst
@@ -1,9 +1,9 @@
-.. _how:
+.. _advanced:
 
-Advanced functionnalities in a benchmark
-=========================================
+Advanced functionalities in a benchmark
+=======================================
 
-This page intends to list some advanced functionnality
+This page intends to list some advanced functionality
 to make it easier to use the benchmark.
 
 .. _skiping_solver:
diff --git a/doc/api.rst b/doc/api.rst
index a4e0c7d..df0c80c 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -1,8 +1,8 @@
 .. _api_documentation:
 
-========================
-Python API Documentation
-========================
+==========
+Python API
+==========
 
 Here is a list of Python function available to construct a new benchmark.
 
diff --git a/doc/cli.rst b/doc/cli.rst
index fdd6a55..ad143c0 100644
--- a/doc/cli.rst
+++ b/doc/cli.rst
@@ -1,8 +1,8 @@
 .. _cli_documentation:
 
-==========================================
-Command Line Interface (CLI) Documentation
-==========================================
+============================
+Command line interface (CLI)
+============================
 
 The following commands are built using the
 `click <https://click.palletsprojects.com/en/8.0.x/>`_ package which provides tab
diff --git a/doc/conf.py b/doc/conf.py
index eb70e30..e868fb7 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -59,7 +59,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'benchopt'
-copyright = u'2020-2020, Benchopt contributors'
+copyright = u'2020-2022, Benchopt contributors'
 author = u'Benchopt contributors'
 
 # The version info for the project you're documenting, acts as replacement for
@@ -113,7 +113,7 @@ html_theme_options = {
         # ("Examples", "auto_examples/index"),
         ("CLI", "cli"),
         ("API", "api"),
-        ("Write a benchmark", "how"),
+        # ("Write a benchmark", "how"),
         ("Results", "https://benchopt.github.io/results", True),
         ("What's new", "whats_new"),
         ("GitHub", "https://github.com/benchopt/benchopt", True)
diff --git a/doc/contrib.rst b/doc/contrib.rst
index e439431..829b501 100644
--- a/doc/contrib.rst
+++ b/doc/contrib.rst
@@ -4,8 +4,8 @@ How to contribute
 =================
 
 
-Submitting a bug report or a feature request
---------------------------------------------
+Bug report and feature request
+------------------------------
 
 We use benchopt `GitHub repo <https://github.com/benchopt/benchopt/issues>`_ to track all bugs and feature requests; feel free to open
 an issue if you have found a bug or wish to see a feature implemented.
@@ -13,7 +13,7 @@ an issue if you have found a bug or wish to see a feature implemented.
 
 
 
-Contributing code
+Code contribution
 -----------------
 
 The preferred way to contribute to benchopt is to fork the `main
diff --git a/doc/index.rst b/doc/index.rst
index b6ab984..2c7b99a 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -33,7 +33,6 @@ give you a benchmark plot on l2-regularized logistic regression:
    :align: center
    :scale: 80%
 
-Learn how to :ref:`how`.
 
 Install
 --------
@@ -69,8 +68,8 @@ This benchmark can be retrieved locally with:
 
     git clone https://github.com/benchopt/benchmark_lasso.git
 
-Quickstart: command line usage on the Lasso benchmark
------------------------------------------------------
+Run a benchmark
+---------------
 
 This section illustrates benchopt's command line interface on the `Lasso benchmark <https://github.com/benchopt/benchmark_lasso>`_; the syntax is applicable to any benchmark.
 All this section assumes that you are in the parent folder of the ``benchmark_lasso`` folder.
@@ -114,14 +113,14 @@ An example of configuration file is:
 .. code-block:: yaml
 
     objective-filter:
-    - Lasso Regression[fit_intercept=False,reg=0.5]
+      - Lasso Regression[fit_intercept=False,reg=0.5]
     dataset:
-    - simulated
-    - leukemia
+      - simulated
+      - leukemia
     solver:
-    - celer
+      - celer
     force-solver:
-    - cd
+      - cd
     n-repetitions: 1
 
 When options are passed both via file and CLI, the CLI takes precedence.
@@ -135,8 +134,20 @@ When options are passed both via file and CLI, the CLI takes precedence.
 to get more details about the different options.
 You can also read the :ref:`cli_documentation`.
 
-Some available benchmarks
--------------------------
+Write a benchmark
+-----------------
+
+Learn how to :ref:`how`, including creating an objective, a solver, and
+a dataset.
+
+
+Available benchmarks
+--------------------
+
+.. note::
+    Some benchmarks are briefly described in the list below. For a complete
+    list of benchmarks, see GitHub repositories of the form `benchopt/benchmark_*
+    <https://github.com/orgs/benchopt/repositories?q=benchmark_&type=all&language=&sort=stargazers/>`_.
 
 **Notation:**  In what follows, n (or n_samples) stands for the number of samples and p (or n_features) stands for the number of features.
 
@@ -217,7 +228,6 @@ linear ICA is to recover :math:`A` up to permutation and scaling of its columns.
 The objective in this benchmark is related to some estimation on :math:`A`
 quantified with the so-called AMARI distance.
 
-See `benchmark_* repositories on GitHub <https://github.com/benchopt/>`_ for more.
 
 Benchmark results
 -----------------
@@ -228,8 +238,8 @@ All the public benchmark results are available at `Benchopt Benchmarks results <
 
 .. include:: contrib.rst
 
-Contents
-========
+Website contents
+================
 
 .. toctree::
    :maxdepth: 1


Test patch:
diff --git a/benchopt/tests/test_cli.py b/benchopt/tests/test_cli.py
index 3f46d4c..0bf96ea 100644
--- a/benchopt/tests/test_cli.py
+++ b/benchopt/tests/test_cli.py
@@ -50,6 +50,7 @@ DATASET_COMPLETION_CASES = [
     ('simu', ['simulated']),
     ('lated', ['simulated']),
 ]
+CURRENT_DIR = Path.cwd()
 
 
 def _get_completion(cmd, args, incomplete):
@@ -105,11 +106,15 @@ class TestRunCmd:
 
     @pytest.mark.parametrize('invalid_benchmark, match', [
         ('invalid_benchmark', "Path 'invalid_benchmark' does not exist."),
-        ('.', "The folder '.' does not contain `objective.py`")],
-        ids=['invalid_path', 'no_objective'])
+        ('.', "The folder '.' does not contain `objective.py`"),
+        ("", rf"The folder '{CURRENT_DIR}' does not contain `objective.py`")],
+        ids=['invalid_path', 'no_objective', "no_objective in default"])
     def test_invalid_benchmark(self, invalid_benchmark, match):
         with pytest.raises(click.BadParameter, match=match):
-            run([invalid_benchmark], 'benchopt', standalone_mode=False)
+            if len(invalid_benchmark) > 0:
+                run([invalid_benchmark], 'benchopt', standalone_mode=False)
+            else:
+                run([], 'benchopt', standalone_mode=False)
 
     def test_invalid_dataset(self):
         with pytest.raises(click.BadParameter, match=r"invalid_dataset"):