Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Requirements installation in venv #686

Merged
merged 5 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/__pycache__/
docs/build/
venv/
env/
*/__TEMP_DATA__/

# File extensions
Expand Down
14 changes: 9 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The [terms of use](https://api.tzkt.io/#section/Terms-of-Use) of TzKT API allow

## Requirements and Setup

Python 3 is required. You can use the following commands to install it.
The setup instructions are Linux specific. Python 3 is required. You can use the following commands to install it.

```bash
sudo apt-get update
Expand All @@ -50,21 +50,25 @@ Download the application repository using git clone:
git clone https://github.com/tezos-reward-distributor-organization/tezos-reward-distributor
```

To install required modules, use pip with `requirements.txt` provided.
To install required modules, use pip with `requirements.txt` provided. Follow the instructions to create a virtual environment for your project specific python installation: https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/

```bash
python3 -m venv env
source env/bin/activate
```

```bash
cd tezos-reward-distributor
pip install -r requirements.txt
python3 -m pip install -r requirements.txt
```

To install the required modules for developers, use pip with `requirements_developer.txt` provided.

```bash
cd tezos-reward-distributor
pip install -r requirements_developer.txt
python3 -m pip install -r requirements_developer.txt
```


Regularly check and upgrade to the latest available version:

```bash
Expand Down
159 changes: 150 additions & 9 deletions src/launch_common.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,51 @@
import os
import sys
import pkg_resources
import subprocess

from time import sleep
from datetime import date

from log_config import main_logger
from Constants import (
PYTHON_MAJOR,
PYTHON_MINOR,
LINER,
NEW_PROTOCOL_DATE,
NEW_PROTOCOL_NAME,
REQUIREMENTS_FILE_PATH,
)
from util.parser import build_parser
from util.args_validator import validate


logger = main_logger
def python_version_ok(args=None):
print("Checking python version ...\n")
major = sys.version_info.major
minor = sys.version_info.minor
if not (
major >= PYTHON_MAJOR
and minor >= PYTHON_MINOR
):
raise Exception(
"... must be using Python {}.{} or later but it installed is {}.{}. Please upgrade!\n".format(
PYTHON_MAJOR,
PYTHON_MINOR,
major,
minor,
)
)
else:
print(
"... installed Python version {}.{} is greater then minimum required version {}.{}. OK!\n".format(
major,
minor,
PYTHON_MAJOR,
PYTHON_MINOR,
)
)
return True


def print_banner(args, script_name):
print(LINER, flush=True)
with open("./banner.txt", "rt") as file:
print(file.read())
print(LINER, flush=True)
Expand All @@ -25,8 +59,115 @@ def print_banner(args, script_name):
print("Tezos Reward Distributor (TRD)" + script_name + " is Starting")


def parse_arguments(args=None):
parser = build_parser()
# Basic validations
args = validate(parser)
return args
def renamed_fee_ini(args=None):
if os.path.isfile("fee.ini"):
print(
"File fee.ini is deprecated. You can change the values at src/pay/batch_payer.py."
)
print("File fee.ini is renamed to fee.ini.old?")
try:
os.rename("fee.ini", "fee.ini.old")
print("File fee.ini has been renamed to fee.ini.old")
except:
print("Failed: File fee.ini needs to be manually deleted or renamed")
return False
return True


def new_protocol_not_live(args=None):
print("Checking ...\n")
today = date.today()
print(("... current date: {}\n").format(today))
print(("... new protocol date: {}\n").format(NEW_PROTOCOL_DATE))
if today >= NEW_PROTOCOL_DATE:
print(
(
"Protocol {} could be live now. If it is live there are risks using this branch.\n"
"It is suggested to reach out to the community to confirm, and switch to the new test branch \n"
"or accept of the risks of using this branch".format(NEW_PROTOCOL_NAME)
)
)
print("Do you want to continue using this branch? (y/N)")
value = input().lower()
if not value or value == "n":
return False
else:
print(("... protocol {} not live yet. OK!").format(NEW_PROTOCOL_NAME))
return True


def in_venv():
return sys.prefix != sys.base_prefix


def installed(package):
"""
The error status is 0. (bool(0) == False)
The success status is 1. (bool(1) == True)
"""
try:
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
return True
except:
return False

# if hasattr(pip, "main"):
# status_code = pip.main(["install", package])
# else:
# status_code = pip._internal.main(["install", package])
# return not bool(status_code)


def requirements_installed(requirement_path=REQUIREMENTS_FILE_PATH):
if not in_venv():
print(
"Please make sure to activate a virtual environment for python due to breaking changes in Ubutu >= 23.XX:\n"
"https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ \n"
)
return False

print("Checking installed packages ...\n")
missing_requirements = []
try:
with open(requirement_path, "r") as requirements:
for requirement in requirements:
try:
pkg_resources.require(requirement)
except Exception as e:
requirement = requirement.replace("\n", "")
missing_requirements.append(requirement)
print(
"... requirement {} was not found: {}\n".format(requirement, e)
)
if len(missing_requirements) > 0:
print("Would you like to install missing requirements? (Y/n)")
value = input().lower()
if not value or value == "y":
success = True
for r in missing_requirements:
success = success and installed(r)
if not success:
print("Could not install missing packages: {}\n".format(r))
break

if value == "n" or not success:
print(
"Please make sure to install all the required packages from 'requirements.txt' before using the TRD:\n"
"https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ \n"
)
return False
else:
print("Requirements successfully installed!\n")
return True
else:
print("... all dependencies available. OK!\n")
return True
except (OSError, IOError) as e:
print(
"Error opening requirements.txt: {}\n"
"Please make sure to install all the required packages from 'requirements.txt' before using the TRD:\n"
"https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/ \n".format(
e
)
)
return False
148 changes: 16 additions & 132 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,147 +1,31 @@
import os
import sys
import pip
import pkg_resources
from datetime import date
from Constants import (
PYTHON_MAJOR,
PYTHON_MINOR,
REQUIREMENTS_FILE_PATH,
NEW_PROTOCOL_DATE,
NEW_PROTOCOL_NAME,
from launch_common import (
new_protocol_not_live,
requirements_installed,
renamed_fee_ini,
python_version_ok,
in_venv,
)


def installed(package):
"""
The error status is 0. (bool(0) == False)
The success status is 1. (bool(1) == True)
"""
if hasattr(pip, "main"):
status_code = pip.main(["install", package])
else:
status_code = pip._internal.main(["install", package])
return not bool(status_code)


def requirements_installed(requirement_path=REQUIREMENTS_FILE_PATH):
print("Checking installed packages ...\n")
missing_requirements = []
try:
with open(requirement_path, "r") as requirements:
for requirement in requirements:
try:
pkg_resources.require(requirement)
except Exception as e:
requirement = requirement.replace("\n", "")
missing_requirements.append(requirement)
print(
"... requirement {} was not found: {}\n".format(requirement, e)
)
if len(missing_requirements) > 0:
print("Would you like to install missing requirements? (y/n)")
value = input().lower()
if value == "y":
success = True
for r in missing_requirements:
success = success and installed(r)
if success:
print("Success: Please restart TRD!\n")
else:
print("Error: Could not install missing packages!\n")

if value != "y" or not success:
print(
"Please make sure to install all the required packages before using the TRD.\n"
"To install the requirements: 'pip3 install -r requirements.txt'\n"
)
return False
else:
print("... all dependencies available!\n")
return True
except (OSError, IOError) as e:
print(
"Error opening requirements.txt: {}\n"
"Please make sure to install all the required packages before using the TRD.\n"
"To install the requirements: 'pip3 install -r requirements.txt'\n".format(
e
)
)
return False


def check_fee_ini(args=None):
# Check if the fee.ini configuration file is still present and, if so,
# warn the user that the file has to be removed or renamed
if os.path.isfile("fee.ini"):
print(
"File fee.ini is deprecated. You can change the values at src/pay/batch_payer.py."
)
print("Would you like to rename fee.ini to fee.ini.old? (y/n)")
value = input().lower()
if value == "yes" or value == "y":
os.rename("fee.ini", "fee.ini.old")
print("File fee.ini has been renamed to fee.ini.old")
else:
print("File fee.ini needs to be manually deleted or renamed")
return 1


def new_protocol_live(args=None):
today = date.today()
print(("Current date: {}").format(today))
print(("TRD sunset date: {}").format(NEW_PROTOCOL_DATE))
if today >= NEW_PROTOCOL_DATE:
print(
(
"Protocol {} could be live now. If it is live there are risks using this branch.\n"
"It is suggested to reach out to the community to confirm, and switch to the new test branch \n"
"or be accept of the risks of using this branch".format(
NEW_PROTOCOL_NAME
)
)
)
print("Do you want to continue using this branch? (y/n) Default is n")
value = input().lower()
if not value:
value = "n"
if value == "y" or value == "Yes":
return False
if value == "n" or value == "No":
return True
else:
new_protocol_live()
return False


def start_application(args=None):
if new_protocol_live():
return 1
check_fee_ini()

# Requirements need to be checked outside of the state machine
# because the library transitions could not be present
if requirements_installed():
ready = (
python_version_ok()
and requirements_installed()
and renamed_fee_ini()
and new_protocol_not_live()
)

if ready:
from util.process_life_cycle import ProcessLifeCycle

life_cycle = ProcessLifeCycle(args)
life_cycle.start()
return 0
return 1
else:
return 1


if __name__ == "__main__":
# Check the python version
if not (
sys.version_info.major >= PYTHON_MAJOR
and sys.version_info.minor >= PYTHON_MINOR
):
raise Exception(
"Must be using Python {}.{} or later but it is {}.{}".format(
PYTHON_MAJOR,
PYTHON_MINOR,
sys.version_info.major,
sys.version_info.minor,
)
)
start_application()
Loading
Loading