# PyLibrus

[![PyPI version](https://badge.fury.io/py/pylibrus.svg)](https://badge.fury.io/py/pylibrus)
[![Python versions](https://img.shields.io/pypi/pyversions/pylibrus.svg)](https://pypi.org/project/pylibrus/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Librus (polish school e-register) unofficial async API client written in Python.

## Features
- ✨ **Async/await support** - Built with `httpx` for modern async Python
- 🔐 OAuth authentication with token refresh
- 📚 Access to all Librus API resources
- 🧪 Comprehensive test suite
- 🔄 GitHub Actions CI/CD
- 📦 Dependabot integration

# Installation
```bash
pip install pylibrus
```

# Usage
(Replace every field containing 'your' with your data)

## Authorization
- Authorize using existing token (load existing tokens pair)  
or
- Generate new OAuth token  
    - using user credentials:
        ```python
        import asyncio
        import pylibrus

        async def main():
            access_token, refresh_token = await pylibrus.auth.user_credentials(
                username="yourusername",
                password="yourpassword",
                long_lived=True  # optional, if set to True (default) token will be valid for 24h
            )
            print(
                access_token,  # used to access resources
                refresh_token  # used to regenerate access token without user credentials
            )

        asyncio.run(main())
        ```
    - using previously generated refresh token:
        ```python
        import asyncio
        import pylibrus

        async def main():
            access_token, refresh_token = await pylibrus.auth.refresh_token(
                refresh_token="yourrefreshtoken",
                long_lived=True  # default True (if not specified)
            )
            print(access_token, refresh_token)

        asyncio.run(main())
        ```

## Accessing resources
Access resources using previously generated access token (see [Authorization](#authorization)):
```python
import asyncio
import pylibrus

async def main():
    async with pylibrus.Librus("youraccesstoken") as lib:
        json_res = await lib.getResource("YourResourceName")
        print(json_res)  # Raw API response (decoded JSON as dict)

asyncio.run(main())
```

List of available resources [here](resources.txt).

## Examples
Get user name using login/password authorization:
```python
import asyncio
import pylibrus

async def main():
    access_token, _ = await pylibrus.auth.user_credentials(
        username="yourusername",
        password="yourpassword",
    )
    async with pylibrus.Librus(access_token) as lib:
        names = (await lib.getResource("Me"))["Me"]["User"]
        print(f"Hello {names['FirstName']} {names['LastName']}")

asyncio.run(main())
```

Get number of user's grades using new access token generated using previously cached refresh token:
```python
import asyncio
import pylibrus

async def main():
    access_token, _ = await pylibrus.auth.refresh_token(
        refresh_token="yourrefreshtoken"
    )
    async with pylibrus.Librus(access_token) as lib:
        grades = (await lib.getResource("Grades"))["Grades"]
        print(len(grades))

asyncio.run(main())
```

# Development
You can set up a development environment like this:
```bash
git clone https://github.com/YOU/YOUR_FORK.git .
python3 -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
```

Run tests:
```bash
pytest
```

Run linting:
```bash
ruff check .
mypy pylibrus
```

# Contribute

We welcome contributions! Here's how to get started:

## Making Changes

1. Fork the repository
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
3. Make your changes
4. Run tests and linting:
   ```bash
   pytest
   ruff check .
   mypy pylibrus
   ```
5. Commit your changes with descriptive messages
6. Push to your fork and open a Pull Request
7. Add appropriate labels to your PR:
   - `feature` - New features or enhancements
   - `bug` - Bug fixes
   - `documentation` - Documentation updates
   - `chore` - Maintenance tasks
   - `breaking` - Breaking changes

## Release Process

This project uses automated releases via GitHub Actions:

1. **Update version** in `setup.py`
2. **Update CHANGELOG.md** (or it will be auto-generated from PRs)
3. **Commit changes**:
   ```bash
   git add setup.py CHANGELOG.md
   git commit -m "Bump version to X.Y.Z"
   ```
4. **Create and push tag**:
   ```bash
   git tag vX.Y.Z
   git push origin main --tags
   ```
5. **Automated workflow** will:
   - Run tests and linting
   - Build the package
   - Publish to PyPI
   - Create GitHub release with changelog

For more details, see [docs/RELEASE.md](docs/RELEASE.md).

## Questions or Issues?

Feel free to open an issue on GitHub!
