I use a setup like this. Essentially, I use pyenv [1] to manage Python versions and Poetry [2] [2](https://python-poetry.org/) for virtualenvs/dependencies.
The workflow for creating a new project looks like this:
1. Create a project directory (e.g. 'myproject') and `cd` into it.
2. `git init`
3. Fixate the Python version for that project with the `pyenv local` command (e.g. `pyenv local 3.8.6`). This creates a `.python-version` file that you can put under source control. Within the `myproject` directory tree, `python` will now be automatically resolved to the specified version. Your system Python (in fact, any other Python versions you might have installed) remain untouched.
4. Create a new poetry project (`poetry init`). This creates a `pyproject.toml` which contains project metadata + dependencies and can also be checked into git.
5. Add dependencies with `poetry add`. Here, you could for instance add Jupyter Lab (`poetry add jupyterlab`).
To access installed dependencies, such as the `jupyter lab` command, you can either execute one command in the virtualenv directly (`poetry run jupyter lab`) or spawn a shell (`poetry shell`). If you open a Jupyter Notebook that way, the packages installed in the virtualenv are directly available from within Jupyter Notebooks, without having to mess around with installing IPython kernels.
I like this approach, because it gives you full flexibility, while being portable and easy to use. It gets you around having to deal with conda (which I found to be frustrating at times). Also, you're not tied to the Jupyter frontends, but could e.g. just install `ipykernel` and open notebooks in VSCode.
The workflow for creating a new project looks like this:
1. Create a project directory (e.g. 'myproject') and `cd` into it. 2. `git init` 3. Fixate the Python version for that project with the `pyenv local` command (e.g. `pyenv local 3.8.6`). This creates a `.python-version` file that you can put under source control. Within the `myproject` directory tree, `python` will now be automatically resolved to the specified version. Your system Python (in fact, any other Python versions you might have installed) remain untouched. 4. Create a new poetry project (`poetry init`). This creates a `pyproject.toml` which contains project metadata + dependencies and can also be checked into git. 5. Add dependencies with `poetry add`. Here, you could for instance add Jupyter Lab (`poetry add jupyterlab`).
To access installed dependencies, such as the `jupyter lab` command, you can either execute one command in the virtualenv directly (`poetry run jupyter lab`) or spawn a shell (`poetry shell`). If you open a Jupyter Notebook that way, the packages installed in the virtualenv are directly available from within Jupyter Notebooks, without having to mess around with installing IPython kernels.
I like this approach, because it gives you full flexibility, while being portable and easy to use. It gets you around having to deal with conda (which I found to be frustrating at times). Also, you're not tied to the Jupyter frontends, but could e.g. just install `ipykernel` and open notebooks in VSCode.
[1](https://github.com/pyenv/pyenv/) [2](https://python-poetry.org/)
Edit: Moved the links