Metadata-Version: 2.4
Name: roest1-pyodbc-sqlserver
Version: 1.0.0
Summary: Lightweight SQL Server helpers built on pyodbc
Author: Riley Oest
License: MIT License
        
        Copyright (c) 2026 Riley Oest
        
        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.
        
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pyodbc>=5.0
Requires-Dist: python-dotenv>=1.0
Dynamic: license-file

# pyodbc-sqlserver

Lightweight, opinionated helpers for connecting to Microsoft SQL Server using
[`pyodbc`](https://github.com/mkleehammer/pyodbc).

Designed for **internal company use** where:

- SQL Server auth is handled via environment variables
- Multiple databases may be accessed from the same app
- You want zero ORM, zero magic, just clean connections

---

> PyPI package name: `roest1-pyodbc-sqlserver`  
> Import name: `pyodbc_sqlserver`

---

## Features

- Simple SQL Server connection factory
- Environment-variable–based configuration
- Supports multiple databases via prefixes (`APPDB_`, `REPORTDB_`, etc.)
- Thin wrapper on top of `pyodbc` (no abstraction leakage)

---

## Installation

### (Optional) Create environment - Conda

```bash
conda create -n envname python=3.10 -y
conda activate envname
```

### Install Dependencies

```bash
conda install -c conda-forge pyodbc unixodbc -y
```

### Preferred (pip)

```bash
pip install roest1-pyodbc-sqlserver
```

### From local source (recommended for internal use)

```bash
cd pyodbc_sqlserver
pip install -e .
```

### Old (but still works)

Or from a private Git repo:

SSH:

```bash
pip install git+ssh://git@github.com/roest1/pyodbc-sqlserver.git
```

HTTP:

```bash
pip install git+https://github.com/roest1/pyodbc-sqlserver.git
```

---

## Environment Configuration / Variable Loading

This package will automatically load a `.env` file from the current working
directory **if one exists**.

- Existing environment variables are **not overridden**
- If no `.env` file is present, no action is taken

This behavior is intended to simplify local development. In production
environments (Docker, CI, servers), environment variables should be provided
by the runtime environment.

### Single database

```env
DB_SERVER=sqlserver.company.local
DB_NAME=MyDatabase
DB_USER=app_user
DB_PASS=secret
```

### Multiple databases (recommended)

Use prefixes to distinguish connections:

```env
APPDB_SERVER=sqlserver.company.local
APPDB_NAME=ApplicationDB
APPDB_USER=app_user
APPDB_PASS=secret

REPORTDB_SERVER=sqlserver.company.local
REPORTDB_NAME=ReportingDB
REPORTDB_USER=report_user
REPORTDB_PASS=secret
```

---

## Usage

```python
from pyodbc_sqlserver.db import get_connection

# Default (no prefix)
with get_connection() as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    print(cursor.fetchone())

# Prefixed database
with get_connection("APP") as conn:
    cursor = conn.cursor()
    cursor.execute("SELECT COUNT(*) FROM dbo.Users")
    print(cursor.fetchone())
```

---

### Update release

````bash
git tag v0.1.2 # v<major>.<minor>.<patch>
```

## System Requirements

This package depends on system-level ODBC libraries.

### Linux

```bash
sudo apt install unixodbc unixodbc-dev
````

### Conda

```bash
conda install -c conda-forge unixodbc
```

## Driver Notes

By default this package uses:

```
ODBC Driver 18 for SQL Server
```

Ensure it is installed on the host system.

Linux:

```bash
msodbcsql18
```

Windows:

- Install via Microsoft ODBC driver installer

---

## Why this exists

This package intentionally does **not**:

- Provide ORM features
- Manage migrations
- Wrap cursors or results

It exists to standardize how our internal Python services connect to SQL Server
without copy/pasting connection logic everywhere.

---

## Developer & Maintainer Guide

This section documents how this package is developed, versioned, and released.
It is intended for maintainers (including future-you).

### Repository Structure

```

.
├── python/pyodbc_sqlserver/   # Package source
│   ├── db.py                 # Connection factory
│   ├── db_reader.py          # Read helpers
│   ├── db_writer.py          # Write helpers
│   └── **init**.py
├── .github/workflows/
│   └── release.yaml          # Tag-based release + PyPI publish
├── pyproject.toml            # Package metadata (single source of truth)
└── README.md

```

### Design Principles

- Explicit over implicit
- No global state beyond environment variables
- No connection pooling or ORM abstractions
- Fail fast if configuration is incomplete
- Thin wrappers only — raw `pyodbc` objects are exposed intentionally

This library is designed to be _boring, predictable, and inspectable_.

---

### Versioning Strategy (SemVer)

This project follows **Semantic Versioning**:

```

MAJOR.MINOR.PATCH

```

- **MAJOR**: breaking API changes
- **MINOR**: backward-compatible features
- **PATCH**: bug fixes, documentation, CI changes

Examples:

- `0.2.1` → workflow or documentation fix
- `0.3.0` → new helper functions
- `1.0.0` → stable API commitment

---

### Release Process (Tag-Based)

Releases are fully automated via GitHub Actions.

#### To publish a new release:

```bash
# Checkout and pull latest updates
git checkout main
git pull origin main

# normal git workflow
git status
git add .
git commit -m "..."
git push origin main

# push tag
git tag vX.Y.Z
git push origin vX.Y.Z
```

This will automatically:

1. Update `pyproject.toml` with the tagged version
2. Commit the version bump to `main`
3. Create a GitHub Release
4. Build source + wheel distributions
5. Publish to PyPI via Trusted Publishing (OIDC)

No manual uploads. No API tokens.

---

### PyPI Trusted Publishing

This repository is configured as a **Trusted Publisher** on PyPI:

- Publisher: GitHub Actions
- Workflow: `release.yaml`
- Environment: `pypi`

This eliminates the need for stored PyPI credentials and ensures that **only tagged releases from this repository** can publish packages.

---

### Local Development

Editable install:

```bash
pip install -e .
```

Run against local environment variables or `.env` files as usual.

---

### Contributing Notes

This is currently a single-maintainer project.

If additional contributors are added in the future:

- All changes should go through pull requests
- Releases remain tag-based only
- `main` should remain protected

```

This section **locks in institutional knowledge** and prevents future drift.

---

## License

MIT
```
