xllify


Namexllify JSON
Version 0.8.2 PyPI version JSON
download
home_pageNone
SummaryPython SDK for creating Excel XLL add-ins with xllify
upload_time2025-11-14 10:18:29
maintainerNone
docs_urlNone
authorAlex Reid
requires_python>=3.8
licenseMIT
keywords excel xll udf add-in finance
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # xllify Python SDK

A Python SDK for creating high-performance Excel add-ins with xllify. Write Python functions and call them from Excel with automatic type conversion, error handling, and real-time updates.

## Installation

You it is strongly recommended that you create a virtual environment and activate it.

```bash
pip install virtualenv # if you don't have it
virtualenv venv
source venv/bin/activate # mac OR
source venv\Scripts\activate # win
```

Then install xllify.

```bash
pip install xllify
xllify-install
```

## Quick Start

### 1. Create your Python functions

```python
# my_functions.py
import xllify

@xllify.fn("xllipy.Hello")
def hello(name: str = "World") -> str:
    return f"Hello, {name}!"

@xllify.fn("xllipy.Add", category="Math")
def add(a: float, b: float) -> float:
    return a + b
```

### 2. Build

```bash
xllify MyAddin.xll my_functions.py
```

### 3. Use in Excel

Functions are immediately available after you open the .xll in Excel.

```
=xllipy.Hello("World")       -> "Hello, World!"
=xllipy.Add(5, 10)           -> 15
```

Functions execute asynchronously - Excel shows #N/A while processing, then updates automatically when complete.

## Workflow

### Build and deployment

For production, Python files are embedded directly into your XLL:

```bash
xllify build MyAddin.xll main.py --requirements requirements.txt
```

When the XLL loads in Excel, Python files are extracted to `%LOCALAPPDATA%\xllify\MyAddin\python\` and the Python process starts automatically.

### Distribution

Just distribute the XLL file. Everything else (Python files, dependencies) is embedded and will be extracted automatically on first load.

## Features

- **Async by default** - Functions run asynchronously so Excel never freezes
- **Auto-reload** - Hot reload functions during development without restarting Excel
- **Matrix support** - Return 2D arrays and pandas DataFrames directly to Excel
- **Type-safe** - Full type hints with `CellValue`, `Matrix`, and `ExcelValue`
- **Simple API** - Just add the `@xllify.fn()` decorator to your existing functions

## Best practices

Our recommended approach is for you to implement your business logic in plain Python modules and call them from short functions wrapped with `@xllify.fn`. This keeps your core logic testable, reusable, and independent of  Excel.

```python
# my_logic.py - Pure Python, no xllify dependencies
def calculate_option_price(spot, strike, time, rate, volatility):
    """Black-Scholes call option pricing - testable business logic"""
    # ... implementation ...
    return price

# excel_functions.py - Thin xllify wrapper
import xllify
from my_logic import calculate_option_price

@xllify.fn("xllipy.BSCall", category="Finance")
def bs_call(s: float, k: float, t: float, r: float, sigma: float) -> float:
    """Excel wrapper for Black-Scholes calculation"""
    return calculate_option_price(s, k, t, r, sigma)
```

Benefits:
- **Testable**: Run `pytest` on `my_logic.py` without Excel or xllify
- **Reusable**: Use the same logic in web apps, CLIs, or other contexts without needing to import xllify
- **Maintainable**: Separate concerns between business logic and Excel integration
- **Debuggable**: Test and debug core logic independently

## Advanced usage

### Batching configuration

By default, xllify batches RTD updates for better performance (batch_size=500, batch_timeout_ms=50). You can customize this:

```python
import xllify

# Configure batching before registering functions
xllify.configure_batching(
    enabled=True,
    batch_size=1000,        # Batch up to 1000 updates together
    batch_timeout_ms=100    # Wait up to 100ms before flushing
)

@xllify.fn("xllipy.Hello")
def hello(name: str) -> str:
    return f"Hello, {name}!"
```

**When to adjust batching:**
- **High-volume scenarios**: Increase `batch_size` (1000+) and `batch_timeout_ms` (100+) for better throughput when handling many concurrent calculations
- **Low-latency requirements**: Decrease `batch_timeout_ms` (10-20ms) or disable batching entirely for faster individual responses
- **Balanced performance**: Use defaults (batch_size=500, batch_timeout_ms=50)

**Disable batching:**
```python
xllify.configure_batching(enabled=False)  # Send updates immediately
```

### Parameter metadata

Provide detailed parameter information for better documentation:

```python
from xllify import fn, Parameter

