CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-poetry-core

Poetry PEP 517 Build Backend for building Python packages with lightweight, compliant, self-contained build system

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities and Validation

Poetry Core provides various utility functions for JSON schema validation, SPDX license handling, file type detection, and other helper functions that support the core functionality.

Core Imports

# JSON validation
from poetry.core.json import validate_object, ValidationError

# SPDX license support
from poetry.core.spdx.license import License
from poetry.core.spdx.helpers import license_by_id

# Helper utilities
from poetry.core.utils.helpers import (
    combine_unicode,
    readme_content_type,
    temporary_directory
)

# Version helpers
from poetry.core.version.helpers import format_python_constraint, PYTHON_VERSION

# VCS support
from poetry.core.vcs.git import Git, GitConfig, ParsedUrl, GitError

# Compatibility utilities
from poetry.core.utils._compat import WINDOWS, tomllib
``` { .api }

## JSON Schema Validation

### validate_object

```python
def validate_object(obj: dict[str, Any], schema_name: str) -> list[str]:
    """
    Validate object against JSON schema.
    
    Args:
        obj: Dictionary object to validate
        schema_name: Name of schema to validate against
        
    Returns:
        List of validation error messages (empty if valid)
        
    Raises:
        ValidationError: If validation fails with detailed error information
        
    Available Schemas:
        - "poetry-schema": Main Poetry configuration schema
        - "poetry-plugins-schema": Poetry plugins configuration
        
    Example:
        >>> config = {"name": "my-package", "version": "1.0.0"}
        >>> errors = validate_object(config, "poetry-schema")
        >>> if errors:
        ...     print("Validation errors:", errors)
        ... else:
        ...     print("Configuration is valid")
    """
``` { .api }

### ValidationError

```python
class ValidationError(ValueError):
    """
    JSON schema validation error.
    
    Raised when object validation against schema fails,
    providing detailed information about validation issues.
    """
    
    def __init__(self, message: str, errors: list[str] | None = None) -> None:
        """
        Create validation error.
        
        Args:
            message: Error message
            errors: List of specific validation errors
        """
        
    @property
    def errors(self) -> list[str]:
        """List of specific validation errors."""
``` { .api }

## SPDX License Support

### License

```python
class License:
    """
    SPDX license information.
    
    Named tuple containing license metadata from SPDX license list.
    """
    
    id: str              # SPDX license identifier (e.g., "MIT", "Apache-2.0")
    name: str           # Full license name
    is_osi_approved: bool    # Whether OSI approved
    is_deprecated: bool      # Whether license is deprecated
    
    def __init__(
        self, 
        id: str, 
        name: str, 
        is_osi_approved: bool = False,
        is_deprecated: bool = False
    ) -> None:
        """
        Create license information.
        
        Args:
            id: SPDX license identifier
            name: Full license name
            is_osi_approved: Whether license is OSI approved
            is_deprecated: Whether license is deprecated
            
        Example:
            >>> license = License(
            ...     id="MIT",
            ...     name="MIT License", 
            ...     is_osi_approved=True
            ... )
        """
``` { .api }

### license_by_id

```python
def license_by_id(license_id: str) -> License:
    """
    Get license information by SPDX identifier.
    
    Args:
        license_id: SPDX license identifier (case-insensitive)
        
    Returns:
        License object with metadata
        
    Raises:
        ValueError: If license ID is not found
        
    Example:
        >>> mit = license_by_id("MIT")
        >>> print(f"{mit.name} (OSI: {mit.is_osi_approved})")
        MIT License (OSI: True)
        
        >>> apache = license_by_id("apache-2.0")  # Case insensitive
        >>> print(apache.name)
        Apache License 2.0
        
        >>> # Check if license exists
        >>> try:
        ...     license = license_by_id("UNKNOWN")
        ... except ValueError:
        ...     print("License not found")
    """
``` { .api }

## Helper Utilities

### combine_unicode

```python
def combine_unicode(string: str) -> str:
    """
    Normalize Unicode string using NFC normalization.
    
    Args:
        string: String to normalize
        
    Returns:
        Normalized Unicode string
        
    Note:
        Uses Unicode NFC (Canonical Decomposition + Canonical Composition)
        normalization to ensure consistent string representation.
        
    Example:
        >>> # Combining characters
        >>> combined = combine_unicode("café")  # e + ́ (combining acute)
        >>> print(repr(combined))  # Single é character
        
        >>> # Already normalized
        >>> normal = combine_unicode("café")  # Single é character
        >>> combined == normal  # True
    """
