### Initialize and run the Resolver Source: https://github.com/sarugaku/resolvelib/blob/main/README.rst Demonstrates the basic setup of a provider and reporter to resolve a list of requirements. ```python import resolvelib # Things I want to resolve. requirements = [...] # Implement logic so the resolver understands the requirement format. class MyProvider: ... provider = MyProvider() reporter = resolvelib.BaseReporter() # Create the (reusable) resolver. resolver = resolvelib.Resolver(provider, reporter) # Kick off the resolution process, and get the final result. result = resolver.resolve(requirements) ``` -------------------------------- ### Install and Test ResolveLib Source: https://github.com/sarugaku/resolvelib/blob/main/DEVELOPMENT.rst Install ResolveLib with test dependencies and run the test suite using pytest. ```shell python -m pip install .[test] ``` ```shell python -m pytest ``` -------------------------------- ### Define Data Structures for Resolution Source: https://context7.com/sarugaku/resolvelib/llms.txt Initial setup for custom requirement and candidate classes required for the resolver. ```python from collections import namedtuple from packaging.specifiers import SpecifierSet from packaging.version import Version import resolvelib # Define data structures class Requirement(namedtuple("Requirement", "name specifier")): def __repr__(self): return f"{self.name}{self.specifier}" class Candidate(namedtuple("Candidate", "name version dependencies")): def __repr__(self): return f"{self.name}=={self.version}" ``` -------------------------------- ### Implement get_preference for SmartProvider Source: https://context7.com/sarugaku/resolvelib/llms.txt This strategy resolves requirements with fewer candidates first to reduce backtracking by pinning constrained packages early. Lower return values indicate higher priority. ```python from resolvelib import AbstractProvider class SmartProvider(AbstractProvider): def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # Strategy: resolve requirements with fewer candidates first # This reduces backtracking by pinning constrained packages early candidate_count = sum(1 for _ in candidates[identifier]) # Already resolved packages should be processed first (keep pinned) is_pinned = identifier in resolutions # Requirements that caused backtracking should be prioritized is_backtrack_cause = any( self.identify(cause.requirement) == identifier for cause in backtrack_causes ) # Return tuple: (not pinned, not cause, candidate count) # Lower = higher priority return (not is_pinned, not is_backtrack_cause, candidate_count) ``` -------------------------------- ### Implement AbstractProvider.identify Source: https://context7.com/sarugaku/resolvelib/llms.txt Shows how to implement the identify method to return unique identifiers for requirements or candidates, including handling for packages with extras. ```python from resolvelib import AbstractProvider class PackageProvider(AbstractProvider): def identify(self, requirement_or_candidate): # Simple case: use package name as identifier return requirement_or_candidate.name # For packages with extras (e.g., requests[security]) def identify_with_extras(self, requirement_or_candidate): base_name = requirement_or_candidate.name extras = getattr(requirement_or_candidate, 'extras', None) if extras: return (base_name, tuple(sorted(extras))) return base_name # Example usage class Req: def __init__(self, name, extras=None): self.name = name self.extras = extras or set() provider = PackageProvider() r1 = Req("requests") r2 = Req("requests") r3 = Req("urllib3") print(provider.identify(r1) == provider.identify(r2)) # True - same package print(provider.identify(r1) == provider.identify(r3)) # False - different packages ``` -------------------------------- ### Record and Playback Resolution Run Source: https://github.com/sarugaku/resolvelib/blob/main/examples/visualization/README.md Use this method to record a dependency resolution process and then play it back to generate an HTML visualization. Requires running `reporter_demo.py` to create an output file, followed by `run.py` to generate the HTML. ```sh python reporter_demo.py > foo.txt python visualization/run.py foo.txt out.html ``` -------------------------------- ### Manage Dependency Graph with ResolveLib Source: https://context7.com/sarugaku/resolvelib/llms.txt Demonstrates how to connect dependencies, query graph structure, and perform basic modifications like removing vertices. ```python graph.connect(None, "flask") # flask is a root dependency graph.connect("flask", "werkzeug") # flask depends on werkzeug graph.connect("flask", "jinja2") # flask depends on jinja2 # Query the graph print(f"Graph has {len(graph)} vertices") # Check if a package is in the graph print(f"flask in graph: {'flask' in graph}") # Iterate all vertices print("All packages:", list(graph)) # Get children (dependencies) print("flask depends on:", list(graph.iter_children("flask"))) # Get parents (dependents) print("werkzeug is needed by:", list(graph.iter_parents("werkzeug"))) # Iterate all edges print("\nAll dependencies:") for parent, child in graph.iter_edges(): print(f" {parent or 'ROOT'} -> {child}") # Check if connected print(f"flask->werkzeug connected: {graph.connected('flask', 'werkzeug')}") # Copy the graph graph_copy = graph.copy() # Remove a vertex (disconnects all edges) graph_copy.remove("jinja2") print(f"After removal: {list(graph_copy)}") ``` -------------------------------- ### Implement a Custom Resolver Source: https://context7.com/sarugaku/resolvelib/llms.txt Demonstrates the implementation of a custom provider and the execution of a dependency resolution process using the Resolver class. ```python import resolvelib from collections import namedtuple from packaging.specifiers import SpecifierSet from packaging.version import Version # Define your requirement and candidate types class Requirement(namedtuple("Requirement", "name specifier")): def __repr__(self): return f"" class Candidate(namedtuple("Candidate", "name version")): def __repr__(self): return f"<{self.name}=={self.version}>" # Define package index with dependencies INDEX = { Candidate("requests", Version("2.28.0")): [ Requirement("urllib3", SpecifierSet(">=1.21.1,<3")), Requirement("charset-normalizer", SpecifierSet(">=2,<4")), ], Candidate("urllib3", Version("2.0.0")): [], Candidate("urllib3", Version("1.26.0")): [], Candidate("charset-normalizer", Version("3.0.0")): [], } # Implement a custom provider class MyProvider(resolvelib.AbstractProvider): def identify(self, requirement_or_candidate): return requirement_or_candidate.name def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # Lower number = higher priority; prioritize packages with fewer candidates return sum(1 for _ in candidates[identifier]) def find_matches(self, identifier, requirements, incompatibilities): bad_versions = {c.version for c in incompatibilities[identifier]} reqs = list(requirements[identifier]) return sorted( [c for c in INDEX.keys() if c.name == identifier and c.version not in bad_versions and all(c.version in r.specifier for r in reqs)], key=lambda c: c.version, reverse=True # Prefer newer versions ) def is_satisfied_by(self, requirement, candidate): return (candidate.name == requirement.name and candidate.version in requirement.specifier) def get_dependencies(self, candidate): return INDEX.get(candidate, []) # Create resolver and resolve provider = MyProvider() reporter = resolvelib.BaseReporter() resolver = resolvelib.Resolver(provider, reporter) requirements = [Requirement("requests", SpecifierSet(">=2.0"))] result = resolver.resolve(requirements, max_rounds=100) # Access results print("Resolved packages:") for name, candidate in result.mapping.items(): print(f" {name}: {candidate.version}") # Output: # requests: 2.28.0 # urllib3: 2.0.0 # charset-normalizer: 3.0.0 ``` -------------------------------- ### Implement AbstractProvider.get_dependencies Source: https://context7.com/sarugaku/resolvelib/llms.txt Provides dependency resolution logic, including handling of conditional dependencies via extras. ```python from resolvelib import AbstractProvider class DependencyProvider(AbstractProvider): def __init__(self): self.packages = { ("flask", "2.0.0"): [ Requirement("werkzeug", ">=2.0"), Requirement("jinja2", ">=3.0"), Requirement("click", ">=7.1.2"), ], ("werkzeug", "2.0.0"): [], ("jinja2", "3.0.0"): [ Requirement("markupsafe", ">=2.0"), ], ("click", "8.0.0"): [], ("markupsafe", "2.1.0"): [], } def get_dependencies(self, candidate): key = (candidate.name, str(candidate.version)) return self.packages.get(key, []) ``` ```python # Example with conditional dependencies (extras) class ExtrasAwareProvider(AbstractProvider): def get_dependencies(self, candidate): deps = list(self._get_base_dependencies(candidate)) # Add extra-specific dependencies if hasattr(candidate, 'extras') and candidate.extras: for extra in candidate.extras: deps.extend(self._get_extra_dependencies(candidate, extra)) # For candidates with extras, add base package as dependency # This ensures X[extra] and X resolve to same version if candidate.extras: base_req = Requirement(candidate.name, f"=={candidate.version}") deps.append(base_req) return deps def _get_base_dependencies(self, candidate): # Return mandatory dependencies return self.index[candidate.name][candidate.version]["requires"] def _get_extra_dependencies(self, candidate, extra): # Return dependencies for specific extra extras_deps = self.index[candidate.name][candidate.version].get("extras", {}) return extras_deps.get(extra, []) ``` -------------------------------- ### AbstractProvider.get_dependencies Source: https://context7.com/sarugaku/resolvelib/llms.txt Retrieves the list of dependencies for a given candidate, including support for conditional dependencies via extras. ```APIDOC ## AbstractProvider.get_dependencies ### Description Returns the dependencies of a candidate, which are then treated as new requirements to be resolved. ### Parameters - **candidate** (object) - Required - The candidate for which to retrieve dependencies. ### Response - **list** - A list of requirement objects. ``` -------------------------------- ### Implement find_matches for PyPIStyleProvider Source: https://context7.com/sarugaku/resolvelib/llms.txt This method simulates a package index to find compatible package versions. Candidates are ordered by version in descending order, preferring newer versions. It filters out incompatible versions and checks if all requirements are satisfied. ```python from resolvelib import AbstractProvider from packaging.version import Version from packaging.specifiers import SpecifierSet class PyPIStyleProvider(AbstractProvider): def __init__(self): # Simulated package index self.index = { "requests": [ {"version": "2.28.0", "deps": ["urllib3>=1.21.1"]}, {"version": "2.27.0", "deps": ["urllib3>=1.21.1"]}, {"version": "2.26.0", "deps": ["urllib3>=1.21.1,<1.27"]}, ], "urllib3": [ {"version": "2.0.0", "deps": []}, {"version": "1.26.15", "deps": []}, {"version": "1.26.0", "deps": []}, ], } def find_matches(self, identifier, requirements, incompatibilities): # Get all requirements for this package reqs = list(requirements[identifier]) # Get versions to exclude bad_versions = {c.version for c in incompatibilities[identifier]} # Build candidates list candidates = [] for pkg_info in self.index.get(identifier, []): version = Version(pkg_info["version"]) # Skip incompatible versions if version in bad_versions: continue # Check all requirements are satisfied if all(version in SpecifierSet(r.specifier) for r in reqs): candidates.append(Candidate(identifier, version, pkg_info["deps"])) # Return sorted by version descending (prefer newer) return sorted(candidates, key=lambda c: c.version, reverse=True) ``` -------------------------------- ### Implement is_satisfied_by for VersionProvider Source: https://context7.com/sarugaku/resolvelib/llms.txt This method performs basic version matching to determine if a candidate satisfies a requirement. It checks if the package names match and if the candidate's version falls within the requirement's specifier. ```python from resolvelib import AbstractProvider from packaging.version import Version from packaging.specifiers import SpecifierSet class VersionProvider(AbstractProvider): def is_satisfied_by(self, requirement, candidate): # Basic version matching if requirement.name != candidate.name: return False return candidate.version in requirement.specifier ``` -------------------------------- ### Implement AbstractProvider.narrow_requirement_selection Source: https://context7.com/sarugaku/resolvelib/llms.txt Optimizes resolution performance by filtering identifiers based on backtrack causes or forced choices. ```python from resolvelib import AbstractProvider class OptimizedProvider(AbstractProvider): def narrow_requirement_selection(self, identifiers, resolutions, candidates, information, backtrack_causes): """Narrow down identifiers before calling get_preference on each.""" # If there are backtrack causes, prioritize those packages if backtrack_causes: cause_identifiers = { self.identify(cause.requirement) for cause in backtrack_causes if cause.requirement is not None } # Return only identifiers involved in backtracking narrowed = [i for i in identifiers if i in cause_identifiers] if narrowed: return narrowed # Otherwise, find packages with only one candidate (forced choices) forced = [] for identifier in identifiers: count = sum(1 for _ in candidates[identifier]) if count == 1: forced.append(identifier) # If we found forced packages, resolve those first if forced: return forced # Return all identifiers if no optimization possible return identifiers ``` -------------------------------- ### Define Package Index and Provider Source: https://context7.com/sarugaku/resolvelib/llms.txt Defines the simulated package repository and the PackageProvider class which implements the resolution logic required by resolvelib. ```python PACKAGES = { "web-app": { "1.0.0": ["flask>=2.0", "requests>=2.25"], }, "flask": { "2.3.0": ["werkzeug>=2.3", "jinja2>=3.1", "click>=8.1"], "2.0.0": ["werkzeug>=2.0", "jinja2>=3.0", "click>=7.1"], }, "werkzeug": { "2.3.0": ["markupsafe>=2.1"], "2.0.0": ["markupsafe>=2.0"], }, "jinja2": { "3.1.0": ["markupsafe>=2.0"], "3.0.0": ["markupsafe>=2.0"], }, "click": {"8.1.0": [], "7.1.0": []}, "markupsafe": {"2.1.0": [], "2.0.0": []}, "requests": { "2.28.0": ["urllib3>=1.21,<3", "charset-normalizer>=2,<4"], "2.25.0": ["urllib3>=1.21,<2", "charset-normalizer>=2,<3"], }, "urllib3": {"2.0.0": [], "1.26.0": []}, "charset-normalizer": {"3.0.0": [], "2.0.0": []}, } def parse_requirement(req_str): """Parse 'name>=1.0,<2.0' into Requirement.""" for op in [">=", "<=", "==", "!=", ">", "<", "~="]: if op in req_str: idx = req_str.index(op) name = req_str[:idx].strip() spec = req_str[idx:].strip() return Requirement(name, SpecifierSet(spec)) return Requirement(req_str.strip(), SpecifierSet()) class PackageProvider(resolvelib.AbstractProvider): def identify(self, requirement_or_candidate): return requirement_or_candidate.name def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # Prioritize: pinned > backtrack causes > fewer candidates if identifier in resolutions: return (0, 0) is_cause = any( self.identify(c.requirement) == identifier for c in backtrack_causes ) return (1 if is_cause else 2, sum(1 for _ in candidates[identifier])) def find_matches(self, identifier, requirements, incompatibilities): if identifier not in PACKAGES: return [] reqs = list(requirements[identifier]) bad = {c.version for c in incompatibilities[identifier]} candidates = [] for ver_str, deps in PACKAGES[identifier].items(): version = Version(ver_str) if version in bad: continue if not all(version in r.specifier for r in reqs): continue dep_reqs = [parse_requirement(d) for d in deps] candidates.append(Candidate(identifier, version, dep_reqs)) return sorted(candidates, key=lambda c: c.version, reverse=True) def is_satisfied_by(self, requirement, candidate): return (requirement.name == candidate.name and candidate.version in requirement.specifier) def get_dependencies(self, candidate): return candidate.dependencies ``` -------------------------------- ### Implement Progress Reporter and Execute Resolution Source: https://context7.com/sarugaku/resolvelib/llms.txt Defines the ProgressReporter for tracking resolution status and executes the resolver with the defined provider. ```python class ProgressReporter(resolvelib.BaseReporter): def starting(self): print("Resolving dependencies...") def pinning(self, candidate): print(f" Selected: {candidate}") def ending(self, state): print(f"Done! Resolved {len(state.mapping)} packages.\n") # Run resolution provider = PackageProvider() reporter = ProgressReporter() resolver = resolvelib.Resolver(provider, reporter) requirements = [parse_requirement("web-app>=1.0")] try: result = resolver.resolve(requirements) print("=== Resolution Result ===") for name, candidate in sorted(result.mapping.items()): print(f" {name}=={candidate.version}") print("\n=== Dependency Graph ===") for parent, child in result.graph.iter_edges(): print(f" {parent or 'ROOT'} -> {child}") except resolvelib.ResolutionImpossible as e: print("Resolution failed!") for cause in e.causes: print(f" Conflict: {cause.requirement}") ``` -------------------------------- ### Generate Visualization During PyPI Run Source: https://github.com/sarugaku/resolvelib/blob/main/examples/visualization/README.md This method generates an HTML visualization while the resolver is actively running with the PyPI wheel provider. Execute `run_pypi.py` with the desired output HTML file name. ```sh python visualization/run_pypi.py out.html ``` -------------------------------- ### Create Release Branch Source: https://github.com/sarugaku/resolvelib/blob/main/DEVELOPMENT.rst Create a new branch for a release, replacing X.Y.Z with the desired version. ```shell git checkout -b release/X.Y.Z ``` -------------------------------- ### AbstractProvider.is_satisfied_by Source: https://context7.com/sarugaku/resolvelib/llms.txt Checks if a candidate satisfies a given requirement based on name, version specifiers, and extras. ```APIDOC ## AbstractProvider.is_satisfied_by ### Description Determines if a specific candidate package meets the criteria defined by a requirement. ### Parameters - **requirement** (object) - Required - The requirement object containing name, specifier, and extras. - **candidate** (object) - Required - The candidate object containing name, version, and available_extras. ### Response - **boolean** - Returns True if the candidate satisfies the requirement, False otherwise. ``` -------------------------------- ### AbstractProvider.get_preference Source: https://context7.com/sarugaku/resolvelib/llms.txt Produces a sort key to determine which requirement should be resolved first. Lower values indicate higher priority. ```APIDOC ## AbstractProvider.get_preference ### Description Produces a sort key to determine which requirement should be resolved first. Lower values indicate higher priority. This method is called for each unresolved requirement to optimize the resolution order. ### Parameters - **identifier** (str) - The identifier of the requirement. - **resolutions** (dict) - Current set of resolved packages. - **candidates** (dict) - Available candidates for requirements. - **information** (dict) - Metadata about requirements. - **backtrack_causes** (list) - List of requirements that triggered backtracking. ### Response - **return** (tuple) - A sortable tuple where lower values represent higher priority. ``` -------------------------------- ### Implement AdvancedProvider for version and extra matching Source: https://context7.com/sarugaku/resolvelib/llms.txt Defines custom logic for checking if a candidate satisfies a requirement, including canonicalization and extra subset validation. ```python class AdvancedProvider(AbstractProvider): def is_satisfied_by(self, requirement, candidate): # Name must match (canonicalized) if self._canonicalize(requirement.name) != self._canonicalize(candidate.name): return False # Version must be in specifier range if candidate.version not in requirement.specifier: return False # If requirement has extras, candidate must provide them req_extras = getattr(requirement, 'extras', set()) cand_extras = getattr(candidate, 'available_extras', set()) if req_extras and not req_extras.issubset(cand_extras): return False return True def _canonicalize(self, name): return name.lower().replace("-", "_").replace(".", "_") ``` ```python # Usage provider = VersionProvider() class Req: def __init__(self, name, spec): self.name = name self.specifier = SpecifierSet(spec) class Cand: def __init__(self, name, ver): self.name = name self.version = Version(ver) req = Req("requests", ">=2.20,<3.0") cand_good = Cand("requests", "2.28.0") cand_bad = Cand("requests", "1.0.0") print(provider.is_satisfied_by(req, cand_good)) # True print(provider.is_satisfied_by(req, cand_bad)) # False ``` -------------------------------- ### Run Nox Release Task Source: https://github.com/sarugaku/resolvelib/blob/main/DEVELOPMENT.rst Execute the nox release task to manage versioning, tagging, building, and uploading distributions. Replace X.Y.Z with the release version and X.Y.Z+1.dev0 with the pre-bump version. ```shell nox -s release -- --repo https://upload.pypi.org/legacy/ --prebump X.Y.Z+1.dev0 --version X.Y.Z ``` -------------------------------- ### Optimize Provider Selection with narrow_requirement_selection Source: https://context7.com/sarugaku/resolvelib/llms.txt Implement this method to perform batch availability checks, reducing the overhead of individual identifier checks during resolution. ```python class BatchOptimizedProvider(AbstractProvider): def narrow_requirement_selection(self, identifiers, resolutions, candidates, information, backtrack_causes): # This method is O(1) per round vs get_preference which is O(n) # Use this for expensive checks that apply to all identifiers identifiers_list = list(identifiers) # Expensive batch operation: check all at once availability = self._batch_check_availability(identifiers_list) # Filter to only available packages return [i for i in identifiers_list if availability.get(i, True)] ``` -------------------------------- ### Push Release Branch Source: https://github.com/sarugaku/resolvelib/blob/main/DEVELOPMENT.rst Push the newly created release branch to the origin remote. ```shell git push origin release/X.Y.Z ``` -------------------------------- ### AbstractProvider.is_satisfied_by Source: https://context7.com/sarugaku/resolvelib/llms.txt Determines whether a candidate satisfies a requirement. ```APIDOC ## AbstractProvider.is_satisfied_by ### Description Determines whether a candidate satisfies a requirement. Returns True if the candidate is a valid solution for the requirement. ### Parameters - **requirement** (object) - The requirement to check. - **candidate** (object) - The candidate to validate against the requirement. ### Response - **return** (bool) - True if the candidate satisfies the requirement, False otherwise. ``` -------------------------------- ### Implement get_preference for PrioritizeDirectDeps Source: https://context7.com/sarugaku/resolvelib/llms.txt This strategy prioritizes direct dependencies by assigning them a lower preference value (0) compared to transitive dependencies (1). It also considers the candidate count. ```python from resolvelib import AbstractProvider class PrioritizeDirectDeps(AbstractProvider): def get_preference(self, identifier, resolutions, candidates, information, backtrack_causes): # Check if this is a direct (root) requirement is_direct = any( info.parent is None for info in information[identifier] ) candidate_count = sum(1 for _ in candidates[identifier]) # Direct dependencies get priority 0, transitive get 1 return (0 if is_direct else 1, candidate_count) ``` -------------------------------- ### AbstractProvider.find_matches Source: https://context7.com/sarugaku/resolvelib/llms.txt Returns all candidates that satisfy the given requirements and are not in the incompatibilities list. ```APIDOC ## AbstractProvider.find_matches ### Description Returns all candidates that satisfy the given requirements and are not in the incompatibilities list. Candidates should be ordered by preference (most preferred first). ### Parameters - **identifier** (str) - The identifier of the requirement. - **requirements** (dict) - The set of requirements to satisfy. - **incompatibilities** (dict) - Versions or candidates that are explicitly incompatible. ### Response - **return** (list or callable) - A list of candidates or a callable that returns candidates. ``` -------------------------------- ### Resolver Class Source: https://context7.com/sarugaku/resolvelib/llms.txt The main entry point for dependency resolution. It processes requirements using a custom provider and optional reporter to resolve dependencies into concrete candidates. ```APIDOC ## Resolver.resolve ### Description Resolves a list of requirements into a mapping of packages to specific versions. ### Parameters - **requirements** (list) - Required - A list of requirement objects to resolve. - **max_rounds** (int) - Optional - The maximum number of resolution rounds to perform. ### Response - **result** (object) - A resolution result object containing the final mapping of packages to versions. ``` -------------------------------- ### AbstractProvider.identify Source: https://context7.com/sarugaku/resolvelib/llms.txt Returns a unique identifier for a requirement or candidate, used to determine if two requirements refer to the same package. ```APIDOC ## AbstractProvider.identify ### Description Returns a unique identifier for a requirement or candidate. This identifier is used to determine if two requirements refer to the same package and should have their specifiers merged. ### Parameters - **requirement_or_candidate** (object) - Required - The requirement or candidate object to identify. ### Response - **identifier** (string/tuple) - A unique identifier representing the package. ``` -------------------------------- ### Push Tags Source: https://github.com/sarugaku/resolvelib/blob/main/DEVELOPMENT.rst Push all tags to the upstream remote, typically used during the release process. ```shell git push upstream --tags ``` -------------------------------- ### Handle Resolution Exceptions Source: https://context7.com/sarugaku/resolvelib/llms.txt Provides patterns for catching and reporting specific resolution failures, including circular dependencies and provider implementation errors. ```python import resolvelib from resolvelib import ( ResolutionImpossible, ResolutionTooDeep, InconsistentCandidate, ) resolver = resolvelib.Resolver(provider, reporter) try: result = resolver.resolve(requirements, max_rounds=100) print("Resolution successful!") except ResolutionImpossible as e: # No valid solution exists print("ERROR: Could not resolve dependencies") print("Conflicting requirements:") for cause in e.causes: req = cause.requirement parent = cause.parent if parent is None: print(f" - {req} (root requirement)") else: print(f" - {req} (required by {parent})") except ResolutionTooDeep as e: # Too many rounds - possible circular dependency print(f"ERROR: Resolution exceeded {e.round_count} rounds") print("This may indicate circular dependencies") print("Try increasing max_rounds or check for dependency cycles") except InconsistentCandidate as e: # Provider bug: candidate doesn't satisfy its own requirements print("ERROR: Provider implementation error") print(f"Candidate {e.candidate} does not satisfy requirements:") for req in e.criterion.iter_requirement(): print(f" - {req}") print("Check your is_satisfied_by() and find_matches() implementations") # Example of extracting useful error information def format_resolution_error(exc): if isinstance(exc, ResolutionImpossible): lines = ["Unable to resolve dependencies:"] # Group causes by package by_package = {} for cause in exc.causes: pkg = cause.requirement.name by_package.setdefault(pkg, []).append(cause) for pkg, causes in by_package.items(): lines.append(f"\n {pkg}:") for cause in causes: if cause.parent: lines.append(f" - {cause.requirement} (from {cause.parent})") else: lines.append(f" - {cause.requirement} (requested)") return "\n".join(lines) return str(exc) ``` -------------------------------- ### Monitor Resolution with BaseReporter Source: https://context7.com/sarugaku/resolvelib/llms.txt Subclass BaseReporter to receive callbacks for logging or UI updates during the resolution process. ```python import resolvelib class VerboseReporter(resolvelib.BaseReporter): def __init__(self): self.rounds = 0 self.pins = [] self.conflicts = [] def starting(self): """Called when resolution begins.""" print("=== Starting dependency resolution ===") def starting_round(self, index): """Called at the start of each resolution round.""" self.rounds = index + 1 print(f"\n--- Round {index + 1} ---") def ending_round(self, index, state): """Called at the end of each round (if not final).""" pinned = len(state.mapping) print(f"Round {index + 1} complete: {pinned} packages pinned") def ending(self, state): """Called when resolution succeeds.""" print(f"\n=== Resolution complete in {self.rounds} rounds ===") print(f"Resolved {len(state.mapping)} packages") def adding_requirement(self, requirement, parent): """Called when a new requirement is discovered.""" if parent is None: print(f" Root requirement: {requirement}") else: print(f" New dependency: {requirement} (from {parent})") def resolving_conflicts(self, causes): """Called when backtracking begins.""" self.conflicts.append(causes) print(f" CONFLICT detected! Backtracking...") for cause in causes: print(f" - {cause.requirement} (via {cause.parent})") def rejecting_candidate(self, criterion, candidate): """Called when a candidate is rejected during backtracking.""" print(f" Rejecting: {candidate}") def pinning(self, candidate): """Called when a candidate is selected.""" self.pins.append(candidate) print(f" Pinning: {candidate}") # Usage reporter = VerboseReporter() resolver = resolvelib.Resolver(provider, reporter) result = resolver.resolve(requirements) print(f"\nStats: {len(reporter.pins)} candidates tried, {len(reporter.conflicts)} conflicts") ``` -------------------------------- ### Inspect Resolution Results Source: https://context7.com/sarugaku/resolvelib/llms.txt Access the mapping, dependency graph, and criteria from the result object returned by the resolver. ```python import resolvelib # After successful resolution result = resolver.resolve(requirements) # result.mapping: dict mapping identifiers to pinned candidates print("Pinned packages:") for identifier, candidate in result.mapping.items(): print(f" {identifier}: {candidate.name}=={candidate.version}") # result.graph: DirectedGraph representing dependency relationships print("\nDependency tree:") for parent in result.graph: children = list(result.graph.iter_children(parent)) if children: if parent is None: print(f" ROOT -> {', '.join(str(c) for c in children)}") else: print(f" {parent} -> {', '.join(str(c) for c in children)}") # Navigate the graph def print_dependency_tree(graph, node, indent=0): prefix = " " * indent print(f"{prefix}{node or 'ROOT'}") for child in graph.iter_children(node): print_dependency_tree(graph, child, indent + 1) print("\nFull tree:") print_dependency_tree(result.graph, None) # result.criteria: dict of Criterion objects with detailed resolution info print("\nResolution details:") for identifier, criterion in result.criteria.items(): requirements = list(criterion.iter_requirement()) print(f" {identifier}: satisfied by {len(requirements)} requirement(s)") for req in requirements: print(f" - {req}") ``` -------------------------------- ### AbstractProvider.narrow_requirement_selection Source: https://context7.com/sarugaku/resolvelib/llms.txt An optional optimization method to filter identifiers during the resolution process. ```APIDOC ## AbstractProvider.narrow_requirement_selection ### Description Filters which requirements are considered during a resolution round to improve performance. ### Parameters - **identifiers** (list) - Required - List of package identifiers. - **resolutions** (dict) - Required - Current state of resolved packages. - **candidates** (dict) - Required - Available candidates for each identifier. - **information** (list) - Required - Information about current resolution state. - **backtrack_causes** (list) - Required - List of causes that triggered backtracking. ### Response - **list** - A subset of identifiers to prioritize for resolution. ``` -------------------------------- ### Implement find_matches_lazy for PyPIStyleProvider Source: https://context7.com/sarugaku/resolvelib/llms.txt This alternative implementation of find_matches returns a callable for lazy evaluation. Candidates are fetched from the index only when the callable is invoked. ```python # Alternative: return a callable for lazy evaluation def find_matches_lazy(self, identifier, requirements, incompatibilities): def get_candidates(): # Candidates are fetched only when needed return self._fetch_from_index(identifier, requirements, incompatibilities) return get_candidates # Return callable, not result ``` -------------------------------- ### Manage DirectedGraph Structures Source: https://context7.com/sarugaku/resolvelib/llms.txt Use DirectedGraph to represent and manipulate dependency relationships manually or via resolution results. ```python from resolvelib.structs import DirectedGraph # The graph is automatically built during resolution # result.graph contains the dependency tree # Manual graph operations graph = DirectedGraph() # Add vertices (packages) graph.add("flask") graph.add("werkzeug") graph.add("jinja2") graph.add(None) # None represents root ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.