Skip to main content

Librería para gestión unificada de archivos en múltiples orígenes de almacenamiento

Project description

TAI-Storage

Librería para gestión unificada de archivos en múltiples orígenes de almacenamiento

Python License

📋 Descripción

tai-storage proporciona una interfaz única y consistente para manejar archivos almacenados en diferentes orígenes:

  • 💾 Sistema de archivos local
  • ☁️ Azure Blob Storage (próximamente)
  • 🔐 Servidores SFTP/FTP (próximamente)
  • 📁 SharePoint Online ✅ (Microsoft Graph API + Azure AD)
  • Y más...

Características Principales

Interfaz Única: Mismo código funciona con cualquier origen 🔄 Modo Desarrollo: Caché local automático para optimizar tiempos de desarrollo 🔒 Gestión Segura de Secretos: Integración con variables de entorno 📊 Logging Avanzado: Integración con tai-alphi 🎯 Type Hints: Soporte completo para IDEs y validación de tipos 🧪 Testeable: Fácil creación de mocks para testing 🔬 Perfilado de Datos: Análisis estadístico de DataFrames vía df.profile

🚀 Instalación

Con Poetry (recomendado)

# Instalación básica
poetry add tai-storage

# Con soporte para Azure
poetry add tai-storage[azure]

# Con soporte para SFTP
poetry add tai-storage[sftp]

# Con soporte para SharePoint
poetry add tai-storage[sharepoint]

# Con módulo de datos (pandas, perfilado, etc.)
poetry add tai-storage[data]

# Con todos los orígenes y módulos
poetry add tai-storage[all]

Con Pip

# Instalación básica
pip install tai-storage

# Con soporte para Azure
pip install tai-storage[azure]

# Con soporte para SharePoint
pip install tai-storage[sharepoint]

# Con módulo de datos (pandas, perfilado, etc.)
pip install tai-storage[data]

# Con todos los orígenes y módulos
pip install tai-storage[all]

📖 Uso Básico

from tai_storage import LocalOrigin

# Crear origen local
origin = LocalOrigin(root_path='/data')

# Obtener carpeta y archivo  
folder = origin.get_folder('reports')
file = folder.get_file('report.csv')

# Leer archivo
data = file.read()
text = file.read_text()

# Listar archivos
files = folder.list_files(pattern=r'.*\.csv$')

Nota: Implementaciones disponibles: Local ✅, SharePoint ✅ y Azure Blob Storage ✅. StorageFactory ✅ disponible.

🏗️ Arquitectura

La librería se basa en tres clases abstractas principales:

1. Origin (Sistema de Almacenamiento)

Representa el origen de datos (Azure, SFTP, local, etc.)

class Origin(ABC):
    def connect()
    def disconnect()
    def get_folder(path) -> Folder
    def create_folder(path) -> Folder
    def folder_exists(path) -> bool
    # ...

2. Folder (Carpeta/Contenedor)

Representa una carpeta dentro de un origen

class Folder(ABC):
    def list_files(pattern, recursive) -> List[str]
    def get_file(filename) -> File
    def upload_file(source, destination) -> File
    def delete_file(filename)
    # ...

3. File (Archivo)

Representa un archivo individual

class File(ABC):
    def read() -> bytes
    def read_text() -> str
    def write(data: bytes)
    def delete()
    def copy_to(destination: File)
    # Properties: name, extension, size, created_time, modified_time
    # ...

🎯 Ejemplos de Uso

Usando StorageFactory (Recomendado)

La forma más sencilla de trabajar con tai-storage es usando StorageFactory:

from tai_storage import StorageFactory

# Sistema Local
local = StorageFactory.create_local(root_path='/data')

# Azure Blob Storage con parámetros
azure = StorageFactory.create_azure(
    account_name='myaccount',
    account_key='mykey123'
)

