ready for try
This commit is contained in:
721
docs/development.md
Normal file
721
docs/development.md
Normal file
@@ -0,0 +1,721 @@
|
||||
# Development Guide
|
||||
|
||||
Guide for contributors and developers working on the Wiki.js Python SDK.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Development Setup](#development-setup)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Testing](#testing)
|
||||
- [Code Quality](#code-quality)
|
||||
- [Documentation](#documentation)
|
||||
- [Release Process](#release-process)
|
||||
|
||||
---
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Python 3.8+** (tested with 3.8, 3.9, 3.10, 3.11, 3.12)
|
||||
- **Git** for version control
|
||||
- **Wiki.js instance** for testing (can be local or remote)
|
||||
|
||||
### Environment Setup
|
||||
|
||||
1. **Clone the repository:**
|
||||
```bash
|
||||
git clone https://github.com/yourusername/wikijs-python-sdk.git
|
||||
cd wikijs-python-sdk
|
||||
```
|
||||
|
||||
2. **Create a virtual environment:**
|
||||
```bash
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
||||
```
|
||||
|
||||
3. **Install development dependencies:**
|
||||
```bash
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
4. **Set up pre-commit hooks:**
|
||||
```bash
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
5. **Configure environment variables:**
|
||||
```bash
|
||||
export WIKIJS_URL='https://your-test-wiki.example.com'
|
||||
export WIKIJS_API_KEY='your-test-api-key'
|
||||
```
|
||||
|
||||
### Verify Setup
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
pytest
|
||||
|
||||
# Check code quality
|
||||
pre-commit run --all-files
|
||||
|
||||
# Verify package can be imported
|
||||
python -c "from wikijs import WikiJSClient; print('✅ Setup successful!')"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
wikijs-python-sdk/
|
||||
├── wikijs/ # Main package
|
||||
│ ├── __init__.py # Package exports
|
||||
│ ├── version.py # Version information
|
||||
│ ├── client.py # Main WikiJS client
|
||||
│ ├── exceptions.py # Exception classes
|
||||
│ ├── auth/ # Authentication handlers
|
||||
│ │ ├── __init__.py # Auth exports
|
||||
│ │ ├── base.py # Base auth handler
|
||||
│ │ ├── api_key.py # API key authentication
|
||||
│ │ └── jwt.py # JWT authentication
|
||||
│ ├── endpoints/ # API endpoints
|
||||
│ │ ├── __init__.py # Endpoint exports
|
||||
│ │ ├── base.py # Base endpoint class
|
||||
│ │ └── pages.py # Pages API endpoint
|
||||
│ ├── models/ # Data models
|
||||
│ │ ├── __init__.py # Model exports
|
||||
│ │ ├── base.py # Base model classes
|
||||
│ │ └── page.py # Page-related models
|
||||
│ └── utils/ # Utility functions
|
||||
│ ├── __init__.py # Utility exports
|
||||
│ └── helpers.py # Helper functions
|
||||
├── tests/ # Test suite
|
||||
│ ├── conftest.py # Test configuration
|
||||
│ ├── auth/ # Authentication tests
|
||||
│ ├── endpoints/ # Endpoint tests
|
||||
│ ├── models/ # Model tests
|
||||
│ └── utils/ # Utility tests
|
||||
├── docs/ # Documentation
|
||||
│ ├── api_reference.md # API reference
|
||||
│ ├── user_guide.md # User guide
|
||||
│ ├── development.md # This file
|
||||
│ └── ...
|
||||
├── examples/ # Usage examples
|
||||
├── .github/ # GitHub workflows
|
||||
│ └── workflows/ # CI/CD pipelines
|
||||
├── pyproject.toml # Project configuration
|
||||
├── setup.py # Package setup
|
||||
├── requirements.txt # Runtime dependencies
|
||||
├── requirements-dev.txt # Development dependencies
|
||||
└── README.md # Project README
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
#### **Client (`wikijs/client.py`)**
|
||||
- Main entry point for the SDK
|
||||
- Manages HTTP sessions and requests
|
||||
- Handles authentication and error handling
|
||||
- Provides access to endpoint handlers
|
||||
|
||||
#### **Authentication (`wikijs/auth/`)**
|
||||
- Base authentication handler interface
|
||||
- Concrete implementations for API key and JWT auth
|
||||
- Extensible for custom authentication methods
|
||||
|
||||
#### **Endpoints (`wikijs/endpoints/`)**
|
||||
- API endpoint implementations
|
||||
- Each endpoint handles a specific Wiki.js API area
|
||||
- Base endpoint class provides common functionality
|
||||
|
||||
#### **Models (`wikijs/models/`)**
|
||||
- Pydantic models for data validation and serialization
|
||||
- Type-safe data structures
|
||||
- Input validation and error handling
|
||||
|
||||
#### **Utilities (`wikijs/utils/`)**
|
||||
- Helper functions for common operations
|
||||
- URL handling, response parsing, etc.
|
||||
- Shared utility functions
|
||||
|
||||
---
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Branch Strategy
|
||||
|
||||
- **`main`**: Stable, production-ready code
|
||||
- **`develop`**: Integration branch for new features
|
||||
- **Feature branches**: `feature/description` for new features
|
||||
- **Bug fixes**: `fix/description` for bug fixes
|
||||
- **Hotfixes**: `hotfix/description` for critical fixes
|
||||
|
||||
### Workflow Steps
|
||||
|
||||
1. **Create a feature branch:**
|
||||
```bash
|
||||
git checkout -b feature/new-awesome-feature
|
||||
```
|
||||
|
||||
2. **Make your changes:**
|
||||
- Write code following our style guidelines
|
||||
- Add tests for new functionality
|
||||
- Update documentation as needed
|
||||
|
||||
3. **Run quality checks:**
|
||||
```bash
|
||||
# Run tests
|
||||
pytest
|
||||
|
||||
# Check code formatting
|
||||
black --check .
|
||||
|
||||
# Check imports
|
||||
isort --check-only .
|
||||
|
||||
# Type checking
|
||||
mypy wikijs
|
||||
|
||||
# Linting
|
||||
flake8 wikijs
|
||||
|
||||
# Security scan
|
||||
bandit -r wikijs
|
||||
```
|
||||
|
||||
4. **Commit your changes:**
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "feat: add awesome new feature"
|
||||
```
|
||||
|
||||
5. **Push and create PR:**
|
||||
```bash
|
||||
git push origin feature/new-awesome-feature
|
||||
# Create pull request on GitHub
|
||||
```
|
||||
|
||||
### Commit Message Format
|
||||
|
||||
We follow [Conventional Commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
**Types:**
|
||||
- `feat`: A new feature
|
||||
- `fix`: A bug fix
|
||||
- `docs`: Documentation only changes
|
||||
- `style`: Changes that don't affect code meaning
|
||||
- `refactor`: Code change that neither fixes a bug nor adds a feature
|
||||
- `test`: Adding missing tests or correcting existing tests
|
||||
- `chore`: Other changes that don't modify src or test files
|
||||
|
||||
**Examples:**
|
||||
```
|
||||
feat(auth): add JWT authentication support
|
||||
fix(client): handle connection timeout properly
|
||||
docs: update API reference for pages endpoint
|
||||
test: add comprehensive model validation tests
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Organization
|
||||
|
||||
- **Unit tests**: Test individual components in isolation
|
||||
- **Integration tests**: Test component interactions
|
||||
- **End-to-end tests**: Test complete workflows
|
||||
- **Mock tests**: Test with mocked external dependencies
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest
|
||||
|
||||
# Run with coverage
|
||||
pytest --cov=wikijs --cov-report=html
|
||||
|
||||
# Run specific test file
|
||||
pytest tests/test_client.py
|
||||
|
||||
# Run specific test
|
||||
pytest tests/test_client.py::TestWikiJSClient::test_basic_initialization
|
||||
|
||||
# Run tests with verbose output
|
||||
pytest -v
|
||||
|
||||
# Run tests and stop on first failure
|
||||
pytest -x
|
||||
```
|
||||
|
||||
### Writing Tests
|
||||
|
||||
#### Test Structure
|
||||
|
||||
```python
|
||||
"""Tests for module_name."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from wikijs.module_name import ClassUnderTest
|
||||
from wikijs.exceptions import SomeException
|
||||
|
||||
|
||||
class TestClassUnderTest:
|
||||
"""Test suite for ClassUnderTest."""
|
||||
|
||||
@pytest.fixture
|
||||
def sample_data(self):
|
||||
"""Sample data for testing."""
|
||||
return {"key": "value"}
|
||||
|
||||
def test_basic_functionality(self, sample_data):
|
||||
"""Test basic functionality."""
|
||||
# Arrange
|
||||
instance = ClassUnderTest()
|
||||
|
||||
# Act
|
||||
result = instance.some_method(sample_data)
|
||||
|
||||
# Assert
|
||||
assert result is not None
|
||||
assert result.key == "value"
|
||||
|
||||
def test_error_handling(self):
|
||||
"""Test proper error handling."""
|
||||
instance = ClassUnderTest()
|
||||
|
||||
with pytest.raises(SomeException, match="Expected error message"):
|
||||
instance.method_that_should_fail()
|
||||
|
||||
@patch('wikijs.module_name.external_dependency')
|
||||
def test_with_mocking(self, mock_dependency):
|
||||
"""Test with mocked dependencies."""
|
||||
# Setup mock
|
||||
mock_dependency.return_value = "mocked result"
|
||||
|
||||
# Test
|
||||
instance = ClassUnderTest()
|
||||
result = instance.method_using_dependency()
|
||||
|
||||
# Verify
|
||||
assert result == "mocked result"
|
||||
mock_dependency.assert_called_once()
|
||||
```
|
||||
|
||||
#### Test Guidelines
|
||||
|
||||
1. **Follow AAA pattern**: Arrange, Act, Assert
|
||||
2. **Use descriptive test names** that explain what is being tested
|
||||
3. **Test both success and failure cases**
|
||||
4. **Mock external dependencies** (HTTP requests, file system, etc.)
|
||||
5. **Use fixtures** for common test data and setup
|
||||
6. **Maintain high test coverage** (target: >85%)
|
||||
|
||||
### Test Configuration
|
||||
|
||||
#### `conftest.py`
|
||||
|
||||
```python
|
||||
"""Shared test configuration and fixtures."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from wikijs import WikiJSClient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_client():
|
||||
"""Create a mock WikiJS client for testing."""
|
||||
client = Mock(spec=WikiJSClient)
|
||||
client.base_url = "https://test-wiki.example.com"
|
||||
return client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_page_data():
|
||||
"""Sample page data for testing."""
|
||||
return {
|
||||
"id": 123,
|
||||
"title": "Test Page",
|
||||
"path": "test-page",
|
||||
"content": "# Test\n\nContent here.",
|
||||
"is_published": True,
|
||||
"tags": ["test"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Code Quality
|
||||
|
||||
### Code Style
|
||||
|
||||
We use several tools to maintain code quality:
|
||||
|
||||
- **Black**: Code formatting
|
||||
- **isort**: Import sorting
|
||||
- **flake8**: Linting
|
||||
- **mypy**: Type checking
|
||||
- **bandit**: Security scanning
|
||||
|
||||
### Configuration Files
|
||||
|
||||
#### `pyproject.toml`
|
||||
|
||||
```toml
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
target-version = ['py38']
|
||||
include = '\.pyi?$'
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
multi_line_output = 3
|
||||
line_length = 88
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "--strict-markers --disable-warnings"
|
||||
```
|
||||
|
||||
### Pre-commit Hooks
|
||||
|
||||
```yaml
|
||||
# .pre-commit-config.yaml
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||
rev: v1.3.0
|
||||
hooks:
|
||||
- id: mypy
|
||||
additional_dependencies: [types-requests]
|
||||
```
|
||||
|
||||
### Quality Checks
|
||||
|
||||
Run these commands before committing:
|
||||
|
||||
```bash
|
||||
# Format code
|
||||
black .
|
||||
isort .
|
||||
|
||||
# Check formatting
|
||||
black --check .
|
||||
isort --check-only .
|
||||
|
||||
# Lint code
|
||||
flake8 wikijs tests
|
||||
|
||||
# Type checking
|
||||
mypy wikijs
|
||||
|
||||
# Security scan
|
||||
bandit -r wikijs
|
||||
|
||||
# Run all pre-commit hooks
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
### Documentation Types
|
||||
|
||||
1. **API Reference**: Auto-generated from docstrings
|
||||
2. **User Guide**: Manual documentation for end users
|
||||
3. **Development Guide**: This document
|
||||
4. **Examples**: Practical usage examples
|
||||
5. **Changelog**: Version history and changes
|
||||
|
||||
### Writing Documentation
|
||||
|
||||
#### Docstring Format
|
||||
|
||||
We use Google-style docstrings:
|
||||
|
||||
```python
|
||||
def create_page(self, page_data: PageCreate) -> Page:
|
||||
"""Create a new page in the wiki.
|
||||
|
||||
Args:
|
||||
page_data: Page creation data containing title, path, content, etc.
|
||||
|
||||
Returns:
|
||||
The created Page object with assigned ID and metadata.
|
||||
|
||||
Raises:
|
||||
ValidationError: If page data is invalid.
|
||||
APIError: If the API request fails.
|
||||
AuthenticationError: If authentication fails.
|
||||
|
||||
Example:
|
||||
>>> from wikijs.models import PageCreate
|
||||
>>> page_data = PageCreate(
|
||||
... title="My Page",
|
||||
... path="my-page",
|
||||
... content="# Hello World"
|
||||
... )
|
||||
>>> created_page = client.pages.create(page_data)
|
||||
>>> print(f"Created page with ID: {created_page.id}")
|
||||
"""
|
||||
```
|
||||
|
||||
#### Documentation Guidelines
|
||||
|
||||
1. **Be clear and concise** in explanations
|
||||
2. **Include examples** for complex functionality
|
||||
3. **Document all public APIs** with proper docstrings
|
||||
4. **Keep documentation up to date** with code changes
|
||||
5. **Use consistent formatting** and style
|
||||
|
||||
### Building Documentation
|
||||
|
||||
```bash
|
||||
# Install documentation dependencies
|
||||
pip install -e ".[docs]"
|
||||
|
||||
# Build documentation (if using Sphinx)
|
||||
cd docs
|
||||
make html
|
||||
|
||||
# Serve documentation locally
|
||||
python -m http.server 8000 -d _build/html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Release Process
|
||||
|
||||
### Version Management
|
||||
|
||||
We use [Semantic Versioning](https://semver.org/):
|
||||
|
||||
- **MAJOR**: Incompatible API changes
|
||||
- **MINOR**: New functionality (backward compatible)
|
||||
- **PATCH**: Bug fixes (backward compatible)
|
||||
|
||||
### Release Steps
|
||||
|
||||
1. **Update version number** in `wikijs/version.py`
|
||||
2. **Update CHANGELOG.md** with new version details
|
||||
3. **Run full test suite** and ensure all checks pass
|
||||
4. **Create release commit**:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "chore: bump version to v1.2.3"
|
||||
```
|
||||
5. **Create and push tag**:
|
||||
```bash
|
||||
git tag v1.2.3
|
||||
git push origin main --tags
|
||||
```
|
||||
6. **GitHub Actions** will automatically:
|
||||
- Run tests
|
||||
- Build package
|
||||
- Publish to PyPI
|
||||
- Create GitHub release
|
||||
|
||||
### Pre-release Checklist
|
||||
|
||||
- [ ] All tests pass
|
||||
- [ ] Code coverage meets requirements (>85%)
|
||||
- [ ] Documentation is updated
|
||||
- [ ] CHANGELOG.md is updated
|
||||
- [ ] Version number is bumped
|
||||
- [ ] No breaking changes without major version bump
|
||||
- [ ] Examples work with new version
|
||||
|
||||
### Release Automation
|
||||
|
||||
Our CI/CD pipeline automatically handles:
|
||||
|
||||
- **Testing**: Run test suite on multiple Python versions
|
||||
- **Quality checks**: Code formatting, linting, type checking
|
||||
- **Security**: Vulnerability scanning
|
||||
- **Building**: Create source and wheel distributions
|
||||
- **Publishing**: Upload to PyPI on tagged releases
|
||||
- **Documentation**: Update documentation site
|
||||
|
||||
---
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
### Getting Started
|
||||
|
||||
1. **Fork the repository** on GitHub
|
||||
2. **Create a feature branch** from `develop`
|
||||
3. **Make your changes** following our guidelines
|
||||
4. **Add tests** for new functionality
|
||||
5. **Update documentation** as needed
|
||||
6. **Submit a pull request**
|
||||
|
||||
### Pull Request Process
|
||||
|
||||
1. **Ensure CI passes** - all tests and quality checks must pass
|
||||
2. **Update documentation** - include any necessary documentation updates
|
||||
3. **Add tests** - maintain or improve test coverage
|
||||
4. **Follow conventions** - use consistent code style and commit messages
|
||||
5. **Be responsive** - address feedback and review comments promptly
|
||||
|
||||
### Code Review Guidelines
|
||||
|
||||
As a reviewer:
|
||||
- **Be constructive** and helpful in feedback
|
||||
- **Check for correctness** and potential issues
|
||||
- **Verify tests** cover new functionality
|
||||
- **Ensure documentation** is adequate
|
||||
- **Approve when ready** or request specific changes
|
||||
|
||||
As an author:
|
||||
- **Respond promptly** to review feedback
|
||||
- **Make requested changes** or explain why they're not needed
|
||||
- **Keep PRs focused** - one feature or fix per PR
|
||||
- **Test thoroughly** before requesting review
|
||||
|
||||
---
|
||||
|
||||
## Debugging and Troubleshooting
|
||||
|
||||
### Common Development Issues
|
||||
|
||||
#### Import Errors
|
||||
|
||||
```bash
|
||||
# Install package in development mode
|
||||
pip install -e .
|
||||
|
||||
# Verify Python path
|
||||
python -c "import sys; print(sys.path)"
|
||||
```
|
||||
|
||||
#### Test Failures
|
||||
|
||||
```bash
|
||||
# Run specific failing test with verbose output
|
||||
pytest -xvs tests/path/to/failing_test.py::test_name
|
||||
|
||||
# Debug with pdb
|
||||
pytest --pdb tests/path/to/failing_test.py::test_name
|
||||
```
|
||||
|
||||
#### Type Checking Issues
|
||||
|
||||
```bash
|
||||
# Run mypy on specific file
|
||||
mypy wikijs/module_name.py
|
||||
|
||||
# Show mypy configuration
|
||||
mypy --config-file
|
||||
```
|
||||
|
||||
### Debugging Tools
|
||||
|
||||
#### Logging
|
||||
|
||||
```python
|
||||
import logging
|
||||
|
||||
# Enable debug logging
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logger = logging.getLogger('wikijs')
|
||||
logger.setLevel(logging.DEBUG)
|
||||
```
|
||||
|
||||
#### Python Debugger
|
||||
|
||||
```python
|
||||
import pdb
|
||||
|
||||
# Set breakpoint
|
||||
pdb.set_trace()
|
||||
|
||||
# Or use built-in breakpoint() (Python 3.7+)
|
||||
breakpoint()
|
||||
```
|
||||
|
||||
#### HTTP Debugging
|
||||
|
||||
```python
|
||||
import http.client
|
||||
|
||||
# Enable HTTP debugging
|
||||
http.client.HTTPConnection.debuglevel = 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
### Useful Links
|
||||
|
||||
- **[Wiki.js API Documentation](https://docs.js.wiki/dev/api)** - Official API docs
|
||||
- **[GraphQL](https://graphql.org/learn/)** - GraphQL learning resources
|
||||
- **[Pydantic](https://pydantic-docs.helpmanual.io/)** - Data validation library
|
||||
- **[Requests](https://docs.python-requests.org/)** - HTTP library documentation
|
||||
- **[pytest](https://docs.pytest.org/)** - Testing framework documentation
|
||||
|
||||
### Development Tools
|
||||
|
||||
- **VS Code Extensions**: Python, Pylance, Black Formatter, isort
|
||||
- **PyCharm**: Professional Python IDE
|
||||
- **Postman**: API testing tool
|
||||
- **GraphQL Playground**: GraphQL query testing
|
||||
|
||||
### Community
|
||||
|
||||
- **GitHub Discussions**: Ask questions and share ideas
|
||||
- **GitHub Issues**: Report bugs and request features
|
||||
- **Pull Requests**: Contribute code improvements
|
||||
|
||||
---
|
||||
|
||||
## Questions?
|
||||
|
||||
If you have questions about development:
|
||||
|
||||
1. **Check this documentation** and the API reference
|
||||
2. **Search existing issues** on GitHub
|
||||
3. **Ask in GitHub Discussions** for community help
|
||||
4. **Create an issue** for bugs or feature requests
|
||||
|
||||
Happy coding! 🚀
|
||||
Reference in New Issue
Block a user