@fn(
    "xllipy.Calculate",
    description="Perform calculation with optional delay",
    category="Math",
    parameters=[
        Parameter("value", type="number", description="Value to process"),
        Parameter("delay", type="number", description="Delay in seconds (optional)")
    ],
    return_type="number"
)
def calculate(value: float, delay: float = 1.0) -> float:
    """Process a value with optional delay"""
    import time
    if delay > 0:
        time.sleep(delay)
    return value * 2
```

### Working with arrays and matrices

Excel ranges are passed as 2D lists. You can also **return** matrices to Excel:

```python
from xllify import Matrix

# Input: Accept ranges as 2D lists
@xllify.fn("xllipy.SumArray", description="Sum all numbers in a range")
def sum_array(numbers: list) -> float:
    """Sum a 2D array from Excel range"""
    total = 0.0
    for row in numbers:
        for cell in row:
            if isinstance(cell, (int, float)):
                total += cell
    return total

# Output: Return matrices to Excel
@xllify.fn("xllipy.GetData")
def get_data() -> Matrix:
    """Return a 2D array to Excel"""
    return [
        [1.0, True, "hello"],
        [2.0, False, None],    # None displays as empty cell
        [3.0, None, "world"]
    ]
```

In Excel:
```
=xllipy.SumArray(A1:C10)           -> Sum of all numbers
=xllipy.GetData()                  -> Spills 3x3 array into cells
```

### Pandas DataFrames

Return DataFrames directly - automatically converted to Excel ranges with headers:

```python
import pandas as pd

@xllify.fn("xllipy.GetDataFrame")
def get_dataframe() -> pd.DataFrame:
    """Return pandas DataFrame to Excel"""
    return pd.DataFrame({
        'Name': ['Alice', 'Bob', 'Charlie'],
        'Age': [25, 30, 35],
        'Score': [95.5, 87.3, 92.1]
    })
```

In Excel, `=xllipy.GetDataFrame()` spills as:
```
Name      Age    Score
Alice     25     95.5
Bob       30     87.3
Charlie   35     92.1
```

### Type mapping

| Excel Type | Python Type |
|------------|-------------|
| Number | `float` |
| String | `str` |
| Boolean | `bool` |
| Range | `List[List]` (2D array) |
| Empty | `None` |

## API reference

### Type definitions

```python
from xllify import CellValue, Matrix, ExcelValue

CellValue = Union[float, bool, str, None]
Matrix = List[List[CellValue]]
ExcelValue = Union[CellValue, Matrix, Any]
```

- **CellValue**: A single Excel cell value (number, boolean, string, or None for empty cells)
- **Matrix**: A 2D array of cell values
- **ExcelValue**: Any value that can be returned to Excel (scalar, matrix, or pandas DataFrame)

### Decorators

#### `@xllify.fn(name, description="", category="", parameters=None, return_type="")`

Register a Python function as an Excel function.

**Arguments:**
- `name` (str): Excel function name (e.g., "xllipy.MyFunc")
- `description` (str, optional): Function description (defaults to docstring)
- `category` (str, optional): Excel function category
- `parameters` (List[Parameter], optional): Parameter metadata
- `return_type` (str, optional): Return type override

**Example:**
```python
@xllify.fn("xllipy.Add", description="Add numbers", category="Math")
def add(a: float, b: float) -> float:
    return a + b
```

### CLI commands

```bash
# Install the xllify tool and xllify-lua
xllify-install

# Clear async function cache
xllify-clear-cache
```

## Error handling

Python exceptions are caught and returned to Excel as error strings:

```python
@xllify.fn("xllipy.Divide")
def divide(a, b):
    if b == 0:
        raise ValueError("Division by zero")
    return a / b
```

In Excel:
```
=xllipy.Divide(10, 0)    -> #ERROR: Division by zero
```

## More examples

### Slow operations (async)

Functions run asynchronously - Excel never freezes:

```python
@xllify.fn("xllipy.SlowCalc")
def slow_calc(seconds: float) -> str:
    import time
    time.sleep(seconds)
    return f"Done after {seconds}s"
```

Excel shows #N/A while waiting, then updates automatically.
> It is worth pointing out that this WILL however block your Python process. A simple workaround is to run multiple processes of the same Python script. `asyncio` support is planned.

### Black-Scholes option pricing

```python
from math import log, sqrt, exp, erf

