TgrEzLi 0.1.2__py3-none-any.whl → 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of TgrEzLi might be problematic. Click here for more details.

@@ -0,0 +1,274 @@
1
+ Metadata-Version: 2.3
2
+ Name: TgrEzLi
3
+ Version: 0.4.0
4
+ Summary: Telegram bot library with sync-style API, handlers for messages/commands/callbacks, and optional embedded API server.
5
+ Author: eaannist
6
+ Author-email: eaannist <eaannist@gmail.com>
7
+ Requires-Dist: ezlog-py>=1.0.5
8
+ Requires-Dist: python-telegram-bot>=21.0
9
+ Requires-Dist: pycypherlib
10
+ Requires-Dist: requests>=2.28.0
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+
14
+ # TgrEzLi
15
+
16
+ Telegram bot library with a **sync-style API**, handlers for messages, commands, and callbacks, and an optional **embedded HTTP server** for custom POST endpoints. Built on [python-telegram-bot](https://pypi.org/project/python-telegram-bot/) and [ezlog](https://pypi.org/project/ezlog-py/) for logging.
17
+
18
+ - **Sync-style usage**: register handlers with decorators, use `TgMsg` / `TgCmd` / `TgCb` / `TgArgs` in handlers (thread-local context).
19
+ - **Multiple chats**: connect with a `{chat_name: chat_id}` dict; restrict handlers per chat.
20
+ - **Optional API server**: expose custom POST routes; call them with the `TReq` client.
21
+ - **Credential encryption**: store token and chats in an encrypted file with **PyCypherLib** (included by default).
22
+
23
+ ---
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ pip install TgrEzLi
29
+ ```
30
+
31
+ Dependencies: `ezlog-py`, `python-telegram-bot`, **PyCypherLib**, `requests`.
32
+
33
+ ---
34
+
35
+ ## Quick start
36
+
37
+ **After `connect()`** the bot starts polling in a **background thread**, so **`send_msg()` and handlers work immediately** (no need to call `run()`). Use **`run()`** only to **block the main thread** until you press Ctrl+C or call `stop()` (e.g. in a script so the process does not exit).
38
+
39
+ ```python
40
+ from TgrEzLi import TEL, TgMsg, TgCmd, TgCb, TgArgs, TReq
41
+
42
+ bot = TEL()
43
+
44
+ # 1) Connect: starts polling in background. send_msg() works right away.
45
+ TOKEN = "123456789:ABCDEFGHIJKLMNO"
46
+ CHAT_DICT = {"chat1": "123456789", "chat2": "789456123"}
47
+ bot.connect(TOKEN, CHAT_DICT)
48
+
49
+ # You can send without calling run() (e.g. from REPL)
50
+ bot.send_msg("Ciao a tutti")
51
+
52
+ # 2) Register handlers (before or after connect)
53
+ @bot.on_message()
54
+ def on_message():
55
+ bot.send_msg(f"Hi {TgMsg.userName}! You wrote: {TgMsg.text}")
56
+
57
+ @bot.on_command("start")
58
+ def on_start():
59
+ bot.send_msg(f"Welcome {TgCmd.userName}!")
60
+ if TgCmd.args:
61
+ bot.send_msg(f"Args: {TgCmd.args}")
62
+
63
+ # 3) Optional: block main thread until Ctrl+C (so the script does not exit)
64
+ bot.run()
65
+ ```
66
+
67
+ From the **REPL**: after `connect()` you can call `bot.send_msg("...")` and it is sent; handlers are active. If you **redefine** a handler (same function name), the new one **replaces** the previous one (no duplicate execution).
68
+
69
+ ---
70
+
71
+ ## Configuration
72
+
73
+ Create the bot with optional config:
74
+
75
+ ```python
76
+ from TgrEzLi import TEL
77
+ from TgrEzLi.types import TgrezliConfig
78
+
79
+ config = TgrezliConfig(
80
+ save_log=True,
81
+ log_file="TgrEzLi.log",
82
+ api_host="localhost",
83
+ api_port=9999,
84
+ )
85
+ bot = TEL(config)
86
+ ```
87
+
88
+ Or mutate after creation:
89
+
90
+ - **`bot.set_save_log(flag)`** – enable/disable writing log lines to the file (console always uses ezlog).
91
+ - **`bot.set_host(host)`** – API server host (used when the first `on_api_req` is registered).
92
+ - **`bot.set_port(port)`** – API server port.
93
+
94
+ Defaults: `save_log=True`, `log_file="TgrEzLi.log"`, `api_host="localhost"`, `api_port=9999`.
95
+
96
+ ---
97
+
98
+ ## Connecting and running
99
+
100
+ - **`connect(token, chat_dict)`** – Prepares the bot and **starts polling in a background thread**. `send_msg()` and handlers work immediately (e.g. from REPL you can send without calling `run()`).
101
+ - **`run()`** – **Optional.** Blocks the main thread until `stop()` (e.g. Ctrl+C). Use in scripts so the process does not exit. If API routes are registered, starts the API server when you call `run()`.
102
+ - **`stop()`** – Stops polling and API server; if `run()` was waiting, it returns. Safe to call from a signal handler (Ctrl+C) or from another thread.
103
+
104
+ **Direct:**
105
+
106
+ ```python
107
+ bot.connect(TOKEN, {"chat1": "123456789", "chat2": "789456123"})
108
+ bot.send_msg("Hello!") # works immediately
109
+ # ... register handlers ...
110
+ bot.run() # optional: block until Ctrl+C
111
+ ```
112
+
113
+ **Encrypted storage (PyCypherLib):**
114
+
115
+ ```python
116
+ # First time: save token and chats with a password (then connects)
117
+ bot.signup(TOKEN, CHAT_DICT, "your_password")
118
+ bot.run()
119
+
120
+ # Later: load and connect
121
+ bot.login("your_password")
122
+ bot.send_msg("Hi from login")
123
+ bot.run()
124
+ ```
125
+
126
+ Data is stored in `tgrdata.cy` by default (PyCypherLib).
127
+
128
+ ---
129
+
130
+ ## Sending content
131
+
132
+ All send methods accept an optional **`chat`**: `None` (default/first chat), a **string** (one chat name), or a **list/set** of names.
133
+
134
+ | Method | Description |
135
+ |--------|--------------|
136
+ | **`send_msg(text, chat=None)`** | Text message |
137
+ | **`reply_to_msg(text, msg_id, chat=None)`** | Reply to a message |
138
+ | **`send_img(photo_path, caption=None, chat=None)`** | Photo |
139
+ | **`send_file(file_path, caption=None, chat=None)`** | Document |
140
+ | **`send_position(latitude, longitude, chat=None)`** | Location |
141
+ | **`send_buttons(text, buttons, chat=None)`** | Message with inline keyboard (see below) |
142
+ | **`send_log(limit=None, chat=None)`** | Last `limit` lines of log file (or full) |
143
+ | **`send_info(chat=None)`** | Bot info (chats, handlers, API server) |
144
+ | **`send_registered_handlers(chat=None)`** | List of registered handlers (debug) |
145
+
146
+ **Inline buttons:** `buttons` is a list of rows; each row is a list of `{"text": "...", "value": "..."}` (value = callback_data).
147
+
148
+ ```python
149
+ bot.send_buttons("Choose:", [
150
+ [{"text": "Red", "value": "red"}, {"text": "Blue", "value": "blue"}],
151
+ [{"text": "Cancel", "value": "cancel"}],
152
+ ])
153
+ ```
154
+
155
+ CamelCase aliases exist: `sendMsg`, `replyToMsg`, `sendImg`, `sendFile`, `sendPosition`, `sendButtons`, `sendLog`, `sendInfo`, `sendRegisteredHandlers`.
156
+
157
+ ---
158
+
159
+ ## Handlers
160
+
161
+ **Replace-by-name:** If you register a handler whose function has the same **name** as an existing one (same type: message, command, or callback), the new handler **replaces** the old one. So in the REPL you can redefine `handle_message` and only the latest version will run.
162
+
163
+ Handlers run in a **background thread**; inside them use the global proxies **`TgMsg`**, **`TgCmd`**, **`TgCb`**, **`TgArgs`** to access the current payload. **`chat`** filters which chats trigger the handler: `None` = default chat, string = one chat, list/set = multiple chats.
164
+
165
+ ### Message handler
166
+
167
+ ```python
168
+ @bot.on_message() # default chat
169
+ @bot.on_message("chat1") # only chat1
170
+ @bot.on_message(["chat1", "chat2"])
171
+
172
+ def on_message():
173
+ # TgMsg: .text, .msgId, .chatId, .userId, .userName, .timestamp, .raw_update
174
+ bot.send_msg(f"Echo: {TgMsg.text}")
175
+ ```
176
+
177
+ ### Command handler
178
+
179
+ ```python
180
+ @bot.on_command("start")
181
+ @bot.on_command("help", "chat1")
182
+
183
+ def on_start():
184
+ # TgCmd: .command, .args, .msgId, .chatId, .userId, .userName, .timestamp, .raw_update
185
+ bot.send_msg(f"Welcome {TgCmd.userName}!")
186
+ if TgCmd.args:
187
+ bot.send_msg(f"You said: {TgCmd.args}")
188
+ ```
189
+
190
+ ### Callback handler (inline buttons)
191
+
192
+ ```python
193
+ @bot.on_callback("chat1")
194
+
195
+ def on_callback():
196
+ # TgCb: .text, .value, .msgId, .chatId, .userId, .userName, .timestamp, .raw_update
197
+ if TgCb.value == "red":
198
+ bot.send_msg(f"You pressed {TgCb.text} -> {TgCb.value}")
199
+ ```
200
+
201
+ ### API request handler
202
+
203
+ Register a POST route; the embedded server starts automatically when the first route is registered.
204
+
205
+ ```python
206
+ @bot.on_api_req("/action", args=["chat", "msg"])
207
+ def action():
208
+ # TgArgs.get(key, default)
209
+ chat_id = TgArgs.get("chat")
210
+ msg = TgArgs.get("msg")
211
+ bot.send_msg(msg, chat=chat_id)
212
+ ```
213
+
214
+ **TReq** – client to call these endpoints:
215
+
216
+ ```python
217
+ from TgrEzLi import TReq
218
+
219
+ TReq("/action").host("127.0.0.1").port(9999).arg("chat", "chat1").arg("msg", "Hello!").send()
220
+ # or
221
+ TReq("/action").body({"chat": "chat1", "msg": "Hello!"}).send()
222
+ ```
223
+
224
+ `.host()`, `.port()`, `.timeout(seconds)` are optional (defaults: localhost, 9999, 30s). `.send()` returns a `requests.Response`; on failure raises **`TgrezliRequestError`**.
225
+
226
+ CamelCase decorator aliases: `onMessage`, `onCommand`, `onCallback`, `onApiReq`.
227
+
228
+ ---
229
+
230
+ ## Data interfaces (handler context)
231
+
232
+ Use only **inside** the corresponding handler; otherwise `TgMsg` / `TgCmd` / `TgCb` / `TgArgs` raise if accessed.
233
+
234
+ | Proxy | Handler | Main fields |
235
+ |-------|---------|-------------|
236
+ | **TgMsg** | `on_message` | `text`, `msgId`, `chatId`, `userId`, `userName`, `timestamp`, `raw_update` |
237
+ | **TgCmd** | `on_command` | `command`, `args`, `msgId`, `chatId`, `userId`, `userName`, `timestamp`, `raw_update` |
238
+ | **TgCb** | `on_callback` | `text`, `value`, `msgId`, `chatId`, `userId`, `userName`, `timestamp`, `raw_update` |
239
+ | **TgArgs** | `on_api_req` | `TgArgs.get(key, default)` for POST body |
240
+
241
+ All IDs/names are available as both **snake_case** (e.g. `msg_id`) and **camelCase** (e.g. `msgId`) on the data objects.
242
+
243
+ ---
244
+
245
+ ## Stopping
246
+
247
+ **`stop()`** stops polling and the API server; if **`run()`** was blocking, it returns. Call **`stop()`** via **Ctrl+C** (SIGINT is handled) or from another thread. After that, to use the bot again you must call **`connect()`** (or **`login()`**) again.
248
+
249
+ ---
250
+
251
+ ## Project layout
252
+
253
+ - **`TgrEzLi`** – main package
254
+ - **`TEL`** – bot class (core)
255
+ - **`TgMsg`, `TgCmd`, `TgCb`, `TgArgs`** – handler context proxies (from `TgrEzLi.models`)
256
+ - **`TReq`, `TgrezliRequestError`** – HTTP client for the embedded API
257
+ - **`TgrezliConfig`** – config dataclass (from `TgrEzLi.types`)
258
+ - **`TgrEzLi.crypto`** – **`CredentialManager`** (uses PyCypherLib): `signup(token, chat_dict, password)`, `login(password)`.
259
+
260
+ Logging is done with **ezlog** on the console; if `save_log` is true, the same messages are appended to the configured log file.
261
+
262
+ ---
263
+
264
+ ## Security and robustness
265
+
266
+ - **API server**: POST body size limited (default 1 MiB); invalid JSON returns 400; unknown route 404. No built-in authentication – protect the server (e.g. firewall, reverse proxy, or add your own auth in routes).
267
+ - **Credentials**: Stored in an encrypted file when using `signup`/`login` (PyCypherLib); decryption only with the correct password. Keep the file and password secure.
268
+ - **Handlers**: User code runs in daemon threads; exceptions are logged and do not crash the bot.
269
+
270
+ ---
271
+
272
+ ## License
273
+
274
+ MIT License. Copyright (c) eaannist.
@@ -0,0 +1,15 @@
1
+ TgrEzLi/__init__.py,sha256=uZ3rxEEzV3dn3Lk4gfvF1IzRlv9HpZEZWPaMEwyRpCI,731
2
+ TgrEzLi/api_server.py,sha256=O_2oU0rs6su6IfDwYjyPm0h6BzhU6a6Qr_B1xSZJbow,5107
3
+ TgrEzLi/config.py,sha256=iyeOUaoIlEozBDl-FNOCXE1IakQaKUrmdRu78vnrkUk,139
4
+ TgrEzLi/core.py,sha256=VSARuDsIqFRFYgeeL8oTMe74RKrPsZiXnN8-q1ShOQI,21075
5
+ TgrEzLi/crypto.py,sha256=UkiaNoI0ScPXBZNVQrpCfkKKs4pftody_B0groU3qfY,1492
6
+ TgrEzLi/defaults.py,sha256=MNRbQs0BmJAd0fbWo_5I7Y5VVR02lD4rkWnqs9aHKbE,351
7
+ TgrEzLi/handlers.py,sha256=qK_sE4BhOkSBEBGvUiJoC_jVyn1COlCVZk2593GIWvY,2939
8
+ TgrEzLi/logger.py,sha256=n2ZiCFishdrgNTuba2ixeeCkHNWQeX3W7dfpNLGzRK8,2075
9
+ TgrEzLi/models.py,sha256=tq8Sf8eyk_IrUC8yTt3rk5yoFGQyN4X4rTubDGgdv2M,2249
10
+ TgrEzLi/requests.py,sha256=kOT1tre22sI8JjWWi02n5PgOrweDpOrhVSON-BACE6Y,1532
11
+ TgrEzLi/types.py,sha256=dc_n91cwjXkPCVbA1ph68PeBJP_r3WG5iUFW6vttXWo,2427
12
+ tgrezli-0.4.0.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
13
+ tgrezli-0.4.0.dist-info/entry_points.txt,sha256=gzH98n-evOMN1c_uOoDPPy5B4eQhFfcT6mm0ghZ7vjY,42
14
+ tgrezli-0.4.0.dist-info/METADATA,sha256=ocKyCTPFfmq9iqdfUeCs61bMjfVX7RVzoq1n9vRm084,10472
15
+ tgrezli-0.4.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.1)
2
+ Generator: uv 0.9.27
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ TgrEzLi = TgrEzLi:main
3
+
@@ -1,238 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: TgrEzLi
3
- Version: 0.1.2
4
- Summary: Easy-to-use synchronous interface for telegram-bot library with async backend and intuitive handlers.
5
- Home-page: https://github.com/eaannist/TgrEzLi
6
- Author: eaannist
7
- Author-email: eaannist@gmail.com
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Operating System :: OS Independent
10
- Requires-Python: >=3.7
11
- Description-Content-Type: text/markdown
12
- Requires-Dist: python-telegram-bot>=20.0
13
- Requires-Dist: requests>=2.28.0
14
- Requires-Dist: PyCypherLib>=1.3.5
15
- Dynamic: author
16
- Dynamic: author-email
17
- Dynamic: classifier
18
- Dynamic: description
19
- Dynamic: description-content-type
20
- Dynamic: home-page
21
- Dynamic: requires-dist
22
- Dynamic: requires-python
23
- Dynamic: summary
24
-
25
- # TgrEzLi
26
-
27
- **TgrEzLi** is a Python library based [telegram-bot](https://pypi.org/project/python-telegram-bot/) that simplifies Telegram bot development by providing a synchronous interface, runs in background with non-blocking operations and offers intuitive handlers for messages, commands, callbacks, and API requests.
28
-
29
- ## Installation
30
-
31
- ```bash
32
- pip install TgrEzLi
33
-
34
- ```
35
- ## Usage
36
-
37
- ```python
38
-
39
-
40
- # Importing the library
41
- from TgrEzLi import TEL, TgMsg, TgCmd, TgCb, TgArgs, TReq
42
- # or
43
- from TgrEzLi import *
44
-
45
- # Initialization
46
- bot = TEL()
47
-
48
- # Some options
49
- # Activate/Deactivate log saving
50
- bot.setSaveLog(True)
51
-
52
- # Set custom HTTP host and port; by default they are "localhost" and 9999
53
- bot.setHost("127.0.0.1")
54
- bot.setPort(8080)
55
-
56
- # Connecting
57
- # You can connect one or multiple chats
58
- TOKEN = "123456789:ABCDEFGHIJKLMNO"
59
- CHAT_DICT = {
60
- "chat1": "123456789",
61
- "chat2": "789456123"
62
- }
63
-
64
- # You can use the .connect() method that takes token and chat dictionary as argument.
65
- bot.connect(TOKEN, CHAT_DICT)
66
-
67
- # You can alsouse the .signup() and .login() methods to insert token and chats only once and secure them with a password
68
- bot.signup(TOKEN, CHAT_DICT, 'password') # only once; it'll store encrypted data in a tgrdata.cy file
69
- bot.login('password') # when already 'signed up'
70
-
71
- # Basic commands to send Messages, Images, Files, Position, Log, Handlers, Bot Info
72
- # Each method has a chat parameter, by defailt it's set to the first chat added to the dictionary
73
- # You can either insert a specific chat name or a List
74
- bot.sendMsg(text, chat)
75
- bot.sendImg(photo_path, caption, chat)
76
- bot.sendFile(file_path, caption, chat)
77
- bot.sendPosition(latitude, longitude, chat)
78
- bot.replyToMsg(text, msg_id, chat_id)
79
- bot.sendLog(limit, chat)
80
- bot.sendInfo(chat)
81
- bot.sendRegisteredHandlers(chat)
82
-
83
- # Methods to create and send Inline Keyboards (simply called Buttons)
84
- bot.sendButtons(text, buttons, chat)
85
-
86
- # Handlers for Messages, Commands, and Callbacks
87
- # Each method has a chat parameter, by defailt it's set to the first chat added to the dictionary
88
- # You can either insert a specific chat name or a List
89
- @bot.onMessage(chat)
90
- @bot.onCommand(command, chat)
91
- @bot.onCallback(chat)
92
- @bot.onApiReq(endpoint, args, host, port)
93
-
94
- # Data Interfaces
95
- # Each Handler has it's own integrated interface to easly access received data
96
-
97
- # TgMsg gets received messages data for .onMessage() handler
98
- TgMsg.text
99
- .msgId
100
- .chatId
101
- .userId
102
- .userName
103
- .timestamp
104
- .raw_update
105
-
106
- # TgCmd gets data and parameters for .onCommand() handler
107
- TgCmd.command
108
- .args # gives text outside the command
109
- .msgId
110
- .chatId
111
- .userId
112
- .userName
113
- .timestamp
114
- .raw_update
115
-
116
- # TgCb gets data for .onCallback() handler
117
- TgCb.text
118
- .value
119
- .msgId
120
- .chatId
121
- .userId
122
- .userName
123
- .timestamp
124
- .raw_update
125
-
126
- # TgArgs gets parameters for .onApiReq() handler
127
- TgArgs.get(key, default)
128
-
129
-
130
- # Treq makes it really easy to send an api request
131
- # It takes the endpoint path like "\action"
132
- # .host and .port are optional, by default "localhost" and 9999
133
- # you can add multiple .arg() methods to add parameters names and values
134
- # or you can use .body() to send the full body
135
- TReq(endpoint)\
136
- .host(host)\
137
- .port(port)\
138
- .arg(name, value)\
139
- .body(body_dict)\
140
- .send()
141
-
142
- ## Examples ##
143
-
144
- # basic commands
145
- bot.sendMsg("Message Test")
146
- bot.sendImg("img.jpg", "Image Test", 'chat1')
147
- bot.sendFile("file.pdf", "File Test", ['chat1', 'chat2'])
148
- bot.sendPosition(45.4642, 9.1900, ['chat1', 'chat2'])
149
-
150
-
151
- # Message Handler
152
- @bot.onMessage()
153
- def on_message_default_chat():
154
- bot.sendMsg(f"Hi {TgMsg.userName}! You wrote: {TgMsg.text}")
155
- reply = f"Message Id: {TgMsg.msgId} User Id: {TgMsg.userId} Raw: {TgMsg.raw_update}"
156
- bot.replyToMsg(reply, msg_id=TgMsg.msgId)
157
-
158
-
159
- # Command Handler
160
- @bot.onCommand("/start")
161
- def handle_start():
162
- bot.sendMsg(f"Welcome to chat 1 {TgCmd.userName}!")
163
- if TgCmd.args : bot.sendMsg(f"You also wrote: {TgCmd.args}!")
164
-
165
- @bot.onCommand("/start", 'chat2')
166
- def handle_start():
167
- bot.sendMsg(f"Welcome to chat 2 {TgCmd.userName}!")
168
-
169
-
170
- # Buttons
171
- @bot.onCommand("/buttons", 'chat1')
172
- def show_buttons():
173
- buttons = [
174
- [{"text": "Button 1", "value": "red"}],
175
- [{"text": "Button 2", "value": "yellow"}]
176
- ]
177
- bot.sendButtons("Scegli un colore:", buttons, "chat1")
178
-
179
- # Callback Handler
180
- @bot.onCallback("chat1")
181
- def on_callback_chat1():
182
- match TgCb.value:
183
- case "red":
184
- bot.sendMsg(f"You pressed {TgCb.text} -> {TgCb.value}!", "chat1")
185
- case "yellow":
186
- bot.sendMsg(f"You pressed {TgCb.text} -> {TgCb.value}!", "chat1")
187
-
188
-
189
- # Api Requests
190
- @bot.onApiReq('/action', args=['chat','msg'])
191
- def action():
192
- id = TgArgs.get('chat')
193
- msg = TgArgs.get('msg')
194
- bot.sendMsg(msg, id)
195
-
196
- # TReq usage
197
- TReq('/action')\
198
- .host('127.0.0.1')\
199
- .port(8080)\
200
- .arg('chat_id', 'chat1')\
201
- .arg('msg', 'Hello from TReq!')\
202
- .send()
203
-
204
- while True:
205
- pass
206
-
207
-
208
- ```
209
-
210
- ## License
211
-
212
- ```txt
213
- MIT License
214
-
215
- Copyright (c) 2025 eaannist
216
-
217
- Permission is hereby granted, free of charge, to any person obtaining a copy
218
- of this software and associated documentation files (the "Software"), to deal
219
- in the Software without restriction, including without limitation the rights
220
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
221
- copies of the Software, and to permit persons to whom the Software is
222
- furnished to do so, subject to the following conditions:
223
-
224
- The above copyright notice and this permission notice shall be included in all
225
- copies or substantial portions of the Software.
226
-
227
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
228
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
229
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
230
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
231
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
232
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
233
- SOFTWARE.
234
- ```
235
-
236
- ## Development status
237
-
238
- **TgrEzLi** is a work-in-progress personal project. Suggestions, feature requests, and constructive feedback are highly welcome. Feel free to open an issue or submit a pull request.
@@ -1,6 +0,0 @@
1
- TgrEzLi/__init__.py,sha256=JhvTNfAcvISzUb0MmLd0aKjb2F_CggnzVLpOKraoVis,153
2
- TgrEzLi/core.py,sha256=QowwsI4I1Pxibg8ZyDImJSc7z4yQQqRzktmKaVfs0eY,19306
3
- tgrezli-0.1.2.dist-info/METADATA,sha256=VGU062ETN5qs37yuqeI-DDMIeXJiuR1hd1EO3Jm8y9k,7173
4
- tgrezli-0.1.2.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
5
- tgrezli-0.1.2.dist-info/top_level.txt,sha256=lkqdMjPkTomQ4pU2UGwbMrrXye2b76cJX1qc3w95skI,8
6
- tgrezli-0.1.2.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- TgrEzLi