CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-fastcore

Python supercharged for fastai development

56

1.36x
Overview
Eval results
Files

system-integration.mddocs/

System Integration

Command-line argument parsing, documentation tools, file system utilities, and development aids that bridge fastcore functionality with system-level operations. This module combines script.py, docments.py, and related utilities for building command-line applications and development tools.

Capabilities

Command-Line Argument Parsing

Advanced argument parsing system that automatically generates CLI interfaces from Python function signatures.

def call_parse(func=None, **kwargs):
    """
    Parse command-line arguments and call function with parsed values.
    
    Automatically creates argument parser from function signature and
    docstrings, then calls the function with parsed command-line arguments.
    This is the main entry point for converting functions into CLI tools.
    
    Parameters:
    - func: function to convert to CLI (uses caller if None)
    - **kwargs: additional arguments for argument parser
    
    Usage:
    def main(input_file, output_file=None, verbose=False):
        '''Process input file and create output.
        
        input_file: Path to input file
        output_file: Path to output file (optional)
        verbose: Enable verbose logging
        '''
        # Function implementation here
        pass
    
    if __name__ == "__main__":
        call_parse(main)
    """

class Param:
    """
    Parameter specification for command-line arguments.
    
    Provides detailed control over how function parameters are converted
    to command-line arguments, including type conversion, validation,
    and help text generation.
    
    Parameters:
    - help: str, help text for the parameter
    - type: callable, type conversion function
    - opt: bool, whether parameter is optional (flag-style)
    - action: str, argparse action ('store_true', 'store_false', etc.)
    - nargs: str|int, number of arguments to consume
    - const: value for const action
    - choices: list, allowed values for parameter
    - required: bool, whether parameter is required
    - default: default value for parameter
    - version: str, version string for --version
    
    Usage:
    def process_data(
        input_file: Param("Input file path", type=str),
        verbose: Param("Enable verbose output", action='store_true'),
        format: Param("Output format", choices=['json', 'csv', 'xml'], default='json')
    ):
        pass
    """
    
    def __init__(self, help="", type=None, opt=True, action=None, nargs=None,
                 const=None, choices=None, required=None, default=None, version=None): ...
    
    def set_default(self, d): ...
    
    @property
    def pre(self): ...
    
    @property 
    def kwargs(self): ...

def anno_parser(func, prog=None):
    """
    Create ArgumentParser from function annotations and docstrings.
    
    Analyzes function signature, type hints, and docstrings to automatically
    generate comprehensive argument parser with proper help text and validation.
    
    Parameters:
    - func: function to analyze
    - prog: str, program name (auto-detected if None)
    
    Returns:
    argparse.ArgumentParser: Configured parser ready for use
    """

def args_from_prog(func, prog):
    """
    Extract arguments from program string for testing.
    
    Parses specially formatted program strings to extract argument
    values for testing command-line interfaces programmatically.
    
    Parameters:
    - func: function being tested
    - prog: str, program string with embedded arguments
    
    Returns:
    dict: Extracted argument values
    """

def store_true():
    """Placeholder for store_true action in Param definitions."""

def store_false():
    """Placeholder for store_false action in Param definitions."""

def bool_arg(v):
    """
    Type converter for boolean command-line arguments.
    
    Converts string arguments to boolean values with flexible parsing
    that handles various common boolean representations.
    
    Parameters:
    - v: str, string value to convert
    
    Returns:
    bool: Converted boolean value
    
    Accepts: true/false, yes/no, 1/0, on/off (case-insensitive)
    """

Documentation Extraction and Analysis

Tools for extracting and processing documentation from Python code.

def docstring(sym):
    """
    Extract docstring from symbol (function, class, or module).
    
    Retrieves docstring with fallback to __init__ method for classes
    and proper handling of various symbol types.
    
    Parameters:
    - sym: function, class, module, or string
    
    Returns:
    str: Extracted docstring or empty string
    """

def parse_docstring(sym):
    """
    Parse numpy-style docstring into structured components.
    
    Extracts and structures docstring components including parameters,
    returns, examples, and other sections using numpy docstring format.
    
    Parameters:
    - sym: function, class, or docstring to parse
    
    Returns:
    AttrDict: Structured docstring components
    """