# O usando variables de entorno
# export AZURE_STORAGE_ACCOUNT_NAME=myaccount
# export AZURE_STORAGE_ACCOUNT_KEY=mykey123
azure = StorageFactory.create_azure()  # ← Lee desde env vars

# SharePoint Online
sharepoint = StorageFactory.create_sharepoint(
    tenant_id='your-tenant-id',
    client_id='your-client-id',
    client_secret='your-secret',
    site_name='Documents',
    hostname='contoso.sharepoint.com'
)

Trabajar con Archivos

# Usar cualquier origin (local, Azure, SharePoint...)
origin = StorageFactory.create_local(root_path='/data')

# Obtener carpeta y archivo
folder = origin.get_folder('documents')
file = folder.get_file('report.pdf')

# Verificar existencia y leer
if file.exists():
    data = file.read()
    print(f"Tamaño: {file.size} bytes")
    print(f"Modificado: {file.modified_time}")

# Listar archivos con patrón
pdf_files = folder.list_files(pattern=r'.*\.pdf$')
for filename in pdf_files:
    print(f"Encontrado: {filename}")

Azure Blob Storage

from tai_storage import StorageFactory

# Opción 1: Connection string
azure = StorageFactory.create_azure(
    connection_string='DefaultEndpointsProtocol=https;...'
)

# Opción 2: Account name + key
azure = StorageFactory.create_azure(
    account_name='mystorageaccount',
    account_key='mykey123...'
)

# Opción 3: Variables de entorno
# export AZURE_STORAGE_CONNECTION_STRING='...'
azure = StorageFactory.create_azure()

# Trabajar con containers (similar a folders)
container = azure.get_folder('documents')
files = container.list_files()

for filename in files:
    file = container.get_file(filename)
    print(f"{filename}: {file.size} bytes")

SharePoint Online

from tai_storage import StorageFactory

# Crear origin de SharePoint
sp = StorageFactory.create_sharepoint(
    tenant_id='your-tenant-id',
    client_id='your-client-id',
    client_secret='your-secret',
    site_name='Documents',
    hostname='contoso.sharepoint.com'
)

# Trabajar con carpetas y archivos
folder = sp.get_folder('Shared Documents/Reports')
files = folder.list_files(pattern=r'.*\.xlsx$')

for filename in files:
    file = folder.get_file(filename)
    data = file.read()
    print(f"Procesado: {filename}")

Copiar entre Orígenes

from tai_storage import StorageFactory

# Crear orígenes
local = StorageFactory.create_local(root_path='/data')
azure = StorageFactory.create_azure()

# Copiar de local a Azure
source_file = local.get_folder('input').get_file('data.csv')
dest_folder = azure.get_folder('backup')

# Opción 1: Usando upload_file
data = source_file.read()
dest_folder.upload_file(data, 'data.csv')

# Opción 2: Usando copy_to
dest_file = dest_folder.get_file('data.csv')
source_file.copy_to(dest_file)

Context Manager

from tai_storage import StorageFactory

# Auto connect/disconnect con context manager
with StorageFactory.create_local(root_path='/data') as origin:
    folder = origin.get_folder('documents')
    files = folder.list_files()
    print(f"Encontrados {len(files)} archivos")
# Automáticamente desconectado al salir del contexto

# También funciona con SharePoint y Azure
with StorageFactory.create_azure() as azure:
    container = azure.get_folder('backups')
    # ... trabajar con archivos
# Desconectado automáticamente

Filtrar Archivos por Fecha

from datetime import datetime, timedelta
from tai_storage import StorageFactory

origin = StorageFactory.create_local(root_path='/data')
folder = origin.get_folder('logs')

# Archivos modificados en los últimos 7 días
since = datetime.now() - timedelta(days=7)
recent_files = folder.filter_files_by_date(modified_after=since)

for filename in recent_files:
    file = folder.get_file(filename)
    print(f"{filename}: modificado {file.modified_time}")

