This Python project demonstrates a modular architecture with cross-project communication capabilities. The project consists of a main controller and two independent sub-projects that can run separately but also share common utilities and import functionality from each other.
The implementation showcases how to structure a Python application where multiple sub-projects coexist, each with their own functionality, while maintaining the ability to share code and communicate between them. This is achieved through dynamic path manipulation using sys.path.append()
to enable cross-module imports.
This educational example illustrates practical approaches to modular Python development, demonstrating both the benefits and limitations of this architecture pattern.
- Modular Architecture: Two distinct sub-projects that can function independently
- Cross-Project Communication: Sub-projects can import and utilize functionality from each other
- Shared Utilities: Common functions accessible to all sub-projects through a shared module
- Menu Interface: Main entry point provides a user-friendly menu to select which sub-project to run
- Dynamic Path Manipulation: Uses
sys.path.append()
to enable cross-module imports - Error Handling: Graceful handling of import failures when sub-projects are run independently
- Clone or download this repository to your local machine
- Ensure you have Python 3.x installed on your system
- No additional dependencies are required - this project uses only Python standard library modules
git clone https://github.com/your-username/python-multi-project-architecture.git
cd python-multi-project-architecture
Execute the main script to access the menu-driven interface:
python main.py
This will display a menu allowing you to choose which sub-project to run:
- Sub-project 1
- Sub-project 2
- Exit
Each sub-project can be run independently:
# Run Sub-project 1
python sub-project-1/main.py
# Run Sub-project 2
python sub-project-2/main.py
When run independently, each sub-project will attempt to import shared utilities and functionality from the other sub-project. If successful, it will demonstrate the cross-project communication capabilities.
python-multi-project-architecture/
├── main.py # Main controller with menu interface
├── sub-project-1/ # First independent sub-project
│ ├── main.py # Entry point for sub-project 1
│ └── project1_utils.py # Project-specific utilities
├── sub-project-2/ # Second independent sub-project
│ ├── main.py # Entry point for sub-project 2
│ └── project2_utils.py # Project-specific utilities
└── shared/ # Shared utilities accessible to all projects
├── __init__.py # Python package initializer
└── common_utils.py # Common functions used by all projects
- main.py: The main entry point that presents a menu to the user and executes the selected sub-project
- sub-project-1/: Contains all files related to the first sub-project
- main.py: Implements sub-project 1 functionality and demonstrates importing from sub-project 2
- project1_utils.py: Utility functions specific to sub-project 1
- sub-project-2/: Contains all files related to the second sub-project
- main.py: Implements sub-project 2 functionality and demonstrates importing from sub-project 1
- project2_utils.py: Utility functions specific to sub-project 2
- shared/: Directory containing utilities shared between all projects
- common_utils.py: Functions that can be used by the main controller and both sub-projects
Cross-project imports are implemented using dynamic path manipulation:
# In sub-project main files
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'shared'))
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'sub-project-2')) # or sub-project-1
This approach allows each sub-project to import functions from:
- The shared utilities module
- The other sub-project
Each sub-project includes error handling for import operations:
try:
from common_utils import greet_user
shared_utils_available = True
except ImportError:
shared_utils_available = False
print("Warning: Could not import shared utilities")
This ensures that sub-projects can run even if some imports fail, making them more robust.
This modular architecture with sys.path.append()
is particularly well-suited for:
-
Educational Projects: This approach is excellent for teaching and learning purposes, as it demonstrates fundamental concepts of modular programming and cross-module communication in a straightforward manner.
-
Prototypes and Proof-of-Concept: When quickly building prototypes or proof-of-concept applications, this architecture allows for rapid development and easy experimentation with different module interactions.
-
Small to Medium-Sized Projects: For projects that don't require complex dependency management, this approach provides a simple way to organize code into logical modules while maintaining flexibility.
-
Projects with Shared Utilities: When you have common functionality that multiple independent modules need to access, this pattern allows for easy sharing without complex packaging.
-
Exploratory Programming: For data science, scripting, or other exploratory programming tasks where you're frequently modifying and reorganizing code, this approach offers flexibility without the overhead of formal packaging.
While this approach has its benefits, there are several scenarios where it should be avoided:
-
Production Applications: For production systems where reliability and maintainability are critical, this approach is not recommended due to its runtime nature of import resolution.
-
Large-Scale Projects: As projects grow in complexity, the lack of explicit dependency management can lead to maintenance challenges and difficulty in tracking module relationships.
-
Projects Requiring Strict Version Control: When you need precise control over module versions and dependencies, this dynamic approach doesn't provide the necessary guarantees.
-
Applications with Complex Packaging Requirements: For applications that will be distributed or installed by others, proper packaging with tools like setuptools is more appropriate.
-
Team Projects with Multiple Developers: In collaborative environments, this approach can lead to confusion about module dependencies and make code reviews more challenging.
-
Simplicity: Extremely simple to implement and understand, making it ideal for educational purposes.
-
Flexibility: Allows for dynamic module loading and easy experimentation with different module combinations.
-
No Complex Dependency Management: Avoids the overhead of managing complex dependency trees or virtual environments.
-
Good for Learning: Clearly demonstrates how Python's import system works and how paths are resolved.
-
Quick Prototyping: Enables rapid development without the need for formal package structure.
-
Runtime Errors: Import issues are only discovered at runtime rather than at import time, which can lead to unexpected failures.
-
Less Robust: More prone to breaking when file structures change compared to proper packaging solutions.
-
Not Suitable for Production: Lacks the reliability and maintainability required for production systems.
-
Can Become Difficult to Manage: In larger projects, tracking all the sys.path modifications can become challenging.
-
IDE Support: Some IDEs may not properly recognize the dynamically added paths, leading to reduced code completion and navigation support.
Contributions to improve this demonstration are welcome! Please follow these steps:
- Fork the repository
- Create a new branch for your feature or bug fix
- Make your changes and ensure they follow the existing code style
- Add comments explaining any complex functionality
- Test your changes thoroughly
- Submit a pull request with a clear description of your changes
Since this is an educational project, please focus on:
- Improving clarity of the examples
- Adding more practical use cases
- Enhancing documentation
- Fixing any bugs or issues
This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.
The Apache License 2.0 is a permissive open-source license that allows for free use, modification, and distribution of the code, both for personal and commercial purposes. It provides additional protections compared to the MIT License, including an express grant of patent rights from contributors to users and a defense clause against patent litigation. The license requires preservation of the copyright notice and disclaimer, but does not require reproduction of the license text in distributions of the software.
This project is designed as an educational example to demonstrate modular Python architecture concepts. It is not intended for production use without significant modifications.