@xllify.fn("xllipy.BSCall", category="Finance")
def black_scholes_call(s: float, k: float, t: float, r: float, sigma: float) -> float:
    """Black-Scholes call option price"""
    if t <= 0:
        return max(s - k, 0)

    d1 = (log(s / k) + (r + 0.5 * sigma ** 2) * t) / (sigma * sqrt(t))
    d2 = d1 - sigma * sqrt(t)

    def norm_cdf(x):
        return 0.5 * (1 + erf(x / sqrt(2)))

    return s * norm_cdf(d1) - k * exp(-r * t) * norm_cdf(d2)
```

Usage: `=xllipy.BSCall(100, 95, 0.25, 0.05, 0.2)`

### HTTP requests

```python
@xllify.fn("xllipy.FetchPrice")
def fetch_price(symbol: str) -> float:
    import requests
    resp = requests.get(f"https://api.example.com/price/{symbol}")
    return resp.json()["price"]
```

### System info

```python
@xllify.fn("xllipy.GetInfo")
def get_info() -> str:
    import sys
    import platform
    return f"Python {sys.version.split()[0]} on {platform.system()}"
```

## Development

### Running tests

```bash
pip install -e ".[dev]"
pytest tests/ -v
```

### Code formatting

```bash
black xllify/ tests/ examples/
```

## License

MIT

## Support

- Issues: https://github.com/xllifycom/xllify-python/issues

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "xllify",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "excel, xll, udf, add-in, finance",
    "author": "Alex Reid",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/fa/86/46a9cf7664f82e5c4ef790bd364faf0a1f1a28bd3c010f8ba492b13f7244/xllify-0.8.2.tar.gz",
    "platform": null,
    "description": "# xllify Python SDK\r\n\r\nA Python SDK for creating high-performance Excel add-ins with xllify. Write Python functions and call them from Excel with automatic type conversion, error handling, and real-time updates.\r\n\r\n## Installation\r\n\r\nYou it is strongly recommended that you create a virtual environment and activate it.\r\n\r\n```bash\r\npip install virtualenv # if you don't have it\r\nvirtualenv venv\r\nsource venv/bin/activate # mac OR\r\nsource venv\\Scripts\\activate # win\r\n```\r\n\r\nThen install xllify.\r\n\r\n```bash\r\npip install xllify\r\nxllify-install\r\n```\r\n\r\n## Quick Start\r\n\r\n### 1. Create your Python functions\r\n\r\n```python\r\n# my_functions.py\r\nimport xllify\r\n\r\n@xllify.fn(\"xllipy.Hello\")\r\ndef hello(name: str = \"World\") -> str:\r\n    return f\"Hello, {name}!\"\r\n\r\n@xllify.fn(\"xllipy.Add\", category=\"Math\")\r\ndef add(a: float, b: float) -> float:\r\n    return a + b\r\n```\r\n\r\n### 2. Build\r\n\r\n```bash\r\nxllify MyAddin.xll my_functions.py\r\n```\r\n\r\n### 3. Use in Excel\r\n\r\nFunctions are immediately available after you open the .xll in Excel.\r\n\r\n```\r\n=xllipy.Hello(\"World\")       -> \"Hello, World!\"\r\n=xllipy.Add(5, 10)           -> 15\r\n```\r\n\r\nFunctions execute asynchronously - Excel shows #N/A while processing, then updates automatically when complete.\r\n\r\n## Workflow\r\n\r\n### Build and deployment\r\n\r\nFor production, Python files are embedded directly into your XLL:\r\n\r\n```bash\r\nxllify build MyAddin.xll main.py --requirements requirements.txt\r\n```\r\n\r\nWhen the XLL loads in Excel, Python files are extracted to `%LOCALAPPDATA%\\xllify\\MyAddin\\python\\` and the Python process starts automatically.\r\n\r\n### Distribution\r\n\r\nJust distribute the XLL file. Everything else (Python files, dependencies) is embedded and will be extracted automatically on first load.\r\n\r\n## Features\r\n\r\n- **Async by default** - Functions run asynchronously so Excel never freezes\r\n- **Auto-reload** - Hot reload functions during development without restarting Excel\r\n- **Matrix support** - Return 2D arrays and pandas DataFrames directly to Excel\r\n- **Type-safe** - Full type hints with `CellValue`, `Matrix`, and `ExcelValue`\r\n- **Simple API** - Just add the `@xllify.fn()` decorator to your existing functions\r\n\r\n## Best practices\r\n\r\nOur recommended approach is for you to implement your business logic in plain Python modules and call them from short functions wrapped with `@xllify.fn`. This keeps your core logic testable, reusable, and independent of  Excel.\r\n\r\n```python\r\n# my_logic.py - Pure Python, no xllify dependencies\r\ndef calculate_option_price(spot, strike, time, rate, volatility):\r\n    \"\"\"Black-Scholes call option pricing - testable business logic\"\"\"\r\n    # ... implementation ...\r\n    return price\r\n\r\n# excel_functions.py - Thin xllify wrapper\r\nimport xllify\r\nfrom my_logic import calculate_option_price\r\n\r\n@xllify.fn(\"xllipy.BSCall\", category=\"Finance\")\r\ndef bs_call(s: float, k: float, t: float, r: float, sigma: float) -> float:\r\n    \"\"\"Excel wrapper for Black-Scholes calculation\"\"\"\r\n    return calculate_option_price(s, k, t, r, sigma)\r\n```\r\n\r\nBenefits:\r\n- **Testable**: Run `pytest` on `my_logic.py` without Excel or xllify\r\n- **Reusable**: Use the same logic in web apps, CLIs, or other contexts without needing to import xllify\r\n- **Maintainable**: Separate concerns between business logic and Excel integration\r\n- **Debuggable**: Test and debug core logic independently\r\n\r\n## Advanced usage\r\n\r\n### Batching configuration\r\n\r\nBy default, xllify batches RTD updates for better performance (batch_size=500, batch_timeout_ms=50). You can customize this:\r\n\r\n```python\r\nimport xllify\r\n\r\n# Configure batching before registering functions\r\nxllify.configure_batching(\r\n    enabled=True,\r\n    batch_size=1000,        # Batch up to 1000 updates together\r\n    batch_timeout_ms=100    # Wait up to 100ms before flushing\r\n)\r\n\r\n@xllify.fn(\"xllipy.Hello\")\r\ndef hello(name: str) -> str:\r\n    return f\"Hello, {name}!\"\r\n```\r\n\r\n**When to adjust batching:**\r\n- **High-volume scenarios**: Increase `batch_size` (1000+) and `batch_timeout_ms` (100+) for better throughput when handling many concurrent calculations\r\n- **Low-latency requirements**: Decrease `batch_timeout_ms` (10-20ms) or disable batching entirely for faster individual responses\r\n- **Balanced performance**: Use defaults (batch_size=500, batch_timeout_ms=50)\r\n\r\n**Disable batching:**\r\n```python\r\nxllify.configure_batching(enabled=False)  # Send updates immediately\r\n```\r\n\r\n### Parameter metadata\r\n\r\nProvide detailed parameter information for better documentation:\r\n\r\n```python\r\nfrom xllify import fn, Parameter\r\n\r\n@fn(\r\n    \"xllipy.Calculate\",\r\n    description=\"Perform calculation with optional delay\",\r\n    category=\"Math\",\r\n    parameters=[\r\n        Parameter(\"value\", type=\"number\", description=\"Value to process\"),\r\n        Parameter(\"delay\", type=\"number\", description=\"Delay in seconds (optional)\")\r\n    ],\r\n    return_type=\"number\"\r\n)\r\ndef calculate(value: float, delay: float = 1.0) -> float:\r\n    \"\"\"Process a value with optional delay\"\"\"\r\n    import time\r\n    if delay > 0:\r\n        time.sleep(delay)\r\n    return value * 2\r\n```\r\n\r\n### Working with arrays and matrices\r\n\r\nExcel ranges are passed as 2D lists. You can also **return** matrices to Excel:\r\n\r\n```python\r\nfrom xllify import Matrix\r\n\r\n# Input: Accept ranges as 2D lists\r\n@xllify.fn(\"xllipy.SumArray\", description=\"Sum all numbers in a range\")\r\ndef sum_array(numbers: list) -> float:\r\n    \"\"\"Sum a 2D array from Excel range\"\"\"\r\n    total = 0.0\r\n    for row in numbers:\r\n        for cell in row:\r\n            if isinstance(cell, (int, float)):\r\n                total += cell\r\n    return total\r\n\r\n# Output: Return matrices to Excel\r\n@xllify.fn(\"xllipy.GetData\")\r\ndef get_data() -> Matrix:\r\n    \"\"\"Return a 2D array to Excel\"\"\"\r\n    return [\r\n        [1.0, True, \"hello\"],\r\n        [2.0, False, None],    # None displays as empty cell\r\n        [3.0, None, \"world\"]\r\n    ]\r\n```\r\n\r\nIn Excel:\r\n```\r\n=xllipy.SumArray(A1:C10)           -> Sum of all numbers\r\n=xllipy.GetData()                  -> Spills 3x3 array into cells\r\n```\r\n\r\n### Pandas DataFrames\r\n\r\nReturn DataFrames directly - automatically converted to Excel ranges with headers:\r\n\r\n```python\r\nimport pandas as pd\r\n\r\n@xllify.fn(\"xllipy.GetDataFrame\")\r\ndef get_dataframe() -> pd.DataFrame:\r\n    \"\"\"Return pandas DataFrame to Excel\"\"\"\r\n    return pd.DataFrame({\r\n        'Name': ['Alice', 'Bob', 'Charlie'],\r\n        'Age': [25, 30, 35],\r\n        'Score': [95.5, 87.3, 92.1]\r\n    })\r\n```\r\n\r\nIn Excel, `=xllipy.GetDataFrame()` spills as:\r\n```\r\nName      Age    Score\r\nAlice     25     95.5\r\nBob       30     87.3\r\nCharlie   35     92.1\r\n```\r\n\r\n### Type mapping\r\n\r\n| Excel Type | Python Type |\r\n|------------|-------------|\r\n| Number | `float` |\r\n| String | `str` |\r\n| Boolean | `bool` |\r\n| Range | `List[List]` (2D array) |\r\n| Empty | `None` |\r\n\r\n## API reference\r\n\r\n### Type definitions\r\n\r\n```python\r\nfrom xllify import CellValue, Matrix, ExcelValue\r\n\r\nCellValue = Union[float, bool, str, None]\r\nMatrix = List[List[CellValue]]\r\nExcelValue = Union[CellValue, Matrix, Any]\r\n```\r\n\r\n- **CellValue**: A single Excel cell value (number, boolean, string, or None for empty cells)\r\n- **Matrix**: A 2D array of cell values\r\n- **ExcelValue**: Any value that can be returned to Excel (scalar, matrix, or pandas DataFrame)\r\n\r\n### Decorators\r\n\r\n#### `@xllify.fn(name, description=\"\", category=\"\", parameters=None, return_type=\"\")`\r\n\r\nRegister a Python function as an Excel function.\r\n\r\n**Arguments:**\r\n- `name` (str): Excel function name (e.g., \"xllipy.MyFunc\")\r\n- `description` (str, optional): Function description (defaults to docstring)\r\n- `category` (str, optional): Excel function category\r\n- `parameters` (List[Parameter], optional): Parameter metadata\r\n- `return_type` (str, optional): Return type override\r\n\r\n**Example:**\r\n```python\r\n@xllify.fn(\"xllipy.Add\", description=\"Add numbers\", category=\"Math\")\r\ndef add(a: float, b: float) -> float:\r\n    return a + b\r\n```\r\n\r\n### CLI commands\r\n\r\n```bash\r\n# Install the xllify tool and xllify-lua\r\nxllify-install\r\n\r\n# Clear async function cache\r\nxllify-clear-cache\r\n```\r\n\r\n## Error handling\r\n\r\nPython exceptions are caught and returned to Excel as error strings:\r\n\r\n```python\r\n@xllify.fn(\"xllipy.Divide\")\r\ndef divide(a, b):\r\n    if b == 0:\r\n        raise ValueError(\"Division by zero\")\r\n    return a / b\r\n```\r\n\r\nIn Excel:\r\n```\r\n=xllipy.Divide(10, 0)    -> #ERROR: Division by zero\r\n```\r\n\r\n## More examples\r\n\r\n### Slow operations (async)\r\n\r\nFunctions run asynchronously - Excel never freezes:\r\n\r\n```python\r\n@xllify.fn(\"xllipy.SlowCalc\")\r\ndef slow_calc(seconds: float) -> str:\r\n    import time\r\n    time.sleep(seconds)\r\n    return f\"Done after {seconds}s\"\r\n```\r\n\r\nExcel shows #N/A while waiting, then updates automatically.\r\n> It is worth pointing out that this WILL however block your Python process. A simple workaround is to run multiple processes of the same Python script. `asyncio` support is planned.\r\n\r\n### Black-Scholes option pricing\r\n\r\n```python\r\nfrom math import log, sqrt, exp, erf\r\n\r\n@xllify.fn(\"xllipy.BSCall\", category=\"Finance\")\r\ndef black_scholes_call(s: float, k: float, t: float, r: float, sigma: float) -> float:\r\n    \"\"\"Black-Scholes call option price\"\"\"\r\n    if t <= 0:\r\n        return max(s - k, 0)\r\n\r\n    d1 = (log(s / k) + (r + 0.5 * sigma ** 2) * t) / (sigma * sqrt(t))\r\n    d2 = d1 - sigma * sqrt(t)\r\n\r\n    def norm_cdf(x):\r\n        return 0.5 * (1 + erf(x / sqrt(2)))\r\n\r\n    return s * norm_cdf(d1) - k * exp(-r * t) * norm_cdf(d2)\r\n```\r\n\r\nUsage: `=xllipy.BSCall(100, 95, 0.25, 0.05, 0.2)`\r\n\r\n### HTTP requests\r\n\r\n```python\r\n@xllify.fn(\"xllipy.FetchPrice\")\r\ndef fetch_price(symbol: str) -> float:\r\n    import requests\r\n    resp = requests.get(f\"https://api.example.com/price/{symbol}\")\r\n    return resp.json()[\"price\"]\r\n```\r\n\r\n### System info\r\n\r\n```python\r\n@xllify.fn(\"xllipy.GetInfo\")\r\ndef get_info() -> str:\r\n    import sys\r\n    import platform\r\n    return f\"Python {sys.version.split()[0]} on {platform.system()}\"\r\n```\r\n\r\n## Development\r\n\r\n### Running tests\r\n\r\n```bash\r\npip install -e \".[dev]\"\r\npytest tests/ -v\r\n```\r\n\r\n### Code formatting\r\n\r\n```bash\r\nblack xllify/ tests/ examples/\r\n```\r\n\r\n## License\r\n\r\nMIT\r\n\r\n## Support\r\n\r\n- Issues: https://github.com/xllifycom/xllify-python/issues\r\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python SDK for creating Excel XLL add-ins with xllify",
    "version": "0.8.2",
    "project_urls": {
        "Documentation": "https://xllify.com",
        "Homepage": "https://xllify.com",
        "Issues": "https://github.com/xllifycom/xllify-python/issues",
        "Repository": "https://github.com/xllifycom/xllify-python"
    },
    "split_keywords": [
        "excel",
        " xll",
        " udf",
        " add-in",
        " finance"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9fec0387f7e6e4139be937c1ae99328a394ce26e5cdfd5c4a4a319b8aef45e82",
                "md5": "34edb63fd1ffa89ad48910c248b207fd",
                "sha256": "497bce3b2aef87f23460593baff6d13361264afd0c2d3a2c1ebf5e64c09f7ce9"
            },
            "downloads": -1,
            "filename": "xllify-0.8.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "34edb63fd1ffa89ad48910c248b207fd",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 31791,
            "upload_time": "2025-11-14T10:18:28",
            "upload_time_iso_8601": "2025-11-14T10:18:28.624096Z",
            "url": "https://files.pythonhosted.org/packages/9f/ec/0387f7e6e4139be937c1ae99328a394ce26e5cdfd5c4a4a319b8aef45e82/xllify-0.8.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "fa8646a9cf7664f82e5c4ef790bd364faf0a1f1a28bd3c010f8ba492b13f7244",
                "md5": "f6de5cbdc3119d2205687074b5797a9f",
                "sha256": "da0f352cf145e84ac11c4b32eb4311b5762f55427ce07636184d28e1b5cda95a"
            },
            "downloads": -1,
            "filename": "xllify-0.8.2.tar.gz",
            "has_sig": false,
            "md5_digest": "f6de5cbdc3119d2205687074b5797a9f",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 34906,
            "upload_time": "2025-11-14T10:18:29",
            "upload_time_iso_8601": "2025-11-14T10:18:29.532969Z",
            "url": "https://files.pythonhosted.org/packages/fa/86/46a9cf7664f82e5c4ef790bd364faf0a1f1a28bd3c010f8ba492b13f7244/xllify-0.8.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-11-14 10:18:29",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "xllifycom",
    "github_project": "xllify-python",
    "github_not_found": true,
    "lcname": "xllify"
}
        
Elapsed time: 2.86461s