🔑 Configurar SharePoint con Azure AD

Para usar SharePoint necesitas registrar una aplicación en Azure AD:

1. Registrar Aplicación en Azure Portal

  1. Ve a Azure PortalAzure Active Directory
  2. En el menú lateral: App registrationsNew registration
  3. Configura:
    • Name: tai-storage-app (o el nombre que prefieras)
    • Supported account types: Accounts in this organizational directory only
    • Redirect URI: Déjalo vacío (no es necesario para aplicaciones daemon)
  4. Click en Register
  5. Copia el Application (client) ID → Este es tu client_id
  6. En la página Overview, copia el Directory (tenant) ID → Este es tu tenant_id

2. Crear Client Secret

  1. En tu aplicación, ve a Certificates & secrets
  2. Click en New client secret
  3. Configura:
    • Description: tai-storage-secret
    • Expires: Selecciona duración apropiada (ej: 24 meses)
  4. Click en Add
  5. ⚠️ IMPORTANTE: Copia el Value inmediatamente → Este es tu client_secret
    • ⚠️ Solo se muestra una vez, no podrás volver a verlo

3. Configurar Permisos de Microsoft Graph API

  1. En tu aplicación, ve a API permissions
  2. Click en Add a permissionMicrosoft GraphApplication permissions
  3. Busca y añade estos permisos:
    • Sites.Selected - Acceso solo a sitios específicos (recomendado)
  4. Click en Add permissions
  5. ⚠️ CRÍTICO: Click en Grant admin consent for [Tu Organización]
    • ⚠️ Necesitas permisos de administrador para este paso
    • Sin esto, la aplicación NO funcionará

4. Otorgar Acceso al Sitio Específico

Ahora debes dar permisos explícitos al sitio concreto usando Microsoft Graph API con PowerShell.

💡 Script disponible: Puedes usar el script completo disponible en scripts/permisos_app_sharepoint.ps1

# 0. Limpiar sesión anterior (opcional pero recomendado)
Disconnect-MgGraph -ErrorAction SilentlyContinue

# 1. Instalar módulo si no lo tienes
Install-Module Microsoft.Graph -Scope CurrentUser

# 2. Conectar con permisos de admin
Connect-MgGraph -Scopes "Sites.FullControl.All" -NoWelcome

# 3. Configuración - REEMPLAZA CON TUS VALORES
$hostName = "<YOUR_TENANT>.sharepoint.com"  # ej: triplealphain.sharepoint.com
$siteName = "<SITE_NAME>"                   # ej: TeamSite, Demeter
$sitePath = "/sites/$siteName" 

$appId = "TU-CLIENT-ID-AQUI"                # Tu Application (client) ID
$appName = "tai-storage-app"                # Nombre de tu aplicación

Write-Host "Buscando sitio en: $hostName$sitePath ..." -ForegroundColor Cyan

