IncludeCPP 2.4.2__tar.gz → 2.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/PKG-INFO +1 -1
- {includecpp-2.4.2 → includecpp-2.4.4}/PKG-INFO +1 -1
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/__init__.py +1 -1
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/cli/commands.py +302 -20
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/build_manager.py +139 -21
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/generator/parser.cpp +61 -3
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/generator/parser.h +6 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/pyproject.toml +1 -1
- {includecpp-2.4.2 → includecpp-2.4.4}/setup.py +1 -1
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/SOURCES.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/dependency_links.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/entry_points.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/requires.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/IncludeCPP.egg-info/top_level.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/LICENSE +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/MANIFEST.in +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/README.md +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/__init__.pyi +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/__main__.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/cli/__init__.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/cli/config_parser.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/__init__.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/cpp_api.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/cpp_api.pyi +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/error_formatter.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/exceptions.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/core/path_discovery.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/generator/__init__.py +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/generator/type_resolver.cpp +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/generator/type_resolver.h +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/includecpp/templates/cpp.proj.template +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/requirements.txt +0 -0
- {includecpp-2.4.2 → includecpp-2.4.4}/setup.cfg +0 -0
|
@@ -1268,14 +1268,159 @@ def minstall(module_name, list_all):
|
|
|
1268
1268
|
ctx.invoke(install, module_name=module_name, list_all=list_all)
|
|
1269
1269
|
|
|
1270
1270
|
@cli.command()
|
|
1271
|
-
|
|
1272
|
-
|
|
1271
|
+
@click.argument('target_version', required=False)
|
|
1272
|
+
@click.option('--version', 'show_version', is_flag=True, help='Show current installed version')
|
|
1273
|
+
@click.option('--all', 'list_all', is_flag=True, help='List all available versions from PyPI')
|
|
1274
|
+
def update(target_version, show_version, list_all):
|
|
1275
|
+
"""Update IncludeCPP package from PyPI.
|
|
1276
|
+
|
|
1277
|
+
Usage:
|
|
1278
|
+
includecpp update Upgrade to latest version
|
|
1279
|
+
includecpp update --version Show current version
|
|
1280
|
+
includecpp update --all List all available versions
|
|
1281
|
+
includecpp update X.X.X Install specific version
|
|
1282
|
+
"""
|
|
1273
1283
|
import subprocess
|
|
1274
1284
|
import urllib.request
|
|
1275
1285
|
import json
|
|
1276
1286
|
|
|
1287
|
+
from .. import __version__ as current_version
|
|
1288
|
+
|
|
1289
|
+
# --version: Show current version
|
|
1290
|
+
if show_version:
|
|
1291
|
+
click.echo("=" * 60)
|
|
1292
|
+
click.secho("IncludeCPP Version Info", fg='cyan', bold=True)
|
|
1293
|
+
click.echo("=" * 60)
|
|
1294
|
+
click.echo()
|
|
1295
|
+
click.echo(f" Installed version: ", nl=False)
|
|
1296
|
+
click.secho(f"{current_version}", fg='green', bold=True)
|
|
1297
|
+
click.echo()
|
|
1298
|
+
click.echo("=" * 60)
|
|
1299
|
+
return
|
|
1300
|
+
|
|
1301
|
+
# --all: List all PyPI versions
|
|
1302
|
+
if list_all:
|
|
1303
|
+
click.echo("=" * 60)
|
|
1304
|
+
click.secho("Available IncludeCPP Versions", fg='cyan', bold=True)
|
|
1305
|
+
click.echo("=" * 60)
|
|
1306
|
+
click.echo(f"Source: https://pypi.org/project/IncludeCPP/")
|
|
1307
|
+
click.echo()
|
|
1308
|
+
|
|
1309
|
+
try:
|
|
1310
|
+
click.echo(" Fetching version list from PyPI...", nl=False)
|
|
1311
|
+
with urllib.request.urlopen("https://pypi.org/pypi/IncludeCPP/json") as response:
|
|
1312
|
+
data = json.loads(response.read())
|
|
1313
|
+
click.secho(" OK", fg='green')
|
|
1314
|
+
click.echo()
|
|
1315
|
+
|
|
1316
|
+
# Get all versions from releases
|
|
1317
|
+
versions = list(data.get('releases', {}).keys())
|
|
1318
|
+
latest_version = data['info']['version']
|
|
1319
|
+
|
|
1320
|
+
if not versions:
|
|
1321
|
+
click.secho(" No versions found.", fg='yellow')
|
|
1322
|
+
else:
|
|
1323
|
+
# Sort versions (newest first)
|
|
1324
|
+
from packaging.version import Version, InvalidVersion
|
|
1325
|
+
valid_versions = []
|
|
1326
|
+
for v in versions:
|
|
1327
|
+
try:
|
|
1328
|
+
valid_versions.append((Version(v), v))
|
|
1329
|
+
except InvalidVersion:
|
|
1330
|
+
valid_versions.append((Version("0.0.0"), v))
|
|
1331
|
+
valid_versions.sort(reverse=True, key=lambda x: x[0])
|
|
1332
|
+
|
|
1333
|
+
click.secho(f"Found {len(versions)} version(s):", fg='green', bold=True)
|
|
1334
|
+
click.echo()
|
|
1335
|
+
|
|
1336
|
+
for _, v in valid_versions:
|
|
1337
|
+
if v == current_version and v == latest_version:
|
|
1338
|
+
click.echo(f" {_BULLET} {v} ", nl=False)
|
|
1339
|
+
click.secho("[installed] [latest]", fg='green', bold=True)
|
|
1340
|
+
elif v == current_version:
|
|
1341
|
+
click.echo(f" {_BULLET} {v} ", nl=False)
|
|
1342
|
+
click.secho("[installed]", fg='cyan')
|
|
1343
|
+
elif v == latest_version:
|
|
1344
|
+
click.echo(f" {_BULLET} {v} ", nl=False)
|
|
1345
|
+
click.secho("[latest]", fg='yellow')
|
|
1346
|
+
else:
|
|
1347
|
+
click.echo(f" {_BULLET} {v}")
|
|
1348
|
+
|
|
1349
|
+
click.echo()
|
|
1350
|
+
click.echo("Install a specific version with:")
|
|
1351
|
+
click.secho(" includecpp update <version>", fg='cyan')
|
|
1352
|
+
|
|
1353
|
+
except Exception as e:
|
|
1354
|
+
click.secho(f" FAILED", fg='red', err=True)
|
|
1355
|
+
click.echo()
|
|
1356
|
+
click.secho(f"Could not fetch version list: {e}", fg='red', err=True)
|
|
1357
|
+
|
|
1358
|
+
click.echo("=" * 60)
|
|
1359
|
+
return
|
|
1360
|
+
|
|
1361
|
+
# Install specific version
|
|
1362
|
+
if target_version:
|
|
1363
|
+
click.echo("=" * 60)
|
|
1364
|
+
click.secho(f"Installing IncludeCPP {target_version}", fg='cyan', bold=True)
|
|
1365
|
+
click.echo("=" * 60)
|
|
1366
|
+
click.echo()
|
|
1367
|
+
|
|
1368
|
+
# Verify version exists on PyPI
|
|
1369
|
+
try:
|
|
1370
|
+
click.echo(" Verifying version on PyPI...", nl=False)
|
|
1371
|
+
with urllib.request.urlopen("https://pypi.org/pypi/IncludeCPP/json") as response:
|
|
1372
|
+
data = json.loads(response.read())
|
|
1373
|
+
available_versions = list(data.get('releases', {}).keys())
|
|
1374
|
+
|
|
1375
|
+
if target_version not in available_versions:
|
|
1376
|
+
click.secho(" NOT FOUND", fg='red')
|
|
1377
|
+
click.echo()
|
|
1378
|
+
click.secho(f"Version '{target_version}' does not exist on PyPI.", fg='red', err=True)
|
|
1379
|
+
click.echo("Use 'includecpp update --all' to see available versions.")
|
|
1380
|
+
click.echo("=" * 60)
|
|
1381
|
+
return
|
|
1382
|
+
|
|
1383
|
+
click.secho(" OK", fg='green')
|
|
1384
|
+
|
|
1385
|
+
except Exception as e:
|
|
1386
|
+
click.secho(f" FAILED ({e})", fg='red', err=True)
|
|
1387
|
+
click.echo("=" * 60)
|
|
1388
|
+
return
|
|
1389
|
+
|
|
1390
|
+
click.echo(f" Current version: {current_version}")
|
|
1391
|
+
click.echo(f" Target version: {target_version}")
|
|
1392
|
+
click.echo()
|
|
1393
|
+
|
|
1394
|
+
if current_version == target_version:
|
|
1395
|
+
click.secho(f"Version {target_version} is already installed!", fg='green', bold=True)
|
|
1396
|
+
click.echo("=" * 60)
|
|
1397
|
+
return
|
|
1398
|
+
|
|
1399
|
+
click.echo(f" Installing IncludeCPP=={target_version}...", nl=False)
|
|
1400
|
+
result = subprocess.run(
|
|
1401
|
+
[sys.executable, "-m", "pip", "install", f"IncludeCPP=={target_version}"],
|
|
1402
|
+
capture_output=True,
|
|
1403
|
+
text=True
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
if result.returncode == 0:
|
|
1407
|
+
click.secho(" OK", fg='green')
|
|
1408
|
+
click.echo()
|
|
1409
|
+
click.secho(f"Successfully installed IncludeCPP {target_version}!", fg='green', bold=True)
|
|
1410
|
+
click.echo("Restart your terminal to use the new version.")
|
|
1411
|
+
else:
|
|
1412
|
+
click.secho(" FAILED", fg='red', err=True)
|
|
1413
|
+
click.echo()
|
|
1414
|
+
click.secho("Installation failed!", fg='red', err=True, bold=True)
|
|
1415
|
+
if result.stderr:
|
|
1416
|
+
click.echo(result.stderr[:500])
|
|
1417
|
+
|
|
1418
|
+
click.echo("=" * 60)
|
|
1419
|
+
return
|
|
1420
|
+
|
|
1421
|
+
# Default: Upgrade to latest
|
|
1277
1422
|
click.echo("=" * 60)
|
|
1278
|
-
click.secho("Checking for IncludeCPP
|
|
1423
|
+
click.secho("Checking for IncludeCPP Updates", fg='cyan', bold=True)
|
|
1279
1424
|
click.echo("=" * 60)
|
|
1280
1425
|
click.echo()
|
|
1281
1426
|
|
|
@@ -1284,9 +1429,8 @@ def update():
|
|
|
1284
1429
|
with urllib.request.urlopen("https://pypi.org/pypi/IncludeCPP/json") as response:
|
|
1285
1430
|
data = json.loads(response.read())
|
|
1286
1431
|
latest_version = data['info']['version']
|
|
1287
|
-
click.secho(
|
|
1432
|
+
click.secho(" OK", fg='green')
|
|
1288
1433
|
|
|
1289
|
-
from .. import __version__ as current_version
|
|
1290
1434
|
click.echo()
|
|
1291
1435
|
click.echo(f" Current version: {current_version}")
|
|
1292
1436
|
click.echo(f" Latest version: {latest_version}")
|
|
@@ -1297,8 +1441,7 @@ def update():
|
|
|
1297
1441
|
click.echo("=" * 60)
|
|
1298
1442
|
return
|
|
1299
1443
|
|
|
1300
|
-
click.
|
|
1301
|
-
click.echo()
|
|
1444
|
+
click.echo(f" Upgrading to version {latest_version}...", nl=False)
|
|
1302
1445
|
|
|
1303
1446
|
result = subprocess.run(
|
|
1304
1447
|
[sys.executable, "-m", "pip", "install", "--upgrade", "IncludeCPP"],
|
|
@@ -1307,18 +1450,89 @@ def update():
|
|
|
1307
1450
|
)
|
|
1308
1451
|
|
|
1309
1452
|
if result.returncode == 0:
|
|
1453
|
+
click.secho(" OK", fg='green')
|
|
1310
1454
|
click.echo()
|
|
1311
1455
|
click.secho(f"Successfully upgraded to IncludeCPP {latest_version}!", fg='green', bold=True)
|
|
1312
1456
|
click.echo("Restart your terminal to use the new version.")
|
|
1313
1457
|
else:
|
|
1458
|
+
click.secho(" FAILED", fg='red', err=True)
|
|
1459
|
+
click.echo()
|
|
1314
1460
|
click.secho("Upgrade failed!", fg='red', err=True, bold=True)
|
|
1315
|
-
|
|
1461
|
+
if result.stderr:
|
|
1462
|
+
click.echo(result.stderr[:500])
|
|
1316
1463
|
|
|
1317
1464
|
except Exception as e:
|
|
1465
|
+
click.secho(f" FAILED", fg='red', err=True)
|
|
1466
|
+
click.echo()
|
|
1318
1467
|
click.secho(f"Failed to check for updates: {e}", fg='red', err=True)
|
|
1319
1468
|
|
|
1320
1469
|
click.echo("=" * 60)
|
|
1321
1470
|
|
|
1471
|
+
|
|
1472
|
+
@cli.command()
|
|
1473
|
+
def reboot():
|
|
1474
|
+
"""Reinstall IncludeCPP (uninstall + install current version).
|
|
1475
|
+
|
|
1476
|
+
This command reinstalls the currently installed version without upgrading.
|
|
1477
|
+
Useful for fixing corrupted installations or resetting to a clean state.
|
|
1478
|
+
"""
|
|
1479
|
+
import subprocess
|
|
1480
|
+
|
|
1481
|
+
from .. import __version__ as current_version
|
|
1482
|
+
|
|
1483
|
+
click.echo("=" * 60)
|
|
1484
|
+
click.secho("IncludeCPP Reboot", fg='cyan', bold=True)
|
|
1485
|
+
click.echo("=" * 60)
|
|
1486
|
+
click.echo()
|
|
1487
|
+
click.echo(f" Current version: {current_version}")
|
|
1488
|
+
click.echo()
|
|
1489
|
+
click.secho("This will reinstall IncludeCPP without changing the version.", fg='yellow')
|
|
1490
|
+
click.echo()
|
|
1491
|
+
|
|
1492
|
+
# Step 1: Uninstall
|
|
1493
|
+
click.echo(f" [1/2] Uninstalling IncludeCPP...", nl=False)
|
|
1494
|
+
result = subprocess.run(
|
|
1495
|
+
[sys.executable, "-m", "pip", "uninstall", "IncludeCPP", "-y"],
|
|
1496
|
+
capture_output=True,
|
|
1497
|
+
text=True
|
|
1498
|
+
)
|
|
1499
|
+
|
|
1500
|
+
if result.returncode != 0:
|
|
1501
|
+
click.secho(" FAILED", fg='red', err=True)
|
|
1502
|
+
click.echo()
|
|
1503
|
+
click.secho("Uninstall failed!", fg='red', err=True, bold=True)
|
|
1504
|
+
if result.stderr:
|
|
1505
|
+
click.echo(result.stderr[:500])
|
|
1506
|
+
click.echo("=" * 60)
|
|
1507
|
+
return
|
|
1508
|
+
|
|
1509
|
+
click.secho(" OK", fg='green')
|
|
1510
|
+
|
|
1511
|
+
# Step 2: Reinstall same version
|
|
1512
|
+
click.echo(f" [2/2] Installing IncludeCPP=={current_version}...", nl=False)
|
|
1513
|
+
result = subprocess.run(
|
|
1514
|
+
[sys.executable, "-m", "pip", "install", f"IncludeCPP=={current_version}"],
|
|
1515
|
+
capture_output=True,
|
|
1516
|
+
text=True
|
|
1517
|
+
)
|
|
1518
|
+
|
|
1519
|
+
if result.returncode == 0:
|
|
1520
|
+
click.secho(" OK", fg='green')
|
|
1521
|
+
click.echo()
|
|
1522
|
+
click.secho(f"Successfully reinstalled IncludeCPP {current_version}!", fg='green', bold=True)
|
|
1523
|
+
click.echo("Restart your terminal to use the reinstalled version.")
|
|
1524
|
+
else:
|
|
1525
|
+
click.secho(" FAILED", fg='red', err=True)
|
|
1526
|
+
click.echo()
|
|
1527
|
+
click.secho("Reinstall failed!", fg='red', err=True, bold=True)
|
|
1528
|
+
if result.stderr:
|
|
1529
|
+
click.echo(result.stderr[:500])
|
|
1530
|
+
click.echo()
|
|
1531
|
+
click.echo("Try manually installing with:")
|
|
1532
|
+
click.secho(f" pip install IncludeCPP=={current_version}", fg='cyan')
|
|
1533
|
+
|
|
1534
|
+
click.echo("=" * 60)
|
|
1535
|
+
|
|
1322
1536
|
@cli.command()
|
|
1323
1537
|
@click.argument('plugin_name')
|
|
1324
1538
|
@click.argument('files', nargs=-1, required=True)
|
|
@@ -1393,10 +1607,58 @@ def plugin(plugin_name, files, private):
|
|
|
1393
1607
|
return class_body[public_start:public_start + next_access.start()]
|
|
1394
1608
|
return class_body[public_start:]
|
|
1395
1609
|
|
|
1610
|
+
def extract_param_types(params_str):
|
|
1611
|
+
"""Extract parameter types from a parameter string like 'double x, double y'."""
|
|
1612
|
+
if not params_str or params_str.strip() == '':
|
|
1613
|
+
return []
|
|
1614
|
+
|
|
1615
|
+
types = []
|
|
1616
|
+
# Split by comma, but be careful with template types like std::vector<int, alloc>
|
|
1617
|
+
depth = 0
|
|
1618
|
+
current = ''
|
|
1619
|
+
for char in params_str:
|
|
1620
|
+
if char in '<(':
|
|
1621
|
+
depth += 1
|
|
1622
|
+
current += char
|
|
1623
|
+
elif char in '>)':
|
|
1624
|
+
depth -= 1
|
|
1625
|
+
current += char
|
|
1626
|
+
elif char == ',' and depth == 0:
|
|
1627
|
+
types.append(current.strip())
|
|
1628
|
+
current = ''
|
|
1629
|
+
else:
|
|
1630
|
+
current += char
|
|
1631
|
+
if current.strip():
|
|
1632
|
+
types.append(current.strip())
|
|
1633
|
+
|
|
1634
|
+
# Extract just the type from each parameter (remove variable name)
|
|
1635
|
+
result = []
|
|
1636
|
+
for param in types:
|
|
1637
|
+
param = param.strip()
|
|
1638
|
+
if not param:
|
|
1639
|
+
continue
|
|
1640
|
+
# Remove default value if present
|
|
1641
|
+
if '=' in param:
|
|
1642
|
+
param = param.split('=')[0].strip()
|
|
1643
|
+
# Find the type: everything before the last word (variable name)
|
|
1644
|
+
# Handle cases like "const std::string& name" -> "const std::string&"
|
|
1645
|
+
parts = param.rsplit(None, 1)
|
|
1646
|
+
if len(parts) == 1:
|
|
1647
|
+
# Just a type, no name (e.g., in declaration "void foo(int)")
|
|
1648
|
+
result.append(parts[0])
|
|
1649
|
+
else:
|
|
1650
|
+
# Check if last part is a pointer/reference suffix attached to type
|
|
1651
|
+
type_part = parts[0]
|
|
1652
|
+
# Handle cases where * or & is attached to variable name
|
|
1653
|
+
if parts[1].startswith('*') or parts[1].startswith('&'):
|
|
1654
|
+
type_part = parts[0] + parts[1][0]
|
|
1655
|
+
result.append(type_part)
|
|
1656
|
+
return result
|
|
1657
|
+
|
|
1396
1658
|
def extract_methods(public_section, class_name):
|
|
1397
1659
|
"""Extract method names from public section, handling inline bodies."""
|
|
1398
1660
|
methods = set()
|
|
1399
|
-
|
|
1661
|
+
constructor_signatures = [] # v2.4.3: List of (param_types) tuples
|
|
1400
1662
|
|
|
1401
1663
|
# Method pattern that handles return types, const, and inline bodies
|
|
1402
1664
|
# Match: [modifiers] return_type method_name(params) [const] [{ body } | ;]
|
|
@@ -1418,8 +1680,7 @@ def plugin(plugin_name, files, private):
|
|
|
1418
1680
|
|
|
1419
1681
|
# Skip if method name is the class name (it's a constructor)
|
|
1420
1682
|
if method_name == class_name:
|
|
1421
|
-
|
|
1422
|
-
continue
|
|
1683
|
+
continue # Will be handled by dedicated constructor pattern
|
|
1423
1684
|
|
|
1424
1685
|
# Skip destructors
|
|
1425
1686
|
if method_name.startswith('~'):
|
|
@@ -1431,12 +1692,17 @@ def plugin(plugin_name, files, private):
|
|
|
1431
1692
|
|
|
1432
1693
|
methods.add(method_name)
|
|
1433
1694
|
|
|
1434
|
-
#
|
|
1435
|
-
constructor_pattern =
|
|
1436
|
-
|
|
1437
|
-
|
|
1695
|
+
# v2.4.3: Extract constructor signatures with parameter types
|
|
1696
|
+
constructor_pattern = re.compile(
|
|
1697
|
+
rf'(?:explicit\s+)?{re.escape(class_name)}\s*\(([^)]*)\)',
|
|
1698
|
+
re.MULTILINE
|
|
1699
|
+
)
|
|
1700
|
+
for match in constructor_pattern.finditer(public_section):
|
|
1701
|
+
params_str = match.group(1).strip()
|
|
1702
|
+
param_types = extract_param_types(params_str)
|
|
1703
|
+
constructor_signatures.append(tuple(param_types))
|
|
1438
1704
|
|
|
1439
|
-
return methods,
|
|
1705
|
+
return methods, constructor_signatures
|
|
1440
1706
|
|
|
1441
1707
|
all_files = cpp_files + h_files
|
|
1442
1708
|
|
|
@@ -1470,12 +1736,17 @@ def plugin(plugin_name, files, private):
|
|
|
1470
1736
|
public_section = extract_public_section(class_body, is_struct)
|
|
1471
1737
|
|
|
1472
1738
|
if class_name not in classes:
|
|
1473
|
-
classes[class_name] = {'methods': set(), 'constructors':
|
|
1739
|
+
classes[class_name] = {'methods': set(), 'constructors': []}
|
|
1474
1740
|
|
|
1475
1741
|
# Extract methods from public section
|
|
1476
|
-
methods,
|
|
1742
|
+
methods, constructor_sigs = extract_methods(public_section, class_name)
|
|
1477
1743
|
classes[class_name]['methods'].update(methods)
|
|
1478
|
-
|
|
1744
|
+
# v2.4.3: Merge constructor signatures (avoid duplicates)
|
|
1745
|
+
existing_ctors = set(classes[class_name]['constructors'])
|
|
1746
|
+
for sig in constructor_sigs:
|
|
1747
|
+
if sig not in existing_ctors:
|
|
1748
|
+
classes[class_name]['constructors'].append(sig)
|
|
1749
|
+
existing_ctors.add(sig)
|
|
1479
1750
|
|
|
1480
1751
|
# Find free functions (not inside class bodies)
|
|
1481
1752
|
# First, remove all class bodies from content to avoid matching class methods
|
|
@@ -1524,7 +1795,18 @@ def plugin(plugin_name, files, private):
|
|
|
1524
1795
|
cls_info = classes[cls_name]
|
|
1525
1796
|
f.write(f' {plugin_name} CLASS({cls_name}) {{\n')
|
|
1526
1797
|
|
|
1527
|
-
|
|
1798
|
+
# v2.4.3: Write all constructor overloads with parameter types
|
|
1799
|
+
if cls_info['constructors']:
|
|
1800
|
+
for ctor_params in cls_info['constructors']:
|
|
1801
|
+
if ctor_params:
|
|
1802
|
+
# Parametrized constructor
|
|
1803
|
+
params_str = ', '.join(ctor_params)
|
|
1804
|
+
f.write(f' CONSTRUCTOR({params_str})\n')
|
|
1805
|
+
else:
|
|
1806
|
+
# Default constructor
|
|
1807
|
+
f.write(f' CONSTRUCTOR()\n')
|
|
1808
|
+
else:
|
|
1809
|
+
# No constructors found, add default
|
|
1528
1810
|
f.write(f' CONSTRUCTOR()\n')
|
|
1529
1811
|
|
|
1530
1812
|
for method in sorted(cls_info['methods']):
|
|
@@ -579,10 +579,46 @@ endif()
|
|
|
579
579
|
else:
|
|
580
580
|
f.write(f' """C++ class: {class_name_inner}"""\n\n')
|
|
581
581
|
|
|
582
|
-
# Constructor
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
582
|
+
# v2.4.3: Constructor overloads with parameter types
|
|
583
|
+
constructors = cls.get('constructors', [])
|
|
584
|
+
if constructors and len(constructors) > 1:
|
|
585
|
+
# Multiple constructors - use @overload
|
|
586
|
+
for ctor in constructors:
|
|
587
|
+
param_types = ctor.get('params', [])
|
|
588
|
+
f.write(' @overload\n')
|
|
589
|
+
if param_types:
|
|
590
|
+
param_list = ['self']
|
|
591
|
+
for i, ptype in enumerate(param_types):
|
|
592
|
+
py_type = self._cpp_to_python_type(ptype)
|
|
593
|
+
param_list.append(f'arg{i}: {py_type}')
|
|
594
|
+
params_str = ', '.join(param_list)
|
|
595
|
+
f.write(f' def __init__({params_str}) -> None: ...\n')
|
|
596
|
+
else:
|
|
597
|
+
f.write(f' def __init__(self) -> None: ...\n')
|
|
598
|
+
f.write('\n')
|
|
599
|
+
# Actual implementation signature
|
|
600
|
+
f.write(' def __init__(self, *args: Any, **kwargs: Any) -> None:\n')
|
|
601
|
+
f.write(f' """Initialize {class_name_inner} instance"""\n')
|
|
602
|
+
f.write(' ...\n\n')
|
|
603
|
+
elif constructors and len(constructors) == 1:
|
|
604
|
+
# Single constructor
|
|
605
|
+
param_types = constructors[0].get('params', [])
|
|
606
|
+
if param_types:
|
|
607
|
+
param_list = ['self']
|
|
608
|
+
for i, ptype in enumerate(param_types):
|
|
609
|
+
py_type = self._cpp_to_python_type(ptype)
|
|
610
|
+
param_list.append(f'arg{i}: {py_type}')
|
|
611
|
+
params_str = ', '.join(param_list)
|
|
612
|
+
f.write(f' def __init__({params_str}) -> None:\n')
|
|
613
|
+
else:
|
|
614
|
+
f.write(f' def __init__(self) -> None:\n')
|
|
615
|
+
f.write(f' """Initialize {class_name_inner} instance"""\n')
|
|
616
|
+
f.write(' ...\n\n')
|
|
617
|
+
else:
|
|
618
|
+
# Fallback - generic constructor
|
|
619
|
+
f.write(' def __init__(self, *args: Any, **kwargs: Any) -> None:\n')
|
|
620
|
+
f.write(f' """Initialize {class_name_inner} instance"""\n')
|
|
621
|
+
f.write(' ...\n\n')
|
|
586
622
|
|
|
587
623
|
# Generate methods
|
|
588
624
|
methods = cls.get('methods', [])
|
|
@@ -645,6 +681,52 @@ endif()
|
|
|
645
681
|
|
|
646
682
|
f.write('\n\n')
|
|
647
683
|
|
|
684
|
+
# v2.4.3: Generate CppApi class with overloaded include() methods
|
|
685
|
+
# This is the KEY to making VSCode autocomplete work for module.Class
|
|
686
|
+
f.write('# CppApi with typed include() overloads for each module\n')
|
|
687
|
+
f.write('class CppApi:\n')
|
|
688
|
+
f.write(' """C++ API Manager with typed module loading.\n\n')
|
|
689
|
+
f.write(' The include() method returns a module wrapper with full type hints\n')
|
|
690
|
+
f.write(' for VSCode/PyCharm autocomplete support.\n')
|
|
691
|
+
f.write(' """\n\n')
|
|
692
|
+
|
|
693
|
+
f.write(' def __init__(self, project_root: Optional[str] = None, auto_update: bool = True) -> None:\n')
|
|
694
|
+
f.write(' """Initialize CppApi.\n\n')
|
|
695
|
+
f.write(' Args:\n')
|
|
696
|
+
f.write(' project_root: Path to project root (default: auto-detect)\n')
|
|
697
|
+
f.write(' auto_update: Whether to auto-rebuild on source changes\n')
|
|
698
|
+
f.write(' """\n')
|
|
699
|
+
f.write(' ...\n\n')
|
|
700
|
+
|
|
701
|
+
# Generate overloaded include() methods for each module
|
|
702
|
+
for module_name, _ in modules.items():
|
|
703
|
+
wrapper_class = f"{module_name.capitalize()}ModuleWrapper"
|
|
704
|
+
f.write(' @overload\n')
|
|
705
|
+
f.write(f' def include(self, module_name: str = "{module_name}", auto_update: Optional[bool] = None) -> {wrapper_class}: ...\n\n')
|
|
706
|
+
|
|
707
|
+
# Fallback overload for unknown modules
|
|
708
|
+
f.write(' @overload\n')
|
|
709
|
+
f.write(' def include(self, module_name: str, auto_update: Optional[bool] = None) -> Any: ...\n\n')
|
|
710
|
+
|
|
711
|
+
# Actual implementation signature
|
|
712
|
+
f.write(' def include(self, module_name: str, auto_update: Optional[bool] = None) -> Any:\n')
|
|
713
|
+
f.write(' """Load a C++ module.\n\n')
|
|
714
|
+
f.write(' Args:\n')
|
|
715
|
+
f.write(' module_name: Name of the module to load\n')
|
|
716
|
+
f.write(' auto_update: Override auto-update setting for this module\n\n')
|
|
717
|
+
f.write(' Returns:\n')
|
|
718
|
+
f.write(' ModuleWrapper with access to C++ classes, functions, and structs\n')
|
|
719
|
+
f.write(' """\n')
|
|
720
|
+
f.write(' ...\n\n')
|
|
721
|
+
|
|
722
|
+
f.write(' def rebuild(self, verbose: bool = False) -> bool:\n')
|
|
723
|
+
f.write(' """Rebuild all C++ modules."""\n')
|
|
724
|
+
f.write(' ...\n\n')
|
|
725
|
+
|
|
726
|
+
f.write(' def list_modules(self) -> List[str]:\n')
|
|
727
|
+
f.write(' """List available modules."""\n')
|
|
728
|
+
f.write(' ...\n')
|
|
729
|
+
|
|
648
730
|
if verbose:
|
|
649
731
|
print(f"Generated VSCode IntelliSense stubs: {pyi_file}")
|
|
650
732
|
|
|
@@ -728,25 +810,61 @@ endif()
|
|
|
728
810
|
else:
|
|
729
811
|
f.write(f' """C++ class: {class_name}"""\n\n')
|
|
730
812
|
|
|
731
|
-
# Constructor with
|
|
732
|
-
|
|
733
|
-
if
|
|
734
|
-
|
|
735
|
-
for
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
813
|
+
# v2.4.3: Constructor overloads with parameter types
|
|
814
|
+
constructors = cls.get('constructors', [])
|
|
815
|
+
if constructors and len(constructors) > 1:
|
|
816
|
+
# Multiple constructors - use @overload
|
|
817
|
+
for ctor in constructors:
|
|
818
|
+
param_types = ctor.get('params', [])
|
|
819
|
+
f.write(' @overload\n')
|
|
820
|
+
if param_types:
|
|
821
|
+
param_list = ['self']
|
|
822
|
+
for i, ptype in enumerate(param_types):
|
|
823
|
+
py_type = self._cpp_to_python_type(ptype)
|
|
824
|
+
param_list.append(f'arg{i}: {py_type}')
|
|
825
|
+
params_str = ', '.join(param_list)
|
|
826
|
+
f.write(f' def __init__({params_str}) -> None: ...\n')
|
|
742
827
|
else:
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
else:
|
|
828
|
+
f.write(f' def __init__(self) -> None: ...\n')
|
|
829
|
+
f.write('\n')
|
|
830
|
+
# Actual implementation signature
|
|
747
831
|
f.write(f' def __init__(self, *args: Any, **kwargs: Any) -> None:\n')
|
|
748
|
-
|
|
749
|
-
|
|
832
|
+
f.write(f' """Initialize {class_name} instance."""\n')
|
|
833
|
+
f.write(' ...\n\n')
|
|
834
|
+
elif constructors and len(constructors) == 1:
|
|
835
|
+
# Single constructor
|
|
836
|
+
param_types = constructors[0].get('params', [])
|
|
837
|
+
if param_types:
|
|
838
|
+
param_list = ['self']
|
|
839
|
+
for i, ptype in enumerate(param_types):
|
|
840
|
+
py_type = self._cpp_to_python_type(ptype)
|
|
841
|
+
param_list.append(f'arg{i}: {py_type}')
|
|
842
|
+
params_str = ', '.join(param_list)
|
|
843
|
+
f.write(f' def __init__({params_str}) -> None:\n')
|
|
844
|
+
else:
|
|
845
|
+
f.write(f' def __init__(self) -> None:\n')
|
|
846
|
+
f.write(f' """Initialize {class_name} instance."""\n')
|
|
847
|
+
f.write(' ...\n\n')
|
|
848
|
+
else:
|
|
849
|
+
# Fallback: legacy format or no constructor info
|
|
850
|
+
constructor_params = cls.get('constructor_params', [])
|
|
851
|
+
if constructor_params:
|
|
852
|
+
param_list = ['self']
|
|
853
|
+
for param in constructor_params:
|
|
854
|
+
param_name = param.get('name', 'arg')
|
|
855
|
+
param_type = self._cpp_to_python_type(param.get('type', 'Any'))
|
|
856
|
+
param_default = param.get('default', None)
|
|
857
|
+
if param_default:
|
|
858
|
+
py_default = self._convert_cpp_default(param_default, param_type)
|
|
859
|
+
param_list.append(f'{param_name}: {param_type} = {py_default}')
|
|
860
|
+
else:
|
|
861
|
+
param_list.append(f'{param_name}: {param_type}')
|
|
862
|
+
params_str = ', '.join(param_list)
|
|
863
|
+
f.write(f' def __init__({params_str}) -> None:\n')
|
|
864
|
+
else:
|
|
865
|
+
f.write(f' def __init__(self, *args: Any, **kwargs: Any) -> None:\n')
|
|
866
|
+
f.write(f' """Initialize {class_name} instance."""\n')
|
|
867
|
+
f.write(' ...\n\n')
|
|
750
868
|
|
|
751
869
|
# Methods
|
|
752
870
|
methods = cls.get('methods', [])
|
|
@@ -395,7 +395,26 @@ ModuleDescriptor API::parse_cp_file(const std::string& filepath) {
|
|
|
395
395
|
std::string mtrim = trim(mline);
|
|
396
396
|
if (mtrim.empty()) continue;
|
|
397
397
|
|
|
398
|
-
|
|
398
|
+
// v2.4.3: Parse CONSTRUCTOR(type1, type2, ...) for parametrized constructors
|
|
399
|
+
if (mtrim.find("CONSTRUCTOR") != std::string::npos) {
|
|
400
|
+
size_t c_start = mtrim.find('(');
|
|
401
|
+
size_t c_end = mtrim.rfind(')');
|
|
402
|
+
if (c_start != std::string::npos && c_end != std::string::npos) {
|
|
403
|
+
std::string params_str = mtrim.substr(c_start + 1, c_end - c_start - 1);
|
|
404
|
+
ConstructorInfo ctor;
|
|
405
|
+
if (!params_str.empty()) {
|
|
406
|
+
auto params = split(params_str, ',');
|
|
407
|
+
for (auto& p : params) {
|
|
408
|
+
std::string param_type = trim(p);
|
|
409
|
+
if (!param_type.empty()) {
|
|
410
|
+
ctor.param_types.push_back(param_type);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
cb.constructors.push_back(ctor);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
else if (mtrim.find("METHOD") != std::string::npos) {
|
|
399
418
|
size_t m_start = mtrim.find('(');
|
|
400
419
|
size_t m_end = mtrim.find(')');
|
|
401
420
|
if (m_start != std::string::npos && m_end != std::string::npos) {
|
|
@@ -594,7 +613,25 @@ std::string API::generate_class_bindings(const ClassBinding& cls, const ModuleDe
|
|
|
594
613
|
|
|
595
614
|
code << " py::class_<" << cls.class_name << ">("
|
|
596
615
|
<< mod.module_name << "_module, \"" << cls.class_name << "\")\n";
|
|
597
|
-
|
|
616
|
+
|
|
617
|
+
// v2.4.3: Generate all constructor overloads from CONSTRUCTOR() entries
|
|
618
|
+
if (cls.constructors.empty()) {
|
|
619
|
+
// Backward compatibility: default constructor if none specified
|
|
620
|
+
code << " .def(py::init<>())";
|
|
621
|
+
} else {
|
|
622
|
+
bool first = true;
|
|
623
|
+
for (const auto& ctor : cls.constructors) {
|
|
624
|
+
if (!first) code << "\n";
|
|
625
|
+
first = false;
|
|
626
|
+
|
|
627
|
+
code << " .def(py::init<";
|
|
628
|
+
for (size_t i = 0; i < ctor.param_types.size(); ++i) {
|
|
629
|
+
if (i > 0) code << ", ";
|
|
630
|
+
code << ctor.param_types[i];
|
|
631
|
+
}
|
|
632
|
+
code << ">())";
|
|
633
|
+
}
|
|
634
|
+
}
|
|
598
635
|
|
|
599
636
|
// Bind Initialize static method (factory method)
|
|
600
637
|
code << "\n .def_static(\"Initialize\", []() { return " << cls.class_name << "(); })";
|
|
@@ -1141,7 +1178,7 @@ std::string API::generate_registry_json(const std::vector<ModuleDescriptor>& mod
|
|
|
1141
1178
|
}
|
|
1142
1179
|
json << " ],\n";
|
|
1143
1180
|
|
|
1144
|
-
// Add classes with methods and documentation
|
|
1181
|
+
// Add classes with methods, constructors, and documentation
|
|
1145
1182
|
json << " \"classes\": [\n";
|
|
1146
1183
|
for (size_t j = 0; j < mod.classes.size(); ++j) {
|
|
1147
1184
|
const auto& cls = mod.classes[j];
|
|
@@ -1150,6 +1187,27 @@ std::string API::generate_registry_json(const std::vector<ModuleDescriptor>& mod
|
|
|
1150
1187
|
if (!cls.documentation.empty()) {
|
|
1151
1188
|
json << ",\n \"doc\": \"" << replace_all(cls.documentation, "\"", "\\\"") << "\"";
|
|
1152
1189
|
}
|
|
1190
|
+
|
|
1191
|
+
// v2.4.3: Add constructor signatures
|
|
1192
|
+
json << ",\n \"constructors\": [\n";
|
|
1193
|
+
if (cls.constructors.empty()) {
|
|
1194
|
+
// Default constructor
|
|
1195
|
+
json << " {\"params\": []}\n";
|
|
1196
|
+
} else {
|
|
1197
|
+
for (size_t k = 0; k < cls.constructors.size(); ++k) {
|
|
1198
|
+
const auto& ctor = cls.constructors[k];
|
|
1199
|
+
json << " {\"params\": [";
|
|
1200
|
+
for (size_t p = 0; p < ctor.param_types.size(); ++p) {
|
|
1201
|
+
json << "\"" << ctor.param_types[p] << "\"";
|
|
1202
|
+
if (p < ctor.param_types.size() - 1) json << ", ";
|
|
1203
|
+
}
|
|
1204
|
+
json << "]}";
|
|
1205
|
+
if (k < cls.constructors.size() - 1) json << ",";
|
|
1206
|
+
json << "\n";
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
json << " ]";
|
|
1210
|
+
|
|
1153
1211
|
json << ",\n \"methods\": [\n";
|
|
1154
1212
|
for (size_t k = 0; k < cls.methods.size(); ++k) {
|
|
1155
1213
|
const auto& method = cls.methods[k];
|
|
@@ -93,12 +93,18 @@ struct FieldInfo {
|
|
|
93
93
|
std::string documentation;
|
|
94
94
|
};
|
|
95
95
|
|
|
96
|
+
// v2.4.3: Constructor parameter types
|
|
97
|
+
struct ConstructorInfo {
|
|
98
|
+
std::vector<std::string> param_types; // e.g., ["double", "double"] for Vector2D(double, double)
|
|
99
|
+
};
|
|
100
|
+
|
|
96
101
|
struct ClassBinding {
|
|
97
102
|
std::string module_name;
|
|
98
103
|
std::string class_name;
|
|
99
104
|
std::vector<std::pair<std::string, std::string>> params;
|
|
100
105
|
std::vector<std::string> methods; // Method names to bind
|
|
101
106
|
std::vector<std::string> fields; // Field names to bind
|
|
107
|
+
std::vector<ConstructorInfo> constructors; // v2.4.3: Constructor overloads
|
|
102
108
|
bool auto_bind_all; // Bind all methods automatically
|
|
103
109
|
std::string documentation; // Class documentation from DOC()
|
|
104
110
|
std::map<std::string, std::string> method_docs; // Method-specific docs: method_name -> doc
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "IncludeCPP"
|
|
7
|
-
version = "2.4.
|
|
7
|
+
version = "2.4.4"
|
|
8
8
|
description = "Professional C++ Python bindings with type-generic templates, pystubs and native threading"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text(encoding="utf-8")
|
|
|
6
6
|
|
|
7
7
|
setup(
|
|
8
8
|
name="IncludeCPP",
|
|
9
|
-
version="2.4.
|
|
9
|
+
version="2.4.4",
|
|
10
10
|
author="IncludeCPP Team",
|
|
11
11
|
author_email="contact@includecpp.dev",
|
|
12
12
|
description="Professional C++ Python bindings with type-generic templates and native threading",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|