def docments(elt, full=False, **kwargs):
    """
    Extract parameter documentation from function comments and annotations.
    
    Analyzes function source code to extract parameter documentation
    from both docstrings and inline comments, creating comprehensive
    parameter information for API documentation.
    
    Parameters:
    - elt: function or class to document
    - full: bool, include all parameter details
    - **kwargs: additional options for extraction
    
    Returns:
    dict: Parameter documentation mapping names to details
    """

def get_source(s):
    """
    Get source code for function, class, or dataclass.
    
    Retrieves source code with proper handling of different object types
    including functions, methods, and dataclasses.
    
    Parameters:
    - s: str|function|class, object to get source for
    
    Returns:
    str: Source code or None if unavailable
    """

def get_name(s):
    """
    Get qualified name for object.
    
    Returns the fully qualified name including module and class context
    for proper object identification.
    
    Parameters:
    - s: object to get name for
    
    Returns:
    str: Qualified name
    """

def qual_name(o):
    """
    Get qualified name with module information.
    
    Parameters:
    - o: object to get qualified name for
    
    Returns:
    str: Fully qualified name including module
    """

def sig2str(sig):
    """
    Convert function signature to string representation.
    
    Parameters:
    - sig: inspect.Signature object
    
    Returns:
    str: String representation of signature
    """

def extract_docstrings(source):
    """
    Extract all docstrings from Python source code.
    
    Parses source code to find and extract all docstrings including
    module, class, and function docstrings with location information.
    
    Parameters:
    - source: str, Python source code
    
    Returns:
    dict: Mapping of locations to docstrings
    """

Development Utilities

Helper functions and classes for development workflow and code analysis.

def isdataclass(s):
    """
    Check if object is a dataclass class (not instance).
    
    Parameters:
    - s: object to check
    
    Returns:
    bool: True if s is dataclass class
    """

def get_dataclass_source(s):
    """
    Get source code for dataclass with special handling.
    
    Parameters:
    - s: dataclass to get source for
    
    Returns:
    str: Source code or empty string
    """

def clean_type_str(x):
    """
    Clean up type string representation for display.
    
    Removes verbose type information and formatting for cleaner
    display in help text and documentation.
    
    Parameters:
    - x: str, type string to clean
    
    Returns:
    str: Cleaned type string
    """

empty = Parameter.empty
"""Sentinel value representing empty/missing parameters."""

SCRIPT_INFO = {}
"""Global dictionary for storing script information and metadata."""

Usage Examples

Creating Command-Line Applications

from fastcore.script import call_parse, Param

# Simple CLI application
def process_file(
    input_file: Param("Path to input file", type=str),
    output_file: Param("Path to output file", type=str, default="output.txt"),
    verbose: Param("Enable verbose output", action='store_true'),
    format: Param("Output format", choices=['json', 'csv', 'xml'], default='json')
):
    """
    Process input file and generate output in specified format.
    
    This tool reads the input file, processes the data, and writes
    the results to the output file in the specified format.
    """
    if verbose:
        print(f"Processing {input_file}...")
        print(f"Output format: {format}")
    
    # Processing logic here
    with open(input_file, 'r') as f:
        data = f.read()
    
    # Transform data based on format
    if format == 'json':
        import json
        result = json.dumps({"data": data, "processed": True})
    elif format == 'csv':
        result = f"data,processed\n{data},true"
    else:  # xml
        result = f"<root><data>{data}</data><processed>true</processed></root>"
    
    with open(output_file, 'w') as f:
        f.write(result)
    
    if verbose:
        print(f"Output written to {output_file}")

if __name__ == "__main__":
    call_parse(process_file)

# Usage from command line:
# python script.py input.txt --output-file result.json --verbose --format json

Advanced Parameter Handling

from fastcore.script import call_parse, Param, bool_arg

