Skip to content

Commit 55bb3a8

Browse files
authored
Merge pull request #1 from hippi345/cursor/repo-health-modernize-b9e7
Repo health: modernize deps, security, tests, docs
2 parents dd0b483 + 2dd9d8c commit 55bb3a8

19 files changed

Lines changed: 678 additions & 30 deletions

‎.editorconfig‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
indent_style = space
9+
indent_size = 4
10+
11+
[*.{yml,yaml,json}]
12+
indent_size = 2
13+
14+
[*.md]
15+
trim_trailing_whitespace = false

‎.env.example‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Azure Blob Storage credentials (never commit real values)
2+
AZURE_STORAGE_ACCOUNT_NAME=your-storage-account-name
3+
AZURE_STORAGE_ACCOUNT_KEY=your-storage-account-key
4+
5+
# File extension to totalize (e.g. .vhd, .png, or vhd)
6+
FILE_TYPE=.vhd

‎.github/dependabot.yml‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: pip
4+
directory: "/"
5+
schedule:
6+
interval: weekly
7+
open-pull-requests-limit: 10
8+
groups:
9+
dev-dependencies:
10+
dependency-type: development
11+
patterns:
12+
- "*"
13+
14+
- package-ecosystem: github-actions
15+
directory: "/"
16+
schedule:
17+
interval: weekly
18+
open-pull-requests-limit: 5

‎.github/workflows/ci.yml‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [master, main]
6+
pull_request:
7+
8+
permissions:
9+
contents: read
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
strategy:
15+
matrix:
16+
python-version: ["3.12", "3.13"]
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
cache: pip
27+
28+
- name: Install dependencies
29+
run: |
30+
python -m pip install --upgrade pip setuptools
31+
pip install -r requirements.lock
32+
pip install -e . --no-deps
33+
34+
- name: Ruff lint
35+
run: ruff check .
36+
37+
- name: Ruff format check
38+
run: ruff format --check .
39+
40+
- name: Run tests
41+
run: pytest --cov=filetype_size --cov-report=term-missing

‎.gitignore‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
build/
8+
develop-eggs/
9+
dist/
10+
downloads/
11+
eggs/
12+
.eggs/
13+
lib/
14+
lib64/
15+
parts/
16+
sdist/
17+
var/
18+
wheels/
19+
*.egg-info/
20+
.installed.cfg
21+
*.egg
22+
MANIFEST
23+
24+
# Virtual environments
25+
.venv/
26+
venv/
27+
ENV/
28+
29+
# Testing / coverage
30+
.pytest_cache/
31+
.coverage
32+
htmlcov/
33+
.mypy_cache/
34+
.ruff_cache/
35+
36+
# IDE
37+
.idea/
38+
.vscode/
39+
*.swp
40+
*.swo
41+
42+
# OS
43+
.DS_Store
44+
Thumbs.db
45+
46+
# Secrets / local config
47+
.env
48+
.env.*
49+
!.env.example
50+
51+
# Logs
52+
*.log

‎LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Joel Shearon
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.

‎README.md‎

Lines changed: 102 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,104 @@
11
# FileTypeSizeAzureStoragePython
22

