Skip to content

Commit a966d17

Browse files
committed
MANY CHANGES (possible revert)
1 parent d9cdc20 commit a966d17

60 files changed

Lines changed: 67802 additions & 852 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-macos.yml

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
- name: Checkout code
1414
uses: actions/checkout@v4
1515

16-
- name: Set up Python
16+
- name: Set up Python (pinned)
1717
uses: actions/setup-python@v5
1818
with:
19-
python-version: '3.13'
19+
python-version: '3.13.7'
2020
cache: 'pip'
2121

2222
- name: Install dependencies
@@ -46,37 +46,9 @@ jobs:
4646
4747
pip install -r requirements-build.txt
4848
49-
echo "Installing PyInstaller (build tool)..."
50-
# Use latest PyInstaller for Python 3.13 compatibility (6.10.0+ required)
51-
pip install --upgrade pyinstaller
52-
echo "PyInstaller version:"
49+
echo "PyInstaller version (pinned from requirements-build.txt):"
5350
pyinstaller --version
5451
55-
# Verify PyInstaller version is >= 6.10.0 (required for Python 3.13 support)
56-
PYINSTALLER_VERSION=$(pyinstaller --version 2>&1 | head -n1 | tr -d ' ')
57-
echo "Checking PyInstaller version: $PYINSTALLER_VERSION"
58-
# Extract version number (e.g., "6.10.0" from "6.10.0" or "6.10.0.dev0")
59-
VERSION_NUM=$(echo "$PYINSTALLER_VERSION" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
60-
if [ -z "$VERSION_NUM" ]; then
61-
echo "Error: Could not parse PyInstaller version from: $PYINSTALLER_VERSION"
62-
exit 1
63-
fi
64-
echo "Parsed version: $VERSION_NUM"
65-
# Compare version using Python (packaging is usually available, but use simple comparison as fallback)
66-
echo "import sys" > /tmp/check_pyinstaller.py
67-
echo "v = sys.argv[1].split('.')" >> /tmp/check_pyinstaller.py
68-
echo "major, minor, patch = int(v[0]), int(v[1]), int(v[2])" >> /tmp/check_pyinstaller.py
69-
echo "required = (6, 10, 0)" >> /tmp/check_pyinstaller.py
70-
echo "if (major, minor, patch) < required:" >> /tmp/check_pyinstaller.py
71-
echo " print(f'Error: PyInstaller {major}.{minor}.{patch} is too old. Need >= 6.10.0 for Python 3.13 support.')" >> /tmp/check_pyinstaller.py
72-
echo " sys.exit(1)" >> /tmp/check_pyinstaller.py
73-
echo "print(f'✅ PyInstaller version {major}.{minor}.{patch} meets requirement (>= 6.10.0)')" >> /tmp/check_pyinstaller.py
74-
python /tmp/check_pyinstaller.py "$VERSION_NUM" || {
75-
echo "Error: PyInstaller version must be >= 6.10.0 for Python 3.13 support"
76-
exit 1
77-
}
78-
rm -f /tmp/check_pyinstaller.py
79-
8052
echo "Installing Playwright browsers (for testing, not bundled)..."
8153
python -m playwright install chromium
8254

.github/workflows/build-windows.yml

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ jobs:
2424
Write-Host "Contents of root directory:"
2525
Get-ChildItem -ErrorAction SilentlyContinue | Select-Object Name, Length | Format-Table
2626
27-
- name: Set up Python
27+
- name: Set up Python (pinned)
2828
uses: actions/setup-python@v5
2929
with:
30-
python-version: '3.13'
30+
python-version: '3.13.7'
3131
cache: 'pip'
3232

3333
- name: Install dependencies
@@ -57,26 +57,9 @@ jobs:
5757
5858
pip install -r requirements-build.txt
5959
60-
Write-Host "Installing PyInstaller (build tool)..."
61-
# Use latest PyInstaller for Python 3.13 compatibility (6.10.0+ required)
62-
pip install --upgrade pyinstaller
63-
Write-Host "PyInstaller version:"
60+
Write-Host "PyInstaller version (pinned from requirements-build.txt):"
6461
pyinstaller --version
6562
66-
# Verify PyInstaller version is >= 6.10.0 (required for Python 3.13 support)
67-
$pyinstallerVersion = (pyinstaller --version).Trim()
68-
Write-Host "Checking PyInstaller version: $pyinstallerVersion"
69-
$versionParts = $pyinstallerVersion -split '\.'
70-
$major = [int]$versionParts[0]
71-
$minor = [int]$versionParts[1]
72-
$patch = [int]$versionParts[2]
73-
74-
if ($major -lt 6 -or ($major -eq 6 -and $minor -lt 10)) {
75-
Write-Error "PyInstaller version must be >= 6.10.0 for Python 3.13 support. Found: $pyinstallerVersion"
76-
exit 1
77-
}
78-
Write-Host "[OK] PyInstaller version check passed (>= 6.10.0)"
79-
8063
Write-Host "Installing Playwright browsers (for testing, not bundled)..."
8164
python -m playwright install chromium
8265

.github/workflows/build.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: Build (Pinned)
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ "main", "v1" ]
7+
pull_request:
8+
branches: [ "main", "v1" ]
9+
10+
jobs:
11+
build:
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
os: [ macos-latest, windows-latest ]
16+
17+
runs-on: ${{ matrix.os }}
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Set up Python (pinned)
24+
uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.13.7"
27+
28+
- name: Upgrade pip tooling
29+
run: python -m pip install --upgrade pip setuptools wheel
30+
31+
- name: Install pinned runtime + build deps
32+
run: |
33+
python -m pip install --no-input -r requirements-build.txt
34+
python -m pip install --no-input -r requirements-dev.txt
35+
36+
- name: Build with PyInstaller (pinned spec)
37+
run: python -m PyInstaller build/pyinstaller.spec --noconfirm
38+

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.11.10
1+
3.13.7
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
<#
2+
.Synopsis
3+
Activate a Python virtual environment for the current PowerShell session.
4+
5+
.Description
6+
Pushes the python executable for a virtual environment to the front of the
7+
$Env:PATH environment variable and sets the prompt to signify that you are
8+
in a Python virtual environment. Makes use of the command line switches as
9+
well as the `pyvenv.cfg` file values present in the virtual environment.
10+
11+
.Parameter VenvDir
12+
Path to the directory that contains the virtual environment to activate. The
13+
default value for this is the parent of the directory that the Activate.ps1
14+
script is located within.
15+
16+
.Parameter Prompt
17+
The prompt prefix to display when this virtual environment is activated. By
18+
default, this prompt is the name of the virtual environment folder (VenvDir)
19+
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
20+
21+
.Example
22+
Activate.ps1
23+
Activates the Python virtual environment that contains the Activate.ps1 script.
24+
25+
.Example
26+
Activate.ps1 -Verbose
27+
Activates the Python virtual environment that contains the Activate.ps1 script,
28+
and shows extra information about the activation as it executes.
29+
30+
.Example
31+
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
32+
Activates the Python virtual environment located in the specified location.
33+
34+
.Example
35+
Activate.ps1 -Prompt "MyPython"
36+
Activates the Python virtual environment that contains the Activate.ps1 script,
37+
and prefixes the current prompt with the specified string (surrounded in
38+
parentheses) while the virtual environment is active.
39+
40+
.Notes
41+
On Windows, it may be required to enable this Activate.ps1 script by setting the
42+
execution policy for the user. You can do this by issuing the following PowerShell
43+
command:
44+
45+
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
46+
47+
For more information on Execution Policies:
48+
https://go.microsoft.com/fwlink/?LinkID=135170
49+
50+
#>
51+
Param(
52+
[Parameter(Mandatory = $false)]
53+
[String]
54+
$VenvDir,
55+
[Parameter(Mandatory = $false)]
56+
[String]
57+
$Prompt
58+
)
59+
60+
<# Function declarations --------------------------------------------------- #>
61+
62+
<#
63+
.Synopsis
64+
Remove all shell session elements added by the Activate script, including the
65+
addition of the virtual environment's Python executable from the beginning of
66+
the PATH variable.
67+
68+
.Parameter NonDestructive
69+
If present, do not remove this function from the global namespace for the
70+
session.
71+
72+
#>
73+
function global:deactivate ([switch]$NonDestructive) {
74+
# Revert to original values
75+
76+
# The prior prompt:
77+
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
78+
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
79+
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
80+
}
81+
82+
# The prior PYTHONHOME:
83+
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
84+
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
85+
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
86+
}
87+
88+
# The prior PATH:
89+
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
90+
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
91+
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
92+
}
93+
94+
# Just remove the VIRTUAL_ENV altogether:
95+
if (Test-Path -Path Env:VIRTUAL_ENV) {
96+
Remove-Item -Path env:VIRTUAL_ENV
97+
}
98+
99+
# Just remove VIRTUAL_ENV_PROMPT altogether.
100+
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
101+
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
102+
}
103+
104+
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
105+
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
106+
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
107+
}
108+
109+
# Leave deactivate function in the global namespace if requested:
110+
if (-not $NonDestructive) {
111+
Remove-Item -Path function:deactivate
112+
}
113+
}
114+
115+
<#
116+
.Description
117+
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
118+
given folder, and returns them in a map.
119+
120+
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
121+
two strings separated by `=` (with any amount of whitespace surrounding the =)
122+
then it is considered a `key = value` line. The left hand string is the key,
123+
the right hand is the value.
124+
125+
If the value starts with a `'` or a `"` then the first and last character is
126+
stripped from the value before being captured.
127+
128+
.Parameter ConfigDir
129+
Path to the directory that contains the `pyvenv.cfg` file.
130+
#>
131+
function Get-PyVenvConfig(
132+
[String]
133+
$ConfigDir
134+
) {
135+
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
136+
137+
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
138+
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
139+
140+
# An empty map will be returned if no config file is found.
141+
$pyvenvConfig = @{ }
142+
143+
if ($pyvenvConfigPath) {
144+
145+
Write-Verbose "File exists, parse `key = value` lines"
146+
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
147+
148+
$pyvenvConfigContent | ForEach-Object {
149+
$keyval = $PSItem -split "\s*=\s*", 2
150+
if ($keyval[0] -and $keyval[1]) {
151+
$val = $keyval[1]
152+
153+
# Remove extraneous quotations around a string value.
154+
if ("'""".Contains($val.Substring(0, 1))) {
155+
$val = $val.Substring(1, $val.Length - 2)
156+
}
157+
158+
$pyvenvConfig[$keyval[0]] = $val
159+
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
160+
}
161+
}
162+
}
163+
return $pyvenvConfig
164+
}
165+
166+
167+
<# Begin Activate script --------------------------------------------------- #>
168+
169+
# Determine the containing directory of this script
170+
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
171+
$VenvExecDir = Get-Item -Path $VenvExecPath
172+
173+
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
174+
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
175+
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
176+
177+
# Set values required in priority: CmdLine, ConfigFile, Default
178+
# First, get the location of the virtual environment, it might not be
179+
# VenvExecDir if specified on the command line.
180+
if ($VenvDir) {
181+
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
182+
}
183+
else {
184+
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
185+
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
186+
Write-Verbose "VenvDir=$VenvDir"
187+
}
188+
189+
# Next, read the `pyvenv.cfg` file to determine any required value such
190+
# as `prompt`.
191+
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
192+
193+
# Next, set the prompt from the command line, or the config file, or
194+
# just use the name of the virtual environment folder.
195+
if ($Prompt) {
196+
Write-Verbose "Prompt specified as argument, using '$Prompt'"
197+
}
198+
else {
199+
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
200+
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
201+
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
202+
$Prompt = $pyvenvCfg['prompt'];
203+
}
204+
else {
205+
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
206+
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
207+
$Prompt = Split-Path -Path $venvDir -Leaf
208+
}
209+
}
210+
211+
Write-Verbose "Prompt = '$Prompt'"
212+
Write-Verbose "VenvDir='$VenvDir'"
213+
214+
# Deactivate any currently active virtual environment, but leave the
215+
# deactivate function in place.
216+
deactivate -nondestructive
217+
218+
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
219+
# that there is an activated venv.
220+
$env:VIRTUAL_ENV = $VenvDir
221+
222+
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
223+
224+
Write-Verbose "Setting prompt to '$Prompt'"
225+
226+
# Set the prompt to include the env name
227+
# Make sure _OLD_VIRTUAL_PROMPT is global
228+
function global:_OLD_VIRTUAL_PROMPT { "" }
229+
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
230+
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
231+
232+
function global:prompt {
233+
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
234+
_OLD_VIRTUAL_PROMPT
235+
}
236+
$env:VIRTUAL_ENV_PROMPT = $Prompt
237+
}
238+
239+
# Clear PYTHONHOME
240+
if (Test-Path -Path Env:PYTHONHOME) {
241+
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
242+
Remove-Item -Path Env:PYTHONHOME
243+
}
244+
245+
# Add the venv to the PATH
246+
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
247+
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"

0 commit comments

Comments
 (0)