def data_analysis(
    dataset: Param("Dataset file path"),
    model_type: Param("ML model type", choices=['linear', 'tree', 'neural'], default='linear'),
    train_size: Param("Training set size", type=float, default=0.8),
    random_seed: Param("Random seed for reproducibility", type=int, default=42),
    normalize: Param("Normalize features", type=bool_arg, default=True),
    output_dir: Param("Output directory", default="./results"),
    verbose: Param("Verbose output", action='store_true'),
    debug: Param("Debug mode", action='store_true'),
    config_file: Param("Configuration file", required=False),
    gpu_count: Param("Number of GPUs to use", type=int, nargs='?', const=1, default=0)
):
    """
    Perform data analysis with machine learning models.
    
    Analyzes the provided dataset using the specified model type
    and configuration parameters. Results are saved to the output directory.
    """
    import os
    
    # Validate inputs
    if not os.path.exists(dataset):
        raise FileNotFoundError(f"Dataset file not found: {dataset}")
    
    if train_size <= 0 or train_size >= 1:
        raise ValueError("Train size must be between 0 and 1")
    
    # Setup output directory
    os.makedirs(output_dir, exist_ok=True)
    
    config = {
        'model_type': model_type,
        'train_size': train_size,
        'random_seed': random_seed,
        'normalize': normalize,
        'gpu_count': gpu_count
    }
    
    if config_file:
        import json
        with open(config_file, 'r') as f:
            file_config = json.load(f)
        config.update(file_config)
    
    if verbose or debug:
        print("Configuration:")
        for key, value in config.items():
            print(f"  {key}: {value}")
    
    # Analysis logic would go here
    print(f"Analyzing {dataset} with {model_type} model...")
    
    # Save results
    results_file = os.path.join(output_dir, "results.json")
    import json
    with open(results_file, 'w') as f:
        json.dump(config, f, indent=2)
    
    print(f"Results saved to {results_file}")

if __name__ == "__main__":
    call_parse(data_analysis)

# Command line usage examples:
# python analysis.py data.csv --model-type neural --normalize true --verbose
# python analysis.py data.csv --train-size 0.7 --gpu-count --debug
# python analysis.py data.csv --config-file config.json --output-dir results/

Documentation Extraction and Processing

from fastcore.docments import docstring, parse_docstring, docments, get_source

def analyze_function_documentation(func):
    """Comprehensive analysis of function documentation."""
    
    # Extract basic docstring
    doc = docstring(func)
    print(f"Docstring: {doc}")
    
    # Parse structured docstring
    parsed = parse_docstring(func)
    print(f"Summary: {parsed.get('Summary', 'No summary')}")
    print(f"Parameters: {parsed.get('Parameters', 'No parameters documented')}")
    
    # Extract detailed parameter documentation
    param_docs = docments(func, full=True)
    print("\nDetailed parameter information:")
    for name, info in param_docs.items():
        print(f"  {name}: {info.get('docment', 'No documentation')}")
        if hasattr(info, 'anno') and info.anno:
            print(f"    Type: {info.anno}")
        if hasattr(info, 'default') and info.default is not None:
            print(f"    Default: {info.default}")
    
    # Get source code
    source = get_source(func)
    if source:
        print(f"\nSource code:\n{source}")

# Example function to analyze
def example_function(
    data: list,
    threshold: float = 0.5,
    normalize: bool = True
) -> dict:
    """
    Process data with threshold filtering.
    
    Parameters
    ----------
    data : list
        Input data to process
    threshold : float, optional
        Filtering threshold (default: 0.5)
    normalize : bool, optional
        Whether to normalize results (default: True)
    
    Returns
    -------
    dict
        Processed results with statistics
    
    Examples
    --------
    >>> result = example_function([1, 2, 3, 4, 5])
    >>> print(result['count'])
    5
    """
    filtered = [x for x in data if x > threshold]
    if normalize:
        total = sum(filtered)
        filtered = [x/total for x in filtered]
    
    return {
        'data': filtered,
        'count': len(filtered),
        'normalized': normalize
    }

# Analyze the function
analyze_function_documentation(example_function)

Automated API Documentation

from fastcore.docments import extract_docstrings, sig2str
from fastcore.script import clean_type_str
import inspect

