From 6f547f93916299a0918804f89a84e18887e680aa Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 21:46:13 +0100 Subject: [PATCH 01/24] Reorganizar los ficheros y ajustar los import --- fabfile.py | 11 ----------- bot.py => pydeckard/bot.py | 0 config.py => pydeckard/config.py | 0 utils.py => pydeckard/utils.py | 2 +- run.sh | 6 ------ 5 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 fabfile.py rename bot.py => pydeckard/bot.py (100%) rename config.py => pydeckard/config.py (100%) rename utils.py => pydeckard/utils.py (99%) delete mode 100755 run.sh diff --git a/fabfile.py b/fabfile.py deleted file mode 100644 index 92c8966..0000000 --- a/fabfile.py +++ /dev/null @@ -1,11 +0,0 @@ -from fabric.api import env, local, cd, run - -env.hosts = ["pythoncanarias.es"] - - -def deploy(): - local("git push") - with cd("~/pydeckard"): - run("git pull") - run("pipenv install") - run("supervisorctl restart pydeckard") diff --git a/bot.py b/pydeckard/bot.py similarity index 100% rename from bot.py rename to pydeckard/bot.py diff --git a/config.py b/pydeckard/config.py similarity index 100% rename from config.py rename to pydeckard/config.py diff --git a/utils.py b/pydeckard/utils.py similarity index 99% rename from utils.py rename to pydeckard/utils.py index d0c8e4f..84e80ca 100644 --- a/utils.py +++ b/pydeckard/utils.py @@ -5,7 +5,7 @@ from typing import Tuple, Optional, NamedTuple from telegram import User -import config +from pydeckard import config def is_chinese(c): diff --git a/run.sh b/run.sh deleted file mode 100755 index 144be68..0000000 --- a/run.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -# Master script. - -cd "$(dirname "$0")" -source ~/.pyenv/versions/3.12.4/envs/pydeckard/bin/activate -exec python bot.py From b15e46381e388a3bb25a832ebc083a8233386770 Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 21:47:11 +0100 Subject: [PATCH 02/24] Ajustar los import de los test --- pydeckard/bot.py | 4 ++-- test/test_bot_detection.py | 2 +- test/test_replies.py | 3 +-- test/test_utils.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pydeckard/bot.py b/pydeckard/bot.py index 4f6a433..27f5a8b 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -13,8 +13,8 @@ from telegram.ext import ApplicationBuilder, filters, MessageHandler, CommandHandler, ContextTypes from telegram.constants import ParseMode -import config -import utils +from pydeckard import config +from pydeckard import utils class DeckardBot(): diff --git a/test/test_bot_detection.py b/test/test_bot_detection.py index b74cd12..51f35c0 100644 --- a/test/test_bot_detection.py +++ b/test/test_bot_detection.py @@ -1,6 +1,6 @@ from unittest.mock import Mock import pytest -import utils +from pydeckard import utils # testing is_chinese diff --git a/test/test_replies.py b/test/test_replies.py index e893a7a..2868b3d 100644 --- a/test/test_replies.py +++ b/test/test_replies.py @@ -1,7 +1,6 @@ import pytest -import config -import utils +from pydeckard import config, utils @pytest.fixture() diff --git a/test/test_utils.py b/test/test_utils.py index 54d7450..fcf4b33 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -6,7 +6,7 @@ import pytest from freezegun import freeze_time -import utils +from pydeckard import utils @freeze_time("2019-05-16 13:35:16") From e504a0b7fce55bf6ac1d29cd6c2d57379799d484 Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 21:49:36 +0100 Subject: [PATCH 03/24] Ajustar .gitignore --- .gitignore | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 88aec55..5116c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,3 @@ -*.pyc -pycache -myconfig.py -virtualenv -.idea -.vscode -.DS_Store +.atico/ .env -.pytest_cache -.python-version bot.log From 413d3e69ddccf2d244ded6d023137146ffda53c6 Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 21:51:04 +0100 Subject: [PATCH 04/24] Actualizar .travis.yml --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 964d029..33cb284 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,10 @@ dist: bionic language: python python: - - 3.6 - - 3.7 + - "3.9" + - "3.10" + - "3.11" + - "3.12" install: - pip install pipenv - pipenv install -d From 50fdfb10361518de85a0ad2c8a27469f62ed2cc6 Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 21:53:56 +0100 Subject: [PATCH 05/24] Rehacer y actualizar pyproject.toml --- pyproject.toml | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ecba4b1..18000fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,43 @@ +[build-system] +requires = ['setuptools>=61.0'] +build-backend = 'setuptools.build_meta' + +[project] +name = 'pydeckard' +description = 'Un bot de Telegram para el canal de Python Canarias' +requires-python = '>=3.10' +authors = [ + { name = 'Python Canarias', email = 'info@pythoncanarias.es' }, +] +classifiers = [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Operating System :: OS Independent", + "Intended Audience :: Developers", + "Topic :: Communications :: Chat", +] +license = "GPL-3.0-or-later" +license-files = ["LICENSE"] +dynamic = ['dependencies', 'readme'] +version="0.1.0" + +[project.urls] +Homepage = "https://github.com/pythoncanarias/pydeckard.git" + +[tool.setuptools.dynamic] +readme = { file = ['README.md', ] } +dependencies = { file = 'requirements.txt' } + +[tool.setuptools.dynamic.optional-dependencies] +dev = { file = ["dev-requirements.txt"] } + +[tool.setuptools.packages.find] +include = ["pydeckard*"] +where = ["."] + +[project.scripts] +bot = "pydeckard.bot:main" + [tool.ruff] line-length = 120 target-version = "py312" - From 2ce109fab8e38bfc2e5ba99eae99f08f1c13cc8d Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 23:20:16 +0100 Subject: [PATCH 06/24] Actualizar README.md --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b5dc7da..c574d2b 100644 --- a/README.md +++ b/README.md @@ -9,19 +9,23 @@ Telegram Bot made in Python to automate different tasks of [Python Canarias](htt ## Installation -Create a virtualenv for Python3 and install dependencies. In this -example we are using pyenv: +Create a virtualenv for Python3 and install dependencies. ~~~console -$ pyenv virtualenv 3.12.4 pydeckard -$ pyenv activate pydeckard -$ pip install -r requirements.txt +$ python3 -m venv /path/to/new/virtual/environment +$ cd /path/to/new/virtual/environment +$ source ./bin/activate +$ ./bin/pip3 install git+https://github.com/pythoncanarias/pydeckard.git ~~~ -A developer needs to install a few more packages: +As a developer, you must install it in this other way: ~~~console -$ pip install -r dev-requirements.txt +$ git clone https://github.com/pythoncanarias/pydeckard.git +cd pydeckard +$ python3 -m venv venv +$ source ./venv/bin/activate +$ pip3 install -e .[dev] ~~~ Next step is to set your bot token for development: From 3058685d0ead66cc16c411f9e3d8aaaa3a17bb01 Mon Sep 17 00:00:00 2001 From: misanram Date: Sat, 18 Apr 2026 23:37:19 +0100 Subject: [PATCH 07/24] Se crea la funcion main en bot.py para arrancar el bot. --- README.md | 4 ++-- pydeckard/bot.py | 10 +++++++++- pyproject.toml | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c574d2b..fe33df8 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Telegram Bot made in Python to automate different tasks of [Python Canarias](htt ## Installation -Create a virtualenv for Python3 and install dependencies. +Create a virtualenv for Python3 and install bot. ~~~console $ python3 -m venv /path/to/new/virtual/environment @@ -22,7 +22,7 @@ As a developer, you must install it in this other way: ~~~console $ git clone https://github.com/pythoncanarias/pydeckard.git -cd pydeckard +$ cd pydeckard $ python3 -m venv venv $ source ./venv/bin/activate $ pip3 install -e .[dev] diff --git a/pydeckard/bot.py b/pydeckard/bot.py index 27f5a8b..9190afc 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -188,6 +188,14 @@ def run(self): application.run_polling(poll_interval=config.POLL_INTERVAL) -if __name__ == "__main__": +def main(): + """ + Arranca el bot + """ + bot = DeckardBot() bot.run() + + +if __name__ == "__main__": + main() diff --git a/pyproject.toml b/pyproject.toml index 18000fd..221cb16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ ] license = "GPL-3.0-or-later" license-files = ["LICENSE"] -dynamic = ['dependencies', 'readme'] +dynamic = ['dependencies', 'readme', 'optional-dependencies'] version="0.1.0" [project.urls] From 36b8486d55e7cb25522bfe839fe9e95eadc7a608 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 00:12:20 +0100 Subject: [PATCH 08/24] =?UTF-8?q?M=C3=ADnimos=20ajustes=20en=20el=20README?= =?UTF-8?q?.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fe33df8..b60ff94 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,8 @@ $ source ./venv/bin/activate $ pip3 install -e .[dev] ~~~ -Next step is to set your bot token for development: +Next step is to set your bot token for development. +In the same directory where bot.py lives, you must create the .env file using the following command: ~~~console $ echo 'TELEGRAM_BOT_TOKEN = ""' > .env @@ -37,13 +38,13 @@ $ echo 'TELEGRAM_BOT_TOKEN = ""' > .env Now you can launch the bot with: ~~~console -$ python bot.py +$ python3 bot.py ~~~ You can use the flag `--verbose` (or `-v') to get more information in rhe console: ~~~console -$ python bot.py --verbose +$ python3 bot.py --verbose ~~~ @@ -52,5 +53,5 @@ $ python bot.py --verbose Use pytest: ~~~console -$ python -m pytest +$ python3 -m pytest ~~~ From 635a9a7ff4851c0a43408e25a73bb05279a566d8 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 00:44:29 +0100 Subject: [PATCH 09/24] =?UTF-8?q?Correcci=C3=B3n=20en=20constate=20REPLIES?= =?UTF-8?q?=20para=20c++?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydeckard/config.py b/pydeckard/config.py index e8f3ced..e59ab2e 100644 --- a/pydeckard/config.py +++ b/pydeckard/config.py @@ -103,7 +103,7 @@ def bot_replies_enabled() -> bool: ("elixir",): "BIBA ELICSÍR!! ¥", ("cobol",): "BIBA KOBOL!! 💾", ("fortran",): "BIBA FORRRTRÁN!! √", - ("c\+\+",): "BIBA CEMASMÁS!! ⊕", + ("c++",): "BIBA CEMASMÁS!! ⊕", ("javascript",): "BIBA JABAESCRIP!! 🔮", ("php",): "BIBA PEACHEPÉ!.! ⛱", ("perl",): "BIBA PERRRRRL! 🐫", From c9963d70969e7a5a451f3a411bdba77806837a5e Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 01:06:04 +0100 Subject: [PATCH 10/24] =?UTF-8?q?Correcci=C3=B3n=20en=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b60ff94..db8bf10 100644 --- a/README.md +++ b/README.md @@ -28,8 +28,8 @@ $ source ./venv/bin/activate $ pip3 install -e .[dev] ~~~ -Next step is to set your bot token for development. -In the same directory where bot.py lives, you must create the .env file using the following command: +Next step is to set your bot token. +In the virtual environment's working directory, you must create the .env file using the following command: ~~~console $ echo 'TELEGRAM_BOT_TOKEN = ""' > .env From 94d57ef5c6dc055a959ab8bde235da6bb2e3ee8b Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 01:13:17 +0100 Subject: [PATCH 11/24] =?UTF-8?q?Se=20crea=20fichero=20=5F=5Finit=5F=5F.py?= =?UTF-8?q?=20para=20m=C3=B3dulo=20pydeckard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 pydeckard/__init__.py diff --git a/pydeckard/__init__.py b/pydeckard/__init__.py new file mode 100644 index 0000000..e69de29 From 8a8157621691d5d824de521fa9acc7669a029737 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 01:17:12 +0100 Subject: [PATCH 12/24] =?UTF-8?q?Correcci=C3=B3n=20en=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db8bf10..e119bfa 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ $ source ./venv/bin/activate $ pip3 install -e .[dev] ~~~ -Next step is to set your bot token. +After installation, the next step is to set your bot token. In the virtual environment's working directory, you must create the .env file using the following command: ~~~console From edd8b65ab6bcfd86509d57f88d171f51fd832bb4 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 09:37:21 +0100 Subject: [PATCH 13/24] =?UTF-8?q?Se=20a=C3=B1ade=20la=20opci=C3=B3n=20setu?= =?UTF-8?q?p=20a=20bot.py,=20y=20se=20crean=20las=20funciones=20setup=5Fbo?= =?UTF-8?q?t=20y=20validate=5Finput=20en=20el=20utils.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/bot.py | 3 + pydeckard/utils.py | 160 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/pydeckard/bot.py b/pydeckard/bot.py index 9190afc..2265087 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -32,8 +32,11 @@ def get_options(self): epilog='Text at the bottom of help', ) parser.add_argument('-v', '--verbose', action='store_true') + parser.add_argument('--setup', action='store_true', help='Start the setup wizard') args = parser.parse_args() self.verbose = args.verbose + if args.setup: + utils.setup_bot() def set_logger(self): self.logger = logging.getLogger('bot') diff --git a/pydeckard/utils.py b/pydeckard/utils.py index 84e80ca..d2f7350 100644 --- a/pydeckard/utils.py +++ b/pydeckard/utils.py @@ -1,7 +1,12 @@ import functools import datetime +import grp +import platform +import pwd import random import re +import sys +from pathlib import Path from typing import Tuple, Optional, NamedTuple from telegram import User @@ -126,3 +131,158 @@ def since(reference) -> str: seconds %= 60 buff.append(f"{seconds} {pluralise(seconds, 'second')}") return " ".join(buff) + + +def validate_input(prompt_head, acceptable=None, typus=None): + """ + This function is designed to capture the parameters that will be used to configure the bot. + It captures input and validates the data obtained. + Steps: + Create a text string to use as a prompt. + Request the input. + Validate the received data. + Return the validated data or None. + Parameter capture can be interrupted with Ctrl+C + + Arguments + prompt_head (str): Start of the message to be displayed to the user. + acceptable (list/tuple, optional): Whitelist of values or range (min, max). + typus (callable): Data type to convert the input to. + + Return + The data validated and converted to type 'typus' or None + """ + + prompt_tail = '' + + if isinstance(acceptable, list): + prompt_tail = f" ({'/'.join(map(str, acceptable))})" + elif isinstance(acceptable, tuple): + prompt_tail = f' ({acceptable[0]}-{acceptable[1]})' + + prompt = f'{prompt_head}{prompt_tail}: ' + + while True: + try: + data = input(prompt).strip() + except KeyboardInterrupt: + raise + + if not (data and callable(typus)): + return None + + try: + if typus is int: + data = int(data, 0) + elif typus is str and acceptable and all(x.isupper() for x in acceptable): + data = data.upper() + elif typus is str or typus is float: + data = typus(data) + else: + return None + except ValueError: + print(f'El valor debe ser de tipo {typus.__name__}') + continue + + if isinstance(acceptable, list) and data not in acceptable: + print(f'El valor debe ser una de estas opciones: {'/'.join(map(str, acceptable))}') + continue + + if isinstance(acceptable, tuple): + if not (acceptable[0] <= data <= acceptable[1]): + print(f'El valor debe estar entre {acceptable[0]} y {acceptable[1]}.') + continue + + return data + + +def setup_bot(): + """ + A wizard starts to configure the bot and create an automatic startup system based on the operating system. + It performs an input for each required configuration parameter. + The "parameters" list contains all the defined parameters, each as a tuple of four elements: + parameter name, + prompt for input, + a tuple with two values to indicate a range of allowed values OR a list with values to indicate the + different allowed options OR None, + a class to cast the value to the allowed type + """ + + root_path = Path(sys.prefix) + bin_path = Path(sys.executable).parent + bot_executable = bin_path / 'bot' + env_path = root_path / '.env' + system_name = platform.system() + + print(f'\n--- Asistente de configuración para PyDeckard (SO: {system_name}) ---\n\n') + + parameters = [('TELEGRAM_BOT_TOKEN', 'Introduzca el Token del Bot', None, str), + ('VERBOSITY', 'Nivel de verbosidad', (0.0, 1.0), float), + ('LOG_LEVEL', 'Nivel de registro de logs', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str), + ('POLL_INTERVAL', 'Intervalo de polling para la API de Telegram', (1, 10), int), + ('BOT_GREETING', 'Saludo del bot', None, str), + ('MAX_HUMAN_USERNAME_LENGTH', 'Longitud máxima del username', None, int), + ('MAX_CHINESE_CHARS_PERCENT', 'Máximo porcentaje de caracteres chinos en username', + (0.0, 1.0), float), + ('WELCOME_DELAY', 'Tiempo de retardo para la bienvenida (seg)', None, int), ] + + try: + items_env = {key: validate_input(*args) for key, *args in parameters} + except KeyboardInterrupt: + print('Asistente cancelado por el usuario.') + sys.exit(1) + + with open(env_path, 'w') as fout: + lines = [f'{key}={value}\n' for key, value in items_env.items() if value] + fout.writelines(lines) + + print(f'\n\nArchivo .env creado en {root_path}') + + if system_name == 'Linux': + stat_info = root_path.stat() + + user_name = pwd.getpwuid(stat_info.st_uid).pw_name + group_name = grp.getgrgid(stat_info.st_gid).gr_name + + service_path = root_path / 'pydeckard.service' + + service_content = f"""[Unit] + Description=PyDeckard + After=network.target + + [Service] + Type=simple + User={user_name} + Group={group_name} + WorkingDirectory={root_path} + ExecStart={bot_executable} + Environment=PYTHONUNBUFFERED=1 + Restart=always + + [Install] + WantedBy=multi-user.target + Alias=PyDeckard.service + """ + + with open(service_path, 'w') as f: + f.write(service_content) + + print(f'\nArchivo pydeckard.service creado en {root_path}') + print(f'\nsudo cp {service_path} /etc/systemd/system/') + print('sudo systemctl daemon-reload') + print('sudo systemctl enable --now pydeckard') + + sys.exit(0) + + elif system_name == 'Darwin': + print('Entorno macOS detectado, configuración realizada, pregúntele a Apple® como arrancarlo.') + sys.exit(1) + + elif system_name == 'Windows': + print('Entorno Windows detectado, configuración realizada, pregúntele a Microsoft® como arrancarlo.') + sys.exit(1) + + elif system_name == 'Java': + print('Entorno Jython detectado. Usted mismo.') + sys.exit(1) + From 27bc70d3db0c0059cffa3844ed455a4159a61f8f Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:03:00 +0100 Subject: [PATCH 14/24] Se documento el proceso de setup en README.md --- pydeckard.service | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 pydeckard.service diff --git a/pydeckard.service b/pydeckard.service deleted file mode 100644 index 50a6d5c..0000000 --- a/pydeckard.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=PyDeckard - -[Service] -Restart=always -WorkingDirectory=/home/jileon/pydeckard/ -ExecStart=/home/jileon/.pyenv/versions/3.12.4/envs/pydeckard/bin/python bot.py - -[Install] -WantedBy=multi-user.target -Alias=PyDeckard.service From 9804bfede063642d0083c41de55acbe774e16518 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:03:55 +0100 Subject: [PATCH 15/24] Se documento el proceso de setup en README.md --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e119bfa..6b06ba6 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,14 @@ $ source ./venv/bin/activate $ pip3 install -e .[dev] ~~~ -After installation, the next step is to set your bot token. -In the virtual environment's working directory, you must create the .env file using the following command: +After installation, the next step is to create the .env configuration file and the file for automatic program +startup. +During the process, you will be asked to enter your Telegram token and will be prompted with other +configuration-related questions. The only required item is the Telegram token. +To do this, run: ~~~console -$ echo 'TELEGRAM_BOT_TOKEN = ""' > .env +$ python3 --setup ~~~ Now you can launch the bot with: From d84c64ee3a3aeb6469249b6db93290a4e8b9fc55 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:16:12 +0100 Subject: [PATCH 16/24] =?UTF-8?q?Se=20elimina=20el=20logueo=20en=20archivo?= =?UTF-8?q?=20y=20la=20opci=C3=B3n=20verbose,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +----- pydeckard/bot.py | 11 ++--------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 6b06ba6..42ec5f2 100644 --- a/README.md +++ b/README.md @@ -38,17 +38,13 @@ To do this, run: $ python3 --setup ~~~ + Now you can launch the bot with: ~~~console $ python3 bot.py ~~~ -You can use the flag `--verbose` (or `-v') to get more information in rhe console: - -~~~console -$ python3 bot.py --verbose -~~~ ## Tests diff --git a/pydeckard/bot.py b/pydeckard/bot.py index 2265087..ab6781d 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -22,7 +22,6 @@ class DeckardBot(): def __init__(self): self.get_options() self.set_logger() - self.verbose = False self.started_at = DateTime.now() def get_options(self): @@ -31,25 +30,19 @@ def get_options(self): description='PyDeckard Bot', epilog='Text at the bottom of help', ) - parser.add_argument('-v', '--verbose', action='store_true') parser.add_argument('--setup', action='store_true', help='Start the setup wizard') args = parser.parse_args() - self.verbose = args.verbose if args.setup: utils.setup_bot() def set_logger(self): self.logger = logging.getLogger('bot') - file_handler = RotatingFileHandler('bot.log', maxBytes=1_000_000, backupCount=5) - console_handler = logging.NullHandler() - if self.verbose: - console_handler = logging.StreamHandler() - + console_handler = logging.StreamHandler() logging.basicConfig( level=logging.WARNING, # Pone el nivel de todos los logger a WARNING format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', - handlers=[file_handler,console_handler], + handlers=[console_handler], force=True ) From 42e47b84b746952ee5b0865a27c69b42b27e395f Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:30:12 +0100 Subject: [PATCH 17/24] =?UTF-8?q?Se=20crean=20los=20test=20para=20las=20nu?= =?UTF-8?q?evas=20funciones.=20Se=20completa=20la=20documentaci=C3=B3n=20e?= =?UTF-8?q?n=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + test/test_utils.py | 453 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 445 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 42ec5f2..d1c0110 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Now you can launch the bot with: $ python3 bot.py ~~~ +...or delegate the startup of the application to your operating system using the instructions that setup has provided. ## Tests diff --git a/test/test_utils.py b/test/test_utils.py index fcf4b33..9b656ce 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -6,55 +6,490 @@ import pytest from freezegun import freeze_time -from pydeckard import utils +from pydeckard.utils import validate_input, since @freeze_time("2019-05-16 13:35:16") def test_since_second(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "1 second" + assert since(ref) == "1 second" @freeze_time("2019-05-16 13:35:21") def test_since_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "6 seconds" + assert since(ref) == "6 seconds" @freeze_time("2019-05-16 13:36:21") def test_since_minute_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "1 minute 6 seconds" + assert since(ref) == "1 minute 6 seconds" @freeze_time("2019-05-16 13:37:21") def test_since_minutes_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "2 minutes 6 seconds" + assert since(ref) == "2 minutes 6 seconds" @freeze_time("2019-05-16 14:37:21") def test_since_hour_and_minutes_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "1 hour 2 minutes 6 seconds" + assert since(ref) == "1 hour 2 minutes 6 seconds" @freeze_time("2019-05-16 15:37:21") def test_since_hours_and_minutes_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "2 hours 2 minutes 6 seconds" + assert since(ref) == "2 hours 2 minutes 6 seconds" @freeze_time("2019-05-17 15:37:21") def test_since_day_hours_and_minutes_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "1 day 2 hours 2 minutes 6 seconds" + assert since(ref) == "1 day 2 hours 2 minutes 6 seconds" @freeze_time("2019-05-19 15:37:21") def test_since_days_hours_and_minutes_and_seconds(): ref = datetime.datetime(2019, 5, 16, 13, 35, 15) - assert utils.since(ref) == "3 days 2 hours 2 minutes 6 seconds" + assert since(ref) == "3 days 2 hours 2 minutes 6 seconds" + + +def test_tipo_none0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', None, None) is None + + +def test_tipo_none1(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', None, None) is None + + +def test_tipo_none2(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1.0') + + assert validate_input('Dato', None, None) is None + + +def test_tipo_none3(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: 'Texto') + + assert validate_input('Dato', None, None) is None + + +def test_tipo_texto0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', None, str) is None + + +def test_tipo_texto1(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', None, str) == '1' + + +def test_tipo_texto2(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1.0') + + assert validate_input('Dato', None, str) == '1.0' + + +def test_tipo_texto3(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: 'Texto') + + assert validate_input('Dato', None, str) == 'Texto' + + +def test_tipo_int0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', None, int) is None + + +def test_tipo_int1(monkeypatch): + # Decimal + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', None, int) == 1 + + +def test_tipo_int2(monkeypatch): + # Octal + monkeypatch.setattr('builtins.input', lambda _: '0o10') + + assert validate_input('Dato', None, int) == 8 + + +def test_tipo_int3(monkeypatch): + # Hexadecimal + monkeypatch.setattr('builtins.input', lambda _: '0xff') + + assert validate_input('Dato', None, int) == 255 + + +def test_tipo_int4(monkeypatch): + # Binario + monkeypatch.setattr('builtins.input', lambda _: '0b11') + + assert validate_input('Dato', None, int) == 3 + + +def test_tipo_int5(monkeypatch): + # Separador _ + monkeypatch.setattr('builtins.input', lambda _: '1_000_000') + + assert validate_input('Dato', None, int) == 1000000 + + +def test_tipo_int6(monkeypatch): + # Cero negativo + monkeypatch.setattr('builtins.input', lambda _: '-0') + + assert validate_input('Dato', None, int) == 0 + + +def test_tipo_int7(monkeypatch): + # Decimal con espacios + monkeypatch.setattr('builtins.input', lambda _: ' 10 ') + + assert validate_input('Dato', None, int) == 10 + + +def test_tipo_int8(monkeypatch): + # Hexadecimal con espacios + monkeypatch.setattr('builtins.input', lambda _: ' 0xff ') + + assert validate_input('Dato', None, int) == 255 + + +def test_tipo_int15(monkeypatch, capsys): + # Float + entradas = iter(['1.0', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', None, int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_tipo_int16(monkeypatch, capsys): + # Texto + entradas = iter(['Texto', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', None, int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_tipo_float0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', None, float) is None + + +def test_tipo_float1(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', None, float) == 1.0 + + +def test_tipo_float2(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '1.0') + + assert validate_input('Dato', None, float) == 1.0 + + +def test_tipo_float3(monkeypatch, capsys): + entradas = iter(['Texto', '1.0']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', None, float) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo float' in imprime + assert resultado == 1.0 + + +def test_tipo_float4(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '-0.0') + + assert validate_input('Dato', None, float) == -0.0 + + +def test_rango_tipo_int0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', (0, 1), int) is None + + +def test_rango_tipo_int1(monkeypatch): + # En rango entero + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', (0, 10), int) == 1 + + +def test_rango_tipo_int2(monkeypatch, capsys): + # Fuera de rango entero + entradas = iter(['20', '-2', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0, 10), int) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe estar entre 0 y 10' in imprime + assert resultado == 1 + + +def test_rango_tipo_int3(monkeypatch, capsys): + # En rango float + entradas = iter(['5.0', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0, 10), int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_rango_tipo_int4(monkeypatch, capsys): + # Fuera de rango float + entradas = iter(['20.0', '-1.0', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0, 10), int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_rango_tipo_int5(monkeypatch, capsys): + # Texto + entradas = iter(['texto', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0, 10), int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_rango_tipo_float0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', (0.0, 1.0), float) is None + + +def test_rango_tipo_float1(monkeypatch): + # En rango entero + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', (0.0, 1.0), float) == 1.0 + + +def test_rango_tipo_float2(monkeypatch, capsys): + # Fuera de rango entero + entradas = iter(['2', '-2','1.0']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0.0, 1.0), float) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe estar entre 0.0 y 1.0' in imprime + assert resultado == 1.0 + + +def test_rango_tipo_float3(monkeypatch): + # En rango float + monkeypatch.setattr('builtins.input', lambda _: '1.0') + + assert validate_input('Dato', (0.0, 1.0), float) == 1.0 + + +def test_rango_tipo_float4(monkeypatch, capsys): + # Fuera de rango float + entradas = iter(['2.0', '-1.0', '1.0']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0.0, 1.0), float) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe estar entre 0.0 y 1.0' in imprime + assert resultado == 1.0 + + +def test_rango_tipo_float5(monkeypatch, capsys): + # Texto + entradas = iter(['texto', '1.0']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', (0.0, 1.0), float) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo float' in imprime + assert resultado == 1.0 + + +def test_option_tipo_int0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', [-2, -1, 0, 1, 2, 3], int) is None + + +def test_option_tipo_int1(monkeypatch): + # En lista entero + monkeypatch.setattr('builtins.input', lambda _: '1') + + assert validate_input('Dato', [-2, -1, 0, 1, 2, 3], int) == 1 + + +def test_option_tipo_int2(monkeypatch, capsys): + # Fuera de lista entero + entradas = iter(['20', '-23', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', [-2, -1, 0, 1, 2, 3], int) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe ser una de estas opciones: -2/-1/0/1/2/3' in imprime + assert resultado == 1 + + +def test_option_tipo_int4(monkeypatch, capsys): + # Fuera de lista float + entradas = iter(['20.0', '-10.0', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', [-2, -1, 0, 1, 2, 3], int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_option_tipo_int5(monkeypatch, capsys): + # Texto + entradas = iter(['texto', '1']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', [-2, -1, 0, 1, 2, 3], int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado == 1 + + +def test_option_tipo_int6(monkeypatch, capsys): + # En lista vacia entero + entradas = iter(['texto', '']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', [], int) + imprime = capsys.readouterr().out + + assert 'El valor debe ser de tipo int' in imprime + assert resultado is None + + +def test_option_tipo_texto0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: '') + + assert validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) is None + + +def test_option_tipo_texto1(monkeypatch, capsys): + # Entero + entradas = iter(['20', 'DEBUG']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe ser una de estas opciones: DEBUG/INFO/WARNING/ERROR' in imprime + assert resultado == 'DEBUG' + + +def test_option_tipo_texto2(monkeypatch, capsys): + # float + entradas = iter(['20.0', 'DEBUG']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe ser una de estas opciones: DEBUG/INFO/WARNING/ERROR' in imprime + assert resultado == 'DEBUG' + + +def test_option_tipo_texto3(monkeypatch, capsys): + # Fuera de lista texto + entradas = iter(['HOLA', 'DEBUG']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe ser una de estas opciones: DEBUG/INFO/WARNING/ERROR' in imprime + assert resultado == 'DEBUG' + + +def test_option_tipo_texto4(monkeypatch): + # Texto + monkeypatch.setattr('builtins.input', lambda _: 'DEBUG') + + assert validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) == 'DEBUG' + + +def test_option_tipo_texto5(monkeypatch): + # Texto minúscula + monkeypatch.setattr('builtins.input', lambda _: 'debug') + + assert validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) == 'DEBUG' + + +def test_option_tipo_texto6(monkeypatch): + # Texto mezcla minúsculas + monkeypatch.setattr('builtins.input', lambda _: 'DebuG') + + assert validate_input('Dato', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str) == 'DEBUG' + + +def test_option_tipo_texto7(monkeypatch, capsys): + # En lista vacia texto + entradas = iter(['texto', '']) + monkeypatch.setattr("builtins.input", lambda _: next(entradas)) + + resultado = validate_input('Dato', [], str) + imprime = capsys.readouterr().out + + assert 'Error: El valor debe ser una de estas opciones: ' in imprime + assert resultado is None + + +def test_tipo_raro0(monkeypatch): + monkeypatch.setattr('builtins.input', lambda _: 'texto') + + assert validate_input('Dato', None, bool) is None + + +def test_tipo_raro1(monkeypatch): + # Tipo no callable + monkeypatch.setattr('builtins.input', lambda _: 'texto') + + assert validate_input('Dato', None, object()) is None if __name__ == "__main__": From 41825ab89f40da0e976166e461afa9ffbd987b39 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:40:14 +0100 Subject: [PATCH 18/24] =?UTF-8?q?Correcci=C3=B3n=20de=20errores=20en=20uti?= =?UTF-8?q?l.py=20y=20en=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- pydeckard/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d1c0110..a1d0e7d 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,10 @@ After installation, the next step is to create the .env configuration file and t startup. During the process, you will be asked to enter your Telegram token and will be prompted with other configuration-related questions. The only required item is the Telegram token. -To do this, run: +To do this, activate the virtual environment and run: ~~~console -$ python3 --setup +$ bot --setup ~~~ diff --git a/pydeckard/utils.py b/pydeckard/utils.py index d2f7350..01633c3 100644 --- a/pydeckard/utils.py +++ b/pydeckard/utils.py @@ -185,7 +185,7 @@ def validate_input(prompt_head, acceptable=None, typus=None): continue if isinstance(acceptable, list) and data not in acceptable: - print(f'El valor debe ser una de estas opciones: {'/'.join(map(str, acceptable))}') + print(f'El valor debe ser una de estas opciones: {"/".join(map(str, acceptable))}') continue if isinstance(acceptable, tuple): From 4d0fc9df49ce193caac705fdf3b3a8f20ad7e9ee Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:49:33 +0100 Subject: [PATCH 19/24] =?UTF-8?q?M=C3=ADnimos=20cambios=20enla=20funci?= =?UTF-8?q?=C3=B3n=20setup=5Fbot=20de=20utils.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/utils.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/pydeckard/utils.py b/pydeckard/utils.py index 01633c3..b37aa11 100644 --- a/pydeckard/utils.py +++ b/pydeckard/utils.py @@ -247,27 +247,30 @@ def setup_bot(): service_path = root_path / 'pydeckard.service' service_content = f"""[Unit] - Description=PyDeckard - After=network.target - - [Service] - Type=simple - User={user_name} - Group={group_name} - WorkingDirectory={root_path} - ExecStart={bot_executable} - Environment=PYTHONUNBUFFERED=1 - Restart=always - - [Install] - WantedBy=multi-user.target - Alias=PyDeckard.service - """ +Description=PyDeckard +After=network.target + +[Service] +Type=simple +User={user_name} +Group={group_name} +WorkingDirectory={root_path} +ExecStart={bot_executable} +Environment=PYTHONUNBUFFERED=1 +Restart=always + +[Install] +WantedBy=multi-user.target +Alias=PyDeckard.service +""" with open(service_path, 'w') as f: f.write(service_content) print(f'\nArchivo pydeckard.service creado en {root_path}') + + print(f'\nPara configurar, activar e iniciar el service en systemd ejecute los siguientes comandos:') + print(f'\nsudo cp {service_path} /etc/systemd/system/') print('sudo systemctl daemon-reload') print('sudo systemctl enable --now pydeckard') From 4aeacbe2b69e33ddde8278924f934381e8c0b644 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 10:52:46 +0100 Subject: [PATCH 20/24] =?UTF-8?q?M=C3=ADnimos=20ajuste=20=20en=20la=20func?= =?UTF-8?q?i=C3=B3n=20get=5Foptions=20de=20bot.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/bot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydeckard/bot.py b/pydeckard/bot.py index ab6781d..d28622d 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -28,7 +28,7 @@ def get_options(self): parser = argparse.ArgumentParser( prog='bot', description='PyDeckard Bot', - epilog='Text at the bottom of help', + epilog='', ) parser.add_argument('--setup', action='store_true', help='Start the setup wizard') args = parser.parse_args() From 4b0540d8be66a63fd62c1e367c3ec1642fa2f2ab Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 11:14:25 +0100 Subject: [PATCH 21/24] Se cambia el nombre del Entry Point y del logger a pydeckard. Se documentan los cambios en README.md --- README.md | 6 +++--- pydeckard/bot.py | 2 +- pyproject.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a1d0e7d..b320062 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,14 @@ configuration-related questions. The only required item is the Telegram token. To do this, activate the virtual environment and run: ~~~console -$ bot --setup +$ pydeckard --setup ~~~ -Now you can launch the bot with: +You can now launch the bot, activating the virtual environment and running:: ~~~console -$ python3 bot.py +$ pydeckard ~~~ ...or delegate the startup of the application to your operating system using the instructions that setup has provided. diff --git a/pydeckard/bot.py b/pydeckard/bot.py index d28622d..b4928e9 100644 --- a/pydeckard/bot.py +++ b/pydeckard/bot.py @@ -36,7 +36,7 @@ def get_options(self): utils.setup_bot() def set_logger(self): - self.logger = logging.getLogger('bot') + self.logger = logging.getLogger('pydeckard') console_handler = logging.StreamHandler() logging.basicConfig( diff --git a/pyproject.toml b/pyproject.toml index 221cb16..077a01e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ include = ["pydeckard*"] where = ["."] [project.scripts] -bot = "pydeckard.bot:main" +pydeckard = "pydeckard.bot:main" [tool.ruff] line-length = 120 From d453741f5e8ab3f828acc2d6f19a14c9c91852a4 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 11:50:50 +0100 Subject: [PATCH 22/24] =?UTF-8?q?Se=20cambia=20la=20funci=C3=B3n=20setup?= =?UTF-8?q?=5Fbot=20en=20utils=20para=20usar=20pydeckard=20como=20ejecutab?= =?UTF-8?q?le.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 - pydeckard/utils.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index b320062..e42ef8f 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,6 @@ To do this, activate the virtual environment and run: $ pydeckard --setup ~~~ - You can now launch the bot, activating the virtual environment and running:: ~~~console diff --git a/pydeckard/utils.py b/pydeckard/utils.py index b37aa11..8641da8 100644 --- a/pydeckard/utils.py +++ b/pydeckard/utils.py @@ -210,7 +210,7 @@ def setup_bot(): root_path = Path(sys.prefix) bin_path = Path(sys.executable).parent - bot_executable = bin_path / 'bot' + bot_executable = bin_path / 'pydeckard' env_path = root_path / '.env' system_name = platform.system() From 988c042ecfa72f778bd6430ee282d1e3bc660788 Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 11:56:35 +0100 Subject: [PATCH 23/24] =?UTF-8?q?Correcci=C3=B3n=20en=20nombre=20de=20clav?= =?UTF-8?q?e=20"BOT=5FVERBOSITY"=20en=20setup=5Fbot.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pydeckard/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydeckard/utils.py b/pydeckard/utils.py index 8641da8..ce97488 100644 --- a/pydeckard/utils.py +++ b/pydeckard/utils.py @@ -217,7 +217,7 @@ def setup_bot(): print(f'\n--- Asistente de configuración para PyDeckard (SO: {system_name}) ---\n\n') parameters = [('TELEGRAM_BOT_TOKEN', 'Introduzca el Token del Bot', None, str), - ('VERBOSITY', 'Nivel de verbosidad', (0.0, 1.0), float), + ('BOT_VERBOSITY', 'Nivel de verbosidad', (0.0, 1.0), float), ('LOG_LEVEL', 'Nivel de registro de logs', ['DEBUG', 'INFO', 'WARNING', 'ERROR'], str), ('POLL_INTERVAL', 'Intervalo de polling para la API de Telegram', (1, 10), int), ('BOT_GREETING', 'Saludo del bot', None, str), From 67a19c83aa21c2b320113ae95ac57531eb55ed3e Mon Sep 17 00:00:00 2001 From: misanram Date: Sun, 19 Apr 2026 12:05:32 +0100 Subject: [PATCH 24/24] =?UTF-8?q?Mejorando=20documentaci=C3=B3n=20en=20REA?= =?UTF-8?q?DME.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e42ef8f..466cf50 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,13 @@ You can now launch the bot, activating the virtual environment and running:: $ pydeckard ~~~ -...or delegate the startup of the application to your operating system using the instructions that setup has provided. +...or delegate the startup of the application to your operating system using the instructions that setup has provided. + +You can view the bot log using: + +~~~console +$ journalctl -u pydeckard.service -f +~~~ ## Tests