Metadata-Version: 2.4
Name: wfrmls
Version: 1.2.2
Summary: Python wrapper for Wasatch Front Regional MLS API
Author-email: WFRMLS API Team <api@utahrealestate.com>
License: MIT License
        
        Copyright (c) 2025 The Perry Group
        
        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/theperrygroup/wfrmls
Project-URL: Documentation, https://theperrygroup.github.io/wfrmls/
Project-URL: Repository, https://github.com/theperrygroup/wfrmls
Project-URL: Issues, https://github.com/theperrygroup/wfrmls/issues
Keywords: wfrmls,mls,real-estate,api,wrapper,reso,utah
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business :: Financial :: Investment
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25.0
Requires-Dist: python-dotenv>=0.19.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
Requires-Dist: responses>=0.23.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: flake8>=6.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: isort>=5.12.0; extra == "dev"
Requires-Dist: pylint>=2.17.0; extra == "dev"
Requires-Dist: types-requests>=2.25.0; extra == "dev"
Dynamic: license-file

# WFRMLS Python Client

A comprehensive Python wrapper for the Wasatch Front Regional MLS (WFRMLS) API, providing easy access to all RESO-certified endpoints.

## ⚠️ Important Notice

**Media, History, and Green Verification endpoints are currently unavailable** due to server-side issues (504 Gateway Timeouts and missing entity types). These features have been temporarily disabled until the server issues are resolved.

## 🚀 Quick Start

```python
from wfrmls import WFRMLSClient

# Initialize client with bearer token
client = WFRMLSClient(bearer_token="your_bearer_token")

# Or use environment variable WFRMLS_BEARER_TOKEN
client = WFRMLSClient()

# Get active properties
properties = client.property.get_properties(
    top=10,
    filter_query="StandardStatus eq 'Active'"
)

# Get property details
property_detail = client.property.get_property("12345678")

# Get member information
members = client.member.get_active_members(top=10)

# Get office information
offices = client.office.get_active_offices(top=10)
```

## 📦 Installation

```bash
pip install wfrmls
```

## 🔧 Setup

### Environment Variables

Create a `.env` file in your project root:

```env
WFRMLS_BEARER_TOKEN=your_bearer_token_here
```

### Getting Your Bearer Token

1. Visit the [Vendor Dashboard](https://vendor.utahrealestate.com)
2. Login to your account
3. Navigate to Service Details to retrieve your bearer token

## 📚 API Reference

### Core Resources

- **Property** - Real estate listings and property data
- **Member** - Real estate agent information  
- **Office** - Brokerage and office details
- **OpenHouse** - Open house schedules and events

### Service Clients

```python
# Property operations
client.property.get_properties()
client.property.get_property(listing_id)
client.property.search_properties_by_radius(lat, lng, radius)

# Member (agent) operations  
client.member.get_members()
client.member.get_member(member_id)

# Office operations
client.office.get_offices()
client.office.get_office(office_id)

# Open house operations
client.openhouse.get_open_houses()
client.openhouse.get_open_house(openhouse_id)
```

## 🔍 Advanced Features

### OData Query Support

```python
# Field selection
properties = client.property.get_properties(
    select=["ListingId", "ListPrice", "StandardStatus"],
    top=50
)

# Complex filtering
properties = client.property.get_properties(
    filter_query="ListPrice ge 200000 and ListPrice le 500000 and StandardStatus eq 'Active'",
    orderby="ListPrice desc"
)

# Include related data
properties = client.property.get_properties(
    expand=["Media", "Member"],
    top=25
)
```

### Geolocation Search

```python
# Search within radius (miles)
properties = client.property.search_properties_by_radius(
    latitude=40.7608,  # Salt Lake City
    longitude=-111.8910,
    radius_miles=10,
    additional_filters="StandardStatus eq 'Active'"
)

# Search within polygon area
polygon = [
    {"lat": 40.7608, "lng": -111.8910},
    {"lat": 40.7708, "lng": -111.8810},
    {"lat": 40.7508, "lng": -111.8710},
    {"lat": 40.7608, "lng": -111.8910}  # Close polygon
]

properties = client.property.search_properties_by_polygon(
    polygon_coordinates=polygon,
    additional_filters="PropertyType eq 'Residential'"
)
```

### Data Synchronization

```python
from datetime import datetime, timedelta

# Get incremental updates (recommended every 15 minutes)
cutoff_time = datetime.utcnow() - timedelta(minutes=15)
updates = client.property.get_properties(
    filter_query=f"ModificationTimestamp gt {cutoff_time.isoformat()}Z"
)

# Track deletions for data integrity
deleted_records = client.deleted.get_deleted(
    filter_query="ResourceName eq 'Property'"
)
```

## 🏗️ Architecture

The client follows a modular architecture with service separation:

```
WFRMLSClient
├── property          # Property listings
├── member           # Real estate agents  
├── office           # Brokerages/offices
├── openhouse        # Open house events
├── lookup           # Lookup tables
├── adu              # Accessory Dwelling Units
├── deleted          # Deletion tracking
└── data_system      # API metadata
```

**Note**: Media, History, and Green Verification clients are currently disabled due to server-side issues.

## ⚠️ Error Handling

```python
from wfrmls.exceptions import (
    WFRMLSError, 
    AuthenticationError, 
    NotFoundError, 
    RateLimitError
)

try:
    property = client.property.get_property("12345678")
except NotFoundError:
    print("Property not found")
except RateLimitError:
    print("Rate limit exceeded - wait before retrying")  
except AuthenticationError:
    print("Invalid bearer token")
except WFRMLSError as e:
    print(f"API error: {e}")
```

## 📊 Utah Grid Address System

The API supports Utah's unique grid address system:

```python
# Standard address: "123 Main Street"
# Grid address: "1300 E 9400 S"

# Grid addresses are automatically detected and handled
properties = client.property.get_properties(
    filter_query="StreetName eq '9400 S'"
)
```

## 🚦 Rate Limits

- **200 records** per request maximum
- **15-minute** recommended update frequency for data sync
- Use NextLink pagination for large datasets (more efficient than $skip)

## 🧪 Development

### Setup Development Environment

```bash
# Clone repository
git clone https://github.com/theperrygroup/wfrmls.git
cd wfrmls

# Create virtual environment
python -m venv venv
source venv/bin/activate  # or venv\Scripts\activate on Windows

# Install development dependencies
pip install -e .[dev]
```

### Running Tests

```bash
# Run tests with coverage
pytest --cov=wfrmls --cov-report=html

# Run specific test file
pytest tests/test_property.py

# Run with verbose output
pytest -v
```

### Code Quality

```bash
# Format code
black wfrmls tests
isort wfrmls tests

# Lint code
flake8 wfrmls tests
pylint wfrmls

# Type checking
mypy wfrmls
```

## 📝 Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Follow the style guide in `STYLE_GUIDE.md`
4. Ensure 100% test coverage
5. Commit changes (`git commit -m 'Add amazing feature'`)
6. Push to branch (`git push origin feature/amazing-feature`)
7. Open a Pull Request

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## 🔗 Links

- [API Documentation](https://docs.utahrealestate.com)
- [Vendor Dashboard](https://vendor.utahrealestate.com)
- [RESO Standards](https://www.reso.org/)

## 🆘 Support

For API access issues, contact UtahRealEstate.com support.
For library issues, open an issue in this repository. 
