c1groupy 0.3.0__tar.gz
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.
- c1groupy-0.3.0/LICENCE +21 -0
- c1groupy-0.3.0/PKG-INFO +604 -0
- c1groupy-0.3.0/README.md +579 -0
- c1groupy-0.3.0/pyproject.toml +36 -0
- c1groupy-0.3.0/src/c1gpy/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/.gitignore +82 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/.pre-commit-config.yaml +43 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/Dockerfile +47 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/README.md.template +161 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/docker-compose.yml +12 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/pyproject.toml.template +21 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/api_interface.py +55 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/endpoints/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/endpoints/router1/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/endpoints/router1/example_endpoint.py +24 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/endpoints/router2/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/endpoints/router2/example_endpoint.py +24 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/entrypoint.sh +17 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/routers/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/routers/router1.py +53 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/src/routers/router2.py +36 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/tests/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/fastapi_project_files/tests/test_example.py +33 -0
- c1groupy-0.3.0/src/c1gpy/google-utils.py +659 -0
- c1groupy-0.3.0/src/c1gpy/init_fastapi_project.py +198 -0
- c1groupy-0.3.0/src/c1gpy/init_streamlit_project.py +190 -0
- c1groupy-0.3.0/src/c1gpy/llm.py +8 -0
- c1groupy-0.3.0/src/c1gpy/logging.py +246 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/.gitignore +82 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/.pre-commit-config.yaml +43 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/Dockerfile +47 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/README.md.template +106 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/docker-compose.yml +12 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/pyproject.toml.template +19 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/App.py.template +21 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/pages/1_Page_1.py +9 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/pages/2_Page_2.py +15 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/pages/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/app/pages/home.py +27 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/src/entrypoint.sh +33 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/tests/__init__.py +0 -0
- c1groupy-0.3.0/src/c1gpy/streamlit_project_files/tests/test_example.py +8 -0
- c1groupy-0.3.0/src/c1gpy/utils.py +207 -0
c1groupy-0.3.0/LICENCE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tim Schendzielorz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
c1groupy-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: c1groupy
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: C1G company Python module for utilities and project setup
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENCE
|
|
7
|
+
Author: Tim M Schendzielorz
|
|
8
|
+
Author-email: tim.schendzielorz@googlemail.com
|
|
9
|
+
Requires-Python: >=3.12, <4.0
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Requires-Dist: argon2-cffi (>=23.0.0,<24.0.0)
|
|
15
|
+
Requires-Dist: google-api-python-client (>=2.0.0,<3.0.0)
|
|
16
|
+
Requires-Dist: google-auth (>=2.0.0,<3.0.0)
|
|
17
|
+
Requires-Dist: google-cloud-logging (>=3.0.0,<4.0.0)
|
|
18
|
+
Requires-Dist: google-cloud-secret-manager (>=2.0.0,<3.0.0)
|
|
19
|
+
Requires-Dist: google-cloud-storage (>=2.0.0,<3.0.0)
|
|
20
|
+
Requires-Dist: httpx[http2] (>=0.27.0,<1.0.0)
|
|
21
|
+
Requires-Dist: langfuse (>=3.6.1,<4.0.0)
|
|
22
|
+
Requires-Dist: rich (>=13.0.0,<14.0.0)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# c1gpy
|
|
26
|
+
|
|
27
|
+
C1G company Python module for utilities and project setup.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
Install the package using pip or uv:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install c1groupy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Or with uv:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv pip install c1groupy
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
### 1. Streamlit Project Initialization
|
|
46
|
+
|
|
47
|
+
The `initialize-streamlit-project` command creates a fully configured Streamlit multi-page application with Docker support and Pre-commit hooks.
|
|
48
|
+
|
|
49
|
+
#### Usage
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
initialize-streamlit-project <project-name> [--path <directory>] [--author-email <email>]
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Arguments:**
|
|
56
|
+
- `project-name` (required): Name of the project to create
|
|
57
|
+
- `--path` (optional): Directory where the project should be created (default: current directory)
|
|
58
|
+
- `--author-email` (optional): Author email address for project metadata
|
|
59
|
+
|
|
60
|
+
**Example:**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
initialize-streamlit-project my-streamlit-app --author-email developer@example.com
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This will create a new directory `my-streamlit-app/` with the following structure:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
my-streamlit-app/
|
|
70
|
+
├── src/
|
|
71
|
+
│ ├── app/ # Streamlit application
|
|
72
|
+
│ │ ├── App.py # Main entry point
|
|
73
|
+
│ │ └── pages/ # Additional pages
|
|
74
|
+
│ │ ├── 1_Page_1.py
|
|
75
|
+
│ │ └── 2_Page_2.py
|
|
76
|
+
│ └── entrypoint.sh # Container entrypoint script
|
|
77
|
+
├── tests/ # Test files
|
|
78
|
+
│ └── test_example.py
|
|
79
|
+
├── Dockerfile # Docker configuration
|
|
80
|
+
├── docker-compose.yml # Docker Compose configuration
|
|
81
|
+
├── pyproject.toml # Project dependencies
|
|
82
|
+
├── .pre-commit-config.yaml # Pre-commit hooks
|
|
83
|
+
├── .gitignore # Git ignore rules
|
|
84
|
+
└── README.md # Project documentation
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### What's Included
|
|
88
|
+
|
|
89
|
+
**Multi-page Streamlit App:**
|
|
90
|
+
- Main page (`App.py`) with welcome content
|
|
91
|
+
- Two example pages demonstrating charts and forms
|
|
92
|
+
- Proper page configuration and navigation
|
|
93
|
+
|
|
94
|
+
**Docker Support:**
|
|
95
|
+
- `Dockerfile` with Python 3.12 and uv package manager
|
|
96
|
+
- `docker-compose.yml` configured for local development
|
|
97
|
+
- Smart entrypoint script that supports:
|
|
98
|
+
- `LOCALRUN=TRUE`: Hot-reloading for development
|
|
99
|
+
- `LOCALRUN=FALSE`: Production mode
|
|
100
|
+
- `PYTEST=TRUE`: Run tests in container
|
|
101
|
+
- Volume mounting of `src/` directory for live code updates
|
|
102
|
+
|
|
103
|
+
**Development Tools:**
|
|
104
|
+
- `.pre-commit-config.yaml` with ruff linting and formatting
|
|
105
|
+
- `.gitignore` configured for Python projects
|
|
106
|
+
- Git repository initialized with initial commit
|
|
107
|
+
- Example test file with pytest
|
|
108
|
+
|
|
109
|
+
**Documentation:**
|
|
110
|
+
- Comprehensive README with setup and usage instructions
|
|
111
|
+
|
|
112
|
+
#### Getting Started with Your New Project
|
|
113
|
+
|
|
114
|
+
After creating a project, navigate to it and choose your development method:
|
|
115
|
+
|
|
116
|
+
**Option 1: Local Development with uv**
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
uv sync
|
|
120
|
+
uv run streamlit run src/app/App.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Option 2: Docker Development**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
docker-compose up --build --force-recreate --remove-orphans
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The application will be available at http://localhost:8501
|
|
130
|
+
|
|
131
|
+
**Option 3: Run Tests**
|
|
132
|
+
|
|
133
|
+
Locally:
|
|
134
|
+
```bash
|
|
135
|
+
uv run pytest tests/
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
In Docker:
|
|
139
|
+
```bash
|
|
140
|
+
docker-compose run -e PYTEST=TRUE streamlit-app
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Adding New Pages
|
|
144
|
+
|
|
145
|
+
This template uses Streamlit's `st.navigation()` for organized multi-page navigation.
|
|
146
|
+
|
|
147
|
+
To add a new page:
|
|
148
|
+
|
|
149
|
+
1. Create a new Python file in `src/app/pages/` (e.g., `analytics.py`)
|
|
150
|
+
2. Add your page content:
|
|
151
|
+
```python
|
|
152
|
+
import streamlit as st
|
|
153
|
+
|
|
154
|
+
st.title("Analytics Dashboard")
|
|
155
|
+
# Your page content here
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
3. Register the page in `src/app/App.py`:
|
|
159
|
+
```python
|
|
160
|
+
pages = {
|
|
161
|
+
"📊 Main": [
|
|
162
|
+
st.Page("pages/1_Page_1.py", title="Page 1", icon="📈"),
|
|
163
|
+
st.Page("pages/analytics.py", title="Analytics", icon="📊"), # New page
|
|
164
|
+
],
|
|
165
|
+
# ...
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Docker Environment Variables
|
|
170
|
+
|
|
171
|
+
The entrypoint script supports the following environment variables:
|
|
172
|
+
|
|
173
|
+
- `LOCALRUN`: Set to `TRUE` for development mode with hot-reloading (default: `FALSE`)
|
|
174
|
+
- `PYTEST`: Set to `TRUE` to run tests instead of the app (default: `FALSE`)
|
|
175
|
+
- `PORT`: Port for Streamlit server (default: `8501`)
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 2. FastAPI Project Initialization
|
|
180
|
+
|
|
181
|
+
The initialize-fastapi-project command creates a fully configured FastAPI application with organized router structure, Docker support, and Pre-commit hooks.
|
|
182
|
+
|
|
183
|
+
### Usage
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
initialize-fastapi-project <project-name> [--path <directory>] [--author-email <email>]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Arguments:**
|
|
190
|
+
- `project-name` (required): Name of the project to create
|
|
191
|
+
- `--path` (optional): Directory where the project should be created (default: current directory)
|
|
192
|
+
- `--author-email` (optional): Author email address for project metadata
|
|
193
|
+
|
|
194
|
+
**Example:**
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
initialize-fastapi-project my-api --author-email developer@example.com
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
This will create a new directory `my-api/` with the following structure:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
my-api/
|
|
204
|
+
├── src/
|
|
205
|
+
│ ├── api_interface.py # Main FastAPI app
|
|
206
|
+
│ ├── routers/ # API routers
|
|
207
|
+
│ │ ├── router1.py
|
|
208
|
+
│ │ └── router2.py
|
|
209
|
+
│ ├── endpoints/ # Endpoint logic
|
|
210
|
+
│ │ ├── router1/
|
|
211
|
+
│ │ │ └── example_endpoint.py
|
|
212
|
+
│ │ └── router2/
|
|
213
|
+
│ │ └── example_endpoint.py
|
|
214
|
+
│ └── entrypoint.sh # Container entrypoint script
|
|
215
|
+
├── tests/ # Test files
|
|
216
|
+
│ └── test_example.py
|
|
217
|
+
├── Dockerfile # Docker configuration
|
|
218
|
+
├── docker-compose.yml # Docker Compose configuration
|
|
219
|
+
├── pyproject.toml # Project dependencies
|
|
220
|
+
├── .pre-commit-config.yaml # Pre-commit hooks
|
|
221
|
+
├── .gitignore # Git ignore rules
|
|
222
|
+
└── README.md # Project documentation
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### What's Included
|
|
226
|
+
|
|
227
|
+
**FastAPI Application:**
|
|
228
|
+
- Main API interface with CORS middleware
|
|
229
|
+
- Two example routers with organized structure
|
|
230
|
+
- Async endpoint examples
|
|
231
|
+
- API key authentication (commented out, ready to enable)
|
|
232
|
+
- Automatic interactive documentation (Swagger UI & ReDoc)
|
|
233
|
+
|
|
234
|
+
**Docker Support:**
|
|
235
|
+
- Multi-stage Dockerfile with Python 3.12 and uv
|
|
236
|
+
- `docker-compose.yml` configured for local development
|
|
237
|
+
- Hypercorn ASGI server with uvloop for performance
|
|
238
|
+
- Smart entrypoint script that supports:
|
|
239
|
+
- `LOCALRUN=TRUE`: Hot-reloading for development
|
|
240
|
+
- `LOCALRUN=FALSE`: Production mode with 4 workers
|
|
241
|
+
- `PYTEST=TRUE`: Run tests in container
|
|
242
|
+
- Volume mounting of `src/` directory for live code updates
|
|
243
|
+
|
|
244
|
+
**Development Tools:**
|
|
245
|
+
- `.pre-commit-config.yaml` with ruff linting and formatting
|
|
246
|
+
- `.gitignore` configured for Python projects
|
|
247
|
+
- Git repository initialized with initial commit
|
|
248
|
+
- Example test file with pytest and TestClient
|
|
249
|
+
|
|
250
|
+
**Documentation:**
|
|
251
|
+
- Comprehensive README with API structure explanation
|
|
252
|
+
- Examples for adding new endpoints and routers
|
|
253
|
+
|
|
254
|
+
### Getting Started with Your New FastAPI Project
|
|
255
|
+
|
|
256
|
+
After creating a project, navigate to it and choose your development method:
|
|
257
|
+
|
|
258
|
+
**Option 1: Local Development with uv**
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
uv sync
|
|
262
|
+
uv run hypercorn src.api_interface:rest_api --bind :8000 --reload
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Option 2: Docker Development**
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
docker-compose up --build --force-recreate --remove-orphans
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The API will be available at:
|
|
272
|
+
- **API**: http://localhost:8000
|
|
273
|
+
- **Interactive Docs**: http://localhost:8000/docs
|
|
274
|
+
- **ReDoc**: http://localhost:8000/redoc
|
|
275
|
+
|
|
276
|
+
**Option 3: Run Tests**
|
|
277
|
+
|
|
278
|
+
Locally:
|
|
279
|
+
```bash
|
|
280
|
+
uv run pytest tests/
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
In Docker:
|
|
284
|
+
```bash
|
|
285
|
+
docker-compose run -e PYTEST=TRUE fastapi-app
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### API Structure
|
|
289
|
+
|
|
290
|
+
The FastAPI template uses a clean separation of concerns:
|
|
291
|
+
|
|
292
|
+
- **`api_interface.py`**: Main FastAPI app with middleware and router registration
|
|
293
|
+
- **`routers/`**: Route definitions and request/response handling
|
|
294
|
+
- **`endpoints/`**: Business logic separated by router
|
|
295
|
+
|
|
296
|
+
### Adding New Endpoints
|
|
297
|
+
|
|
298
|
+
1. Create endpoint logic in `src/endpoints/router_name/new_endpoint.py`:
|
|
299
|
+
```python
|
|
300
|
+
async def get_data() -> dict:
|
|
301
|
+
return {"data": "example"}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
2. Add route in `src/routers/router_name.py`:
|
|
305
|
+
```python
|
|
306
|
+
from endpoints.router_name import new_endpoint
|
|
307
|
+
|
|
308
|
+
@router.get("/data")
|
|
309
|
+
async def get_data():
|
|
310
|
+
return await new_endpoint.get_data()
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### API Security
|
|
314
|
+
|
|
315
|
+
The template includes commented-out API key authentication that can be easily enabled:
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
# In routers/router1.py
|
|
319
|
+
from fastapi.security import APIKeyHeader
|
|
320
|
+
api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
|
|
321
|
+
|
|
322
|
+
@router.get("/secure")
|
|
323
|
+
async def secure_endpoint(api_key: str = Security(api_key_header)):
|
|
324
|
+
# Validate api_key
|
|
325
|
+
return {"secure": "data"}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Docker Environment Variables
|
|
329
|
+
|
|
330
|
+
- `PORT`: Port for the API server (default: `8000`)
|
|
331
|
+
- `LOCALRUN`: Set to `TRUE` for development mode with hot-reloading (default: `FALSE`)
|
|
332
|
+
- `PYTEST`: Set to `TRUE` to run tests instead of the app (default: `FALSE`)
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 3. Logging
|
|
337
|
+
|
|
338
|
+
Reusable logging utilities with colorized console output and Google Cloud Logging support.
|
|
339
|
+
|
|
340
|
+
### Local Development Logger
|
|
341
|
+
|
|
342
|
+
Pretty-printed console output with colors using Rich, plus optional file logging.
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
from c1gpy.logging import get_logger
|
|
346
|
+
|
|
347
|
+
# Basic usage
|
|
348
|
+
logger = get_logger(__name__, level="DEBUG")
|
|
349
|
+
logger.info("Application started")
|
|
350
|
+
logger.debug("Debug information")
|
|
351
|
+
logger.error("Something went wrong")
|
|
352
|
+
|
|
353
|
+
# With file logging
|
|
354
|
+
logger = get_logger(
|
|
355
|
+
__name__,
|
|
356
|
+
level="INFO",
|
|
357
|
+
log_dir="./logs",
|
|
358
|
+
log_filename="app.log"
|
|
359
|
+
)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Fluent builder pattern:**
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
from c1gpy.logging import C1GLogger
|
|
366
|
+
|
|
367
|
+
logger = (
|
|
368
|
+
C1GLogger("my_app")
|
|
369
|
+
.with_level("DEBUG")
|
|
370
|
+
.with_file_logging("./logs", filename="app.log")
|
|
371
|
+
.build()
|
|
372
|
+
)
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Parameters:**
|
|
376
|
+
- `name`: Logger name (typically `__name__`)
|
|
377
|
+
- `level`: Log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`)
|
|
378
|
+
- `console_format`: Format string for console output
|
|
379
|
+
- `file_format`: Format string for file output
|
|
380
|
+
- `log_dir`: Directory for log files (enables file logging)
|
|
381
|
+
- `log_filename`: Custom log file name
|
|
382
|
+
|
|
383
|
+
### Google Cloud Logger
|
|
384
|
+
|
|
385
|
+
For production deployments on GCP. Sends logs to Google Cloud Logging without console output.
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from c1gpy.logging import get_cloud_logger
|
|
389
|
+
|
|
390
|
+
logger = get_cloud_logger(__name__, level="INFO")
|
|
391
|
+
logger.info("Application started")
|
|
392
|
+
logger.error("Something went wrong") # Visible in GCP Error Reporting
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
**Fluent builder pattern:**
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
from c1gpy.logging import C1GCloudLogger
|
|
399
|
+
|
|
400
|
+
logger = (
|
|
401
|
+
C1GCloudLogger("my_app")
|
|
402
|
+
.with_level("DEBUG")
|
|
403
|
+
.build()
|
|
404
|
+
)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Requirements:**
|
|
408
|
+
- `google-cloud-logging` package (included in dependencies)
|
|
409
|
+
- GCP authentication (Application Default Credentials, service account, etc.)
|
|
410
|
+
|
|
411
|
+
**Parameters:**
|
|
412
|
+
- `name`: Logger name (typically `__name__`)
|
|
413
|
+
- `level`: Log level (`DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`)
|
|
414
|
+
- `log_format`: Format string for log messages
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## 4. Utilities
|
|
419
|
+
|
|
420
|
+
Common utility functions for authentication and HTTP requests.
|
|
421
|
+
|
|
422
|
+
### Password Hashing (Argon2)
|
|
423
|
+
|
|
424
|
+
Secure password hashing using Argon2id algorithm.
|
|
425
|
+
|
|
426
|
+
```python
|
|
427
|
+
from c1gpy.utils import hash_password, verify_password
|
|
428
|
+
|
|
429
|
+
# Hash password for storage
|
|
430
|
+
hashed = hash_password("user_password")
|
|
431
|
+
|
|
432
|
+
# Verify on login
|
|
433
|
+
if verify_password(input_password, stored_hash):
|
|
434
|
+
print("Login successful")
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Async HTTP Client
|
|
438
|
+
|
|
439
|
+
HTTP client with retry, rate limiting, exponential backoff, and HTTP/2 support.
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
from c1gpy.utils import AsyncHTTPClient, HTTPClientError, JSONDecodeError
|
|
443
|
+
|
|
444
|
+
# Basic usage (no retries, HTTP/2 enabled)
|
|
445
|
+
async with AsyncHTTPClient() as client:
|
|
446
|
+
data = await client.get("https://api.example.com/data")
|
|
447
|
+
|
|
448
|
+
# With retries and backoff
|
|
449
|
+
client = AsyncHTTPClient(
|
|
450
|
+
base_url="https://api.example.com",
|
|
451
|
+
retries=3,
|
|
452
|
+
backoff_factor=2.0, # delays: 2s, 4s, 8s
|
|
453
|
+
rate_limit_delay=0.5, # min 0.5s between requests
|
|
454
|
+
http2=True, # default
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
try:
|
|
458
|
+
data = await client.get("/endpoint")
|
|
459
|
+
data = await client.post("/create", json={"key": "value"})
|
|
460
|
+
except HTTPClientError as e:
|
|
461
|
+
print(f"Request failed: {e}, status: {e.status_code}")
|
|
462
|
+
except JSONDecodeError as e:
|
|
463
|
+
print(f"Invalid JSON response: {e}")
|
|
464
|
+
finally:
|
|
465
|
+
await client.close()
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Parameters:**
|
|
469
|
+
- `base_url`: Optional base URL for all requests
|
|
470
|
+
- `retries`: Number of retry attempts (default: 0)
|
|
471
|
+
- `backoff_factor`: Multiplier for exponential backoff (default: 1.0)
|
|
472
|
+
- `rate_limit_delay`: Minimum delay between requests in seconds (default: 0)
|
|
473
|
+
- `timeout`: Request timeout in seconds (default: 30)
|
|
474
|
+
- `http2`: Use HTTP/2 protocol (default: True)
|
|
475
|
+
|
|
476
|
+
**Methods:** `get`, `post`, `put`, `patch`, `delete`
|
|
477
|
+
|
|
478
|
+
**Exceptions:**
|
|
479
|
+
- `HTTPClientError`: Raised when request fails after all retries (includes `status_code`)
|
|
480
|
+
- `JSONDecodeError`: Raised when response is not a valid JSON dict
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
|
|
484
|
+
## 5. Google Cloud Utilities
|
|
485
|
+
|
|
486
|
+
Clients for Google Cloud services. All clients support service account JSON credentials or Application Default Credentials.
|
|
487
|
+
|
|
488
|
+
### Secret Manager
|
|
489
|
+
|
|
490
|
+
```python
|
|
491
|
+
from c1gpy.google_utils import SecretManagerClient
|
|
492
|
+
|
|
493
|
+
client = SecretManagerClient("my-project")
|
|
494
|
+
|
|
495
|
+
# Get a secret
|
|
496
|
+
api_key = client.get_secret("api-key")
|
|
497
|
+
db_password = client.get_secret("db-password", version="2")
|
|
498
|
+
|
|
499
|
+
# Create a new secret
|
|
500
|
+
client.create_secret("new-secret", "secret-value")
|
|
501
|
+
|
|
502
|
+
# List all secrets
|
|
503
|
+
secrets = client.list_secrets()
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
### Google Sheets
|
|
507
|
+
|
|
508
|
+
```python
|
|
509
|
+
from c1gpy.google_utils import GoogleSheetsClient
|
|
510
|
+
|
|
511
|
+
client = GoogleSheetsClient("service-account.json")
|
|
512
|
+
|
|
513
|
+
# Read data
|
|
514
|
+
data = client.read_sheet("spreadsheet_id", "Sheet1!A1:D10")
|
|
515
|
+
|
|
516
|
+
# Write data
|
|
517
|
+
client.write_sheet("spreadsheet_id", "Sheet1!A1", [["Name", "Age"], ["Alice", 30]])
|
|
518
|
+
|
|
519
|
+
# Append data
|
|
520
|
+
client.append_sheet("spreadsheet_id", "Sheet1!A1", [["Bob", 25]])
|
|
521
|
+
|
|
522
|
+
# Clear a range
|
|
523
|
+
client.clear_sheet("spreadsheet_id", "Sheet1!A1:D10")
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Cloud Storage
|
|
527
|
+
|
|
528
|
+
```python
|
|
529
|
+
from c1gpy.google_utils import CloudStorageClient
|
|
530
|
+
|
|
531
|
+
client = CloudStorageClient()
|
|
532
|
+
|
|
533
|
+
# Upload data
|
|
534
|
+
client.upload_blob("my-bucket", "data.json", '{"key": "value"}')
|
|
535
|
+
client.upload_file("my-bucket", "image.png", "/path/to/image.png")
|
|
536
|
+
|
|
537
|
+
# Download data
|
|
538
|
+
content = client.download_blob("my-bucket", "data.json")
|
|
539
|
+
client.download_blob_to_file("my-bucket", "data.json", "/local/path.json")
|
|
540
|
+
|
|
541
|
+
# List and check blobs
|
|
542
|
+
blobs = client.list_blobs("my-bucket", prefix="data/")
|
|
543
|
+
exists = client.blob_exists("my-bucket", "data.json")
|
|
544
|
+
|
|
545
|
+
# Delete
|
|
546
|
+
client.delete_blob("my-bucket", "data.json")
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
### Google Drive
|
|
550
|
+
|
|
551
|
+
```python
|
|
552
|
+
from c1gpy.google_utils import GoogleDriveClient
|
|
553
|
+
|
|
554
|
+
client = GoogleDriveClient("service-account.json")
|
|
555
|
+
|
|
556
|
+
# List files
|
|
557
|
+
files = client.list_files()
|
|
558
|
+
files = client.list_files(folder_id="folder_id")
|
|
559
|
+
|
|
560
|
+
# Upload
|
|
561
|
+
result = client.upload_file("/path/to/file.pdf", name="document.pdf", folder_id="folder_id")
|
|
562
|
+
result = client.upload_bytes(b"content", "file.txt")
|
|
563
|
+
|
|
564
|
+
# Download
|
|
565
|
+
content = client.download_file("file_id")
|
|
566
|
+
client.download_file_to_path("file_id", "/local/path.pdf")
|
|
567
|
+
|
|
568
|
+
# Create folder
|
|
569
|
+
folder = client.create_folder("New Folder", parent_folder_id="parent_id")
|
|
570
|
+
|
|
571
|
+
# Delete
|
|
572
|
+
client.delete_file("file_id")
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Google Docs
|
|
576
|
+
|
|
577
|
+
```python
|
|
578
|
+
from c1gpy.google_utils import GoogleDocsClient
|
|
579
|
+
|
|
580
|
+
client = GoogleDocsClient("service-account.json")
|
|
581
|
+
|
|
582
|
+
# Read document
|
|
583
|
+
doc = client.get_document("document_id")
|
|
584
|
+
text = client.get_document_text("document_id")
|
|
585
|
+
|
|
586
|
+
# Create document
|
|
587
|
+
new_doc = client.create_document("My Document")
|
|
588
|
+
|
|
589
|
+
# Edit document
|
|
590
|
+
client.insert_text("document_id", "Hello, World!", index=1)
|
|
591
|
+
client.replace_text("document_id", "old text", "new text")
|
|
592
|
+
client.delete_content("document_id", start_index=1, end_index=10)
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
**Requirements:**
|
|
596
|
+
- GCP authentication (service account JSON or Application Default Credentials)
|
|
597
|
+
- Appropriate API permissions enabled in GCP project
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## License
|
|
602
|
+
|
|
603
|
+
MIT
|
|
604
|
+
|