You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

cppython

Package Overview
Dependencies
Maintainers
1
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cppython - pypi Package Compare versions

Comparing version
0.9.4
to
0.9.5.dev1
+135
-90
cppython/plugins/conan/plugin.py

@@ -8,3 +8,2 @@ """Conan Provider Plugin

import logging
from pathlib import Path

@@ -82,22 +81,37 @@ from typing import Any

try:
logger = logging.getLogger('cppython.conan')
logger.debug('Starting dependency installation/update (update=%s)', update)
# Setup environment and generate conanfile
conan_api, conanfile_path = self._prepare_installation()
# Load dependency graph
deps_graph = self._load_dependency_graph(conan_api, conanfile_path, update)
# Install dependencies
self._install_binaries(conan_api, deps_graph, update)
# Generate consumer files
self._generate_consumer_files(conan_api, deps_graph)
except Exception as e:
operation = 'update' if update else 'install'
raise ProviderInstallationError('conan', f'Failed to {operation} dependencies: {e}', e) from e
def _prepare_installation(self) -> tuple[ConanAPI, Path]:
"""Prepare the installation environment and generate conanfile.
Returns:
Tuple of (ConanAPI instance, conanfile path)
Raises:
ProviderInstallationError: If conanfile generation or setup fails
"""
try:
# Resolve dependencies and generate conanfile.py
resolved_dependencies = [resolve_conan_dependency(req) for req in self.core_data.cppython_data.dependencies]
logger.debug(
'Resolved %d dependencies: %s', len(resolved_dependencies), [str(dep) for dep in resolved_dependencies]
)
# Generate conanfile.py
self.builder.generate_conanfile(self.core_data.project_data.project_root, resolved_dependencies)
logger.debug('Generated conanfile.py at %s', self.core_data.project_data.project_root)
# Ensure build directory exists
self.core_data.cppython_data.build_path.mkdir(parents=True, exist_ok=True)
logger.debug('Created build path: %s', self.core_data.cppython_data.build_path)
# Initialize Conan API
# Setup paths and API
conan_api = ConanAPI()
# Get project paths
project_root = self.core_data.project_data.project_root

@@ -109,16 +123,27 @@ conanfile_path = project_root / 'conanfile.py'

# Get all remotes
return conan_api, conanfile_path
except Exception as e:
raise ProviderInstallationError('conan', f'Failed to prepare installation environment: {e}', e) from e
def _load_dependency_graph(self, conan_api: ConanAPI, conanfile_path: Path, update: bool):
"""Load and build the dependency graph.
Args:
conan_api: The Conan API instance
conanfile_path: Path to the conanfile.py
update: Whether to check for updates
Returns:
The loaded dependency graph
Raises:
ProviderInstallationError: If dependency graph loading fails
"""
try:
all_remotes = conan_api.remotes.list()
logger.debug('Available remotes: %s', [remote.name for remote in all_remotes])
# Get profiles from resolved data
profile_host, profile_build = self.data.host_profile, self.data.build_profile
path = str(conanfile_path)
remotes = all_remotes
update_flag = None if not update else True
check_updates_flag = update
deps_graph = conan_api.graph.load_graph_consumer(
path=path,
return conan_api.graph.load_graph_consumer(
path=str(conanfile_path),
name=None,

@@ -129,5 +154,5 @@ version=None,

lockfile=None,
remotes=remotes,
update=update_flag,
check_updates=check_updates_flag,
remotes=all_remotes,
update=update or None,
check_updates=update,
is_build_require=False,

@@ -138,10 +163,25 @@ profile_host=profile_host,

logger.debug('Dependency graph loaded with %d nodes', len(deps_graph.nodes))
except Exception as e:
raise ProviderInstallationError('conan', f'Failed to load dependency graph: {e}', e) from e
def _install_binaries(self, conan_api: ConanAPI, deps_graph, update: bool) -> None:
"""Analyze and install binary dependencies.
Args:
conan_api: The Conan API instance
deps_graph: The dependency graph
update: Whether to check for updates
Raises:
ProviderInstallationError: If binary analysis or installation fails
"""
try:
all_remotes = conan_api.remotes.list()
# Analyze binaries to determine what needs to be built/downloaded
conan_api.graph.analyze_binaries(
graph=deps_graph,
build_mode=['missing'], # Only build what's missing
build_mode=['missing'],
remotes=all_remotes,
update=None if not update else True,
update=update or None,
lockfile=None,

@@ -153,3 +193,18 @@ )

# Generate files for the consumer (conandata.yml, conan_toolchain.cmake, etc.)
except Exception as e:
raise ProviderInstallationError('conan', f'Failed to install binary dependencies: {e}', e) from e
def _generate_consumer_files(self, conan_api: ConanAPI, deps_graph) -> None:
"""Generate consumer files (CMake toolchain, deps, etc.).
Args:
conan_api: The Conan API instance
deps_graph: The dependency graph
Raises:
ProviderInstallationError: If consumer file generation fails
"""
try:
project_root = self.core_data.project_data.project_root
conan_api.install.install_consumer(

@@ -162,8 +217,4 @@ deps_graph=deps_graph,

logger.debug('Successfully installed dependencies using Conan API')
except Exception as e:
operation = 'update' if update else 'install'
error_msg = str(e)
raise ProviderInstallationError('conan', f'Failed to {operation} dependencies: {error_msg}', e) from e
raise ProviderInstallationError('conan', f'Failed to generate consumer files: {e}', e) from e

@@ -209,3 +260,3 @@ def install(self) -> None:

raise NotSupportedError('OOF')
raise NotSupportedError(f'Unsupported sync types: {consumer.sync_types()}')

@@ -219,3 +270,2 @@ @classmethod

"""Publishes the package using conan create workflow."""
# Get the project root directory where conanfile.py should be located
project_root = self.core_data.project_data.project_root

@@ -227,26 +277,10 @@ conanfile_path = project_root / 'conanfile.py'

# Initialize Conan API
conan_api = ConanAPI()
# Get configured remotes from Conan API and filter by our configuration
# TODO: We want to replace the global conan remotes with the ones configured in CPPython.
all_remotes = conan_api.remotes.list()
if not self.data.local_only:
# Filter remotes to only include those specified in configuration
configured_remotes = [remote for remote in all_remotes if remote.name in self.data.remotes]
if not configured_remotes:
available_remotes = [remote.name for remote in all_remotes]
raise ProviderConfigurationError(
'conan',
f'No configured remotes found. Available remotes: {available_remotes}, '
f'Configured remotes: {self.data.remotes}',
'remotes',
)
else:
configured_remotes = []
# Configure remotes for upload
configured_remotes = self._get_configured_remotes(all_remotes)
# Step 1: Export the recipe to the cache
# This is equivalent to the export part of `conan create`
ref, conanfile = conan_api.export.export(
# Export the recipe to cache
ref, _ = conan_api.export.export(
path=str(conanfile_path),

@@ -258,14 +292,9 @@ name=None,

lockfile=None,
remotes=all_remotes, # Use all remotes for dependency resolution during export
remotes=all_remotes,
)
# Step 2: Get profiles from resolved data
# Build dependency graph and install
profile_host, profile_build = self.data.host_profile, self.data.build_profile
# Step 3: Build dependency graph for the package - prepare parameters
path = str(conanfile_path)
remotes = all_remotes # Use all remotes for dependency resolution
deps_graph = conan_api.graph.load_graph_consumer(
path=path,
path=str(conanfile_path),
name=None,

@@ -276,3 +305,3 @@ version=None,

lockfile=None,
remotes=remotes,
remotes=all_remotes,
update=None,

@@ -285,7 +314,7 @@ check_updates=False,

# Step 4: Analyze binaries and install/build them if needed
# Analyze and build binaries
conan_api.graph.analyze_binaries(
graph=deps_graph,
build_mode=['*'], # Build from source (equivalent to the create behavior)
remotes=all_remotes, # Use all remotes for dependency resolution
build_mode=['*'],
remotes=all_remotes,
update=None,

@@ -295,26 +324,42 @@ lockfile=None,

# Step 5: Install all dependencies and build the package
conan_api.install.install_binaries(deps_graph=deps_graph, remotes=all_remotes)
# If not local only, upload the package
# Upload if not local only
if not self.data.local_only:
# Get all packages matching the created reference
ref_pattern = ListPattern(f'{ref.name}/*', package_id='*', only_recipe=False)
package_list = conan_api.list.select(ref_pattern)
self._upload_package(conan_api, ref, configured_remotes)
if package_list.recipes:
# Use the first configured remote for upload
remote = configured_remotes[0]
def _get_configured_remotes(self, all_remotes):
"""Get and validate configured remotes for upload."""
if self.data.local_only:
return []
# Upload the package to configured remotes
conan_api.upload.upload_full(
package_list=package_list,
remote=remote,
enabled_remotes=configured_remotes, # Only upload to configured remotes
check_integrity=False,
force=False,
metadata=None,
dry_run=False,
)
else:
raise ProviderInstallationError('conan', 'No packages found to upload')
configured_remotes = [remote for remote in all_remotes if remote.name in self.data.remotes]
if not configured_remotes:
available_remotes = [remote.name for remote in all_remotes]
raise ProviderConfigurationError(
'conan',
f'No configured remotes found. Available: {available_remotes}, Configured: {self.data.remotes}',
'remotes',
)
return configured_remotes
def _upload_package(self, conan_api, ref, configured_remotes):
"""Upload the package to configured remotes."""
ref_pattern = ListPattern(f'{ref.name}/*', package_id='*', only_recipe=False)
package_list = conan_api.list.select(ref_pattern)
if not package_list.recipes:
raise ProviderInstallationError('conan', 'No packages found to upload')
remote = configured_remotes[0]
conan_api.upload.upload_full(
package_list=package_list,
remote=remote,
enabled_remotes=configured_remotes,
check_integrity=False,
force=False,
metadata=None,
dry_run=False,
)
+1
-1
Metadata-Version: 2.1
Name: cppython
Version: 0.9.4
Version: 0.9.5.dev1
Summary: A Python management solution for C++ dependencies

@@ -5,0 +5,0 @@ Author-Email: Synodic Software <contact@synodic.software>

@@ -17,3 +17,3 @@ [project]

]
version = "0.9.4"
version = "0.9.5.dev1"

@@ -20,0 +20,0 @@ [project.license]