Skip to content

Commit f004ff2

Browse files
committed
Support 3.14 Tasks .vscode
* [UPDATE] : .vscode/tasks.json : - modification for Generate doc assets (shell syntax) - modification for Coverage full (shell syntax) - modification for Reinstall guidata/plotpy/sigima dev (shell syntax) - modification for launchng .bat in windows (instanciation of env before with run_with_env.py) - add reinstall_dev.py * [UPDATE] : run_with_env.py (minor modification for path) * [UPDATE] : utils.bat (skip mode) * [UPDATE] : pyproject.toml add exclusion for python venv named : venv* and .venv* * [FIX] : build_inplace.bat and build_wheels.bat in script (work with native python)
1 parent 6215a33 commit f004ff2

5 files changed

Lines changed: 206 additions & 48 deletions

File tree

.vscode/tasks.json

Lines changed: 53 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@
374374
},
375375
{
376376
"label": "🛠️ Generate doc assets",
377-
"command": "${command:python.interpreterPath} scripts/run_with_env.py ${command:python.interpreterPath} -m guidata.utils.genreqs all && ${command:python.interpreterPath} scripts/run_with_env.py ${command:python.interpreterPath} doc/update_validation_status.py",
377+
"command": "${command:python.interpreterPath} scripts/run_with_env.py ${command:python.interpreterPath} -m guidata.utils.genreqs all; if ($?) { ${command:python.interpreterPath} scripts/run_with_env.py ${command:python.interpreterPath} doc/update_validation_status.py }",
378378
"options": {
379379
"cwd": "${workspaceFolder}",
380380
"statusbar": {
@@ -431,7 +431,7 @@
431431
"label": "📊 Coverage full",
432432
"type": "shell",
433433
"windows": {
434-
"command": "${command:python.interpreterPath} -m coverage combine && ${command:python.interpreterPath} -m coverage html && start htmlcov\\index.html",
434+
"command": "${command:python.interpreterPath} -m coverage combine; if ($?) { ${command:python.interpreterPath} -m coverage html; if ($?) { start htmlcov\\index.html } }",
435435
},
436436
"linux": {
437437
"command": "${command:python.interpreterPath} -m coverage combine && ${command:python.interpreterPath} -m coverage html && xdg-open htmlcov/index.html",
@@ -493,15 +493,12 @@
493493
{
494494
"label": "🔁 Reinstall guidata/plotpy/sigima dev",
495495
"type": "shell",
496-
"windows": {
497-
"command": ".venv/scripts/pip uninstall -y guidata plotpy sigima; Remove-Item -Recurse -Force .venv/Lib/site-packages/guidata -ErrorAction SilentlyContinue; Remove-Item -Recurse -Force .venv/Lib/site-packages/plotpy -ErrorAction SilentlyContinue; Remove-Item -Recurse -Force .venv/Lib/site-packages/sigima -ErrorAction SilentlyContinue; .venv/scripts/pip install -e ../guidata; .venv/scripts/pip install -e ../plotpy; .venv/scripts/pip install -e ../sigima",
498-
},
499-
"linux": {
500-
"command": ".venv/bin/pip uninstall -y guidata plotpy sigima && rm -rf .venv/lib/python*/site-packages/guidata && rm -rf .venv/lib/python*/site-packages/plotpy && rm -rf .venv/lib/python*/site-packages/sigima && .venv/bin/pip install -e ../guidata && .venv/bin/pip install -e ../plotpy && .venv/bin/pip install -e ../sigima",
501-
},
502-
"osx": {
503-
"command": ".venv/bin/pip uninstall -y guidata plotpy sigima && rm -rf .venv/lib/python*/site-packages/guidata && rm -rf .venv/lib/python*/site-packages/plotpy && rm -rf .venv/lib/python*/site-packages/sigima && .venv/bin/pip install -e ../guidata && .venv/bin/pip install -e ../plotpy && .venv/bin/pip install -e ../sigima",
504-
},
496+
"command": "${config:python.defaultInterpreterPath}",
497+
"args": [
498+
"scripts/run_with_env.py",
499+
"${config:python.defaultInterpreterPath}",
500+
"${workspaceFolder}/scripts/reinstall_dev.py",
501+
],
505502
"options": {
506503
"cwd": "${workspaceFolder}",
507504
"statusbar": {
@@ -543,9 +540,15 @@
543540
{
544541
"label": "Create executable",
545542
"type": "shell",
546-
"command": "cmd",
543+
"command": "${command:python.interpreterPath}",
544+
"args": [
545+
"scripts/run_with_env.py",
546+
"cmd",
547+
"/c",
548+
"scripts\\build_exe.bat",
549+
],
547550
"options": {
548-
"cwd": "scripts",
551+
"cwd": "${workspaceFolder}",
549552
"env": {
550553
"PYTHON": "${command:python.interpreterPath}",
551554
// "RELEASE": "1",
@@ -555,10 +558,6 @@
555558
"hide": true,
556559
},
557560
},
558-
"args": [
559-
"/c",
560-
"build_exe.bat",
561-
],
562561
"problemMatcher": [],
563562
"group": {
564563
"kind": "build",
@@ -576,9 +575,15 @@
576575
{
577576
"label": "Create installer",
578577
"type": "shell",
579-
"command": "cmd",
578+
"command": "${command:python.interpreterPath}",
579+
"args": [
580+
"scripts/run_with_env.py",
581+
"cmd",
582+
"/c",
583+
"scripts\\build_installer.bat",
584+
],
580585
"options": {
581-
"cwd": "scripts",
586+
"cwd": "${workspaceFolder}",
582587
"env": {
583588
"PYTHON": "${command:python.interpreterPath}",
584589
"UNATTENDED": "1",
@@ -587,10 +592,6 @@
587592
"hide": true,
588593
},
589594
},
590-
"args": [
591-
"/c",
592-
"build_installer.bat",
593-
],
594595
"problemMatcher": [],
595596
"group": {
596597
"kind": "build",
@@ -608,9 +609,9 @@
608609
{
609610
"label": "Build PDF doc",
610611
"type": "shell",
611-
"command": "cmd",
612+
"command": "${command:python.interpreterPath}",
612613
"options": {
613-
"cwd": "scripts",
614+
"cwd": "${workspaceFolder}",
614615
"env": {
615616
"PYTHON": "${command:python.interpreterPath}",
616617
"QT_COLOR_MODE": "light",
@@ -622,8 +623,10 @@
622623
},
623624
},
624625
"args": [
626+
"scripts/run_with_env.py",
627+
"cmd",
625628
"/c",
626-
"build_doc.bat",
629+
"scripts\\build_doc.bat"
627630
],
628631
"problemMatcher": [],
629632
"group": {
@@ -703,9 +706,15 @@
703706
{
704707
"label": "GitHub Pages: build",
705708
"type": "shell",
706-
"command": "cmd",
709+
"command": "${command:python.interpreterPath}",
710+
"args": [
711+
"scripts/run_with_env.py",
712+
"cmd",
713+
"/c",
714+
"scripts\\build_ghpages.bat",
715+
],
707716
"options": {
708-
"cwd": "scripts",
717+
"cwd": "${workspaceFolder}",
709718
"env": {
710719
"PYTHON": "${command:python.interpreterPath}",
711720
"QT_COLOR_MODE": "light",
@@ -716,10 +725,6 @@
716725
"hide": true,
717726
},
718727
},
719-
"args": [
720-
"/c",
721-
"build_ghpages.bat",
722-
],
723728
"problemMatcher": [],
724729
"group": {
725730
"kind": "build",
@@ -741,9 +746,15 @@
741746
{
742747
"label": "GitHub Pages: preview",
743748
"type": "shell",
744-
"command": "cmd",
749+
"command": "${command:python.interpreterPath}",
750+
"args": [
751+
"scripts/run_with_env.py",
752+
"cmd",
753+
"/c",
754+
"scripts\\preview_ghpages.bat",
755+
],
745756
"options": {
746-
"cwd": "scripts",
757+
"cwd": "${workspaceFolder}",
747758
"env": {
748759
"PYTHON": "${command:python.interpreterPath}",
749760
"QT_COLOR_MODE": "light",
@@ -754,10 +765,6 @@
754765
"hide": true,
755766
},
756767
},
757-
"args": [
758-
"/c",
759-
"preview_ghpages.bat",
760-
],
761768
"problemMatcher": [],
762769
"group": {
763770
"kind": "build",
@@ -816,9 +823,15 @@
816823
{
817824
"label": "Build Python packages",
818825
"type": "shell",
819-
"command": "cmd",
826+
"command": "${command:python.interpreterPath}",
827+
"args": [
828+
"scripts/run_with_env.py",
829+
"cmd",
830+
"/c",
831+
"scripts\\build_dist.bat",
832+
],
820833
"options": {
821-
"cwd": "scripts",
834+
"cwd": "${workspaceFolder}",
822835
"env": {
823836
"PYTHON": "${command:python.interpreterPath}",
824837
// "RELEASE": "1",
@@ -828,10 +841,6 @@
828841
"hide": true,
829842
},
830843
},
831-
"args": [
832-
"/c",
833-
"build_dist.bat",
834-
],
835844
"problemMatcher": [],
836845
"group": {
837846
"kind": "build",

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ classifiers = [
3131
"Programming Language :: Python :: 3.11",
3232
"Programming Language :: Python :: 3.12",
3333
"Programming Language :: Python :: 3.13",
34+
"Programming Language :: Python :: 3.14",
3435
"Topic :: Scientific/Engineering",
3536
"Topic :: Scientific/Engineering :: Image Processing",
3637
"Topic :: Scientific/Engineering :: Human Machine Interfaces",
@@ -141,7 +142,7 @@ filterwarnings = [
141142
]
142143

143144
[tool.ruff]
144-
exclude = [".git", ".vscode", "build", "dist", "*.ipynb"]
145+
exclude = [".git", ".vscode", "build", "dist", "*.ipynb","venv*",".venv*",]
145146
line-length = 88 # Same as Black.
146147
indent-width = 4 # Same as Black.
147148
target-version = "py39" # Assume Python 3.9.

scripts/reinstall_dev.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# script/reinstall_dev.py
2+
"""
3+
Reinstall multiple local libraries in editable mode for development.
4+
5+
Workflow:
6+
1) Try to uninstall all target libraries in one command (ignore errors if some are not installed).
7+
2) Reinstall each library in editable mode from a sibling folder: ../<library>.
8+
9+
This script uses the same Python interpreter that runs it (sys.executable),
10+
so pip operations happen in the same environment (e.g., your active venv).
11+
"""
12+
13+
from __future__ import annotations
14+
15+
import os
16+
import shutil
17+
import subprocess
18+
import sys
19+
import sysconfig
20+
from typing import Iterable
21+
22+
# Absolute path to the Python executable that runs this script.
23+
# Using sys.executable ensures pip targets the same environment (e.g., your venv).
24+
PY = sys.executable
25+
26+
27+
def run(cmd: list[str]) -> None:
28+
"""
29+
Echo and execute a subprocess command.
30+
Raises:
31+
subprocess.CalledProcessError: if the command returns a non-zero exit code.
32+
"""
33+
print("$", " ".join(cmd), flush=True)
34+
subprocess.check_call(cmd)
35+
36+
37+
def uninstall_many(packages: Iterable[str]) -> None:
38+
"""
39+
Attempt to uninstall multiple packages at once.
40+
If uninstall fails (e.g., a package is not installed), we keep going.
41+
42+
Args:
43+
packages: An iterable of package names (pip distribution names).
44+
"""
45+
pkgs = list(packages)
46+
if not pkgs:
47+
return
48+
try:
49+
run([PY, "-m", "pip", "uninstall", "-y", *pkgs])
50+
except subprocess.CalledProcessError as e:
51+
# Continue even if the uninstall step fails (for one or more packages)
52+
print(f"[WARN] Uninstall returned {e.returncode} — continuing...", flush=True)
53+
54+
55+
def install_editable_many(packages: Iterable[str]) -> None:
56+
"""
57+
Install each package in editable mode from ../<package_dir>.
58+
59+
Assumes your project layout has sibling folders one level up, e.g.:
60+
../guidata
61+
../plotpy
62+
../sigima
63+
64+
Args:
65+
packages: An iterable of package names (also used as directory names).
66+
"""
67+
for pkg in packages:
68+
run([PY, "-m", "pip", "install", "-e", f"../{pkg}"])
69+
70+
71+
def remove_residual_dirs(packages: Iterable[str]) -> None:
72+
"""
73+
Force remove residual package directories from site-packages.
74+
This mimics: rm -rf .venv/Lib/site-packages/<pkg>
75+
to ensure a clean slate before reinstalling.
76+
"""
77+
# Locates site-packages, e.g. .venv/Lib/site-packages
78+
site_packages = sysconfig.get_path("purelib")
79+
80+
for pkg in packages:
81+
target = os.path.join(site_packages, pkg)
82+
if os.path.isdir(target):
83+
print(f"Removing residual directory: {target}", flush=True)
84+
try:
85+
shutil.rmtree(target)
86+
except OSError as e:
87+
print(f"[WARN] Failed to remove {target}: {e}", flush=True)
88+
89+
90+
def reinstall_packages(packages: list[str]) -> None:
91+
"""
92+
High-level orchestration for many packages:
93+
- Uninstall all of them (ignore failures)
94+
- Force remove residual directories from site-packages
95+
- Install each in editable mode
96+
"""
97+
# 1) Uninstall (ignore if not installed)
98+
uninstall_many(packages)
99+
100+
# 2) Force remove residual directories (essential for clean reinstall)
101+
remove_residual_dirs(packages)
102+
103+
# 3) Editable installs
104+
install_editable_many(packages)
105+
106+
107+
if __name__ == "__main__":
108+
# ⭐ Fixed, editable local libraries to manage (edit as needed)
109+
PACKAGES = ["guidata", "plotpy", "sigima"]
110+
111+
print("🏃 Reinstalling editable packages:", ", ".join(PACKAGES))
112+
reinstall_packages(PACKAGES)

scripts/run_with_env.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212

1313
def load_env_file(env_path: str | None = None) -> None:
1414
"""Load environment variables from a .env file."""
15+
# Set a flag to indicate that the environment has been loaded by this script
16+
# This prevents batch scripts (like utils.bat) from reloading .env and overwriting variables
17+
os.environ["DATALAB_ENV_LOADED"] = "1"
18+
1519
if env_path is None:
16-
# Get ".eenv" file from the current directory
20+
# Get ".env" file from the current directory
1721
env_path = Path.cwd() / ".env"
1822
if not Path(env_path).is_file():
1923
raise FileNotFoundError(f"Environment file not found: {env_path}")
@@ -24,8 +28,32 @@ def load_env_file(env_path: str | None = None) -> None:
2428
if not line or line.startswith("#") or "=" not in line:
2529
continue
2630
key, value = line.split("=", 1)
27-
os.environ[key.strip()] = value.strip()
28-
print(f" Loaded variable: {key.strip()}={value.strip()}")
31+
value = os.path.expandvars(value.strip())
32+
33+
# Handle PATH variable specifically:
34+
# 1. Convert relative paths to absolute paths
35+
# 2. Normalize path separators
36+
if key.strip().upper() == "PATH":
37+
paths = value.split(os.pathsep)
38+
abs_paths = []
39+
for p in paths:
40+
p = p.strip()
41+
if not p:
42+
continue
43+
# Check if it looks like a relative path component
44+
# (not starting with drive or root)
45+
# Note: This simple check assumes standard usage in .env
46+
if not os.path.isabs(p) and not p.startswith("%"):
47+
try:
48+
# Resolve relative to .env file directory
49+
p = str((Path(env_path).parent / p).resolve())
50+
except Exception:
51+
pass # Keep as is if resolution fails
52+
abs_paths.append(os.path.normpath(p))
53+
value = os.pathsep.join(abs_paths)
54+
55+
os.environ[key.strip()] = value
56+
print(f" Loaded variable: {key.strip()}={value}")
2957

3058

3159
def execute_command(command: list[str]) -> int:

0 commit comments

Comments
 (0)