Contributing Guide

Thank you for your interest in contributing to the Upstox TOTP Python SDK! This guide will help you get started with contributing to the project.

Getting Started

Development Setup

  1. Fork the repository on GitHub

  2. Clone your fork locally:

    git clone https://github.com/your-username/upstox-totp.git
    cd upstox-totp
    
  3. Install dependencies with uv:

    # Install the package in development mode
    uv sync
    
    # Install development dependencies
    uv sync --group dev
    
    # Install documentation dependencies
    uv sync --group docs
    
  4. Set up environment for testing:

    # Copy example environment file
    cp example.env .env
    
    # Edit .env with your test credentials
    # (Use test/sandbox credentials, never production)
    

Project Structure

upstox-totp/
├── src/upstox_totp/        # Main package code
│   ├── __init__.py         # Package initialization
│   ├── client.py          # Main client class
│   ├── models.py          # Data models
│   ├── errors.py          # Exception classes
│   ├── cli.py             # CLI implementation
│   └── _api/              # API modules
├── docs/                  # Documentation
├── examples/              # Usage examples
├── tests/                 # Test suite (to be added)
├── pyproject.toml         # Project configuration
└── README.md              # Main documentation

Contributing Guidelines

Code Style

We use strict coding standards to ensure consistency:

Formatting:

# Format code with black
uv run black src/

# Sort imports with isort
uv run isort src/

# Run both before committing
uv run black src/ && uv run isort src/

Type Hints:

# Always use type hints
def get_token(self, username: str) -> AccessTokenResponse:
    """Get access token for user."""
    pass

# Use proper return types
from typing import Optional, List, Dict, Any

Docstrings:

def example_function(param1: str, param2: int = 10) -> bool:
    """Brief description of the function.

    Args:
        param1: Description of param1
        param2: Description of param2, defaults to 10

    Returns:
        Description of return value

    Raises:
        ValueError: When param1 is invalid
        ConfigurationError: When configuration is missing

    Example:
        >>> result = example_function("test", 5)
        >>> print(result)
        True
    """
    pass

Pydantic Models

Follow Pydantic v2 best practices:

from pydantic import BaseModel, Field, ConfigDict
from typing import Optional

class ExampleModel(BaseModel):
    """Example model with proper configuration."""

    model_config = ConfigDict(
        strict=True,          # Enable strict mode
        extra='forbid',       # Forbid extra fields
        validate_assignment=True,  # Validate on assignment
    )

    # Required field with validation
    id: int = Field(gt=0, description="Unique identifier")

    # Optional field with default
    name: Optional[str] = Field(None, max_length=100)

    # Custom validation
    @field_validator('name')
    @classmethod
    def validate_name(cls, v: Optional[str]) -> Optional[str]:
        if v is not None and not v.strip():
            raise ValueError('Name cannot be empty')
        return v

Error Handling

Use custom exception classes:

from upstox_totp.errors import UpstoxError

class NewFeatureError(UpstoxError):
    """Raised when new feature encounters an error."""
    pass

def new_feature():
    try:
        # Implementation
        pass
    except SomeException as e:
        raise NewFeatureError(f"Feature failed: {e}") from e

Testing

Writing Tests

We use pytest for testing. Create tests in the tests/ directory:

# tests/test_client.py

import pytest
from unittest.mock import patch, Mock
from upstox_totp import UpstoxTOTP, ConfigurationError

class TestUpstoxTOTP:
    def test_initialization_success(self):
        """Test successful client initialization."""
        with patch.dict('os.environ', {
            'UPSTOX_USERNAME': '9876543210',
            'UPSTOX_PASSWORD': 'password',
            # ... other env vars
        }):
            client = UpstoxTOTP()
            assert client.username == '9876543210'

    def test_initialization_missing_env(self):
        """Test initialization with missing environment variables."""
        with patch.dict('os.environ', {}, clear=True):
            with pytest.raises(ConfigurationError):
                UpstoxTOTP()

    @patch('requests.Session.post')
    def test_token_generation_success(self, mock_post):
        """Test successful token generation."""
        # Mock response
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            'status': 'success',
            'data': {
                'access_token': 'test-token'
            }
        }
        mock_post.return_value = mock_response

        client = UpstoxTOTP()
        response = client.app_token.get_access_token()

        assert response.success
        assert response.data.access_token == 'test-token'

Running Tests

# Run all tests
uv run pytest

# Run with coverage
uv run pytest --cov=upstox_totp

# Run specific test file
uv run pytest tests/test_client.py

# Run with verbose output
uv run pytest -v

Test Configuration

Create test fixtures:

# tests/conftest.py

import pytest
from unittest.mock import patch
from upstox_totp import UpstoxTOTP

@pytest.fixture
def mock_env():
    """Mock environment variables for testing."""
    env_vars = {
        'UPSTOX_USERNAME': '9876543210',
        'UPSTOX_PASSWORD': 'test-password',
        'UPSTOX_PIN_CODE': '1234',
        'UPSTOX_TOTP_SECRET': 'JBSWY3DPEHPK3PXP',
        'UPSTOX_CLIENT_ID': 'test-client-id',
        'UPSTOX_CLIENT_SECRET': 'test-client-secret',
        'UPSTOX_REDIRECT_URI': 'https://test.com/callback'
    }

    with patch.dict('os.environ', env_vars):
        yield env_vars