3-
For helping with determining total byte size of certain file types in Azure Storage
4-
Ex. after providing your storage account name and key, you could type in .vhd and it would return total bytes of all vhd files in your storage account
3+
[![CI](https://github.com/hippi345/FileTypeSizeAzureStoragePython/actions/workflows/ci.yml/badge.svg)](https://github.com/hippi345/FileTypeSizeAzureStoragePython/actions/workflows/ci.yml)
4+
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5+
6+
Calculate the **total byte size** of blobs matching a file extension across all containers in an Azure Storage account—for example, sum every `.vhd` or `.png` in the account.
7+
8+
The tool uses the current [Azure Storage Blob SDK for Python](https://learn.microsoft.com/en-us/python/api/azure-storage-blob/) (`azure-storage-blob` v12+). Credentials are read from the environment or interactive prompts; they are never stored in the repository.
9+
10+
## Features
11+
12+
- Lists every container and blob (name and size) in the storage account
13+
- Totals sizes for blobs whose names end with your chosen extension (e.g. `.vhd`)
14+
- Supports non-interactive runs via environment variables
15+
- Offline unit tests with mocked Azure clients
16+
17+
## Requirements
18+
19+
- Python **3.12+**
20+
- An Azure Storage account with account name and key (or use a connection string pattern via env vars above)
21+
22+
## Setup
23+
24+
```bash
25+
git clone https://github.com/hippi345/FileTypeSizeAzureStoragePython.git
26+
cd FileTypeSizeAzureStoragePython
27+
python3 -m venv .venv
28+
source .venv/bin/activate # Windows: .venv\Scripts\activate
29+
pip install -e ".[dev]"
30+
```
31+
32+
Copy `.env.example` to `.env` and fill in values locally (`.env` is gitignored).
33+
34+
## Configuration
35+
36+
| Variable | Description |
37+
| -------- | ----------- |
38+
| `AZURE_STORAGE_ACCOUNT_NAME` | Storage account name |
39+
| `AZURE_STORAGE_ACCOUNT_KEY` | Storage account access key |
40+
| `FILE_TYPE` | Extension to match (e.g. `.vhd` or `vhd`) |
41+
42+
If any variable is missing, the program prompts for it on stdin.
43+
44+
## Usage
45+
46+
**With environment variables:**
47+
48+
```bash
49+
export AZURE_STORAGE_ACCOUNT_NAME=myaccount
50+
export AZURE_STORAGE_ACCOUNT_KEY='...'
51+
export FILE_TYPE=.vhd
52+
python main.py
53+
```
54+
55+
**Console script (after install):**
56+
57+
```bash
58+
filetype-size-azure
59+
```
60+
61+
**Interactive (no env vars):**
62+
63+
```bash
64+
python main.py
65+
```
66+
67+
Example output:
68+
69+
```
70+
Welcome to the file size calculator for Azure Storage on Python
71+
Printing out containers:
72+
my-container:
73+
Blob name: backups/disk.vhd
74+
Blob size: 1073741824
75+
Total size of .vhd files: 1073741824
76+
```
77+
78+
## Running tests
79+
80+
Tests run fully offline with mocked Azure APIs:
81+
82+
```bash
83+
ruff check .
84+
ruff format --check .
85+
pytest --cov=filetype_size
86+
```
87+
88+
## Project structure
89+
90+
```
91+
├── filetype_size/
92+
│ ├── azure_client.py # BlobServiceClient helpers
93+
│ ├── calculator.py # Extension matching and totals
94+
│ └── cli.py # Prompts / env / output
95+
├── main.py # Entry point
96+
├── tests/
97+
├── pyproject.toml # Package metadata and tool config
98+
├── requirements.txt # Runtime pins (source)
99+
└── requirements.lock # Locked versions for CI/reproducible installs
100+
```
101+
102+
## License
103+
104+
MIT License — see [LICENSE](LICENSE) (Copyright © 2026 Joel Shearon).

‎SECURITY.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Security Policy
2+
3+
## Supported versions
4+
5+
| Version | Supported |
6+
| ------- | --------- |
7+
| 2.x | Yes |
8+
9+
## Reporting a vulnerability
10+
11+
If you discover a security issue, please **do not** open a public GitHub issue with sensitive details.
12+
13+
1. Open a private security advisory on GitHub for this repository, or contact the repository owner directly.
14+
2. Include steps to reproduce, impact, and any suggested fix.
15+
16+
## Secrets and credentials
17+
18+
- Never commit storage account keys, connection strings, or SAS tokens to the repository.
19+
- Configure credentials via environment variables (`AZURE_STORAGE_ACCOUNT_NAME`, `AZURE_STORAGE_ACCOUNT_KEY`) or a local `.env` file that is listed in `.gitignore`.
20+
- Rotate any credential that may have been exposed in git history or logs.
21+
22+
## Dependencies
23+
24+
Dependency updates are managed via Dependabot. Keep `azure-storage-blob` and other packages current to receive security fixes from upstream.

‎filetype_size/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Calculate blob sizes by file extension in Azure Blob Storage."""
2+
3+
__version__ = "2.0.0"

‎filetype_size/azure_client.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""Azure Blob Storage client helpers."""
2+
3+
from __future__ import annotations
4+
5+
from collections.abc import Iterator
6+
7+
from azure.storage.blob import BlobServiceClient
8+
9+
from filetype_size.calculator import BlobInfo
10+
11+
12+
class ListedBlob:
13+
"""Adapter exposing name and size for calculator protocols."""
14+
15+
def __init__(self, name: str, size: int) -> None:
16+
self.name = name
17+
self.size = size
18+
19+
20+
def create_blob_service_client(account_name: str, account_key: str) -> BlobServiceClient:
21+
account_url = f"https://{account_name}.blob.core.windows.net"
22+
return BlobServiceClient(account_url=account_url, credential=account_key)
23+
24+
25+
def iter_containers_with_blobs(
26+
client: BlobServiceClient,
27+
) -> Iterator[tuple[str, list[BlobInfo]]]:
28+
"""List every container and its blobs (name + size)."""
29+
for container in client.list_containers():
30+
name = container.name
31+
container_client = client.get_container_client(name)
32+
blobs: list[BlobInfo] = [
33+
ListedBlob(blob.name, blob.size) for blob in container_client.list_blobs()
34+
]
35+
yield name, blobs

0 commit comments

Comments
 (0)