HNHacker News
TopNewBestAskShowJobs

yeti-sh

34 karma · joined May 2, 2022

https://github.com/anatoly-scherbakov | https://yeti.sh

Python developer, interested in:

- software architecture & code quality

- linked data & semantic web (more at https://iolanta.tech)

- tools for development productivity (more at https://jeeves.sh)

submissionscomments
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
The exception is raised if the command returns a non-zero error code. If it returns a zero error code then the return value of, say,

    compose.up()
contains the command's stdout.

In addition stdout can be redirected to a file, or to another command, or to a callable, ­— which will be called for chunks of stdout while the command is in operation.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
No it does not, in fact; errors or warnings will pop up as an unhandled exception and print:

- command actually executed,

- snippet of stdout

- and snippet of stderr.

They can be handled using standard exception techniques.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
To change the wording in the title of this post would be improper in view of multitude of comments referring to this title. I will consider rebranding this.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I feel the majority still uses qwerty keyboards; I assumed that when choosing the name and the shortcut for the tool.

Experiences differ, and de gustibus on est disputandum; in my bubble, virtualenv is a must-have for Python development.

I have multiple Python projects, they run different versions of Python itself and its libraries, and for many of them Docker would be an overkill; so it is hard for me to imagine my routine without virtual environments.

I employ pyenv to manage them but venv is a venv.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I see. The P key isn't that ergonomically placed though; and again, one will have to do this time and again for each virtual environment, right?

Why not use native Python methods, namely endpoints, instead, and automate this away?

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Regarding sync checks which Make has as a built-in feature, I am not yet positive how to best implement it. Maybe something like

    @pre(file_name=_file_is_in_sync)
    def build(file_name: Path):
        ...
I believe such libraries do exist even, but I haven't yet researched the topic; if jeeves proves to be useful for the simplest use case then it will make sense to expand its scope.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
> argh & a symlink in /usr/bin.

- Is putting a symlink to one of your project directories, probably residing in $HOME, to /usr/bin/ a good practice?

- As an alternative one can put a symlink into ~/bin; but what if you have multiple different projects?

- And they can have different jeeves commands and different plugins installed. For instance, `j lint` implementations in different projects are work on are completely different.

Because these are different projects.

Rather, I prefer to have jeeves automatically create the executable command in each virtual env, and its behavior in different virtual envs will be different.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
There are a lot of projects, both commercial and OSS, which have a Makefile for linting, version releases, etc, — and never use its dependency graph feature; or, their usage is so superficial that implementing it, say,

- via direct function calls in Python code,

- or using Typer callback functions

…is easy.

There are potential approaches worth exploring (annotations, decorators, …). I might come up with a list of options with syntax examples and ask for community's thoughts about it, — but at this point jeeves, as an MVP, is already useful for me and a few people I work with, and that motivated me to share it with the community.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
That's right; Google also published a similar package named `fire`, I used it a lot.

> just `python your_file.py`

That's actually one of the points.

    j lint
is shorter than

    python scripts.py lint
and the letter `j` is what the index finger of your right hand is pointing to on the keyboard. There is usually a tactile bump on that key. It is something you can type very quickly. You can also install shell completion to improve the experience further.

Ergonomics matters.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
An example from the top of my head:

    compose = sh.docker.compose.bake('-f', 'deploy/dev.yml')
    …
    compose.down()
    …
    compose.up('--force-recreate', '-d')
I feel this is a major improvement on top of Makefiles + shell commands in them. Nice API _matters_; it is ergonomics and therefore productivity.

You can specify `_out=rich.print` and it will work but AFAIK it won't scrape ASCII terminal formatting characters.

I had to fix these characters in my `sh` based scripts but do not consider that as a big deal.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Saying 'GNU Make' particularly was an automatism. When I use Make I do use GNU Make specifically. I do not have experience with BSD Make, or other Make dialects.

> did actually do a suitable job of replacing gnu make

The title does not say _a replacement_, it says _an alternative_. I never intended to replace GNU Make; if I said that anywhere — that was a mistake on my part.

> do improve upon those who created unix

I did not intend to improve upon UNIX ideas or philosophy. The improvements I am aiming for are:

- developer experience,

- conciseness and maintainability of the code.

…and these are being addressed for a narrow use case. For that use case, in my experience, Make is very often used.

I argue that within the bounds of this use case, this is an alternative which can be of use to improve productivity and everyday experience.

> I don't really understand the full job make does, so here is something which only does a simpler job which I do understand, and I like python

I classify these assumptions about my understanding or misunderstanding as ad hominem and unprofessional.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
For a Python project, I'd recommend doing this as a dev dependency.

* jeeves is the name of the project which I'm advertising, which converts a Python file to a set of commands; * `j` is the name of executable which aformentioned project exposes; * and `sh` is the library (the correct link to which you have provided) which is an optional dependency of `jeeves` and provides a more convenient interface to calling processes and executing commands from Python than `subprocess.run()`.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
You are right, jeeves doesn't do that. Your example reminds me of how I first learnt to use Make; I built my LaTeX stuff from source when in university.

However, dealing with Python mostly in my time in the industry, I scarcely ever had the need to use these particular features of Make. I used it as a task runner, guilty of that, — and that's what I wanted to reimplement in Python.

Even writing in Rust, everything I have to do is `cargo build`, — there is no need to write Makefiles for building the project.

I will consider changing that wording to set proper expectations, but I still feel that for me "a Pythonic alternative to Make" perfectly conveys the use case I daily employ this thing for.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
You can also install a jeeves plugin with pip. Say,

    pip install jeeves-yeti-pyproject
will provide you with jeeves, a bunch of commands, and a pack of dev dependencies which I personally happen to like and to use in my projects.

I don't believe Make has plugins.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I looked at pyinvoke before I started jeeves. Roughly, as much as I can recall, there were a few reservations:

- no type hints for docs & validation, I wanted them

- Makefile in its basic form is very concise and doesn't require a @task decorator, I didn't want it either

I didn't need dependency graph much.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Please elaborate. Do you mean submitting commands via ssh to remote servers from the script?

The way I'd recommend to run shell commands from jeeves is `sh` library. It has features for ssh support: https://sh.readthedocs.io/en/latest/sections/contrib.html#ss...

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I like sh for brevity of its API. I often have to use `_tty_out=False`, but this is easy to fix once and for all commands in a script:

    my_sh = sh.bake(_tty_out=False)
    my_sh.do_whatever()
The way how sh captures output can apparently be altered, say, by providing a callable to _out argument.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Thanks, will check this out!
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Thanks for the point. I've had to deal with argparse-based code (not finding it very enjoyable) but didn't recognize the resemblance.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
That's right. For projects which only use subset of Make features described by (1) jeeves can be considered an alternative for Make, and I would believe there are quite a few such projects.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
With interpretable languages, this feature of Make is IMHO rarely called for. Task running is; Makefile still is a standard way to do project maintenance, both locally and CI. jeeves is an attempt to extract that feature of Make, and provide it in a more accessible way.

By making .PHONY and .ONESHELL labels history, as a particular example.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I wouldn't necessarily agree. I've seen may instances of Make particularly being used to run tedious commands — linting, testing, deployment, et cetera; for these things, jeeves can be a perfect replacement. A and B are usually called alternatives if they have an intersection in their feature sets; there are no perfect alternatives.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Indeed, they are out of scope. But I still would argue this does have something in common with Make — just as Make, jeeves can be used as a command runner, in which role Make is oftentimes used as well.

Instead of `make` as entry point for all project-specific commands (like `make lint`, `make build`, `make deploy`), users can rely upon `j` — both locally and CI.

Regarding your particular points:

* dependency graphs aren't presently at scope, I haven't yet come up with the method of expressing them in Python which would have entirely satisfied me;

* I am not so sure I would want to implement pattern rules due to complexity they bring about. Maybe just writing explicit Python code would be enough for cases where they're used. No strong opinion though.

yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
I've never used waf, but from its documentation it would seem that waf is a build system, implementing a concept of a DAG governing build of a project. That implies that waf is rather complicated.

jeeves, on the other hand, does no such thing. It is a command runner: you write a function → it is converted into a shell command.

I believe jeeves is easier to get started with, partially due to its simplicity and partially because it follows Python standards. For instance, waf uses a peculiar syntax to define command parameters:

waf employs a peculiar method to configure command options:

    ctx.add_option('--foo', action='store', default=False, help='Silly test')
while jeeves relies upon function arguments and type hints (as it is based upon Typer):

    def do(foo: Annotated[Option(help='Silly test')]):
        …
While jeeves is easy to start with it also promises ability to scale: with modular packages for commands, subcommands, and installable/shareable plugins.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Thanks for the hint, I didn't know about this project; will check it out.
yeti-sh··on Show HN: Jeeves – A Pythonic Alternative to GNU Make
Thanks!

Perhaps this particular robot is running a much more civilized version of Skynet/Cyberdyne firmware.

And is sure to be speaking impeccable English.