@pytest.fixture
def upstox_client(mock_env):
    """Create UpstoxTOTP client for testing."""
    return UpstoxTOTP()

Documentation

Building Documentation

# Install documentation dependencies
uv sync --group docs

# Build documentation
cd docs
make html

# View documentation
open _build/html/index.html

# Clean build
make clean

Writing Documentation

Follow these guidelines:

  1. Use reStructuredText for documentation files

  2. Include code examples for all features

  3. Add docstrings to all public functions/classes

  4. Update the changelog for user-facing changes

Example documentation:

New Feature
-----------

Description of the new feature and why it's useful.

Usage
~~~~~

.. code-block:: python

   from upstox_totp import UpstoxTOTP

   # Example usage
   upx = UpstoxTOTP()
   result = upx.new_feature()

Parameters
~~~~~~~~~~

.. list-table::
   :header-rows: 1

   * - Parameter
     - Type
     - Description
   * - param1
     - str
     - Description of param1

Pull Request Process

Before Submitting

  1. Ensure tests pass:

    uv run pytest
    
  2. Format code:

    uv run black src/
    uv run isort src/
    
  3. Check type hints:

    uv run mypy src/
    
  4. Update documentation if needed

  5. Add/update tests for new features

Pull Request Template

Use this template for pull requests:

## Description
Brief description of changes made.

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update

## Testing
- [ ] Tests pass locally
- [ ] Added tests for new functionality
- [ ] Manual testing completed

## Documentation
- [ ] Documentation updated
- [ ] Docstrings added/updated
- [ ] Examples provided

## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Code is commented where necessary
- [ ] Breaking changes are documented

Review Process

  1. Automated checks must pass (CI/CD)

  2. Code review by maintainers

  3. Testing on different platforms if needed

  4. Documentation review

  5. Approval and merge

Types of Contributions

Bug Fixes

  1. Create an issue first (unless it’s trivial)

  2. Include reproduction steps

  3. Add tests that fail before the fix

  4. Ensure tests pass after the fix

New Features

  1. Discuss the feature in an issue first

  2. Follow existing patterns in the codebase

  3. Add comprehensive tests

  4. Include documentation

  5. Consider backward compatibility

Documentation

  • Fix typos and grammar

  • Improve existing examples

  • Add new examples

  • Translate documentation

  • Improve API documentation

Performance Improvements

  1. Benchmark before and after

  2. Include performance tests

  3. Document the improvement

  4. Ensure no breaking changes

Code Review Guidelines

For Reviewers

  1. Be constructive and helpful

  2. Explain the “why” behind suggestions

  3. Test the changes locally if possible

  4. Check documentation is updated

  5. Verify tests are adequate

For Contributors

  1. Respond to feedback promptly

  2. Ask questions if feedback is unclear

  3. Make requested changes or explain why not

  4. Keep discussions focused on the code

  5. Be patient with the review process

Development Workflow

Git Workflow

# 1. Create feature branch
git checkout -b feature/new-feature

# 2. Make changes and commit
git add .
git commit -m "Add new feature: description"

# 3. Keep branch updated
git fetch origin
git rebase origin/master

# 4. Push branch
git push origin feature/new-feature

# 5. Create pull request on GitHub

Commit Messages

Follow conventional commits:

feat: add new token caching mechanism
fix: resolve TOTP timing issue
docs: update installation guide
test: add unit tests for client
refactor: improve error handling
style: format code with black
chore: update dependencies

Branch Naming

Use descriptive branch names:

  • feature/token-caching

  • fix/totp-timing-issue

  • docs/api-reference

  • refactor/error-handling

Release Process

Version Numbering

We follow semantic versioning (SemVer):

  • MAJOR.MINOR.PATCH (e.g., 1.2.3)

  • MAJOR: Breaking changes

  • MINOR: New features (backward compatible)

  • PATCH: Bug fixes (backward compatible)

Changelog

Update CHANGELOG.md for all releases:

## [1.1.0] - 2025-01-15

### Added
- New token caching mechanism
- Support for custom timeout values

### Fixed
- TOTP timing synchronization issue
- Memory leak in session management

### Changed
- Improved error messages
- Updated dependencies

### Deprecated
- Old configuration method (use new method)

Communication

GitHub Issues

Use GitHub issues for:

  • Bug reports with reproduction steps

  • Feature requests with use cases

  • Questions about usage

  • Documentation improvements

Discussions

Use GitHub Discussions for:

  • General questions about the project

  • Ideas for new features

  • Show and tell your projects using the SDK

  • Community support

Getting Help

If you need help contributing:

  1. Check existing issues and documentation

  2. Create a GitHub issue with your question

  3. Join discussions for community help

  4. Contact maintainers for complex issues

Resources

Useful links for contributors:

Code of Conduct

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See CODE_OF_CONDUCT.md for details.

License

By contributing to this project, you agree that your contributions will be licensed under the MIT License.

Thank You!

Thank you for contributing to the Upstox TOTP Python SDK! Your contributions help make this project better for everyone. 🎉