CategoriesPython

Xonsh Alias: Setup a Python Project

Recently, I was reading The Pragmatic Programmer, and the section on continual learning, especially learning how to use new tools, really stuck with me.

With that in mind, I turned my attention to ways to improve my process for starting up a new project, which is something I do fairly often to experiment.

There are several aspects of setting up a new project, and managing all of them manually can be repetitive, error-prone, and difficult. Some of the ones I wanted to take care of using tools include:

  • Structuring the project directory structure
  • Creating a virtual environment and activating it every time
  • Managing dependencies

The tools I decided to use are poetry and vox/autovox. Poetry takes care of a lot of project management issues, while vox allows me to use virtualenvs that play well with Xonsh. In the future, I’d also like to explore using cookiecutter for templates.

I tied all of these tools–of course, plus git–together into a Xonsh alias. If you’re not familiar with that, check out my introduction to Xonsh and my article about using an alias to filter Mut.py results.

xontrib load vox, autovox

from pathlib import Path


def _create_project(args):
    project_name = args[0]
    poetry config virtualenvs.create false
    poetry new @(project_name)
    cd @(project_name)
    
    env_name = str(Path.cwd())[1:]
    print("Removing previous virtualenv, if it exists (KeyError means that it did not exist)")
    vox deactivate
    vox remove @(env_name)
    
    pyenv_path = Path($(pyenv root).strip()) / "versions"
    interpreter = $(pyenv version-name).split(":")[0]
    interpreter_path = str(pyenv_path / interpreter / "bin" / "python")
    print("Using Python " + interpreter + " at " + str(interpreter_path))
    
    vox new @(env_name) --interpreter @(interpreter_path)
    git init
    rm pyproject.toml
    poetry init

aliases["create_project"] = _create_project


@events.autovox_policy
def auto_based_on_dir(path, **_):
    venv = Path($HOME + "/.virtualenvs" + str(path))
    if venv.exists():
        return venv

The usage is simple: $ create_project project_name will use poetry to create a new project directory project_name, then creates an environment, initializes the git repository, removes the pyproject.toml made by poetry new, and finally runs poetry init to interactively create a new pyproject.toml.

Most of this is pretty simple, but it takes care of several steps at once with one command, which allows me to jump right in to coding when I have a new idea or want to experiment with something.

The most complicated part is the creation of the virtual environment and registering an autovox policy to automatically activate the environment. Vox creates all virtual environments in ~/.virtualenvs. So, for example, if I start a project in /home/harrison/project_name, then a virtual environment gets created at ~/.virtualenvs/home/harrison/project_name.

The auto_based_on_dir function gets registered with autovox and controls activating the proper environment based on what directory I’m working on. It does this by checking whether a virtual environment based on a particular path exists, and returns the path to it if it does.

Conclusion

I’m excited to continue to improve the tools I use in my projects. In particular, poetry seems like a good way to manage and publish projects to the PyPI. It only took a little bit of time to put this together, and I expect it will result in a lot of good.

Switching to vox and using autovox to activate virtual environments should also save a lot of time. In the past, I’ve used pyenv virtualenv and manually activated environments as needed.

What tools do you use as part of your workflow?

Leave a Reply

Your email address will not be published.