class APIDocumentationGenerator:
    """Generate API documentation from Python modules."""
    
    def __init__(self, module):
        self.module = module
        self.functions = []
        self.classes = []
        
        # Analyze module contents
        for name in dir(module):
            obj = getattr(module, name)
            if not name.startswith('_'):
                if inspect.isfunction(obj):
                    self.functions.append((name, obj))
                elif inspect.isclass(obj):
                    self.classes.append((name, obj))
    
    def generate_function_doc(self, name, func):
        """Generate documentation for a function."""
        sig = inspect.signature(func)
        doc = docstring(func)
        
        # Clean up signature display
        params = []
        for param_name, param in sig.parameters.items():
            param_str = param_name
            if param.annotation != inspect.Parameter.empty:
                type_str = clean_type_str(param.annotation)
                param_str += f": {type_str}"
            if param.default != inspect.Parameter.empty:
                param_str += f" = {param.default}"
            params.append(param_str)
        
        signature = f"{name}({', '.join(params)})"
        if sig.return_annotation != inspect.Parameter.empty:
            return_type = clean_type_str(sig.return_annotation)
            signature += f" -> {return_type}"
        
        return {
            'name': name,
            'signature': signature,
            'docstring': doc,
            'source_file': inspect.getfile(func) if hasattr(func, '__file__') else None
        }
    
    def generate_class_doc(self, name, cls):
        """Generate documentation for a class."""
        doc = docstring(cls)
        methods = []
        
        for method_name in dir(cls):
            if not method_name.startswith('_') or method_name == '__init__':
                method = getattr(cls, method_name)
                if inspect.isfunction(method) or inspect.ismethod(method):
                    methods.append(self.generate_function_doc(method_name, method))
        
        return {
            'name': name,
            'docstring': doc,
            'methods': methods,
            'source_file': inspect.getfile(cls) if hasattr(cls, '__file__') else None
        }
    
    def generate_markdown(self):
        """Generate markdown documentation."""
        lines = [f"# {self.module.__name__} API Documentation\n"]
        
        if self.module.__doc__:
            lines.append(f"{self.module.__doc__}\n")
        
        if self.functions:
            lines.append("## Functions\n")
            for name, func in self.functions:
                doc = self.generate_function_doc(name, func)
                lines.append(f"### {doc['signature']}\n")
                if doc['docstring']:
                    lines.append(f"{doc['docstring']}\n")
                lines.append("")
        
        if self.classes:
            lines.append("## Classes\n")
            for name, cls in self.classes:
                doc = self.generate_class_doc(name, cls)
                lines.append(f"### class {doc['name']}\n")
                if doc['docstring']:
                    lines.append(f"{doc['docstring']}\n")
                
                if doc['methods']:
                    lines.append("#### Methods\n")
                    for method in doc['methods']:
                        lines.append(f"**{method['signature']}**\n")
                        if method['docstring']:
                            lines.append(f"{method['docstring']}\n")
                        lines.append("")
        
        return '\n'.join(lines)

# Generate documentation for fastcore.basics
import fastcore.basics
doc_gen = APIDocumentationGenerator(fastcore.basics)
markdown_docs = doc_gen.generate_markdown()

# Save to file
with open('api_docs.md', 'w') as f:
    f.write(markdown_docs)

print("API documentation generated in api_docs.md")

Testing Command-Line Interfaces

from fastcore.script import args_from_prog, call_parse
import subprocess
import tempfile
import os

def test_cli_application():
    """Test CLI application programmatically."""
    
    def sample_app(
        input_file: str,
        output_file: str = "output.txt",
        verbose: bool = False
    ):
        """Sample application for testing."""
        if verbose:
            print(f"Processing {input_file} -> {output_file}")
        
        with open(input_file, 'r') as f:
            content = f.read()
        
        with open(output_file, 'w') as f:
            f.write(f"Processed: {content}")
        
        return output_file
    
    # Test with temporary files
    with tempfile.TemporaryDirectory() as temp_dir:
        # Create test input file
        input_path = os.path.join(temp_dir, "input.txt")
        with open(input_path, 'w') as f:
            f.write("Test content")
        
        # Test different argument combinations
        test_cases = [
            # Basic usage
            {
                'args': [input_path],
                'expected_output': 'output.txt'
            },
            # Custom output file
            {
                'args': [input_path, '--output-file', 'custom.txt'],
                'expected_output': 'custom.txt'
            },
            # Verbose mode
            {
                'args': [input_path, '--verbose'],
                'expected_output': 'output.txt'
            }
        ]
        
        for i, test_case in enumerate(test_cases):
            print(f"Running test case {i + 1}: {test_case['args']}")
            
            # Simulate command-line execution
            import sys
            old_argv = sys.argv
            try:
                sys.argv = ['test_script.py'] + test_case['args']
                result = call_parse(sample_app)
                
                # Verify output file was created
                expected_file = test_case['expected_output']
                if os.path.exists(expected_file):
                    with open(expected_file, 'r') as f:
                        content = f.read()
                        assert "Processed: Test content" in content
                    print(f"✓ Test case {i + 1} passed")
                    os.remove(expected_file)  # Cleanup
                else:
                    print(f"✗ Test case {i + 1} failed: output file not found")
                    
            finally:
                sys.argv = old_argv

