The DefaultFileReader class has been refactored to improve testability, readability, and maintainability. This document outlines the changes made and how to use the new implementation.
- File path resolution is now handled by dedicated methods
- File opening is separated from path resolution
- Configuration management is centralized and configurable
- Dependency injection through constructor parameters
- Mockable methods for unit testing
- Clear interfaces between different responsibilities
- Comprehensive test coverage with isolated test cases
- Custom exception hierarchy for different error types
- Descriptive error messages with context
- Proper exception chaining for debugging
- Configurable defaults that can be overridden
- Environment-specific settings support
- Clear configuration contract
- Comprehensive docstrings for all methods
- Clear method names that describe their purpose
- Logical method organization from public to private
- Type hints throughout the codebase
The main class that provides the file reading framework:
class DefaultFileReader(BaseDataAccessLayer):
# Configuration constants
DEFAULT_CODE_PACKAGE = 'payload'
DEFAULT_FILE_FOLDER = 'files'
DEFAULT_CONFIG_FILE = 'config.json'
def __init__(self, code_package=None, file_folder=None, config_file=None):
# Initialize with custom or default configuration
def file_open(self, file_name: str) -> io.TextIOWrapper:
# Main public method for opening files
def get_search_locations(self) -> list[Path]:
# Get all possible search locationsFileReaderError (base)
├── FileNotFoundError (file not found in any location)
└── FileAccessError (permission, I/O errors, etc.)from datacustomcode.file.reader.default import DefaultFileReader
# Use default configuration
reader = DefaultFileReader()
with reader.file_open('data.csv') as f:
content = f.read()from datacustomcode.file.reader.default import DefaultFileReader
# Custom configuration
reader = DefaultFileReader(
code_package='my_package',
file_folder='data',
config_file='settings.json'
)try:
with reader.file_open('data.csv') as f:
content = f.read()
except FileNotFoundError as e:
print(f"File not found: {e}")
except FileAccessError as e:
print(f"Access error: {e}")The file reader uses a two-tier search strategy:
- Primary Location:
{code_package}/{file_folder}/{filename} - Fallback Location:
{config_file_parent}/{file_folder}/{filename}
This allows for flexible deployment scenarios where files might be in different locations depending on the environment.
The refactored class includes comprehensive unit tests covering:
- Configuration initialization
- File path resolution
- Error handling scenarios
- File opening operations
- Search location determination
The class is designed for easy mocking in tests:
from unittest.mock import patch
with patch('DefaultFileReader._resolve_file_path') as mock_resolve:
mock_resolve.return_value = Path('/test/file.txt')
# Test file opening logicIntegration tests verify the complete file resolution and opening flow using temporary directories and real file operations.
The old implementation had these issues:
- Hardcoded configuration values
- Mixed responsibilities in single methods
- Limited error handling
- Difficult to test
- Update imports: Use
DefaultFileReaderfromdatacustomcode.file.reader.default - Error handling: Catch specific exceptions instead of generic ones
- Configuration: Use constructor parameters for custom settings
- Testing: Leverage the new mockable methods
- Easier debugging with clear error messages
- Better IDE support with type hints and docstrings
- Simplified testing with dependency injection
- Clearer code structure with separated responsibilities
- Easier to extend with new file resolution strategies
- Better error tracking with custom exception types
- Improved test coverage with isolated test cases
- Clearer documentation with comprehensive docstrings
- More reliable with proper error handling
- More flexible with configurable behavior
- Better debugging with descriptive error messages
- Consistent interface across different implementations
The refactored structure makes it easy to add:
- Additional file resolution strategies (URLs, cloud storage, etc.)
- File format detection and automatic handling
- Caching mechanisms for frequently accessed files
- Async file operations for better performance
- File validation and integrity checking
The refactored DefaultFileReader class provides a solid foundation for file reading operations while maintaining backward compatibility. The improvements in testability, readability, and maintainability make it easier to develop, test, and maintain file reading functionality in the Data Cloud Custom Code SDK.