switched to uv and gitea-actions-based pipeline
All checks were successful
Build container / Build (pull_request) Successful in 43s
All checks were successful
Build container / Build (pull_request) Successful in 43s
This commit is contained in:
32
.gitea/workflows/build_container.yaml
Normal file
32
.gitea/workflows/build_container.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
name: Build container
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: https://gitea.com/actions/checkout@v4
|
||||
|
||||
- name: Login to Docker Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.kluster.moll.re
|
||||
username: ${{ gitea.repository_owner }}
|
||||
password: ${{ secrets.PACKAGE_REGISTRY_ACCESS }}
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
# use the current commit SHA as the tag
|
||||
tags: git.kluster.moll.re/remoll/journal-bot:${{ gitea.sha }}
|
||||
push: true
|
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,9 +1,13 @@
|
||||
# Nix shell files
|
||||
.direnv/
|
||||
|
||||
|
||||
|
||||
# Secrets
|
||||
dev.env
|
||||
secret.yaml
|
||||
*.secret.yaml
|
||||
|
||||
# Static data
|
||||
.bot_storage/
|
||||
.bot/
|
||||
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.13
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -6,7 +6,7 @@
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: Current project",
|
||||
"type": "python",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bot/main.py",
|
||||
"console": "integratedTerminal",
|
||||
@@ -14,4 +14,4 @@
|
||||
"envFile": "${workspaceFolder}/dev.env",
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
19
Dockerfile
19
Dockerfile
@@ -1,17 +1,14 @@
|
||||
FROM python:3-slim
|
||||
ENV DOCKERIZED=true
|
||||
ARG BOT_VERSION
|
||||
# set at build time
|
||||
ENV BOT_VERSION=$BOT_VERSION
|
||||
FROM docker.io/python:3.13-alpine
|
||||
# use the latest version of uv, independently of the python version
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
WORKDIR /app
|
||||
RUN pip install pipenv
|
||||
|
||||
# copy the requirements and install them
|
||||
COPY pyproject.toml uv.lock .
|
||||
RUN uv sync --frozen
|
||||
|
||||
COPY Pipfile Pipfile.lock ./
|
||||
|
||||
RUN pipenv install --system --deploy
|
||||
|
||||
# copy the rest of the code
|
||||
COPY bot .
|
||||
|
||||
CMD ["python", "main.py"]
|
||||
CMD ["uv", "run", "main.py"]
|
||||
|
7
Makefile
7
Makefile
@@ -1,7 +0,0 @@
|
||||
CURRENT_DIR := $(shell pwd)
|
||||
DOTENV := ${CURRENT_DIR}/dev.env
|
||||
PIPENV_CMD_PREFIX := PIPENV_DOTENV_LOCATION=${DOTENV} pipenv run
|
||||
|
||||
|
||||
run:
|
||||
${PIPENV_CMD_PREFIX} python bot/main.py
|
14
Pipfile
14
Pipfile
@@ -1,14 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
peewee = "*"
|
||||
python-telegram-bot = {extras = ["job-queue"], version = "*"}
|
||||
anyio = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[pipenv]
|
||||
allow_prereleases = true
|
131
Pipfile.lock
generated
131
Pipfile.lock
generated
@@ -1,131 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "5458e81c4f85af776acc44f46af838644ef8c00ccf4223fbe06f9d76a4717fc6"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"anyio": {
|
||||
"hashes": [
|
||||
"sha256:48d53f0b141f5757c38d648309e6fe254857fae092d67f938fa248d7c0f36804",
|
||||
"sha256:596b09c520820e7eed961ddc889540972f92d5e8fcb081117fc054c409df34ae"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.0rc1"
|
||||
},
|
||||
"apscheduler": {
|
||||
"hashes": [
|
||||
"sha256:0293937d8f6051a0f493359440c1a1b93e882c57daf0197afeff0e727777b96e",
|
||||
"sha256:e813ad5ada7aff36fb08cdda746b520531eaac7757832abc204868ba78e0c8f6"
|
||||
],
|
||||
"version": "==3.10.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082",
|
||||
"sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2023.7.22"
|
||||
},
|
||||
"h11": {
|
||||
"hashes": [
|
||||
"sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d",
|
||||
"sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.14.0"
|
||||
},
|
||||
"httpcore": {
|
||||
"hashes": [
|
||||
"sha256:a6f30213335e34c1ade7be6ec7c47f19f50c56db36abef1a9dfa3815b1cb3888",
|
||||
"sha256:c2789b767ddddfa2a5782e3199b2b7f6894540b17b16ec26b2c4d8e103510b87"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.17.3"
|
||||
},
|
||||
"httpx": {
|
||||
"hashes": [
|
||||
"sha256:06781eb9ac53cde990577af654bd990a4949de37a28bdb4a230d434f3a30b9bd",
|
||||
"sha256:5853a43053df830c20f8110c5e69fe44d035d850b2dfe795e196f00fdb774bdd"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.24.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
|
||||
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.4"
|
||||
},
|
||||
"peewee": {
|
||||
"hashes": [
|
||||
"sha256:10769981198c7311f84a0ca8db892fa213303a8eb1305deb795a71e7bd606a91"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.16.2"
|
||||
},
|
||||
"python-telegram-bot": {
|
||||
"extras": [
|
||||
"job-queue"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:a6ac3f9c9674aaf7d1c7e652d8b75cde969fb872f75e9521b8516eceaba82b1b",
|
||||
"sha256:e426404b0006989a5bcc05e11a7ef3ffe0c086b684a4e963db5bda1d361a049a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.4"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588",
|
||||
"sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"
|
||||
],
|
||||
"version": "==2023.3"
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
"sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
|
||||
"sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==68.0.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"sniffio": {
|
||||
"hashes": [
|
||||
"sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101",
|
||||
"sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"tzlocal": {
|
||||
"hashes": [
|
||||
"sha256:46eb99ad4bdb71f3f72b7d24f4267753e240944ecfc16f25d2719ba89827a803",
|
||||
"sha256:f3596e180296aaf2dbd97d124fe76ae3a0e3d32b258447de7b939b3fd4be992f"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==5.0.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
@@ -38,7 +38,7 @@ class JournalHandler(BaseHandler):
|
||||
|
||||
async def entry_point(self, update, context):
|
||||
await super().entry_point(update, context)
|
||||
if os.getenv("DOCKERIZED", "false") == "true" and os.getenv("CHAT_ID") != str(update.message.chat_id):
|
||||
if models.IS_PRODUCTION and os.getenv("CHAT_ID") != str(update.message.chat_id):
|
||||
await update.message.reply_text("You are not authorized to use this bot")
|
||||
return ConversationHandler.END
|
||||
|
||||
@@ -79,7 +79,7 @@ class JournalHandler(BaseHandler):
|
||||
else:
|
||||
await query.edit_message_text(text="An entry already exists for this date")
|
||||
return ConversationHandler.END
|
||||
|
||||
|
||||
return CONTENT_ENTRY
|
||||
|
||||
|
||||
@@ -113,13 +113,13 @@ class JournalHandler(BaseHandler):
|
||||
|
||||
async def date_entry(self, update, context):
|
||||
date = update.message.text
|
||||
|
||||
|
||||
try:
|
||||
date = datetime.datetime.strptime(date, "%d%m%Y").date()
|
||||
except ValueError:
|
||||
await update.message.reply_text("Please enter the date in the format _DDMMYYYY_", parse_mode=ParseMode.MARKDOWN_V2)
|
||||
return ENTRY_OPTIONS
|
||||
|
||||
|
||||
if context.chat_data.get("delete", False): # if not set, delete was not chosen
|
||||
with models.db:
|
||||
self.current_model = models.JournalEntry.get_or_none(
|
||||
@@ -158,7 +158,7 @@ class JournalHandler(BaseHandler):
|
||||
file = await update.message.effective_attachment[-1].get_file()
|
||||
else:
|
||||
file = await update.message.effective_attachment.get_file()
|
||||
|
||||
|
||||
file_bytes = await file.download_as_bytearray()
|
||||
file_path = file.file_path
|
||||
self.current_model.save_media(file_bytes, file_path)
|
||||
@@ -211,7 +211,7 @@ def get_names(dates: list):
|
||||
suffix = ""
|
||||
if models.JournalEntry.get_or_none(date = d):
|
||||
suffix = " ✅"
|
||||
|
||||
|
||||
if d == datetime.datetime.now().date():
|
||||
names.append("Today" + suffix)
|
||||
elif d == datetime.datetime.now().date() - datetime.timedelta(days = 1):
|
||||
|
@@ -3,7 +3,7 @@ from telegram.ext import ConversationHandler, CommandHandler, MessageHandler, fi
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup, Update, InputMediaPhoto
|
||||
import models
|
||||
from telegram.constants import ParseMode
|
||||
# ACTION_CHOICE, DATE_ENTRY, ADD_CONTENT = range(3)
|
||||
|
||||
MEMORY_CHOICE = range(1)
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class MemoryHandler(BaseHandler):
|
||||
|
||||
async def entry_point(self, update: Update, context: CallbackContext):
|
||||
await super().entry_point(update, context)
|
||||
if os.getenv("DOCKERIZED", "false") == "true" and os.getenv("CHAT_ID") != str(update.message.chat_id):
|
||||
if models.IS_PRODUCTION and os.getenv("CHAT_ID") != str(update.message.chat_id):
|
||||
await update.message.reply_text("You are not authorized to use this bot")
|
||||
return ConversationHandler.END
|
||||
|
||||
@@ -56,9 +56,9 @@ class MemoryHandler(BaseHandler):
|
||||
await update.message.reply_text(
|
||||
f"Which moment would you like to remember?", reply_markup=keyboard
|
||||
)
|
||||
|
||||
|
||||
context.chat_data["kept_matches"] = list(matching_models)
|
||||
|
||||
|
||||
return MEMORY_CHOICE
|
||||
|
||||
async def choose_memory(self, update: Update, context: CallbackContext):
|
||||
|
@@ -13,8 +13,8 @@ class SetChatPhotoJob():
|
||||
def __init__(self, bot: ExtBot, job_queue):
|
||||
self.bot = bot
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
|
||||
if os.getenv("DOCKERIZED", "false") != "true":
|
||||
|
||||
if models.IS_PRODUCTION:
|
||||
# when running locally, annoy the programmer every 60 seconds <3
|
||||
job_queue.run_repeating(self.callback_photo, interval=60)
|
||||
else:
|
||||
@@ -24,13 +24,13 @@ class SetChatPhotoJob():
|
||||
|
||||
|
||||
async def callback_photo(self, context):
|
||||
|
||||
|
||||
# last_seen of memory must be older than 10 days in past or None
|
||||
with models.db:
|
||||
possible_photos = models.JournalEntry.select().where(
|
||||
models.JournalEntry.media_path != None
|
||||
).order_by(fn.Random())
|
||||
|
||||
|
||||
try:
|
||||
chosen_entry = possible_photos.get()
|
||||
except:
|
||||
|
@@ -4,13 +4,14 @@ import os
|
||||
from peewee import fn
|
||||
import logging
|
||||
import models
|
||||
from telegram.ext import ExtBot
|
||||
|
||||
class RandomMemoryJob():
|
||||
def __init__(self, bot, job_queue):
|
||||
def __init__(self, bot: ExtBot, job_queue):
|
||||
self.bot = bot
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
|
||||
if os.getenv("DOCKERIZED", "false") != "true":
|
||||
|
||||
if models.IS_PRODUCTION:
|
||||
# when running locally, annoy the programmer every 60 seconds <3
|
||||
job_queue.run_repeating(self.callback_memory, interval=3600)
|
||||
self.min_age = 0 # do not filter messages: show them all
|
||||
@@ -22,14 +23,14 @@ class RandomMemoryJob():
|
||||
|
||||
|
||||
async def callback_memory(self, context):
|
||||
|
||||
|
||||
# last_seen of memory must be older than 10 days in past or None
|
||||
with models.db:
|
||||
possible_entries = models.JournalEntry.select().where(
|
||||
(models.JournalEntry.last_shown <= datetime.today().date() - timedelta(days=self.min_age)) | \
|
||||
(models.JournalEntry.last_shown == None)
|
||||
).order_by(fn.Random())
|
||||
|
||||
|
||||
try:
|
||||
chosen_entry = possible_entries.get()
|
||||
except:
|
||||
|
@@ -2,7 +2,7 @@ from peewee import *
|
||||
from pathlib import Path
|
||||
import re
|
||||
import os
|
||||
import datetime
|
||||
import socket
|
||||
|
||||
ID_MAPPINGS = {
|
||||
"Lia": 5603036217,
|
||||
@@ -11,9 +11,9 @@ ID_MAPPINGS = {
|
||||
ID_MAPPINGS_REV = dict((v, k) for k, v in ID_MAPPINGS.items())
|
||||
|
||||
RATING_MAPPING = {
|
||||
1: "😵",
|
||||
2: "☹️",
|
||||
3: "😐",
|
||||
1: "🙁",
|
||||
2: "😐",
|
||||
3: "🙂",
|
||||
4: "😃",
|
||||
5: "🥰"
|
||||
}
|
||||
@@ -21,6 +21,11 @@ RATING_MAPPING = {
|
||||
MEDIA_DIR = Path(os.getenv("MEDIA_DIR"))
|
||||
MEDIA_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# check if we are running on a cluster
|
||||
IS_PRODUCTION = os.getenv('KUBERNETES_SERVICE_HOST') is not None
|
||||
|
||||
|
||||
|
||||
db = DatabaseProxy()
|
||||
|
||||
class BaseModel(Model):
|
||||
@@ -37,11 +42,11 @@ class JournalEntry(BaseModel):
|
||||
media_path = TextField(null=True)
|
||||
last_shown = DateField(null=True)
|
||||
rating = IntegerField(null=True) # mapped by RATING_MAPPING
|
||||
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
return Path(self.media_path).open('rb')
|
||||
|
||||
|
||||
def save_media(self, media: bytearray, file_name: str):
|
||||
ext = Path(file_name).suffix
|
||||
file_name = f"{self.date.isoformat()}-media{ext}"
|
||||
@@ -87,7 +92,7 @@ class JournalEntry(BaseModel):
|
||||
group_to_replace = match[0]
|
||||
new_text = new_text.replace(group_to_replace, f"<tg-spoiler>{group_to_replace}</tg-spoiler>")
|
||||
return new_text
|
||||
|
||||
|
||||
|
||||
def set_db(db_path):
|
||||
db.initialize(SqliteDatabase(db_path))
|
||||
|
29
default.nix
Normal file
29
default.nix
Normal file
@@ -0,0 +1,29 @@
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
name = "journal-bot-shell";
|
||||
|
||||
buildInputs = with pkgs; [
|
||||
# python
|
||||
python313
|
||||
# setuptools as downloaded by uv seems to be broken on nixos
|
||||
python313Packages.setuptools
|
||||
uv
|
||||
];
|
||||
|
||||
|
||||
# fix library dependencies:
|
||||
env.LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
||||
# required by numpy and the likes
|
||||
pkgs.stdenv.cc.cc.lib
|
||||
pkgs.libz
|
||||
];
|
||||
|
||||
# tell UV where to put the virtualenv:
|
||||
# env.UV_PROJECT_ENVIRONMENT = ".cache/uv-venvs/thesis";
|
||||
|
||||
# install the python packages through uv:
|
||||
shellHook = "
|
||||
uv sync
|
||||
source .venv/bin/activate
|
||||
";
|
||||
}
|
3
dev.env
Normal file
3
dev.env
Normal file
@@ -0,0 +1,3 @@
|
||||
MEDIA_DIR="./.bot/media"
|
||||
PERSISTENCE_DIR="./.bot/persistence"
|
||||
DB_PATH="./.bot/db.sqlite"
|
11
pyproject.toml
Normal file
11
pyproject.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[project]
|
||||
name = "journal-bot"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"anyio>=4.9.0",
|
||||
"peewee>=3.18.2",
|
||||
"python-telegram-bot[job-queue]>=22.3",
|
||||
]
|
153
uv.lock
generated
Normal file
153
uv.lock
generated
Normal file
@@ -0,0 +1,153 @@
|
||||
version = 1
|
||||
revision = 2
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "idna" },
|
||||
{ name = "sniffio" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "apscheduler"
|
||||
version = "3.11.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tzlocal" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/00/6d6814ddc19be2df62c8c898c4df6b5b1914f3bd024b780028caa392d186/apscheduler-3.11.0.tar.gz", hash = "sha256:4c622d250b0955a65d5d0eb91c33e6d43fd879834bf541e0a18661ae60460133", size = 107347, upload-time = "2024-11-24T19:39:26.463Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d0/ae/9a053dd9229c0fde6b1f1f33f609ccff1ee79ddda364c756a924c6d8563b/APScheduler-3.11.0-py3-none-any.whl", hash = "sha256:fc134ca32e50f5eadcc4938e3a4545ab19131435e851abb40b34d63d5141c6da", size = 64004, upload-time = "2024-11-24T19:39:24.442Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.7.14"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h11"
|
||||
version = "0.16.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "certifi" },
|
||||
{ name = "h11" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.28.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "certifi" },
|
||||
{ name = "httpcore" },
|
||||
{ name = "idna" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "journal-bot"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "anyio" },
|
||||
{ name = "peewee" },
|
||||
{ name = "python-telegram-bot", extra = ["job-queue"] },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "anyio", specifier = ">=4.9.0" },
|
||||
{ name = "peewee", specifier = ">=3.18.2" },
|
||||
{ name = "python-telegram-bot", extras = ["job-queue"], specifier = ">=22.3" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peewee"
|
||||
version = "3.18.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/89/76f6f1b744c8608e0d416b588b9d63c2a500ff800065ae610f7c80f532d6/peewee-3.18.2.tar.gz", hash = "sha256:77a54263eb61aff2ea72f63d2eeb91b140c25c1884148e28e4c0f7c4f64996a0", size = 949220, upload-time = "2025-07-08T12:52:03.941Z" }
|
||||
|
||||
[[package]]
|
||||
name = "python-telegram-bot"
|
||||
version = "22.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/db/fc/0196e0d7ad247011a560788db204e0a28d76ab75b3d7c7131878f8fb5a06/python_telegram_bot-22.3.tar.gz", hash = "sha256:513d5ab9db96dcf25272dad0a726555e80edf60d09246a7d0d425b77115f5440", size = 1464513, upload-time = "2025-07-20T20:03:09.805Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/54/0955bd46a1e046169500e129c7883664b6675d580074d68823485e4d5de1/python_telegram_bot-22.3-py3-none-any.whl", hash = "sha256:88fab2d1652dbfd5379552e8b904d86173c524fdb9270d3a8685f599ffe0299f", size = 717115, upload-time = "2025-07-20T20:03:07.261Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
job-queue = [
|
||||
{ name = "apscheduler" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sniffio"
|
||||
version = "1.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzlocal"
|
||||
version = "5.3.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" },
|
||||
]
|
Reference in New Issue
Block a user