try {
    # 4. Obtener el sitio usando la API directa
    $apiUrl = "https://graph.microsoft.com/v1.0/sites/$($hostName):$($sitePath)"
    
    $site = Invoke-MgGraphRequest -Method GET -Uri $apiUrl
    
    Write-Host "¡EXITO! Sitio encontrado." -ForegroundColor Green
    Write-Host "Nombre: $($site.displayName)"
    Write-Host "ID: $($site.id)" -ForegroundColor Gray

    # 5. Asignar permisos write (lectura y escritura)
    $params = @{
        roles = @("write")  # Opciones: read, write, owner
        grantedToIdentities = @(
            @{
                application = @{
                    id = $appId
                    displayName = $appName
                }
            }
        )
    }

    Invoke-MgGraphRequest -Method POST `
        -Uri "https://graph.microsoft.com/v1.0/sites/$($site.id)/permissions" `
        -Body ($params | ConvertTo-Json -Depth 5) `
        -ContentType "application/json"

    Write-Host "Permisos asignados correctamente." -ForegroundColor Green

} catch {
    # Manejo de errores
    Write-Host "ERROR AL BUSCAR EL SITIO:" -ForegroundColor Red
    
    if ($_.Exception.Message -match "Not Found" -or $_.ErrorDetails.Message -match "Not Found") {
        Write-Host "El sitio '$sitePath' NO EXISTE." -ForegroundColor Yellow
        Write-Host "Verifica el nombre del sitio en SharePoint."
    } else {
        Write-Host $_.Exception.Message -ForegroundColor Yellow
        if ($_.Exception.InnerException) {
            Write-Host "Detalle: $($_.Exception.InnerException.Message)" -ForegroundColor DarkYellow
        }
    }
}

5. Obtener Información del Sitio de SharePoint

  1. Ve a tu sitio de SharePoint: https://<YOUR_TENANT>.sharepoint.com/sites/<SITE_NAME>
  2. De la URL extrae:
    • hostname: <YOUR_TENANT>.sharepoint.com (ej: contoso.sharepoint.com, triplealphain.sharepoint.com)
    • site_name: <SITE_NAME> (la parte después de /sites/, ej: TeamSite, ProjectSite)

6. Configurar Variables de Entorno

# En tu sistema o .env
export SHAREPOINT_TENANT_ID="12345678-1234-1234-1234-123456789abc"
export SHAREPOINT_CLIENT_ID="87654321-4321-4321-4321-cba987654321"
export SHAREPOINT_CLIENT_SECRET="tu~secret~super~secreto"
export SHAREPOINT_SITE_NAME="<SITE_NAME>"  # ej: TeamSite, ProjectSite
export SHAREPOINT_HOSTNAME="<YOUR_TENANT>.sharepoint.com"  # ej: contoso.sharepoint.com

7. Usar en tu Código

from tai_storage import SharePointOrigin
from tai_storage.secrets import SecretManager

origin = SharePointOrigin(
    tenant_id=SecretManager.get_secret(env_var="SHAREPOINT_TENANT_ID"),
    client_id=SecretManager.get_secret(env_var="SHAREPOINT_CLIENT_ID"),
    client_secret=SecretManager.get_secret(env_var="SHAREPOINT_CLIENT_SECRET"),
    site_name=SecretManager.get_secret(env_var="SHAREPOINT_SITE_NAME"),
    hostname=SecretManager.get_secret(env_var="SHAREPOINT_HOSTNAME")
)

origin.connect()
# ... trabajar con SharePoint
origin.disconnect()

📋 Checklist de Verificación

  • Aplicación registrada en Azure AD
  • Application (client) ID copiado → client_id
  • Directory (tenant) ID copiado → tenant_id
  • Client secret creado y copiado → client_secret
  • Permiso Sites.Selected añadido (NO Sites.ReadWrite.All)
  • Admin consent otorgado (paso crítico)
  • Permisos específicos del sitio otorgados (PowerShell/API - paso crítico)
  • Hostname y site_name del sitio de SharePoint identificados
  • Variables de entorno configuradas
  • pip install tai-storage[sharepoint] ejecutado (o msal y requests instalados)

🔒 Ventajas de usar Sites.Selected

  • Seguridad mejorada: La app solo accede al sitio específico que necesita
  • Principio de mínimo privilegio: No tiene acceso a otros sitios de la organización
  • Auditoría clara: Fácil ver qué apps tienen acceso a qué sitios
  • Revocación simple: Puedes revocar acceso sin eliminar la app
  • ⚠️ Requiere configuración adicional: Necesitas otorgar permisos explícitamente con PowerShell/API

⚠️ Errores Comunes

  • "Insufficient privileges": No se otorgó admin consent o no se otorgaron permisos al sitio específico
  • "Access denied": Usaste Sites.Selected pero no otorgaste permisos al sitio con PowerShell/API
  • "Application not found": Tenant ID o Client ID incorrectos
  • "Invalid client secret": El secret expiró o se copió incorrectamente
  • "Site not found": Hostname o site_name incorrectos
  • ImportError msal: Falta pip install msal requests

🔄 Para otorgar acceso a múltiples sitios

Si necesitas acceso a varios sitios específicos, repite el paso 4 para cada sitio:

# Sitio 1
$site1 = Get-MgSite -Search "<SITE_NAME_1>"  # ej: TeamSite
Invoke-MgGraphRequest -Method POST `
    -Uri "https://graph.microsoft.com/v1.0/sites/$($site1.Id)/permissions" `
    -Body $params

# Sitio 2
$site2 = Get-MgSite -Search "<SITE_NAME_2>"  # ej: ProjectSite
Invoke-MgGraphRequest -Method POST `
    -Uri "https://graph.microsoft.com/v1.0/sites/$($site2.Id)/permissions" `
    -Body $params

📖 Referencias

Filtrar Archivos por Fecha

from datetime import datetime, timedelta

folder = origin.get_folder('logs')

# Archivos de los últimos 7 días
since = datetime.now() - timedelta(days=7)
recent_files = folder.filter_files_by_date(since=since)

for file_meta in recent_files:
    print(f"{file_meta['name']}: {file_meta['modified_time']}")

🔬 Módulo de Datos

Requiere instalación con el extra [data]:

pip install tai-storage[data]

Leer archivos como DataFrame

Cualquier File expone el método get_data() que detecta automáticamente el formato (CSV, Excel, Parquet, JSON) e infiere tipos de datos:

from tai_storage import LocalOrigin

origin = LocalOrigin(root_path='/data')
file = origin.get_folder('reports').get_file('ventas.xlsx')

# Leer como DataFrame con inferencia de tipos
df = file.get_data().to_dataframe(sheet_name='Ventas', infer_types=True)

# O usar los métodos específicos por formato
df = file.get_data().to_csv(sep=';')
df = file.get_data().to_excel(sheet_name='Ventas')
df = file.get_data().to_parquet()

Accessor df.profile

Al importar tai_storage.data se registra automáticamente el accessor .profile en todos los DataFrames de pandas:

import pandas as pd
import tai_storage.data  # activa df.profile

df = pd.read_csv('ventas.csv')

# Nombrar el dataset (opcional, mejora los reportes)
df.profile.data_name = 'ventas_2024'

# Perfil de una columna específica
col = df.profile.get('precio')
print(col.type)           # 'numeric'
print(col.num_unicos)     # nº de valores únicos
print(col.relative_vacios)  # fracción de nulos (0.0 – 1.0)
print(col.unicos)         # lista de valores únicos ordenados

# Acceso también vía []
col = df.profile['fecha']

# Generar y mostrar todos los perfiles
df.profile.generate()   # genera todos (lazy, solo columnas nuevas)
df.profile.show()       # imprime por consola (auto-genera si falta)

# Análisis de correlación entre columnas
df.profile.show_correlation_matrix()            # nulos = coincidencia
df.profile.show_correlation_matrix(include_na=False)

# Detectar columnas funcionalmente determinadas por una clave
df.profile.show_duplicates_by_key('cliente_id')
df.profile.show_duplicates_by_key(['pais', 'provincia'])

Integridad referencial entre columnas

col_a = df_pedidos.profile['cliente_id']
col_b = df_clientes.profile['id']

col_a.referencial_integrity_with(col_b)
# ✅ SI. Considera: "clientes[id]" -- one to many -- "pedidos[cliente_id]"

Perfilado programático

from tai_storage.data import Profiles, ColumnProfile

profiles = Profiles(df, data_name='ventas')
profiles.generate()

col = profiles.get('precio')
print(col.type)           # 'numeric'
print(col.num_vacios)     # int
print(col.relative_vacios)  # float
print(col.distribucion)   # list[(valor, frecuencia%)]

Nota: Los perfiles se cachean por instancia de DataFrame. Llamar df.profile.get('col') varias veces devuelve siempre el mismo objeto.


⚙️ Configuración

Logging con tai-alphi

from tai_storage import configure_logger

# Configurar logging
configure_logger(
    log_level='DEBUG',  # DEBUG, INFO, WARN, ERROR, CRIT
    display_info=['asctime', 'levelname', 'funcName'],
    time_format='%H:%M:%S'
)

# Para acceder directamente al logger desde otros módulos:
from tai_alphi import Alphi
logger = Alphi.get_logger_by_name('tai-storage')
logger.info('Mensaje personalizado')

Variables de Entorno

StorageFactory puede obtener credenciales de variables de entorno:

# Local
export STORAGE_LOCAL_ROOT_PATH="/data/files"

# Azure Blob Storage (Opción 1: Connection String)
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...;EndpointSuffix=core.windows.net"

# Azure Blob Storage (Opción 2: Account + Key)
export AZURE_STORAGE_ACCOUNT_NAME="mystorageaccount"
export AZURE_STORAGE_ACCOUNT_KEY="mykey123..."

# SharePoint Online
export SHAREPOINT_TENANT_ID="12345678-1234-1234-1234-123456789abc"
export SHAREPOINT_CLIENT_ID="87654321-4321-4321-4321-cba987654321"
export SHAREPOINT_CLIENT_SECRET="tu~secret~super~secreto"
export SHAREPOINT_SITE_NAME="TeamSite"  # Nombre del sitio
export SHAREPOINT_HOSTNAME="contoso.sharepoint.com"  # Tu tenant

Luego puedes crear origins sin parámetros:

from tai_storage import StorageFactory

# Lee credenciales de variables de entorno
local = StorageFactory.create_local()
azure = StorageFactory.create_azure()
sharepoint = StorageFactory.create_sharepoint()

Parámetros vs Variables de Entorno

StorageFactory prioriza parámetros directos sobre variables de entorno:

# 1. Parámetros directos (prioridad alta)
origin = StorageFactory.create_azure(
    account_name='myaccount',
    account_key='mykey'
)

# 2. Variables de entorno (fallback)
# export AZURE_STORAGE_ACCOUNT_NAME=myaccount
origin = StorageFactory.create_azure()  # Usa env vars

# 3. Mix (parámetros + env vars)
# export AZURE_STORAGE_ACCOUNT_KEY=mykey
origin = StorageFactory.create_azure(
    account_name='myaccount'  # key viene de env var
)

🧪 Testing

from tai_storage import LocalOrigin
import tempfile

def test_file_operations():
    with tempfile.TemporaryDirectory() as tmpdir:
        origin = LocalOrigin(root_path=tmpdir)
        folder = origin.create_folder('test')
        
        # Test upload
        folder.upload_file(b'test data', 'test.txt')
        
        # Test read
        file = folder.get_file('test.txt')
        assert file.read() == b'test data'
        
        # Test delete
        file.delete()
        assert not file.exists()

Ejecutar tests:

# Tests de fundamentos (Fase 1)
python -m pytest tests/test_fase1.py -v

# Tests de implementación local (Fase 2)
python -m pytest tests/test_fase2_local.py -v

# Tests de SharePoint (requiere credenciales configuradas)
python -m pytest tests/test_sharepoint.py -v

# Todos los tests
python -m pytest tests/ -v

# Ejemplos funcionales
python examples_local.py
python examples_sharepoint.py  # Requiere credenciales

📦 Estructura del Proyecto

tai_storage/
├── base/                      # Clases abstractas
│   ├── origin.py
│   ├── folder.py
│   └── file.py
├── implementations/           # Implementaciones
│   ├── local/                # ✅ Sistema de archivos local
│   │   ├── origin.py
│   │   ├── folder.py
│   │   └── file.py
│   ├── sharepoint/           # ✅ SharePoint Online (Graph API)
│   │   ├── origin.py
│   │   ├── folder.py
│   │   └── file.py
│   ├── azure/                # ✅ Azure Blob Storage
│   │   ├── origin.py
│   │   ├── folder.py
│   │   └── file.py
│   ├── sftp/                 # 🔜 SFTP
│   └── ftp/                  # 🔜 FTP
├── cache/                     # Sistema de caché para modo DEV
│   ├── cached_origin.py
│   ├── cached_folder.py
│   └── cached_file.py
├── data/                      # Módulo de datos (extra [data])
│   ├── readers.py             # CSV, Excel, Parquet, JSON readers
│   ├── file_reader.py         # FileDataReader (detección automática)
│   ├── types.py               # TypeInferencer, infer_and_convert_dataframe
│   ├── transformers.py        # normalizar_texto y otras transformaciones
│   ├── profile.py             # ColumnProfile, Profiles, CorrelationMatrix
│   └── accessor.py            # Accessor df.profile para pandas
├── factory.py                 # StorageFactory
├── secrets.py                 # SecretManager
├── exceptions.py              # Excepciones personalizadas
├── logger.py                  # Configuración de logging
└── utils.py                   # Utilidades

🗺️ Roadmap

  • Fase 1: Fundamentos (clases base, excepciones, secretos) ✅
  • Fase 2: Implementación Local ✅
  • Fase 2.5: Implementación SharePoint (Microsoft Graph API + MSAL) ✅
  • Fase 3: Sistema de Caché (Modo DEV)
  • Fase 4: Factory y Secrets
  • Fase 5: Implementación Azure Blob Storage
  • Fase 6: Implementaciones SFTP, FTP

🤝 Contribución

Las contribuciones son bienvenidas. Por favor:

  1. Fork el proyecto
  2. Crea una rama para tu feature (git checkout -b feature/amazing)
  3. Commit tus cambios (git commit -m 'Add amazing feature')
  4. Push a la rama (git push origin feature/amazing)
  5. Abre un Pull Request

📄 Licencia

MIT License - ver archivo LICENSE para más detalles

🆘 Soporte

Para reportar bugs o solicitar features:

  • Abre un issue en GitHub
  • Contacta al equipo de desarrollo

👥 Autores

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tai_storage-0.1.16.tar.gz (70.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tai_storage-0.1.16-py3-none-any.whl (90.4 kB view details)

Uploaded Python 3

File details

Details for the file tai_storage-0.1.16.tar.gz.

File metadata

  • Download URL: tai_storage-0.1.16.tar.gz
  • Upload date:
  • Size: 70.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.4 CPython/3.11.0 Linux/6.17.0-1010-azure

File hashes

Hashes for tai_storage-0.1.16.tar.gz
Algorithm Hash digest
SHA256 4fe40d0ec136c98eb82f3214f02f5e56ebb2b21b02d15d40805305b78aa32242
MD5 dbffcdb316fc52c16ee76f9934e13a10
BLAKE2b-256 173ded0e4c8837fd0f9cc905c569e7e8098f8a2ae1245fe6caea65716e736788

See more details on using hashes here.

File details

Details for the file tai_storage-0.1.16-py3-none-any.whl.

File metadata

  • Download URL: tai_storage-0.1.16-py3-none-any.whl
  • Upload date:
  • Size: 90.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.3.4 CPython/3.11.0 Linux/6.17.0-1010-azure

File hashes

Hashes for tai_storage-0.1.16-py3-none-any.whl
Algorithm Hash digest
SHA256 257da0f9e97975eeb7978ca401347c698bad4ced846909b153330a5fe0b31825
MD5 174123a72d417145dab64d4aed968e99
BLAKE2b-256 92ecf83c19d48ee2d87808e48f39026bdd5620d3c39512d0fa65d846a17224ab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page