A robust Python client for the Nuclear Regulatory Commission's ADAMS API
Project description
ADAMSNRC API Client
This code was created by ChatGPT and Cursor. On ChatGPT the pdf with the API documentation was uploaded and simple prompt sent: "create simple python code to interface each endpoint on adams library api".
With the code generated I switched to Cursor, set model to Any and started vibe coding.
The result after many interactions and minor code edits is this package.
A robust Python client for the Nuclear Regulatory Commission's ADAMS (Agencywide Documents Access and Management System) API.
Features
- Type Safety: Full type hints for better IDE support and code clarity
- Error Handling: Comprehensive exception handling with custom error types
- Input Validation: Robust validation of all input parameters
- Retry Logic: Automatic retry mechanism for network requests
- Logging: Configurable logging for debugging and monitoring
- Configuration: Environment-based configuration management
- Utilities: Helper functions for data processing and validation
- Testing: Comprehensive test suite
Installation
pip install -r requirements.txt
Quick Start
from adamsnrc.main import content_search, advanced_search
# Simple content search
result = content_search(
properties_search=[("DocumentType", "ends", "NUREG")],
single_content_search="steam generator",
sort="DocumentDate",
order="DESC"
)
print(f"Found {result.count} documents")
for doc in result.results:
print(f"- {doc.get('title', 'No title')}")
# Advanced search with date range
from datetime import datetime
from adamsnrc.utils import build_date_range
date_range = build_date_range(
"01/01/2023 12:00 AM",
"12/31/2023 11:59 PM"
)
result = advanced_search(
properties_search_all=[("AuthorName", "starts", "Macfarlane")],
date_range=date_range,
sort="$title",
order="ASC"
)
Configuration
The client can be configured using environment variables:
# API Configuration
export ADAMS_BASE_URL="https://adams.nrc.gov/wba/services/search/advanced/nrc"
export ADAMS_TIMEOUT="60"
export ADAMS_MAX_RETRIES="3"
export ADAMS_RETRY_DELAY="1.0"
# Logging Configuration
export ADAMS_LOG_LEVEL="INFO"
API Reference
Main Functions
content_search()
Content search in the public library.
def content_search(
properties_search: Optional[List[Tuple[str, str, Any]]] = None,
properties_search_any: Optional[List[Tuple[str, str, Any]]] = None,
single_content_search: str = "",
sort: str = "DocumentDate",
order: str = "DESC"
) -> SearchResult
advanced_search()
Advanced search with additional options.
def advanced_search(
properties_search_all: Optional[List[Tuple[str, str, Any]]] = None,
properties_search_any: Optional[List[Tuple[str, str, Any]]] = None,
public_library: bool = True,
legacy_library: bool = False,
added_today: bool = False,
added_this_month: bool = False,
within_folder_enable: bool = False,
within_folder_insubfolder: bool = False,
within_folder_path: str = "",
sort: str = "$title",
order: str = "ASC"
) -> SearchResult
part21_search_content()
Search for Part 21 correspondence using content search.
part21_search_advanced()
Search for Part 21 correspondence using advanced search.
operating_reactor_ir_search_content()
Search for operating reactor inspection reports using content search.
operating_reactor_ir_search_advanced()
Search for operating reactor inspection reports using advanced search.
Data Structures
SearchResult
Container for search results with metadata.
@dataclass
class SearchResult:
meta: Dict[str, str] # Metadata (count, matches, etc.)
results: List[Dict[str, str]] # List of document results
@property
def count(self) -> int: # Number of results as integer
@property
def matches(self) -> int: # Number of matches as integer
Exception Types
ADAMSError: Base exception for all ADAMS API errorsADAMSRequestError: Request-related errors (timeout, network issues)ADAMSValidationError: Input validation errorsADAMSParseError: XML parsing errors
Utility Functions
Date and Time Utilities
from adamsnrc.utils import build_date_range, validate_and_format_date
# Build date range
date_range = build_date_range("01/01/2023 12:00 AM", "12/31/2023 11:59 PM")
# Validate and format date
formatted_date = validate_and_format_date("01/15/2023 02:30 PM")
Text Processing
from adamsnrc.utils import escape_special_chars, normalize_whitespace, truncate_text
# Escape special characters
escaped = escape_special_chars("test (with) [special] {chars}")
# Normalize whitespace
normalized = normalize_whitespace(" multiple spaces ")
# Truncate text
truncated = truncate_text("Very long text...", max_length=50)
Result Processing
from adamsnrc.utils import (
extract_metadata_from_result,
filter_results_by_date,
group_results_by_field,
calculate_result_stats
)
# Extract metadata
metadata = extract_metadata_from_result(result_dict)
# Filter by date
filtered = filter_results_by_date(results, start_date, end_date)
# Group by field
grouped = group_results_by_field(results, "AuthorName")
# Calculate statistics
stats = calculate_result_stats(results)
Examples
Basic Search
from adamsnrc.main import content_search
# Search for NUREG documents about steam generators
result = content_search(
properties_search=[("DocumentType", "ends", "NUREG")],
single_content_search="steam generator",
sort="DocumentDate",
order="DESC"
)
print(f"Found {result.count} NUREG documents about steam generators")
Advanced Search with Date Range
from adamsnrc.main import advanced_search
from adamsnrc.utils import build_date_range
# Search for documents by a specific author in a date range
date_range = build_date_range("01/01/2023 12:00 AM", "12/31/2023 11:59 PM")
result = advanced_search(
properties_search_all=[
("AuthorName", "starts", "Macfarlane"),
("DocumentType", "starts", "Speech")
],
date_range=date_range,
sort="$title",
order="ASC"
)
Part 21 Search
from adamsnrc.main import part21_search_content
# Search for Part 21 correspondence about safety valves
result = part21_search_content(
extra_and=[("AuthorAffiliation", "infolder", "NRC/NRR")],
text="safety valve",
sort="$size",
order="DESC"
)
Result Processing
from adamsnrc.utils import calculate_result_stats, group_results_by_field
# Get search results
result = content_search(properties_search=[("DocumentType", "ends", "NUREG")])
# Calculate statistics
stats = calculate_result_stats(result.results)
print(f"Total results: {stats['total_results']}")
print(f"Unique authors: {stats['unique_authors']}")
print(f"Average file size: {stats['average_size']} bytes")
# Group by author
grouped = group_results_by_field(result.results, "AuthorName")
for author, docs in grouped.items():
print(f"{author}: {len(docs)} documents")
Error Handling
from adamsnrc.main import content_search, ADAMSError, ADAMSValidationError
try:
result = content_search(
properties_search=[("DocumentType", "ends", "NUREG")],
order="INVALID" # This will raise an error
)
except ADAMSValidationError as e:
print(f"Validation error: {e}")
except ADAMSError as e:
print(f"ADAMS API error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
Testing
Run the test suite:
python -m pytest adamsnrc/test_main.py -v
Or run specific test classes:
python -m pytest adamsnrc/test_main.py::TestSearchFunctions -v
Logging
The client uses Python's standard logging module. Configure logging level:
import logging
logging.getLogger('adamsnrc').setLevel(logging.DEBUG)
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
Version 2.0.0 (Refactored)
- Added comprehensive type hints
- Implemented robust error handling with custom exceptions
- Added input validation for all parameters
- Implemented retry logic for network requests
- Added configuration management
- Created utility functions for data processing
- Added comprehensive test suite
- Improved documentation and examples
- Added logging support
- Made the code more maintainable and robust
How to Build and Publish Your Package to PyPI
Your project is already well-prepared for PyPI distribution! Here's the complete process:
1. Prerequisites Setup
First, ensure you have the necessary tools and accounts:
# Install build tools
pip install build twine
# Create PyPI account at https://pypi.org/account/register/
# Create TestPyPI account at https://test.pypi.org/account/register/
2. Configure PyPI Credentials
Create a ~/.pypirc file in your home directory:
[distutils]
index-servers =
pypi
testpypi
[pypi]
username = __token__
password = pypi-your-api-token-here
[testpypi]
repository = https://test.pypi.org/legacy/
username = __token__
password = pypi-your-test-api-token-here
3. Update Package Information
Before publishing, you need to update the placeholder information in your configuration files:
In pyproject.toml:
authors = [
{name = "Your Actual Name", email = "your.actual.email@example.com"}
]
maintainers = [
{name = "Your Actual Name", email = "your.actual.email@example.com"}
]
In setup.py:
author="Your Actual Name",
author_email="your.actual.email@example.com",
url="https://github.com/your-actual-username/adamsnrc",
Update URLs in both files:
- Replace
yourusernamewith your actual GitHub username - Update documentation URLs if you have them
4. Build the Package
# Clean previous builds (optional)
rm -rf build/ dist/ *.egg-info/
# Build the package
python -m build
This will create:
dist/adamsnrc-2.0.0.tar.gz(source distribution)dist/adamsnrc-2.0.0-py3-none-any.whl(wheel distribution)
5. Test on TestPyPI (Recommended)
# Upload to TestPyPI first
twine upload --repository testpypi dist/*
# Test installation from TestPyPI
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ adamsnrc
# Test the package
python -c "import adamsnrc; print(adamsnrc.__version__)"
6. Publish to PyPI
# Upload to PyPI
twine upload dist/*
# Or upload specific files
twine upload dist/adamsnrc-2.0.0.tar.gz dist/adamsnrc-2.0.0-py3-none-any.whl
7. Verify the Publication
# Install from PyPI
pip install adamsnrc
# Test the package
python -c "import adamsnrc; print(adamsnrc.__version__)"
Automated Publishing with GitHub Actions
Your project already has GitHub Actions configured! Here's how to use them:
1. Set up GitHub Secrets
- Go to your repository settings
- Navigate to "Secrets and variables" → "Actions"
- Add
PYPI_API_TOKENwith your PyPI API token
2. Bump Version (Automated)
Use the included version bumping script to automatically update all version numbers:
# Bump patch version (2.0.0 -> 2.0.1)
./bump.sh patch
# Bump minor version (2.0.0 -> 2.1.0)
./bump.sh minor
# Bump major version (2.0.0 -> 3.0.0)
./bump.sh major
# Dry run to see what would change
./bump.sh patch --dry-run
# Complete release workflow (bump + git + GitHub release)
./bump.sh patch --auto-git
The script automatically updates:
pyproject.tomlsetup.pyadamsnrc/__init__.pyCHANGELOG.md(adds new version entry)
With --auto-git flag, it also:
- Commits all changes with descriptive message
- Pushes to main branch
- Creates and pushes git tag
- Creates GitHub release (if gh CLI is available)
3. Create a Release (Manual)
If you didn't use --auto-git, run these commands manually:
# Commit version changes
git add .
git commit -m "bump: version 2.0.0 -> 2.0.1"
git push origin main
# Create and push a tag
git tag v2.0.1
git push origin v2.0.1
# Create GitHub release (this triggers automatic publishing)
gh release create v2.0.1 --title "Version 2.0.1" --notes "Bug fixes and improvements"
Or use the automated workflow:
# Complete release workflow in one command
./bump.sh patch --auto-git
Package Quality Checklist
Before publishing, ensure:
✅ Configuration Files: pyproject.toml, setup.py, MANIFEST.in are properly configured
✅ Documentation: README.md is comprehensive and up-to-date
✅ Dependencies: All required packages are listed in dependencies
✅ Version: Version is consistent across all files
✅ License: MIT license is included
✅ Tests: Test suite passes
✅ Code Quality: Ruff linting and formatting pass
Your Package is Ready!
Your package is already well-structured with:
- ✅ Modern
pyproject.tomlconfiguration - ✅ Comprehensive
setup.py - ✅ Proper
MANIFEST.infor file inclusion - ✅ Automated version bumping script (
bump.shandbump_version.py) - ✅ Detailed
PUBLISHING.mdguide - ✅ GitHub Actions workflows
- ✅ Built distributions in
dist/directory - ✅ Professional README.md
- ✅ Proper package structure
The main steps you need to take are:
- Update the placeholder information (name, email, URLs)
- Get PyPI API tokens
- Configure
~/.pypirc - Build and upload
Your package will be available at https://pypi.org/project/adamsnrc/ once published!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adamsnrc-2.0.13.tar.gz.
File metadata
- Download URL: adamsnrc-2.0.13.tar.gz
- Upload date:
- Size: 44.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b286480fcf2ab3b1e3de16899d0f016000f053aa9a729e9cf906ab20e27372d
|
|
| MD5 |
27c91c27baad3e24b37e885db896814f
|
|
| BLAKE2b-256 |
4436331cdf6c49eb119bf0af7b0c563a3a7a5185f7352153515eb9d1be29a32c
|
File details
Details for the file adamsnrc-2.0.13-py3-none-any.whl.
File metadata
- Download URL: adamsnrc-2.0.13-py3-none-any.whl
- Upload date:
- Size: 43.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a74384d61326ddff2935a5aacdbd82b2ee568b0d7134afccdb185392bf3a0be
|
|
| MD5 |
25375b8ffb0e671fd05b826642f79bc2
|
|
| BLAKE2b-256 |
00bed98a338e0566a7c3986175641f78249888071de3554b44f8aea2433e297f
|