``` { .api }

### readme_content_type

```python
def readme_content_type(readme_path: Path) -> str:
    """
    Detect README content type from file extension.
    
    Args:
        readme_path: Path to README file
        
    Returns:
        MIME content type string
        
    Supported Extensions:
        - .md, .markdown -> "text/markdown"
        - .rst -> "text/x-rst" 
        - .txt -> "text/plain"
        - Other -> "text/plain"
        
    Example:
        >>> content_type = readme_content_type(Path("README.md"))
        >>> print(content_type)
        text/markdown
        
        >>> content_type = readme_content_type(Path("README.rst"))
        >>> print(content_type) 
        text/x-rst
        
        >>> content_type = readme_content_type(Path("README.txt"))
        >>> print(content_type)
        text/plain
    """
``` { .api }

### temporary_directory

```python
@contextmanager
def temporary_directory() -> Iterator[Path]:
    """
    Context manager for temporary directory creation.
    
    Yields:
        Path to temporary directory
        
    Note:
        Directory is automatically cleaned up when context exits.
        
    Example:
        >>> from poetry.core.utils.helpers import temporary_directory
        >>> 
        >>> with temporary_directory() as tmp_dir:
        ...     print(f"Temp dir: {tmp_dir}")
        ...     # Use temporary directory
        ...     temp_file = tmp_dir / "test.txt"
        ...     temp_file.write_text("Hello")
        ... # Directory automatically cleaned up here
    """
``` { .api }

## Version Helpers

### format_python_constraint

Formats Python version constraints into proper constraint strings, transforming disjunctive constraints into readable forms.

```python { .api }
def format_python_constraint(constraint: VersionConstraint) -> str:
    """
    Format Python version constraint for display.
    
    Transforms disjunctive version constraints into proper constraint strings
    suitable for Python version specifications.
    
    Args:
        constraint: Version constraint to format
        
    Returns:
        Formatted constraint string (e.g., ">=3.8, !=3.9.*")
        
    Examples:
        - Version("3.8") -> "~3.8"
        - Version("3") -> "^3.0" 
        - Complex unions -> ">=3.8, !=3.9.*, !=3.10.*"
    """

PYTHON_VERSION

Comprehensive list of supported Python version patterns for constraint formatting.

PYTHON_VERSION: list[str] = [
    "2.7.*",
    "3.0.*", "3.1.*", "3.2.*", "3.3.*", "3.4.*", "3.5.*",
    "3.6.*", "3.7.*", "3.8.*", "3.9.*", "3.10.*", "3.11.*", 
    "3.12.*", "3.13.*"
]

VCS Support

Git

class Git:
    """
    Git operations wrapper.
    
    Provides interface for common Git operations needed
    for VCS dependency handling and project management.
    """
    
    def __init__(self, work_dir: Path | None = None) -> None:
        """
        Initialize Git wrapper.
        
        Args:
            work_dir: Working directory for Git operations
        """
        
    @classmethod
    def clone(
        cls,
        repository: str,
        dest: Path,
        branch: str | None = None,
        tag: str | None = None,
    ) -> Git:
        """
        Clone Git repository.
        
        Args:
            repository: Repository URL
            dest: Destination directory
            branch: Branch to checkout
            tag: Tag to checkout
            
        Returns:
            Git instance for cloned repository
            
        Raises:
            GitError: If clone operation fails
        """
        
    def checkout(self, rev: str) -> None:
        """
        Checkout specific revision.
        
        Args:
            rev: Revision (branch, tag, commit hash)
            
        Raises:
            GitError: If checkout fails
        """
        
    def rev_parse(self, rev: str) -> str:
        """
        Get full commit hash for revision.
        
        Args:
            rev: Revision to resolve
            
        Returns:
            Full commit hash
            
        Raises:
            GitError: If revision cannot be resolved
        """
        
    @property
    def head(self) -> str:
        """Current HEAD commit hash."""
        
    @property
    def is_clean(self) -> bool:
        """Whether working directory is clean (no uncommitted changes)."""
