Repository: smarie/mkdocs-gallery

Issue:
Error when examples source dir is located outside docs dir 
The [mkdcos-gallery webpage](https://smarie.github.io/mkdocs-gallery/) says that you can have your source gallery examples folder located either inside or outside the base mkdocs docs directory. But when I try to put the examples outside the docs directory, I get an error.

## Situation

The mkdocs-gallery [docs main page](https://github.com/smarie/mkdocs-gallery/blob/main/docs/index.md#1-create-a-source-gallery-folder) says:
> ...the folder can be located inside the usual mkdocs source folder:
> ```
> docs/                    # base mkdocs source directory
>└── examples/            # base 'Gallery of Examples' directory
>└── README.md
> ```
> or not
> ```
> examples/            # base 'Gallery of Examples' directory
> └── README.md
> docs/                # base mkdocs source directory
> ```

## To reproduce

1. Create a virtual environment, and make sure the following packages are installed:
```
mkdocs==1.2.4
mkdocs-material
mkdocs-gallery
jupyter 
numpy
matplotlib
```

2. Clone this example repository, and fetch the tags:
```
git clone https://github.com/GenevieveBuckley/mkdocs-example.git
cd mkdocs-example
git fetch --tags
```

3. Checkout the first, working example, where the gallery examples live in a folder underneath the main docs folder. The documentation build succeeds.
```
git checkout tags/examples-inside-docs-folder -b examples-inside-docs-folder-main
mkdocs build
mkdocs serve
```
After checking that the build succeeds, you can delete the generated docs content:
```
rm -rf site
rm -rf docs/generated
```

4. Now, checkout the second example tag, where the examples have been moved outside the docs folder (so they are at the same heirarchy level). This time, the documentation build fails.
```
git checkout tags/broken-example -b broken-example-main
mkdocs build
```

## What happened

A value error is raised at this line:

https://github.com/smarie/mkdocs-gallery/blob/68791f52d7d43301a44586bfd33ad47f0f9d6a1a/src/mkdocs_gallery/plugin.py#L250

```python-traceback
ValueError: '/Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/examples' is not in the subpath of '/Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/docs' OR one path is relative and the other is absolute.
```

<details>
<summary>Full error message:</summary>

```python-traceback
mkdocs build
INFO     -  generating gallery...
generating gallery for /Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/do
INFO     -  computation time summary:
INFO     -      - examples/plot_example.py:   0.00 sec   0.0 MB
INFO     -  Cleaning site directory
INFO     -  Building documentation to directory:
            /Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/site
Traceback (most recent call last):
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/bin/mkdocs", line 10, in <module>
    sys.exit(cli())
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/mkdocs/__main__.py", line 187, in build_command
    build.build(config.load_config(**kwargs), dirty=not clean)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/mkdocs/commands/build.py", line 282, in build
    files = config['plugins'].run_event('files', files, config=config)
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/site-packages/mkdocs/plugins.py", line 102, in run_event
    result = method(item, **kwargs)
  File "/Users/genevieb/temp/gallery/mkdocs-gallery/src/mkdocs_gallery/plugin.py", line 250, in on_files
    examples_dirs = self._get_dirs_relative_to(self.config['examples_dirs'], rel_to_dir=config['docs_dir'])
  File "/Users/genevieb/temp/gallery/mkdocs-gallery/src/mkdocs_gallery/plugin.py", line 305, in _get_dirs_relative_to
    return [Path(e).relative_to(rel_to_dir).as_posix() for e in dir_or_list_of_dirs]
  File "/Users/genevieb/temp/gallery/mkdocs-gallery/src/mkdocs_gallery/plugin.py", line 305, in <listcomp>
    return [Path(e).relative_to(rel_to_dir).as_posix() for e in dir_or_list_of_dirs]
  File "/Users/genevieb/mambaforge/envs/mkdocs-gallery-dev/lib/python3.10/pathlib.py", line 818, in relative_to
    raise ValueError("{!r} is not in the subpath of {!r}"
ValueError: '/Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/examples' is not in the subpath of '/Users/genevieb/Documents/GitHub/mkdocs-example-2/docs/docs' OR one path is relative and the other is absolute.
```

</details>

## What to do?

Either the mkdocs-gallery documentation should be updated, or a change made to the code so this behaviour is supported.

It's probably easiest to update the docs page than to change the code - I had a look at it but am having a hard time with interactive debugging. The easiest starting point for me is `mkdocs build` but I can't easily drop into the python debugger when it hits an error. I can maybe try to call the mkdocs build function from python directly, but then I need to also set up the mkdocs config object to pass in and it's not as convenient. Is there an easier way I should try?

Discussion:

Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index b3d415e..259221f 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -1,5 +1,9 @@
 # Changelog
 
+### 0.10.1
+
+- `examples` folder is not required to be in a subfolder of `docs` anymore. Fixes [#54](https://github.com/smarie/mkdocs-gallery/issues/54). PR [#92](https://github.com/smarie/mkdocs-gallery/pull/92) by [Louis-Pujol](https://github.com/Louis-Pujol).
+
 ### 0.10.0 - Support for asynchronous code
 
 - Gallery scripts now support top-level asynchronous code. PR [#90](https://github.com/smarie/mkdocs-gallery/pull/90) by [pmeier](https://github.com/pmeier)
@@ -12,7 +16,7 @@
 
  - Mayavi can now be used in gallery examples just as in `sphinx-gallery`. PR [#69](https://github.com/smarie/mkdocs-gallery/pull/69) by [GenevieveBuckley](https://github.com/GenevieveBuckley)
  - Fixed for `README.md` that contains `html` comments. Fixes [#85](https://github.com/smarie/mkdocs-gallery/issues/85). PR [#86](https://github.com/smarie/mkdocs-gallery/pull/86) by [AntoineD](https://github.com/AntoineD).
- 
+
 ### 0.7.10 - `sys.path` is not reset between code blocks
 
  - `sys.path` modifications now persist across blocks of an example. `sys.path` is still reset after each example. PR [#82](https://github.com/smarie/mkdocs-gallery/pull/82) by [Louis-Pujol](https://github.com/Louis-Pujol).
@@ -46,7 +50,7 @@
 
  - Python scripts are now correctly skipped in case of identical md5 hash. Fixes [#29](https://github.com/smarie/mkdocs-gallery/issues/29). PR [#27](https://github.com/smarie/mkdocs-gallery/pull/27) by [mchaaler](https://github.com/mchaaler).
  - Fixed error when `edit_url` is set to empty to [disable the "edit page" feature](https://www.mkdocs.org/user-guide/configuration/#edit_uri). Fixes [#32](https://github.com/smarie/mkdocs-gallery/issues/32). PR [#27](https://github.com/smarie/mkdocs-gallery/pull/27) by [mchaaler](https://github.com/mchaaler).
- 
+
 This release was yanked because of [#34](https://github.com/smarie/mkdocs-gallery/issues/34).
 
 ### 0.7.3 - Bugfix
@@ -80,7 +84,7 @@ This release was yanked because of [#34](https://github.com/smarie/mkdocs-galler
 
 Initial release with:
 
- - Basic features: 
+ - Basic features:
    - pages generation with markdown-based gallery examples. Currently only the `material` theme renders correctly
    - download buttons (both on each example and on the summaries) and page header link to the downloads section
    - subgalleries
diff --git a/docs/examples/README.md b/examples/README.md
similarity index 100%
rename from docs/examples/README.md
rename to examples/README.md
diff --git a/docs/examples/local_module.py b/examples/local_module.py
similarity index 100%
rename from docs/examples/local_module.py
rename to examples/local_module.py
diff --git a/docs/examples/no_output/README.md b/examples/no_output/README.md
similarity index 100%
rename from docs/examples/no_output/README.md
rename to examples/no_output/README.md
diff --git a/docs/examples/no_output/just_code.py b/examples/no_output/just_code.py
similarity index 100%
rename from docs/examples/no_output/just_code.py
rename to examples/no_output/just_code.py
diff --git a/docs/examples/no_output/plot_raise.py b/examples/no_output/plot_raise.py
similarity index 100%
rename from docs/examples/no_output/plot_raise.py
rename to examples/no_output/plot_raise.py
diff --git a/docs/examples/no_output/plot_strings.py b/examples/no_output/plot_strings.py
similarity index 100%
rename from docs/examples/no_output/plot_strings.py
rename to examples/no_output/plot_strings.py
diff --git a/docs/examples/no_output/plot_syntaxerror.py b/examples/no_output/plot_syntaxerror.py
similarity index 100%
rename from docs/examples/no_output/plot_syntaxerror.py
rename to examples/no_output/plot_syntaxerror.py
diff --git a/docs/examples/plot_00_sin.py b/examples/plot_00_sin.py
similarity index 100%
rename from docs/examples/plot_00_sin.py
rename to examples/plot_00_sin.py
diff --git a/docs/examples/plot_01_exp.py b/examples/plot_01_exp.py
similarity index 100%
rename from docs/examples/plot_01_exp.py
rename to examples/plot_01_exp.py
diff --git a/docs/examples/plot_02_seaborn.py b/examples/plot_02_seaborn.py
similarity index 100%
rename from docs/examples/plot_02_seaborn.py
rename to examples/plot_02_seaborn.py
diff --git a/docs/examples/plot_03_capture_repr.py b/examples/plot_03_capture_repr.py
similarity index 100%
rename from docs/examples/plot_03_capture_repr.py
rename to examples/plot_03_capture_repr.py
diff --git a/docs/examples/plot_04_choose_thumbnail.py b/examples/plot_04_choose_thumbnail.py
similarity index 100%
rename from docs/examples/plot_04_choose_thumbnail.py
rename to examples/plot_04_choose_thumbnail.py
diff --git a/docs/examples/plot_04b_provide_thumbnail.py b/examples/plot_04b_provide_thumbnail.py
similarity index 100%
rename from docs/examples/plot_04b_provide_thumbnail.py
rename to examples/plot_04b_provide_thumbnail.py
diff --git a/docs/examples/plot_05_unicode_everywhere.py b/examples/plot_05_unicode_everywhere.py
similarity index 100%
rename from docs/examples/plot_05_unicode_everywhere.py
rename to examples/plot_05_unicode_everywhere.py
diff --git a/docs/examples/plot_06_function_identifier.py b/examples/plot_06_function_identifier.py
similarity index 100%
rename from docs/examples/plot_06_function_identifier.py
rename to examples/plot_06_function_identifier.py
diff --git a/docs/examples/plot_07_sys_argv.py b/examples/plot_07_sys_argv.py
similarity index 100%
rename from docs/examples/plot_07_sys_argv.py
rename to examples/plot_07_sys_argv.py
diff --git a/docs/examples/plot_08_animations.py b/examples/plot_08_animations.py
similarity index 100%
rename from docs/examples/plot_08_animations.py
rename to examples/plot_08_animations.py
diff --git a/docs/examples/plot_09_plotly.py b/examples/plot_09_plotly.py
similarity index 100%
rename from docs/examples/plot_09_plotly.py
rename to examples/plot_09_plotly.py
diff --git a/docs/examples/plot_10_mayavi.py b/examples/plot_10_mayavi.py
similarity index 100%
rename from docs/examples/plot_10_mayavi.py
rename to examples/plot_10_mayavi.py
diff --git a/docs/examples/plot_11_pyvista.py b/examples/plot_11_pyvista.py
similarity index 100%
rename from docs/examples/plot_11_pyvista.py
rename to examples/plot_11_pyvista.py
diff --git a/mkdocs.yml b/mkdocs.yml
index 4719f48..37c6d4d 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -22,7 +22,7 @@ plugins:
   - gallery:
       conf_script: docs/gallery_conf.py  # Base conf. Possibly modified by items below
       examples_dirs:
-        - docs/examples          # path to your example scripts, relative to mkdocs.yml
+        - examples          # path to your example scripts, relative to mkdocs.yml
         - docs/tutorials
       gallery_dirs:
         - docs/generated/gallery  # where to save gallery generated output. Note that you may or may not include them in
@@ -39,8 +39,8 @@ plugins:
       # specify the order of examples to be according to filename
       within_subsection_order: FileNameSortKey
       expected_failing_examples:
-         - docs/examples/no_output/plot_raise.py
-         - docs/examples/no_output/plot_syntaxerror.py
+         - examples/no_output/plot_raise.py
+         - examples/no_output/plot_syntaxerror.py
 
 #      min_reported_time: min_reported_time,  in conf file
       binder:
diff --git a/noxfile.py b/noxfile.py
index 6ebdc8a..59a4acf 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -103,7 +103,7 @@ def tests(session: PowerSession, coverage, pkg_specs):
         with open("mkdocs-no-mayavi.yml", "w") as f:
             for line in mkdocs_config:
                 if line == "      expected_failing_examples:\n":
-                    line = line + "         - docs/examples/plot_10_mayavi.py\n"
+                    line = line + "         - examples/plot_10_mayavi.py\n"
                 f.write(line)
 
     # install CI-only dependencies
diff --git a/src/mkdocs_gallery/plugin.py b/src/mkdocs_gallery/plugin.py
index 26e93b8..236832f 100644
--- a/src/mkdocs_gallery/plugin.py
+++ b/src/mkdocs_gallery/plugin.py
@@ -7,6 +7,7 @@
 The mkdocs plugin entry point
 """
 import os
+from os.path import relpath
 import re
 from pathlib import Path
 from typing import Any, Dict, List, Union
@@ -342,7 +343,7 @@ markdown_extensions:
             dir_or_list_of_dirs = [dir_or_list_of_dirs]
 
         # Get them relative to the mkdocs source dir
-        return [Path(e).relative_to(rel_to_dir).as_posix() for e in dir_or_list_of_dirs]
+        return [Path(relpath(Path(e), start=Path(rel_to_dir))).as_posix() for e in dir_or_list_of_dirs]
 
     # def on_nav(self, nav, config, files):
     #     # Nav is already modded in on_pre_build, do not change it


Test patch:
diff --git a/tests/test_config.py b/tests/test_config.py
index 7bc0f5b..2d6de5b 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -68,7 +68,7 @@ def test_full_conf(basic_mkdocs_config, monkeypatch):
     full_config = yaml_load("""
 conf_script: docs/gallery_conf.py
 examples_dirs:
-  - docs/examples
+  - examples
   - docs/tutorials
   # TODO mayavi_examples
 gallery_dirs:
@@ -83,8 +83,8 @@ image_scrapers: matplotlib
 compress_images: ['images', 'thumbnails']
 within_subsection_order: FileNameSortKey
 expected_failing_examples:
-   - docs/examples/no_output/plot_raise.py
-   - docs/examples/no_output/plot_syntaxerror.py
+   - examples/no_output/plot_raise.py
+   - examples/no_output/plot_syntaxerror.py
 
 # min_reported_time: min_reported_time,  in conf file
 
diff --git a/tests/test_gen_md.py b/tests/test_gen_md.py
index 4ae48df..6e4f392 100644
--- a/tests/test_gen_md.py
+++ b/tests/test_gen_md.py
@@ -50,7 +50,7 @@ CONTENT = [
 
 TESTS_ROOT = Path(__file__).parent
 DOCS_ROOT = TESTS_ROOT / "../docs"
-EXAMPLES_DIR = DOCS_ROOT / "examples"
+EXAMPLES_DIR = TESTS_ROOT / "../examples"
 TUTORIALS_DIR = DOCS_ROOT / "tutorials"