My Project's structure :
root
|-Pipfile
|-main.py
|
|-first_plugin
| |-Pipfile
| |-main.py
|-second_plugin
| |-Pipfile
| |-main.py
The projects's main.py
functionalities are to :
- Run
git clone
in order to download each plugin fromGithub
- Run
pipenv install
in order to install their dependencies - Execute the
run()
function from each of the plugins'main.py
.
The root/Pipfile
:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
GitPython = ">=3.1"
PyYAML = ">=6.0"
[dev-packages]
[requires]
python_version = "3.8"
The first_plugin/Pipfile
:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
"-e ." = "*"
PyYAML = ">=6.0"
requests = "*"
[dev-packages]
[requires]
python_version = "3.8"
The first_plugin/main.py
:
from Plugins.plugin import Plugin
import requests
class FirstPlugin(Plugin):
def run(self):
if self.is_activated:
print("The First Plugin is being run..")
else:
print("The First Plugin can not run because it is not activated")
The function read_from_yml
downloads the plugins with git clone
nad runs pipenv install
in order to instrall their dependencies :
import yaml
import git
import os
import shutil
import subprocess as sp
import sys
"""
Reads plugins from a Yaml file and downloads them
with git clone if there is not a subdirectory with their
name in the Plugins directory
The format of the Yaml file must be as shown bellow:
- It must contain a single list of dictionaries that must have the keys bellow :
- name : The name of the plugin
- url : a url of the git repo in which the plugin is stored
"""
def read_from_yml():
#Open the yml file
with open("plugins.yml", "r") as stream:
try:
plugins = yaml.safe_load(stream)
#Get all the subdirectories of the Plugins directory
PluginFolder = "Plugins/"
possible_plugins = os.listdir(PluginFolder)
for plugin in plugins:
#if the plugin does not have a url, do nothing
if plugin["url"] == '':
print("Not in the web")
else:
#if the plugin has a url, try to remove the directory of the
# plugin from the Plugins directory. We do that in order to download the latest version of
# the plugin from the internet
try:
shutil.rmtree(PluginFolder + plugin["name"])
except OSError as e:
print("Error: %s - %s." % (e.filename, e.strerror))
# Git clone the repository of the plugin into the Plugins directory
git.Repo.clone_from(plugin["url"], os.path.join(os.getcwd(), PluginFolder + plugin["name"]))
all_files = os.listdir(PluginFolder + plugin["name"])
# Check if there is a requirements.txt file and install
# the dependencies it contains
if "Pipfile" in all_files:
os.chdir(os.getcwd() + "/" + PluginFolder + plugin["name"])
print(os.getcwd())
sp.check_call(["pipenv", "install"])
sp.check_call(["pipenv", "graph"])
new_cwd = os.getcwd().replace("/" + PluginFolder + plugin["name"], '')
os.chdir(new_cwd)
print(os.getcwd())
except yaml.YAMLError as exc:
print(exc)
The problem :
When I run the project with the cmd python3 main.py
the plugins' dependencies are installed as expected. But when I use the cmd pipenv run python3 main.py
, the plugins' dependencies are not installed and the program crashes at the first plugin with this error message :
File "Plugins/First_plugin/main.py", line 2, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
Edit ;
This cmd sp.check_call(["pipenv", "graph"])
prints all the pacages downloaded by pipenv
. I call it in the First_plugin
dir and this is the result
PyYAML==6.0
requests==2.26.0
- certifi [required: >=2017.4.17, installed: 2021.10.8]
- charset-normalizer [required: ~=2.0.0, installed: 2.0.9]
- idna [required: >=2.5,<4, installed: 3.3]
- urllib3 [required: >=1.21.1,<1.27, installed: 1.26.7]
This means that the requests
packages is installed. But the program still prints the previous error message afterwards :
File "Plugins/First_plugin/main.py", line 2, in <module>
import requests
ModuleNotFoundError: No module named 'requests'