``` { .api }

### GitConfig

```python
class GitConfig:
    """
    Git configuration management.
    
    Provides access to Git configuration values
    with fallback to global and system configs.
    """
    
    def get(self, key: str, default: str | None = None) -> str | None:
        """
        Get Git configuration value.
        
        Args:
            key: Configuration key (e.g., "user.name", "user.email")
            default: Default value if key not found
            
        Returns:
            Configuration value or default
            
        Example:
            >>> config = GitConfig()
            >>> name = config.get("user.name")
            >>> email = config.get("user.email")
            >>> print(f"Git user: {name} <{email}>")
        """
``` { .api }

### ParsedUrl

```python
class ParsedUrl:
    """
    Parsed Git URL representation.
    
    Handles various Git URL formats and provides
    normalized access to URL components.
    """
    
    @classmethod
    def parse(cls, url: str) -> ParsedUrl:
        """
        Parse Git URL into components.
        
        Args:
            url: Git URL in various formats
            
        Returns:
            ParsedUrl instance with normalized components
            
        Supported Formats:
            - HTTPS: https://github.com/user/repo.git
            - SSH: git@github.com:user/repo.git
            - GitHub shorthand: github:user/repo
            
        Example:
            >>> parsed = ParsedUrl.parse("git@github.com:user/repo.git")
            >>> print(parsed.url)  # Normalized URL
            >>> print(parsed.hostname)  # github.com
        """
        
    @property
    def url(self) -> str:
        """Normalized Git URL."""
        
    @property
    def hostname(self) -> str:
        """Git server hostname."""
        
    @property
    def pathname(self) -> str:
        """Repository path."""
``` { .api }

### GitError

```python
class GitError(RuntimeError):
    """
    Git operation error.
    
    Raised when Git operations fail, providing
    context about the specific operation and error.
    """
    
    def __init__(self, message: str, return_code: int | None = None) -> None:
        """
        Create Git error.
        
        Args:
            message: Error message
            return_code: Git command return code
        """
``` { .api }

## Compatibility Utilities

### Platform Detection

```python
WINDOWS: bool
"""
Platform detection constant.

True if running on Windows, False otherwise.
Used for platform-specific code paths.

Example:
    >>> from poetry.core.utils._compat import WINDOWS
    >>> if WINDOWS:
    ...     print("Running on Windows")
    ... else:
    ...     print("Running on Unix-like system")
"""
``` { .api }

### TOML Support

```python
tomllib: ModuleType
"""
TOML parsing library compatibility layer.

Uses tomllib (Python 3.11+) or tomli (older Python versions).
Provides consistent TOML parsing interface across Python versions.

Example:
    >>> from poetry.core.utils._compat import tomllib
    >>> 
    >>> # Parse TOML file
    >>> with open("pyproject.toml", "rb") as f:
    ...     data = tomllib.load(f)
    
    >>> # Parse TOML string
    >>> toml_string = '''
    ... [tool.poetry]
    ... name = "my-package"
    ... '''
    >>> data = tomllib.loads(toml_string)
"""
``` { .api }

## Usage Examples

### Configuration Validation

```python
from poetry.core.json import validate_object, ValidationError
from poetry.core.pyproject.toml import PyProjectTOML

def validate_poetry_config(pyproject_path: Path):
    """Validate Poetry configuration with detailed error reporting."""
    
    try:
        # Load configuration
        pyproject = PyProjectTOML(pyproject_path)
        poetry_config = pyproject.poetry_config
        
        # Validate against schema
        errors = validate_object(poetry_config, "poetry-schema")
        
        if not errors:
            print("✅ Configuration is valid")
            return True
            
        print("❌ Configuration validation failed:")
        for error in errors:
            print(f"  • {error}")
            
        return False
        
    except ValidationError as e:
        print(f"❌ Validation error: {e}")
        if hasattr(e, 'errors') and e.errors:
            for error in e.errors:
                print(f"  • {error}")
        return False
        
    except Exception as e:
        print(f"❌ Unexpected error: {e}")
        return False

# Usage
is_valid = validate_poetry_config(Path("pyproject.toml"))
``` { .api }

### License Information

```python
from poetry.core.spdx.helpers import license_by_id

def show_license_info(license_ids: list[str]):
    """Display information about SPDX licenses."""
    
    print("📜 License Information:")
    print("=" * 50)
    
    for license_id in license_ids:
        try:
            license_info = license_by_id(license_id)
            
            print(f"\n🔖 {license_info.id}")
            print(f"   Name: {license_info.name}")
            print(f"   OSI Approved: {'✅' if license_info.is_osi_approved else '❌'}")
            print(f"   Deprecated: {'⚠️' if license_info.is_deprecated else '✅'}")
            
        except ValueError:
            print(f"\n❌ {license_id}: License not found")

# Common licenses
common_licenses = [
    "MIT", "Apache-2.0", "GPL-3.0-or-later", 
    "BSD-3-Clause", "ISC", "LGPL-2.1"
]

show_license_info(common_licenses)
``` { .api }

### File Type Detection

```python
from pathlib import Path
from poetry.core.utils.helpers import readme_content_type

def analyze_readme_files(project_dir: Path):
    """Analyze README files in project directory."""
    
    readme_patterns = ["README*", "readme*", "Readme*"]
    readme_files = []
    
    for pattern in readme_patterns:
        readme_files.extend(project_dir.glob(pattern))
    
    if not readme_files:
        print("❌ No README files found")
        return
        
    print("📄 README Files Analysis:")
    print("=" * 40)
    
    for readme_file in readme_files:
        if readme_file.is_file():
            content_type = readme_content_type(readme_file)
            size = readme_file.stat().st_size
            
            print(f"\n📝 {readme_file.name}")
            print(f"   Content-Type: {content_type}")
            print(f"   Size: {size:,} bytes")
            
            # Preview content
            try:
                with readme_file.open('r', encoding='utf-8') as f:
                    preview = f.read(200).strip()
                    if len(preview) == 200:
                        preview += "..."
                    print(f"   Preview: {preview[:50]}...")
            except UnicodeDecodeError:
                print("   Preview: <Binary content>")

# Usage
analyze_readme_files(Path("./my-project"))
``` { .api }

### VCS Operations

```python
from pathlib import Path
from poetry.core.vcs.git import Git, GitError, ParsedUrl

def clone_and_analyze_repo(repo_url: str, target_dir: Path):
    """Clone repository and analyze its structure."""
    
    try:
        # Parse repository URL
        parsed_url = ParsedUrl.parse(repo_url)
        print(f"🔗 Repository: {parsed_url.url}")
        print(f"   Host: {parsed_url.hostname}")
        print(f"   Path: {parsed_url.pathname}")
        
        # Clone repository
        print(f"\n📥 Cloning to {target_dir}...")
        git = Git.clone(repo_url, target_dir)
        
        # Get repository information
        head_commit = git.head
        is_clean = git.is_clean
        
        print(f"✅ Clone successful")
        print(f"   HEAD: {head_commit[:8]}")
        print(f"   Clean: {'✅' if is_clean else '❌'}")
        
        # Check for pyproject.toml
        pyproject_file = target_dir / "pyproject.toml"
        if pyproject_file.exists():
            print(f"📋 Found pyproject.toml")
            
            # Quick analysis
            from poetry.core.pyproject.toml import PyProjectTOML
            try:
                pyproject = PyProjectTOML(pyproject_file)
                if pyproject.is_poetry_project():
                    config = pyproject.poetry_config
                    print(f"   Poetry project: {config.get('name', 'Unknown')}")
                else:
                    print(f"   Not a Poetry project")
            except Exception as e:
                print(f"   Error reading config: {e}")
        else:
            print(f"❌ No pyproject.toml found")
            
        return git
        
    except GitError as e:
        print(f"❌ Git error: {e}")
        return None
        
    except Exception as e:
        print(f"❌ Unexpected error: {e}")
        return None

# Usage
git = clone_and_analyze_repo(
    "https://github.com/python-poetry/poetry-core.git",
    Path("./temp-clone")
)
``` { .api }

### Temporary File Operations

```python
from poetry.core.utils.helpers import temporary_directory
from pathlib import Path
import shutil

def process_with_temp_workspace(source_files: list[Path]):
    """Process files using temporary workspace."""
    
    with temporary_directory() as temp_dir:
        print(f"🛠️  Working in: {temp_dir}")
        
        # Copy source files to temp directory
        temp_files = []
        for source_file in source_files:
            if source_file.exists():
                temp_file = temp_dir / source_file.name
                shutil.copy2(source_file, temp_file)
                temp_files.append(temp_file)
                print(f"   Copied: {source_file.name}")
        
        # Process files in temp directory
        print(f"🔄 Processing {len(temp_files)} files...")
        results = []
        
        for temp_file in temp_files:
            try:
                # Example processing: count lines
                with temp_file.open('r') as f:
                    lines = len(f.readlines())
                
                results.append({
                    "file": temp_file.name,
                    "lines": lines,
                    "size": temp_file.stat().st_size
                })
                
                print(f"   {temp_file.name}: {lines} lines")
                
            except Exception as e:
                print(f"   ❌ Error processing {temp_file.name}: {e}")
        
        # Temporary directory is automatically cleaned up
        print(f"✅ Processing complete, temp directory cleaned")
        return results

# Usage
source_files = [
    Path("README.md"),
    Path("pyproject.toml"),
    Path("src/mypackage/__init__.py")
]

results = process_with_temp_workspace(source_files)
``` { .api }

### Unicode Normalization

```python
from poetry.core.utils.helpers import combine_unicode
import unicodedata

def normalize_project_strings(config: dict):
    """Normalize Unicode strings in project configuration."""
    
    print("🔤 Unicode Normalization:")
    
    string_fields = ["name", "description", "authors", "maintainers"]
    
    for field in string_fields:
        if field in config:
            original = config[field]
            
            if isinstance(original, str):
                normalized = combine_unicode(original)
                
                # Check if normalization changed anything
                if original != normalized:
                    print(f"   {field}: Normalized")
                    print(f"     Before: {repr(original)}")
                    print(f"     After:  {repr(normalized)}")
                    config[field] = normalized
                else:
                    print(f"   {field}: Already normalized")
                    
            elif isinstance(original, list):
                # Handle list of strings (authors, maintainers)
                normalized_list = []
                changed = False
                
                for item in original:
                    if isinstance(item, str):
                        normalized_item = combine_unicode(item)
                        normalized_list.append(normalized_item)
                        if item != normalized_item:
                            changed = True
                    else:
                        normalized_list.append(item)
                
                if changed:
                    print(f"   {field}: Normalized list items")
                    config[field] = normalized_list
                else:
                    print(f"   {field}: List already normalized")
    
    return config

# Example usage
project_config = {
    "name": "café-package",  # May contain combining characters
    "description": "A café management system",
    "authors": ["José García <jose@example.com>"]
}

normalized_config = normalize_project_strings(project_config)
``` { .api }

## Error Handling Utilities

### Safe Operations

```python
from poetry.core.json import ValidationError
from poetry.core.spdx.helpers import license_by_id
from poetry.core.vcs.git import GitError

def safe_validation_operations():
    """Demonstrate safe utility operations with error handling."""
    
    # Safe license lookup
    def safe_license_lookup(license_id: str):
        try:
            return license_by_id(license_id)
        except ValueError:
            print(f"❌ Unknown license: {license_id}")
            return None
    
    # Safe validation
    def safe_validation(obj: dict, schema: str):
        try:
            from poetry.core.json import validate_object
            errors = validate_object(obj, schema)
            return errors
        except ValidationError as e:
            print(f"❌ Validation failed: {e}")
            return [str(e)]
        except Exception as e:
            print(f"❌ Unexpected validation error: {e}")
            return [f"Unexpected error: {e}"]
    
    # Safe Git operations
    def safe_git_operation(func, *args, **kwargs):
        try:
            return func(*args, **kwargs)
        except GitError as e:
            print(f"❌ Git operation failed: {e}")
            return None
        except Exception as e:
            print(f"❌ Unexpected Git error: {e}")
            return None
    
    # Usage examples
    license_info = safe_license_lookup("MIT")
    if license_info:
        print(f"✅ License found: {license_info.name}")
    
    validation_errors = safe_validation({"name": "test"}, "poetry-schema")
    if not validation_errors:
        print("✅ Validation passed")
    else:
        print(f"❌ Validation errors: {validation_errors}")

safe_validation_operations()
``` { .api }

## Type Definitions

```python
from typing import Any, Dict, List, Iterator
from pathlib import Path

# Validation types
ValidationErrors = List[str]
SchemaName = str

# License types
LicenseId = str

# VCS types
GitUrl = str
GitRevision = str
GitBranch = str
GitTag = str

# Utility types
ContentType = str
UnicodeString = str
``` { .api }

Install with Tessl CLI

npx tessl i tessl/pypi-poetry-core

docs

build-backend.md

builders.md

configuration.md

constraints.md

factory-core.md

index.md

json-validation.md

packages.md

utilities.md

vcs-support.md

version-system.md

tile.json