- Download the latest Python version (3.9.6 when this was written)
- Update pip using:
pip install --user --upgrade pip
- Run the following command to create a virtual environment
virtualenv -p python3 venv
- To open the virtualenv, use the appropriate command among the followings, depending on the shell:
- PowerShell:
.\venv\Scripts\activate.ps1
- bash:
/venv/bin/activate
- PowerShell:
- Once in the virtualenv, install the application's requirements using:
pip install -r requirements.txt
You should always activate the virtual env; everything written here assumes that you have activated it
Now that the bot has been installed, you must create a config.py file in the lot_bot directory, copying the sample_config.py.
In the config.py file, add all the values to the variables marked with "TBA" (To Be Added). They are all set to None
, so the bot won't work if you don't set them first.
LoTBot has three different environments:
- Development: the default environment, used when developing the application. Everything should be as local as possible and should not rely on external parts.
- Testing: the environment in which tests (both unit and integration) are run. More on those two in the Testing section.
- Production: the environment in which the bot is run once it is deployed.
To run the bot locally, simply run:
py .\main.py
git branch <local branch name>
to create a new local branchgit checkout <local branch name>
to move on the new local branch- create commits with the new code on the newly created branch
git remote add <remote branch name> https://github.com/LeoCal4/LoTBot.git
to create a new remote branchgit push --set-upstream <remote branch name> <local branch name>
to connect the local branch to the remote one- now you can push your commits to the remote branch
- once you have done your work on the branch, create a pull request on GitHub and solve the eventual conflicts
- you can then delete the branch directly on GitHub
git branch -d <local branch name>
to remove the useless local branchgit fetch --prune
to remove references to useless remote branches (they won't show up anymore withgit branch -a
)
-
git branch
: lists local branches -
git branch -a
: lists remote branches -
git branch -m <new branch name>
: renames the current branch -
git branch -d
: deletes the current branch (if it has no uncommited changes) -
git push origin --delete remote_branch_name
: deletes the remote branch -
git branch local_branch_name
: creates a local branch with the specified name -
git remote add remote_branch_name repository_link
: creates a new remote branch on the repo -
git checkout branch_name
: switches to the specified (local or remote) branch -
git push <remote_branch_name> local_branch_name~
: pushes the local branch to the remote one -
git fetch --all
: fetches the contents of the remote branches -
git checkout -b local_branch_name2 local_branch_name1
: creates a new branch based on local_branch_name2 -
git fetch --prune
: deletes useless branches (for example after merging them)
LoTBot has three main components, that are initialized in the main entry point of the application and that are shared among different modules:
- config: an object containing constant data, which varies among the different environments. It must be the first to be initialized.
- logger: the object used to log information across the modules. It must be initialized after config and before mongo, as it depends on settings specified in congif.
- mongo: the object representing the database, it must be initialized after the previous two, as it depends on both of them, and must be used only from the managers in DAO.
In the virtualenv, install the desired package using:
pip install <package_name>
Once you have installed it, run:
pip freeze > requirements.txt
to add the new package in the requirements file.
https://docs.python.org/3/howto/logging.html
The logger can be used instead of normal prints, since they either appear on the console or they can be redirected to actual log files if needed.
They implicitely define the following levels of information:
- debug info:
logger.debug("...)
- normal event:
logger.info("...")
- warning:
logger.warning("...")
- error or exception:
logger.error("...")
As of now, the DEBUG level is set only when in development; for all the other envs
it is set to INFO (this means that all the info reported using logger.debug()
will be seen only in development).
As it stands now, to deploy the application in production, you must define the ENV enviromental variable and set it to "dotenv", in order to read the .env file that will be placed on the server and load the right env vars.
There are three different database settings, one for each environment:
- Development: a local db can be used. In order to do so, Mongo must be installed on the local machine (alternatively, you can use the integration test db)
- Testing:
- Unit Tests: a mock database is used, everything is automatically set up at the start of the tests
- Integration Tests: a remote test db hosted on cloud.mongo is used
- Production: the actual production remote db hosted on cloud.mongo is used
The following coding conventions should be maintained during the development of the bot:
-
use snake_case for variables and modules (file names)
-
use UpperCamelCase for classes
-
when importing a local module, import it directly
from lot_bot import module [as ...]
instead of importing single functions or variables
from lot_bot.module import function/variable
This ensures that the code is more readable and that any change on the module is reflected on all the other modules importing it (this is the case of the three base modules of the application: config.py, logger.py, database.py, which ideally should be modified only by the main entry point of the bot, which as of now is main.py)
-
there is no convention when importing external modules (libraries)
-
all of the operation involving the database must be implemented in a DAO, in the appropriate manager. For example: all the methods involving users operations can be found in lot_bot/dao/user_manager.py
-
use models/sports.py/sports_container and models/strategies.py/strategies_container to access sports and strategies.
- specifically, use
get_sport/strategy_from_string(sport/strategy_string)
to obtain the correct object
- specifically, use
Ideally, every function of the codebase should have its own tests, which inspect the correctness of said function in normal and extreme cases.
To run all the tests, simply run the following command
pytest
You can also run unit and integration tests separately:
pytest .\tests\unit
pytest .\tests\integration
This kind of tests only check for the correctness of single functions in an isolate environment. To do so, mocks (fake objects/results) are employed in order to mimic external parts, such as databases.
Integration tests are used to test the bot using external parts, which are as similiar as possible to the real ones, used in production.
To do so, a test bot has been created in Telegram's test servers and a test db has been created on cloud.mongo.
The code in conftests.py
takes care of running the bot automatically, at the beginning of the tests.
There are tests which require to have a client which is the admin of one of the sport test channels.
Integration tests involving said channels won't work if you have not performed the following steps yet.
To create an admin for the channel, choose a phone number among the
available ones (those with pattern 99966<dc_id><4 random digits>) and run the following lines of code to have that
account join the channel:
from telethon.tl.functions.channels import JoinChannelRequest
await channel_admin_client(JoinChannelRequest(channel))
where channel_admin_client
is the client and channel
is the id of the channel.
Once the client is part of the channel, you have to manually make it an admin.
All the information regarding where are tests found and the implicit command line arguments for the pytest
command can be found in the pytest.ini file.