Repository navigation
Development Guide
This document provides comprehensive guidance for developers contributing to the Secure Browser project, including setup, coding standards, testing, and contribution guidelines.
- Overview
- Development Environment Setup
- Project Structure
- Coding Standards
- Adding New Features
- Testing
- Debugging
- Documentation
- Contribution Guidelines
- Release Process
This guide is intended for developers who want to contribute to the Secure Browser project. It covers setting up the development environment, understanding the codebase, adding new features, testing, and contributing changes.
- Python 3.7 or higher
- Git
- Code editor (VS Code, PyCharm, or similar)
- Virtual environment tool (venv or conda)
git clone <repository-url>
cd secure_browser# Using venv
python3 -m venv .venv-dev
source .venv-dev/bin/activate # Linux/macOS
# .venv-dev\Scripts\activate # Windows
# Using conda
conda create -n secure-browser-dev python=3.9
conda activate secure-browser-dev# Install runtime dependencies
pip install -r requirements.txt
# Install development dependencies
pip install pytest pytest-cov black flake8 mypy pylintVS Code Settings (.vscode/settings.json):
{
"python.linting.enabled": true,
"python.linting.flake8Enabled": true,
"python.linting.mypyEnabled": true,
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"python.testing.pytestEnabled": true,
"python.testing.pytestArgs": [
"tests"
]
}PyCharm Configuration:
- Set Python interpreter to virtual environment
- Enable Black formatter
- Configure Flake8 linter
- Set pytest as test runner
# Run the application
python main.py --help
# Run tests (if available)
pytest
# Check code style
black --check src/
flake8 src/secure_browser/
├── src/
│ ├── __init__.py # Package initialization
│ ├── browsers/ # Browser implementations
│ │ ├── __init__.py
│ │ ├── hope.py # PyQt5 browser
│ │ ├── secure_browser.py # Tkinter browser
│ │ └── modern_browser.py # WebView browser
│ └── tools/ # Utility tools
│ ├── __init__.py
│ ├── search.py # Search operators tool
│ └── dev_tools_integration.py # Developer tools
├── assets/ # Static assets
│ ├── html/ # HTML resources
│ └── extensions/ # Browser extensions
├── config/ # Configuration files
│ └── user_settings.json # User settings
├── docs/ # Documentation
│ ├── index.md
│ ├── architecture.md
│ ├── api.md
│ ├── browsers.md
│ ├── security.md
│ ├── configuration.md
│ ├── development.md
│ └── troubleshooting.md
├── tests/ # Test files (to be created)
├── main.py # Entry point
├── requirements.txt # Dependencies
└── README.md # Project overview
- Command-line argument parsing
- Browser selection and initialization
- Entry point for all browser implementations
- Browser implementations for different GUI frameworks
- Each browser is self-contained and independent
- Common interface for navigation and settings
- Utility tools and helper applications
- Search operators tool
- Developer tools integration
- Configuration files and settings
- User preferences and security settings
- Project documentation
- API reference, architecture docs, guides
Follow PEP 8 style guidelines with the following additional rules:
- Maximum line length: 100 characters
- Use implicit string concatenation for long strings
- Group imports in this order:
- Standard library imports
- Third-party imports
- Local application imports
- Use absolute imports for local modules
# Standard library
import sys
import os
from pathlib import Path
# Third-party
from PyQt5.QtWidgets import QMainWindow
import webview
# Local
from src.browsers import Browser
from src.tools import SearchOperatorsToolClasses: PascalCase
class SimpleBrowser:
pass
class SettingsDialog:
passFunctions and Variables: snake_case
def load_url():
pass
def update_navigation_controls():
passConstants: UPPER_SNAKE_CASE
DEFAULT_HOME_URL = "https://search.brave.com/"
SECURITY_HEADERS = {...}Private Members: _leading_underscore
class Browser:
def __init__(self):
self._private_var = None
self._private_method()Use Google style docstrings:
def load_url(self, url):
"""Load a URL in the browser.
Args:
url (str): The URL to load.
Returns:
bool: True if successful, False otherwise.
Raises:
ValueError: If the URL is invalid.
"""
passUse type hints for function signatures:
from typing import Optional, List
def load_url(self, url: str) -> bool:
"""Load a URL in the browser."""
pass
def get_bookmarks(self) -> List[str]:
"""Get the list of bookmarks."""
passclass ClassName:
"""Brief description of the class."""
def __init__(self, param1, param2):
"""Initialize the class.
Args:
param1: Description of param1
param2: Description of param2
"""
self.param1 = param1
self.param2 = param2
def public_method(self):
"""Public method description."""
pass
def _private_method(self):
"""Private method description."""
pass
@property
def property_name(self):
"""Property description."""
return self._property_name
@property_name.setter
def property_name(self, value):
"""Property setter description."""
self._property_name = value- Imports
- Constants
- Class definitions
- Function definitions
- Main execution block
# Imports
import sys
from typing import Optional
# Constants
DEFAULT_URL = "https://example.com"
# Classes
class Browser:
pass
# Functions
def helper_function():
pass
# Main execution
if __name__ == "__main__":
pass# Format code
black src/
# Check formatting without changing
black --check src/
# Format specific file
black src/browsers/hope.py# Lint code
flake8 src/
# Lint with specific exclusions
flake8 src/ --exclude=src/legacy/
# Lint with line length override
flake8 src/ --max-line-length=100# Type check code
mypy src/
# Type check with strict mode
mypy src/ --strict
# Type check specific file
mypy src/browsers/hope.pyCreate a new file in src/browsers/:
# src/browsers/my_browser.py
import sys
from typing import Optional
class MyBrowser:
"""Custom browser implementation."""
def __init__(self):
"""Initialize the browser."""
self.home_url = "https://search.brave.com/"
self.history = []
self.current_index = -1
def load_url(self, url: str) -> None:
"""Load a URL in the browser.
Args:
url: The URL to load.
"""
if not url.startswith(("http://", "https://")):
url = "https://" + url
# Implementation here
def go_back(self) -> None:
"""Navigate back in history."""
pass
def go_forward(self) -> None:
"""Navigate forward in history."""
pass
def reload_page(self) -> None:
"""Reload the current page."""
pass
def go_home(self) -> None:
"""Navigate to the home page."""
pass
def main():
"""Main entry point for the browser."""
app = MyBrowser()
# Start application
if __name__ == "__main__":
main()Add to src/browsers/__init__.py:
from .hope import Browser
from .secure_browser import SimpleBrowser as SecureBrowser
from .modern_browser import SimpleBrowser as ModernBrowser
from .my_browser import MyBrowser # Add this line
__all__ = ['Browser', 'SecureBrowser', 'ModernBrowser', 'MyBrowser']Add to main.py:
parser.add_argument(
"--browser",
choices=["pyqt5", "tkinter", "webview", "search", "mybrowser"], # Add "mybrowser"
default="pyqt5",
help="Select browser implementation (default: pyqt5)"
)
# Add initialization logic
elif args.browser == "mybrowser":
from src.browsers.my_browser import main as mybrowser_main
mybrowser_main()Add to requirements.txt:
# My Browser dependencies
my-browser-lib>=1.0.0
Add documentation to:
-
docs/browsers.md- Browser implementation details -
docs/api.md- API reference -
README.md- Project overview
Create a new file in src/tools/:
# src/tools/my_tool.py
import sys
from typing import Optional
class MyTool:
"""Custom tool implementation."""
def __init__(self):
"""Initialize the tool."""
pass
def execute(self) -> None:
"""Execute the tool."""
pass
def main():
"""Main entry point for the tool."""
tool = MyTool()
tool.execute()
if __name__ == "__main__":
main()Add to src/tools/__init__.py:
from .search import SearchOperatorsTool
from .dev_tools_integration import Browser
from .my_tool import MyTool # Add this line
__all__ = ['SearchOperatorsTool', 'Browser', 'MyTool']Add to main.py:
parser.add_argument(
"--browser",
choices=["pyqt5", "tkinter", "webview", "search", "mytool"], # Add "mytool"
default="pyqt5",
help="Select browser implementation (default: pyqt5)"
)
# Add initialization logic
elif args.browser == "mytool":
from src.tools.my_tool import main as mytool_main
mytool_main()Add the security feature to the appropriate browser class:
class SimpleBrowser:
def __init__(self):
# ... existing code ...
self.ad_blocking_enabled = False
def toggle_ad_blocking(self):
"""Toggle ad blocking."""
self.ad_blocking_enabled = not self.ad_blocking_enabled
print(f"Ad blocking: {'Enabled' if self.ad_blocking_enabled else 'Disabled'}")
def apply_ad_blocking(self, content):
"""Apply ad blocking to content."""
if self.ad_blocking_enabled:
# Ad blocking logic here
pass
return contentAdd UI controls to the settings window:
def open_settings(self):
# ... existing code ...
# Ad Blocking Section
tk.Label(settings_window, text="Enable Ad Blocking:").pack(anchor=tk.W, padx=10, pady=5)
self.ad_blocking_var = tk.BooleanVar(value=False)
self.ad_blocking_checkbox = tk.Checkbutton(
settings_window,
text="Enable Ad Blocking",
variable=self.ad_blocking_var,
command=self.toggle_ad_blocking
)
self.ad_blocking_checkbox.pack(anchor=tk.W, padx=10)Add to configuration file structure:
{
"security": {
"ad_blocking_enabled": false
}
}Add documentation to docs/security.md.
Create a tests/ directory with the following structure:
tests/
├── __init__.py
├── conftest.py
├── test_browsers/
│ ├── test_hope.py
│ ├── test_secure_browser.py
│ └── test_modern_browser.py
├── test_tools/
│ ├── test_search.py
│ └── test_dev_tools.py
└── test_main.py
# tests/test_browsers/test_secure_browser.py
import pytest
import tkinter as tk
from src.browsers.secure_browser import SimpleBrowser
@pytest.fixture
def browser():
"""Create a browser instance for testing."""
root = tk.Tk()
browser = SimpleBrowser(root)
yield browser
root.destroy()
def test_initialization(browser):
"""Test browser initialization."""
assert browser.home_url == "https://search.brave.com/"
assert browser.current_index == -1
assert len(browser.history) == 0
def test_https_enforcement(browser):
"""Test HTTPS enforcement."""
browser.url_entry.delete(0, tk.END)
browser.url_entry.insert(0, "example.com")
browser.load_url()
assert browser.url_entry.get().startswith("https://")
def test_history_management(browser):
"""Test history management."""
browser.url_entry.delete(0, tk.END)
browser.url_entry.insert(0, "https://example.com")
browser.load_url()
assert len(browser.history) == 1
assert browser.current_index == 0
def test_navigation_controls(browser):
"""Test navigation controls state."""
# Initially, back and forward should be disabled
assert browser.back_button['state'] == tk.DISABLED
assert browser.forward_button['state'] == tk.DISABLED# tests/test_tools/test_search.py
import pytest
from PyQt5.QtWidgets import QApplication
from src.tools.search import SearchOperatorsTool
@pytest.fixture
def app():
"""Create QApplication instance."""
app = QApplication([])
yield app
app.quit()
@pytest.fixture
def search_tool(app):
"""Create search tool instance."""
tool = SearchOperatorsTool()
yield tool
def test_initialization(search_tool):
"""Test tool initialization."""
assert search_tool.windowTitle() == "Advanced Search Operators Tool"
def test_query_generation(search_tool):
"""Test query generation."""
search_tool.query_input.setText("Python tutorial")
search_tool.site_checkbox.setChecked(True)
search_tool.site_input.setText("docs.python.org")
search_tool.generate_query()
query = search_tool.preview_output.toPlainText()
assert "Python tutorial" in query
assert "site:docs.python.org" in query# Run all tests
pytest
# Run specific test file
pytest tests/test_browsers/test_secure_browser.py
# Run with coverage
pytest --cov=src --cov-report=html
# Run with verbose output
pytest -v
# Run specific test
pytest tests/test_browsers/test_secure_browser.py::test_https_enforcementAim for at least 80% code coverage. Generate coverage reports:
pytest --cov=src --cov-report=html --cov-report=termView the HTML report in htmlcov/index.html.
def load_url(self, url):
print(f"Loading URL: {url}") # Debug print
# ... implementation ...
print(f"URL loaded successfully") # Debug printUse Python's logging module:
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
def load_url(self, url):
logger.debug(f"Loading URL: {url}")
try:
# ... implementation ...
logger.info(f"URL loaded successfully: {url}")
except Exception as e:
logger.error(f"Error loading URL: {e}")import pdb
def load_url(self, url):
pdb.set_trace() # Breakpoint
# ... implementation ...Use your IDE's built-in debugger:
- VS Code: Set breakpoints and use the debugger
- PyCharm: Set breakpoints and use the debugger
- Check URL validation
- Verify network connectivity
- Check proxy settings
- Review error messages in console
- Verify settings are saved
- Check configuration file
- Verify settings are loaded on startup
- Check for exceptions in settings code
- Check for blocking operations
- Verify event loop is running
- Check for infinite loops
- Review threading issues
- All classes must have docstrings
- All public methods must have docstrings
- Use Google style docstrings
- Include type hints
- Keep README.md up to date
- Update API documentation when adding new methods
- Document new features in appropriate docs
- Add examples for complex features
## New Feature
Description of the new feature.
### Usage
```bash
python main.py --new-featureAdd configuration details here.
#### Adding to API Documentation
```markdown
### NewClass
**Location**: `src/new_module.py`
**Description**: Description of the new class.
#### `new_method(param)`
**Description**: Description of the method.
**Parameters**:
- `param` (type): Description
**Returns**: type
**Example**:
```python
obj = NewClass()
obj.new_method("value")
## Contribution Guidelines
### Workflow
1. **Fork the Repository**
- Fork the project on GitHub
- Clone your fork locally
2. **Create a Branch**
```bash
git checkout -b feature/your-feature-name
-
Make Changes
- Follow coding standards
- Add tests for new features
- Update documentation
-
Commit Changes
git add . git commit -m "feat: add new feature"
Use conventional commits:
-
feat:New feature -
fix:Bug fix -
docs:Documentation changes -
style:Code style changes -
refactor:Code refactoring -
test:Test changes -
chore:Maintenance tasks
-
-
Push Changes
git push origin feature/your-feature-name
-
Create Pull Request
- Provide clear description
- Reference related issues
- Include screenshots if applicable
-
Self-Review
- Review your own changes
- Run tests
- Check code style
-
Submit PR
- Create pull request
- Request review from maintainers
-
Address Feedback
- Respond to review comments
- Make requested changes
- Update tests and documentation
-
Merge
- After approval, merge the PR
- Delete the feature branch
- Code follows project style guidelines
- Tests added for new features
- All tests pass
- Documentation updated
- Commit messages follow conventional commits
- No merge conflicts
- Ready for review
Follow Semantic Versioning (SemVer):
- MAJOR.MINOR.PATCH
- MAJOR: Incompatible API changes
- MINOR: Backwards-compatible functionality additions
- PATCH: Backwards-compatible bug fixes
- Update version number
- Update CHANGELOG.md
- Update README.md if needed
- Run full test suite
- Create release notes
- Tag release
- Create GitHub release
- Update documentation
# Update version
echo "1.2.0" > VERSION
# Commit changes
git add VERSION CHANGELOG.md README.md
git commit -m "chore: release version 1.2.0"
# Tag release
git tag -a v1.2.0 -m "Release version 1.2.0"
# Push tag
git push origin v1.2.0
# Create GitHub release through web interface-
Use Hot Reload (if applicable)
- Reload code changes without restarting
-
Use Virtual Environments
- Keep dependencies isolated
- Easy to recreate environment
-
Use Git Effectively
- Commit frequently
- Use meaningful commit messages
- Use branches for features
-
Automate Testing
- Run tests on save
- Use pre-commit hooks
-
Use IDE Features
- Code completion
- Refactoring tools
- Integrated debugging
-
Keep Functions Small
- Single responsibility
- Easy to test
- Easy to understand
-
DRY Principle
- Don't Repeat Yourself
- Extract common code
- Use helper functions
-
YAGNI Principle
- You Aren't Gonna Need It
- Don't add unnecessary features
- Keep it simple
-
SOLID Principles
- Single Responsibility
- Open/Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
-
Test-Driven Development
- Write tests first
- Write code to pass tests
- Refactor as needed
- PEP 8 - Style guide
- PEP 257 - Docstring conventions
- The Hitchhiker's Guide to Python
- GitHub Issues: Report bugs and request features
- GitHub Discussions: Ask questions and discuss ideas
- Code Reviews: Get feedback on your contributions
If you encounter issues during development:
- Check existing documentation
- Search existing issues
- Create a new issue with:
- Clear description of the problem
- Steps to reproduce
- Expected behavior
- Actual behavior
- Environment details
This development guide provides the foundation for contributing to the Secure Browser project. Following these standards and practices will ensure high-quality contributions and a smooth development experience.
Thank you for your interest in contributing to Secure Browser!