# Run the test
test_cli_application()

Integration with Other FastCore Components

from fastcore.script import call_parse, Param
from fastcore.parallel import parallel
from fastcore.foundation import L
from fastcore.xtras import walk
from fastcore.net import urlread
import json

def web_scraper_cli(
    urls_file: Param("File containing URLs to scrape"),
    output_dir: Param("Output directory for scraped content", default="./scraped"),
    workers: Param("Number of parallel workers", type=int, default=4),
    delay: Param("Delay between requests (seconds)", type=float, default=1.0),
    format: Param("Output format", choices=['json', 'txt'], default='json'),
    verbose: Param("Verbose output", action='store_true')
):
    """
    Scrape content from URLs in parallel using FastCore utilities.
    
    Reads URLs from file, scrapes content in parallel, and saves results
    in the specified format. Demonstrates integration of multiple FastCore
    components in a real application.
    """
    import os
    from urllib.parse import urlparse
    import time
    
    # Create output directory
    os.makedirs(output_dir, exist_ok=True)
    
    # Read URLs from file
    with open(urls_file, 'r') as f:
        urls = [line.strip() for line in f if line.strip()]
    
    if verbose:
        print(f"Found {len(urls)} URLs to scrape")
        print(f"Using {workers} parallel workers")
    
    def scrape_url(url):
        """Scrape a single URL with error handling."""
        try:
            if delay > 0:
                time.sleep(delay)
            
            content = urlread(url)
            
            # Generate filename from URL
            parsed = urlparse(url)
            filename = f"{parsed.netloc}_{parsed.path.replace('/', '_')}"
            if not filename.endswith('.txt') and format == 'txt':
                filename += '.txt'
            elif not filename.endswith('.json') and format == 'json':
                filename += '.json'
            
            filepath = os.path.join(output_dir, filename)
            
            # Save content
            if format == 'json':
                data = {
                    'url': url,
                    'content': content,
                    'scraped_at': time.time()
                }
                with open(filepath, 'w') as f:
                    json.dump(data, f, indent=2)
            else:
                with open(filepath, 'w') as f:
                    f.write(f"URL: {url}\n")
                    f.write(f"Content:\n{content}")
            
            if verbose:
                print(f"✓ Scraped {url} -> {filename}")
            
            return {'url': url, 'file': filepath, 'success': True}
            
        except Exception as e:
            if verbose:
                print(f"✗ Failed to scrape {url}: {e}")
            return {'url': url, 'error': str(e), 'success': False}
    
    # Scrape URLs in parallel
    results = parallel(scrape_url, urls, n_workers=workers, progress=verbose)
    
    # Generate summary
    successful = L(results).filter(lambda x: x['success'])
    failed = L(results).filter(lambda x: not x['success'])
    
    summary = {
        'total_urls': len(urls),
        'successful': len(successful),
        'failed': len(failed),
        'output_directory': output_dir,
        'files_created': [r['file'] for r in successful if 'file' in r]
    }
    
    # Save summary
    summary_file = os.path.join(output_dir, 'scraping_summary.json')
    with open(summary_file, 'w') as f:
        json.dump(summary, f, indent=2)
    
    print(f"\nScraping completed!")
    print(f"Successful: {summary['successful']}/{summary['total_urls']}")
    print(f"Results saved in: {output_dir}")
    
    if failed:
        print(f"Failed URLs: {len(failed)}")
        for result in failed:
            print(f"  {result['url']}: {result['error']}")

if __name__ == "__main__":
    call_parse(web_scraper_cli)

# Usage:
# python scraper.py urls.txt --workers 8 --format json --verbose
# python scraper.py urls.txt --output-dir ./data --delay 2.0

Install with Tessl CLI

npx tessl i tessl/pypi-fastcore

docs

collections.md

core-utilities.md

extended.md

index.md

metaprogramming.md

networking.md

parallel.md

system-integration.md

testing.md

xml-html.md

tile.json