The layering in the cards project is important because it ensures a clear separation of concerns. The CLI layer handles the user interface, the API layer contains the business logic, and the DB layer manages database interactions. This strict separation prevents direct access between layers, ensuring that the CLI does not directly access the database and the API does not interact with the CLI, promoting modularity and maintainability.
Using `import cards` in CLI.py instead of `from . import API` allows the CLI to serve as an example of how to use the cards API from an external project. This approach mimics how a third-party application would import and use the cards package, making the CLI a practical reference for API usage. It also ensures that the CLI remains a true example of using the cards package as a library, rather than just importing internal modules directly.
When `import cards` is executed in a REPL, the `cards` variable holds the module defined in `__init__.py`. This module includes the version string, the app object from CLI, and everything imported via `from .api import *`, which is controlled by the `__all__` list in `api.py`. Essentially, `cards` represents the top-level package interface.
Having multiple clients for an API, such as CLI and tests, provides additional opportunities to evaluate the API's usability and design. If the API is difficult to use in tests or the CLI, it may indicate issues that need addressing before wider adoption. This approach aligns with test-driven development principles, ensuring the API is robust and user-friendly before being exposed to external users.
Moving the version string from `__init__.py` to `api.py` requires adding it to the `__all__` list in `api.py` to make it accessible. While this change can be made to fix test failures, it is not ideal because it disrupts the traditional placement of version strings, which are typically in `__init__.py` or `pyproject.toml`. Additionally, it makes the CLI less representative of how external users would interact with the package.
from . import module
and import package
.import package
is preferred over from . import API
in this context.
In this episode we're talking about importing part of a package into another part of the same package.
We'll look at: from . import module
and from .module import something
and also: import package
to access the external API from with the package.
Why would we use import package
if from . import api
would work fine?
** Learn pytest**