Splitting python code into multiple services inside of a single folder/monorepo using VS Code while ensuring automatic pylint coverage.

VS Code Screenshot of multi-root workspace in VS Code

Or.. why you should learn how to use workspaces in VS Code

TL;DR Issue: I wanted to have multiple sub-folders inside of a project act as their own root space, using their own virtualenvs, with their own Dockerfiles and Pipefiles, etc.. but ran into an issue with the pylint extension not referencing the correct virtualenv

TL;DR Solution: Make a .vscode folder in your root that has a “project-name.code-workspace” file inside of it that looks like the below and then open your Workspace in VS Code using that file (and not the root project folder). See sample repo here:
https://github.com/TheRightChoyce/example-vscode-multi-root-workspace-pylint

Background

I have a project that is conceptually structured as a few different services layers, but is physically structured as a monolith application with a tightly coupled code structure. As I am trying to focus on ensuring even small projects can be easily deployed and scaled as services, I took this as an opportunity to “de-couple” the code into discrete service containers. For my purposes I wanted to keep everything in a single code repo e.g. “Monorepo”. No idea if that will help or hurt down the road, but trying to minimizing managing different repos for now.

Here is example code structure before:

app
| index.py

lib
| service1
	| get.py
	| create.py
| service2.py
	| get.py
	| create.py
| shared
	| get.py
	| create.py

Pipfile
Pipfile.lock


Here is the structure I am moving to:

app
| index.py

services
| service1
	| src
		| get.py
		| create.py
	| Dockerfile
	| Pipfile
	| Pipfile.lock
| service2
	| src
		| get.py
		| create.py
    | Dockerfile
	| Pipfile
	| Pipfile.lock

(TBD on how I want to implemented the shared functionality)

The Solution

Setting that up in VS Code is trivial because you’re just moving files. But if I opened the project root folder in VS Code.. I immediately had some issues with pylint not being able to reference anything I installed locally with Pipenv (in this case Quart, an asyncio framework compatible with Flask)

Unable to import 'quart' pylint(import-error)

$ from quart import Quart
Unable to import ‘quart’

For reference, here is the Pipfile:

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[packages]
quart = "*"

[dev-packages]
pylint = "*"

[requires]
python_version = "3.9"

After some trial and I error I was able to get it to work by using a .code-workspace file to define a “multi-root workspace” in VS Code. Essentially this tells VS Code to view each service as the “root” of its own project and apply any extensions, linters, etc.. to only the local service. OR, simply, each folder should reference its own (and only its own) Pipfile and virtualenv.

Here is an example of what the “project-name.code-workspace” file should look like, where “project-name” is whatever name you want to give your project. This name will also show up at the top of the Explorer.

{
    "folders": [
        {
            "name": "ROOT",
            "path": "../"
        },
        {
            "name": "service1",
            "path": "../services/service1"
        },
        {
            "name": "service2",
            "path": "../services/service2"
        },
    ],
    "settings": {
        "files.exclude": {
        }
    }
}
  • folders” — These define the folders in your project that you want to treat as “root” folders that show in up the Explorer view. For me this was each service/project, but you could also customize this for individual use and only display the relevant services.
  • name” — Optional; the name to display in the Explorer view
  • path” — The relative path to the folder for each service/project
  • settings” — Any other global/project-wide settings

The “ROOT” folder is optional, but it easily lets you dig into all files and anything that is not contained inside of one of your service folders.

Once you have this, save it, close the VS Code project. Do File -> Open workspace -> then select the “project-name.code-workspace” file.

Hint– If you can’t see the .vscode folder on a Mac, press [CMD]+[SHIFT]+[.] to show “hidden” files and folders

Your explorer should look something like this now:

VS Code explorer with three top-level folders: ROOT, service1, and service2. the service folders all have their own src folder, Dockerfile, and Pipfiles.

And you linting issues should be gone!

Source Code

Here is a full example repo that you can clone to see this working in action:
https://github.com/TheRightChoyce/example-vscode-multi-root-workspace-pylint

References:

VS Code Workspace docs
https://code.visualstudio.com/docs/editor/workspaces

Quart
https://pgjones.gitlab.io/quart/index.html

Docker / Python Quickstart
https://docs.docker.com/language/python/

BONUS: Some Monorepo vs. Multirepo/Polyrepo discussions:

No Monorepos:
https://medium.com/@mattklein123/monorepos-please-dont-e9a279be011b

No Polyrepos:

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s