Skip to content

Establish Rules for Dependencies Between Your Packages

If you're working on a bigger and more complex application, you probably follow some structure and organize your code into packages. In that case, it might make sense to establish some rules how these packages communicate with each other.

Here are some ideas that might make sense depending on your project's structure:

  • The api package can depend on any other package. But no other package in your project should depend on api.
  • Only the api package should use the api_utils package.
  • Only the core package should use the db package.

Establish Rules for Dependencies Between Your Packages with Sourcery Custom Rules

Currently, you need to define 2 Sourcery custom rules to flag various ways of dependency. 1 flags import statements and 1 flags from ... import statements.

Here is an example to flag all the cases when another package in your project depends on api:

rules:
  - id: no-dependency-api-import
    description: Do not import the `api` library in other packages
    pattern: import ..., ${module}, ...
    condition: module.matches_regex(r"^api\b")
    paths:
      exclude:
        - api/
        - test/
    tests:
      - match: import api
      - match: import api.auth
      - match: import api as my_api
      - match: import api.auth as api_auth
      - match: import json, api, datetime
      - no-match: import apiness

  - id: no-dependency-api-from
    description: Do not import the `api` library in other packages
    pattern: from ${module} import ...
    condition: module.matches_regex(r"^api\b")
    paths:
      exclude:
        - api/
        - test/
    tests:
      - match: from api import util
      - match: from api import util, auth
      - match: from api.whatever import SomeApiStuff
      - match: from api.level.other import util, other
      - match: from api import util as u, auth as a
      - match: from api import *
      - match: from api.books import *
      - no-match: from apiness import util
      - no-match: from api2 import util

Checklist for Dependency Rules

  • Always create 2 Sourcery custom rules: 1 for import statements, 1 for from ... import statements.
  • Add exclude paths: Imports within the package itself and in tests should be allowed.

Out of Scope

Please note that these rules find only direct references to a library in import and from ... import statements. The following is out of scope:

  • reimporting imported names
  • __import__ built-in function
  • importlib

General Import Conventions

We recommend to follow some conventions for imports. That makes your code easier to read for humans and easier to work with for tools.

Follow the import rules of the Google Python Style Guide:

  • Do not use relative imports.
  • Do not use star imports.

You can enforce these rules by enabling the gpsg-import rule package in your Sourcery config file:

rule_settings:
  enable:
    - default
    - gpsg-import

Use a tool to sort and format your imports. Great options include: