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

configuration.mddocs/

PyProject Configuration

Poetry Core provides robust pyproject.toml parsing and management with full support for Poetry configuration sections and standard build system configuration. This handles both the [tool.poetry] section and the standard PEP 517 [build-system] configuration.

Core Imports

from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.pyproject.tables import BuildSystem
from poetry.core.pyproject.exceptions import PyProjectError
``` { .api }

## PyProjectTOML

Main class for handling pyproject.toml file reading and configuration management.

### PyProjectTOML.__init__

```python
class PyProjectTOML:
    def __init__(self, path: Path) -> None:
        """
        Initialize PyProject TOML handler.
        
        Args:
            path: Path to pyproject.toml file
            
        Note:
            File is loaded lazily on first access to data/configuration.
            
        Example:
            >>> from pathlib import Path
            >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        """
``` { .api }

### Properties

#### path

```python
@property
def path(self) -> Path:
    """
    Path to the pyproject.toml file.
    
    Returns:
        Path object pointing to the TOML file
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> print(pyproject.path)
        /path/to/project/pyproject.toml
    """
``` { .api }

#### data

```python
@property  
def data(self) -> dict[str, Any]:
    """
    Raw TOML data from the pyproject.toml file.
    
    Returns:
        Dictionary containing all TOML sections and data
        
    Raises:
        PyProjectError: If TOML file is malformed or cannot be parsed
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> data = pyproject.data
        >>> print(data.keys())
        dict_keys(['build-system', 'tool', 'project'])
        
        >>> # Access sections
        >>> build_system = data.get('build-system', {})
        >>> tool_section = data.get('tool', {})
    """
``` { .api }

#### poetry_config

```python
@property
def poetry_config(self) -> dict[str, Any]:
    """
    Poetry configuration from [tool.poetry] section.
    
    Returns:
        Dictionary containing Poetry-specific configuration
        
    Raises:
        PyProjectError: If [tool.poetry] section is not found
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> config = pyproject.poetry_config
        >>> print(config['name'])
        my-package
        >>> print(config['version'])
        1.0.0
        >>> print(config.get('description', ''))
        A sample package
    """
``` { .api }

#### build_system

```python
@property
def build_system(self) -> BuildSystem:
    """
    Build system configuration from [build-system] section.
    
    Returns:
        BuildSystem object with build backend and requirements
        
    Note:
        If no [build-system] section exists, defaults to Poetry Core backend
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> build_sys = pyproject.build_system
        >>> print(build_sys.build_backend)
        poetry.core.masonry.api
        >>> print(build_sys.requires)
        ['poetry-core']
    """
``` { .api }

### Methods

#### is_poetry_project

```python
def is_poetry_project(self) -> bool:
    """
    Check if project is a valid Poetry project.
    
    Returns:
        True if project has [tool.poetry] section or valid [project] metadata
        
    Note:
        A project is considered a Poetry project if:
        1. It has a [tool.poetry] section, OR  
        2. It has [project] section with name and version (no dynamic fields)
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> if pyproject.is_poetry_project():
        ...     print("This is a Poetry project")
        ... else:
        ...     print("Not a Poetry project")
    """
``` { .api }

#### save

```python
def save(self) -> None:
    """
    Save changes to the pyproject.toml file.
    
    Raises:
        IOError: If file cannot be written
        
    Note:
        This writes the current data dictionary back to the file.
        Use with caution as it overwrites the entire file.
        
    Example:
        >>> pyproject = PyProjectTOML(Path("pyproject.toml"))
        >>> data = pyproject.data
        >>> data['tool']['poetry']['version'] = '2.0.0'
        >>> pyproject.save()  # Write changes back
    """
``` { .api }

## BuildSystem

Represents the [build-system] table configuration according to PEP 517/518.

### BuildSystem.__init__

```python
class BuildSystem:
    def __init__(
        self, 
        build_backend: str | None = None, 
        requires: list[str] | None = None
    ) -> None:
        """
        Create build system configuration.
        
        Args:
            build_backend: Build backend module path
            requires: List of build requirements
            
        Defaults:
            build_backend: "setuptools.build_meta:__legacy__" if None
            requires: ["setuptools", "wheel"] if None
            
        Example:
            >>> build_sys = BuildSystem(
            ...     build_backend="poetry.core.masonry.api",
            ...     requires=["poetry-core"]
            ... )
        """
``` { .api }

### Properties

#### build_backend

```python
@property
def build_backend(self) -> str:
    """
    Build backend module path.
    
    Returns:
        Module path to PEP 517 build backend
        
    Example:
        >>> build_sys.build_backend
        'poetry.core.masonry.api'
    """
``` { .api }

#### requires

```python
@property  
def requires(self) -> list[str]:
    """
    Build requirements list.
    
    Returns:
        List of PEP 508 requirement strings needed for building
        
    Example:
        >>> build_sys.requires
        ['poetry-core']
    """
``` { .api }

#### dependencies

```python
@property
def dependencies(self) -> list[Dependency]:
    """
    Build dependencies as Dependency objects.
    
    Returns:
        List of Dependency objects parsed from requires list
        
    Note:
        Automatically handles PEP 508 strings, local files, and directories
        
    Example:
        >>> deps = build_sys.dependencies
        >>> for dep in deps:
        ...     print(f"{dep.name}: {dep.constraint}")
        poetry-core: *
    """
``` { .api }

## Configuration Examples

### Loading and Inspecting Configuration

```python
from pathlib import Path
from poetry.core.pyproject.toml import PyProjectTOML

def inspect_pyproject(project_path: Path):
    """Inspect pyproject.toml configuration."""
    
    pyproject_file = project_path / "pyproject.toml"
    
    try:
        pyproject = PyProjectTOML(pyproject_file)
        
        # Check if it's a Poetry project
        if not pyproject.is_poetry_project():
            print("❌ Not a Poetry project")
            return
            
        print("✅ Poetry project detected")
        print(f"📁 Config file: {pyproject.path}")
        
        # Poetry configuration
        config = pyproject.poetry_config
        print(f"\n📦 Package Information:")
        print(f"  Name: {config.get('name', 'Unknown')}")
        print(f"  Version: {config.get('version', 'Unknown')}")
        print(f"  Description: {config.get('description', 'No description')}")
        
        # Authors
        authors = config.get('authors', [])
        if authors:
            print(f"  Authors: {', '.join(authors)}")
            
        # Dependencies
        dependencies = config.get('dependencies', {})
        if dependencies:
            print(f"\n🔗 Dependencies ({len(dependencies)}):")
            for name, constraint in dependencies.items():
                print(f"  {name}: {constraint}")
                
        # Development dependencies
        group_deps = config.get('group', {})
        if 'dev' in group_deps and 'dependencies' in group_deps['dev']:
            dev_deps = group_deps['dev']['dependencies']
            print(f"\n🛠️  Dev Dependencies ({len(dev_deps)}):")
            for name, constraint in dev_deps.items():
                print(f"  {name}: {constraint}")
        
        # Build system
        build_sys = pyproject.build_system
        print(f"\n🏗️  Build System:")
        print(f"  Backend: {build_sys.build_backend}")
        print(f"  Requires: {', '.join(build_sys.requires)}")
        
    except Exception as e:
        print(f"❌ Error reading configuration: {e}")

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

### Creating Configuration Programmatically

```python
import toml
from pathlib import Path
from poetry.core.pyproject.toml import PyProjectTOML

def create_pyproject_config(project_dir: Path):
    """Create a new pyproject.toml configuration."""
    
    config = {
        "build-system": {
            "requires": ["poetry-core"],
            "build-backend": "poetry.core.masonry.api"
        },
        "tool": {
            "poetry": {
                "name": "my-new-package",
                "version": "0.1.0", 
                "description": "A new Python package",
                "authors": ["Your Name <you@example.com>"],
                "readme": "README.md",
                "packages": [{"include": "my_new_package"}],
                "dependencies": {
                    "python": "^3.8"
                },
                "group": {
                    "dev": {
                        "dependencies": {
                            "pytest": "^7.0.0",
                            "black": "^22.0.0",
                            "isort": "^5.0.0"
                        }
                    }
                }
            }
        }
    }
    
    # Write to file
    pyproject_file = project_dir / "pyproject.toml"
    with pyproject_file.open("w") as f:
        toml.dump(config, f)
    
    # Verify with PyProjectTOML
    pyproject = PyProjectTOML(pyproject_file)
    print(f"✅ Created Poetry project: {pyproject.poetry_config['name']}")
    
    return pyproject

# Usage  
project = create_pyproject_config(Path("./new-project"))
``` { .api }

### Configuration Validation

```python
from poetry.core.factory import Factory
from poetry.core.pyproject.toml import PyProjectTOML

def validate_pyproject_config(pyproject_path: Path):
    """Validate Poetry configuration against schemas."""
    
    try:
        pyproject = PyProjectTOML(pyproject_path)
        
        if not pyproject.is_poetry_project():
            print("❌ Not a Poetry project")
            return False
            
        # Validate using Factory
        validation_result = Factory.validate(pyproject.data)
        
        # Report errors
        if validation_result["errors"]:
            print("❌ Configuration Errors:")
            for error in validation_result["errors"]:
                print(f"  • {error}")
                
        # Report warnings  
        if validation_result["warnings"]:
            print("⚠️  Configuration Warnings:")
            for warning in validation_result["warnings"]:
                print(f"  • {warning}")
                
        # Overall status
        is_valid = not validation_result["errors"]
        if is_valid:
            print("✅ Configuration is valid")
        else:
            print("❌ Configuration has errors")
            
        return is_valid
        
    except Exception as e:
        print(f"❌ Validation failed: {e}")
        return False

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

### Working with Different Configuration Sections

```python
from poetry.core.pyproject.toml import PyProjectTOML

def explore_config_sections(pyproject_path: Path):
    """Explore different sections of pyproject.toml."""
    
    pyproject = PyProjectTOML(pyproject_path)
    data = pyproject.data
    
    print("📋 PyProject Configuration Sections:")
    print("=" * 50)
    
    # Build system section
    if "build-system" in data:
        build_sys = data["build-system"]
        print("🏗️  [build-system]")
        print(f"  requires = {build_sys.get('requires', [])}")
        print(f"  build-backend = '{build_sys.get('build-backend', '')}'")
        print()
    
    # Project section (PEP 621)
    if "project" in data:
        project = data["project"] 
        print("📦 [project]")
        print(f"  name = '{project.get('name', '')}'")
        print(f"  version = '{project.get('version', '')}'")
        print(f"  description = '{project.get('description', '')}'")
        if "dependencies" in project:
            print(f"  dependencies = {project['dependencies']}")
        print()
    
    # Tool sections
    if "tool" in data:
        tool = data["tool"]
        print("🔧 [tool] sections:")
        
        for tool_name in tool.keys():
            print(f"  • tool.{tool_name}")
            
        # Poetry-specific configuration
        if "poetry" in tool:
            poetry_config = tool["poetry"]
            print(f"\n🎭 [tool.poetry]")
            print(f"  name = '{poetry_config.get('name', '')}'")
            print(f"  version = '{poetry_config.get('version', '')}'")
            
            # Dependencies
            if "dependencies" in poetry_config:
                deps = poetry_config["dependencies"]
                print(f"  dependencies = {dict(list(deps.items())[:3])}...")
                
            # Dependency groups
            if "group" in poetry_config:
                groups = poetry_config["group"]
                print(f"  dependency groups: {list(groups.keys())}")
                
            # Scripts and entry points
            if "scripts" in poetry_config:
                scripts = poetry_config["scripts"]
                print(f"  scripts: {list(scripts.keys())}")
                
    print("\n" + "=" * 50)

# Usage
explore_config_sections(Path("pyproject.toml"))
``` { .api }

### Dynamic Configuration Updates

```python
from poetry.core.pyproject.toml import PyProjectTOML

def update_pyproject_config(pyproject_path: Path):
    """Demonstrate dynamic configuration updates."""
    
    pyproject = PyProjectTOML(pyproject_path)
    
    # Get current data
    data = pyproject.data
    poetry_config = pyproject.poetry_config
    
    print(f"Current version: {poetry_config.get('version')}")
    
    # Update version
    new_version = "2.0.0"
    if "tool" not in data:
        data["tool"] = {}
    if "poetry" not in data["tool"]:
        data["tool"]["poetry"] = {}
        
    data["tool"]["poetry"]["version"] = new_version
    
    # Add new dependency
    if "dependencies" not in data["tool"]["poetry"]:
        data["tool"]["poetry"]["dependencies"] = {}
        
    data["tool"]["poetry"]["dependencies"]["requests"] = "^2.28.0"
    
    # Add development dependency
    if "group" not in data["tool"]["poetry"]:
        data["tool"]["poetry"]["group"] = {}
    if "dev" not in data["tool"]["poetry"]["group"]:
        data["tool"]["poetry"]["group"]["dev"] = {"dependencies": {}}
        
    data["tool"]["poetry"]["group"]["dev"]["dependencies"]["pytest"] = "^7.0.0"
    
    # Update metadata
    data["tool"]["poetry"]["description"] = "Updated package description"
    data["tool"]["poetry"]["keywords"] = ["python", "package", "updated"]
    
    print(f"✅ Updated configuration:")
    print(f"  Version: {data['tool']['poetry']['version']}")
    print(f"  Description: {data['tool']['poetry']['description']}")
    print(f"  New dependencies: {list(data['tool']['poetry']['dependencies'].keys())}")
    
    # Save changes (uncomment to actually save)
    # pyproject.save()
    # print("💾 Changes saved to pyproject.toml")

# Usage
update_pyproject_config(Path("pyproject.toml"))
``` { .api }

## Error Handling

### Configuration Error Handling

```python
from poetry.core.pyproject.toml import PyProjectTOML
from poetry.core.pyproject.exceptions import PyProjectError

def safe_config_loading(pyproject_path: Path):
    """Safely load configuration with comprehensive error handling."""
    
    try:
        # Check if file exists
        if not pyproject_path.exists():
            print(f"❌ File not found: {pyproject_path}")
            return None
            
        pyproject = PyProjectTOML(pyproject_path)
        
        # Try to access data (triggers parsing)
        try:
            data = pyproject.data
            print(f"✅ Successfully loaded TOML data")
            
        except PyProjectError as e:
            print(f"❌ TOML parsing error: {e}")
            return None
            
        # Try to access Poetry config
        try:
            poetry_config = pyproject.poetry_config
            print(f"✅ Found Poetry configuration")
            
        except PyProjectError as e:
            print(f"⚠️  No Poetry configuration: {e}")
            # Could still be a valid project with [project] section
            
        # Try to access build system
        try:
            build_sys = pyproject.build_system
            print(f"✅ Build system: {build_sys.build_backend}")
            
        except Exception as e:
            print(f"⚠️  Build system error: {e}")
            
        return pyproject
        
    except Exception as e:
        print(f"❌ Unexpected error: {e}")
        return None

def validate_required_fields(pyproject: PyProjectTOML):
    """Validate required configuration fields."""
    
    try:
        config = pyproject.poetry_config
        
        # Required fields
        required_fields = ["name", "version"]
        missing_fields = []
        
        for field in required_fields:
            if field not in config:
                missing_fields.append(field)
                
        if missing_fields:
            print(f"❌ Missing required fields: {missing_fields}")
            return False
            
        # Validate field formats
        name = config["name"]
        version = config["version"]
        
        if not isinstance(name, str) or not name.strip():
            print(f"❌ Invalid name: '{name}'")
            return False
            
        if not isinstance(version, str) or not version.strip():
            print(f"❌ Invalid version: '{version}'") 
            return False
            
        print(f"✅ Required fields valid: {name} v{version}")
        return True
        
    except PyProjectError:
        print("❌ Cannot validate - no Poetry configuration")
        return False

# Usage
pyproject = safe_config_loading(Path("pyproject.toml"))
if pyproject:
    validate_required_fields(pyproject)
``` { .api }

## Type Definitions

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

# Configuration types
ConfigDict = Dict[str, Any]
TomlData = Dict[str, Any]
PoetryConfig = Dict[str, Any]

# Build system types  
BuildBackend = str
BuildRequirements = List[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