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

Group meson commands in preparation for other build systems #52

Merged
merged 1 commit into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 49 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,44 @@ As an example, see the `[tool.devpy]` section of [an example `pyproject.toml`](h
The `[tool.devpy]` section should contain:

```
package = 'pkg_importname' # used by pytest
commands = ['devpy.build', 'devpy.test']
package = "pkg_importname" # name of your package
commands = [
"devpy.cmds.meson.build",
"devpy.cmds.meson.test"
]
```

See [the command selection](#built-in-commands) below.

### Command sections

Once you have several commands, it may be useful to organize them into sections.
In `pyproject.toml`, instead of specifying the commands as a list, use the following structure:

```toml
[tool.devpy.commands]
"Build" = [
"devpy.cmds.meson.build",
"devpy.cmds.meson.test"
]
"Environments" = [
"devpy.cmds.meson.shell",
"devpy.cmds.meson.ipython",
"devpy.cmds.meson.python"
]
```

These commands will then be rendered as:

```
Build:
build 🔧 Build package with Meson/ninja and install
test 🔧 Run tests

Environments:
shell 💻 Launch shell with PYTHONPATH set
ipython 💻 Launch IPython shell with PYTHONPATH set
python 🐍 Launch Python shell with PYTHONPATH set
```

## Running
Expand All @@ -45,12 +81,22 @@ On Unix-like systems, you can also copy the [`dev.py` script](https://github.com

## Built-in commands

### [Meson](https://meson-python.readthedocs.io)

Choose a reason for hiding this comment

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

https://mesonbuild.com/ should be the right link here.

devpy does not invoke meson-python through the devpy meson commands so this could be confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

The build backend is mesonpy, but the build engine is meson. My thought was that this is an easier place to start:

https://meson-python.readthedocs.io/en/latest/tutorials/introduction.html#tutorial-introduction


```
build 🔧 Build package with Meson/ninja and install to `build-install`
ipython 💻 Launch IPython shell with PYTHONPATH set
python 🐍 Launch Python shell with PYTHONPATH set
shell 💻 Launch shell with PYTHONPATH set
test 🔧 Run tests
test 🔧 Run pytest
```

### [Build](https://pypa-build.readthedocs.io/en/stable/) (PEP 517 builder)

`devpy` was started with Meson in mind, but we're working on expanding commands for PEP 517 `build`.

```
sdist 📦 Build a source distribution in `dist/`.
```

## 🧪 Custom commands
Expand Down Expand Up @@ -82,30 +128,6 @@ def example():
print(config["tool.devpy"])
```

### Command sections

Once you have several commands, it may be useful to organize them into sections.
In `pyproject.toml`, instead of specifying the commands as a list, use the following structure:

```toml
[tool.devpy.commands]
"Build" = ["devpy.build_meson", "devpy.test"]
"Environments" = ["devpy.shell", "devpy.ipython", "devpy.python"]
```

These commands will then be rendered as:

```
Build:
build 🔧 Build package with Meson/ninja and install
test 🔧 Run tests

Environments:
shell 💻 Launch shell with PYTHONPATH set
ipython 💻 Launch IPython shell with PYTHONPATH set
python 🐍 Launch Python shell with PYTHONPATH set
```

## History

The `dev.py` tool was [proposed for SciPy](https://github.com/scipy/scipy/issues/15489) by Ralf Gommers and [implemented](https://github.com/scipy/scipy/pull/15959) by Sayantika Banik, Eduardo Naufel Schettino, and Ralf Gommers (also see [Sayantika's blog post](https://labs.quansight.org/blog/the-evolution-of-the-scipy-developer-cli)).
Expand Down
63 changes: 40 additions & 23 deletions devpy/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ def __getitem__(self, key):
print("No configuration found in [pyproject.toml] for [tool.devpy]")
sys.exit(1)

commands = {
f"devpy.{name}": getattr(cmds, name)
for name in dir(cmds)
if not name.startswith("_")
}

proj_name = project_config.get("name", config["package"])

@click.group(help=f"Developer tool for {proj_name}", cls=SectionedHelpGroup)
Expand All @@ -69,31 +63,54 @@ def group(ctx):
if isinstance(config_cmds, list):
config_cmds = {"Commands": config_cmds}

# Backward compatibility workaround
# Originally, you could specify any of these commands as `devpy.cmd`
# and we'd fetch it from util
commands = {
"devpy.build": cmds.meson.build,
"devpy.test": cmds.meson.test,
"devpy.ipython": cmds.meson.ipython,
"devpy.python": cmds.meson.python,
"devpy.shell": cmds.meson.shell,
}

for section, cmds in config_cmds.items():
for cmd in cmds:
if cmd not in commands:
try:
path, func = cmd.split(":")
spec = importlib.util.spec_from_file_location("custom_mod", path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
# First, see if we can directly import the command
if not ":" in cmd:
path, func = cmd.rsplit(".", maxsplit=1)
try:
mod = importlib.import_module(path)
except ImportError:
print(
f"!! Could not import module `{path}` to load command `{cmd}`"
)
continue
else:
try:
cmd_func = getattr(mod, func)
except AttributeError:
path, func = cmd.split(":")
spec = importlib.util.spec_from_file_location(
"custom_mod", path
)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
except FileNotFoundError:
print(
f"!! Could not load command `{func}` from file `{path}`.\n"
f"!! Could not find file `{path}` to load custom command `{cmd}`.\n"
)
continue
except FileNotFoundError:
print(
f"!! Could not find file `{path}` to load custom command `{cmd}`.\n"
)
except Exception as e:
print(
f"!! Could not import file `{path}` to load custom command `{cmd}`.\n"
)
raise e

try:
cmd_func = getattr(mod, func)
except AttributeError:
print(f"!! Could not load command `{func}` from file `{path}`.\n")
continue
except Exception as e:
print(
f"!! Could not import file `{path}` to load custom command `{cmd}`.\n"
)
raise e

commands[cmd] = cmd_func

Expand Down
11 changes: 8 additions & 3 deletions devpy/cmds/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
from ._build import build
from ._test import test
from ._shell import ipython, python, shell
from . import meson

# Backward compatibility with older versions
build = meson.build

Choose a reason for hiding this comment

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

Can we issue a deprecation warning for people still using these directly?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, do you know of an easy way to implement that?

Copy link

@lithomas1 lithomas1 Mar 11, 2023

Choose a reason for hiding this comment

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

You can try a module-level __getattr__ (for python 3.7+), that raises the Deprecation/FutureWarning.

test = meson.test
ipython = meson.ipython
python = meson.python
shell = meson.shell
69 changes: 0 additions & 69 deletions devpy/cmds/_build.py

This file was deleted.

77 changes: 0 additions & 77 deletions devpy/cmds/_shell.py

This file was deleted.

48 changes: 0 additions & 48 deletions devpy/cmds/_test.py

This file was deleted.

Loading