Metadata-Version: 2.4
Name: lazyrefresh
Version: 0.1.0
Summary: Near-realtime attribute refresh system with dynamic interception and safe concurrent refresh handling.
Author-email: Troy Hoffman <troywhoffman@gmail.com>
License: MIT License
        
        Copyright (c) 2026 troyhoffman
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/troyhoffman/lazyrefresh
Project-URL: Issues, https://github.com/troyhoffman/lazyrefresh/issues
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# LazyRefresh  
A lightweight Python utility that automatically refreshes object attributes on access using a grouped ReactiveModel pattern. Ideal for API clients, distributed systems, dashboards, polling loops, and automation frameworks that need near‑real‑time data without boilerplate `@property` methods. 

LazyRefresh provides reactive, grouped attribute updates without the overhead of observer frameworks or repetitive `@property` methods.

---

## Features
- **Automatic refresh on attribute access**  
- **Grouped refresh operations** (one call updates many attributes)  
- **Configurable refresh frequency**  
- **Truthiness‑based stop behavior** (stop refreshing once a flag becomes meaningful)  
- **PEP8 key normalization** (dictionary keys → Pythonic attribute names)  
- **No boilerplate properties**  
- **Zero external dependencies**

---

## Installation
```bash
pip install lazyrefresh
```

## Example

```python
from lazyrefresh import LazyRefresh

class MyLazyClass(LazyRefresh):
    def __init__(self):
        self.last_updated = None
        self.next_update = None
        self._register_refresh_method(self.api_refresh)

        self.text_file_contents = ""
        self._filename = "testfile.txt"
        self._register_refresh_method(self.read_file, refresh_frequency=0)

        self.is_complete = False
        self._register_refresh_method(self.check_status, refresh_frequency=30, stop_when_set=True)

    def api_refresh(self):
        return {
            "last_updated": "2026-08-18T08:00:00",
            "next_update": "2026-08-18T08:10:00"
        }

    def read_file(self):
        with open(self._filename) as f:
            return {"text_file_contents": f.read()}

    def check_status(self):
        return {"is_complete": True}
```

## How It Works

LazyRefresh intercepts `__getattribute__()` and determines whether an attribute should be refreshed based on:
- **the last update time**
- **the refresh frequency**
- **whether the attribute has been accessed before**
- **optional truthiness‑based stop rules**

Attributes beginning with `_` are never refreshed.
Each call to `_register_refresh_method()` creates a refresh group containing all attributes defined since the previous registration.

## Refresh Methods

A refresh method:
- **takes no parameters**
- **returns a dict mapping attribute names → values**
- **may pull from any source: APIs, SQL, files, sockets, message buses, etc.**
- **may return keys in any naming style — they are normalized to PEP8 automatically**

---

Example:
```python
def api_refresh(self):
    return {
        "ResponseDate": "2026-08-18",
        "UserCount": 42
    }
```
Becomes:
```python
self.response_date
self.user_count
```

## Example Behavior

Group 1: `last_updated`, `next_update`
Refreshes every 10 seconds (default).

Group 2: `text_file_contents`
Refreshes only once because `refresh_frequency`=0.

Group 3: `is_complete`
Refreshes until the value becomes truthy, then stops permanently.

Ungrouped: `database_server`
Never refreshes because it was defined after the last registration.

## Use Cases

LazyRefresh is ideal for:
- **API clients with cached responses**
- **distributed system polling**
- **file/directory monitors**
- **real‑time dashboards**
- **background workers**
- **automation frameworks needing reactive data models**

It centralizes refresh logic and eliminates repetitive `@property` code.

## License

MIT License. See the LICENSE file for details
