Skip to content

Commit d069665

Browse files
committed
Merge branch 'develop' into synpy-1636-move-to-electron
2 parents dca8111 + a557de9 commit d069665

220 files changed

Lines changed: 44331 additions & 3901 deletions

File tree

Some content is hidden

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

.github/scripts/delete_evaluations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from synapseclient import Evaluation, Synapse
55

66
syn = Synapse()
7-
syn.login()
7+
syn.login(profile=None)
88

99
# Maximum number of concurrent deletion operations
1010
MAX_CONCURRENT_DELETIONS = 5

.github/scripts/delete_projects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from synapseclient import Synapse
55

66
syn = Synapse()
7-
syn.login()
7+
syn.login(profile=None)
88

99
# Maximum number of concurrent deletion operations
1010
MAX_CONCURRENT_DELETIONS = 5

.github/scripts/delete_teams.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from synapseclient import Synapse
55

66
syn = Synapse()
7-
syn.login()
7+
syn.login(profile=None)
88

99
# Maximum number of concurrent team deletions
1010
MAX_CONCURRENT_DELETIONS = 5

.github/scripts/empty_trash.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from synapseclient import Synapse
55

66
syn = Synapse()
7-
syn.login()
7+
syn.login(profile=None)
88

99
# Maximum number of concurrent deletion operations
1010
MAX_CONCURRENT_DELETIONS = 5

.github/workflows/build.yml

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,27 @@ concurrency:
3434
cancel-in-progress: true
3535

3636
jobs:
37-
3837
pre-commit:
3938
runs-on: ubuntu-latest
4039
steps:
41-
- uses: actions/checkout@v4
42-
- uses: actions/setup-python@v5
43-
with:
44-
python-version: '3.13'
45-
- uses: pre-commit/action@v3.0.1
40+
- uses: actions/checkout@v4
41+
- uses: actions/setup-python@v5
42+
with:
43+
python-version: '3.13'
44+
- uses: pre-commit/action@v3.0.1
4645

4746
# run unit (and integration tests if account secrets available) on our build matrix
4847
test:
4948
needs: [pre-commit]
5049

5150
strategy:
51+
fail-fast: false
5252
matrix:
5353
os: [ubuntu-22.04, macos-13, windows-2022]
5454

5555
# if changing the below change the run-integration-tests versions and the check-deploy versions
5656
# Make sure that we are running the integration tests on the first and last versions of the matrix
57-
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
57+
python: ['3.10', '3.11', '3.12', '3.13', '3.14']
5858

5959
runs-on: ${{ matrix.os }}
6060

@@ -83,15 +83,15 @@ jobs:
8383
path: |
8484
${{ steps.get-dependencies.outputs.site_packages_loc }}
8585
${{ steps.get-dependencies.outputs.site_bin_dir }}
86-
key: ${{ runner.os }}-${{ matrix.python }}-build-${{ env.cache-name }}-${{ hashFiles('setup.py') }}-v24
86+
key: ${{ runner.os }}-${{ matrix.python }}-build-${{ env.cache-name }}-${{ hashFiles('setup.py') }}-v29
8787

8888
- name: Install py-dependencies
8989
if: steps.cache-dependencies.outputs.cache-hit != 'true'
9090
shell: bash
9191
run: |
9292
python -m pip install --upgrade pip
9393
94-
pip install -e ".[boto3,pandas,pysftp,tests]"
94+
pip install -e ".[boto3,pandas,pysftp,tests,curator]"
9595
9696
# ensure that numpy c extensions are installed on windows
9797
# https://stackoverflow.com/a/59346525
@@ -108,7 +108,7 @@ jobs:
108108
pytest -sv --cov-append --cov=. --cov-report xml tests/unit
109109
- name: Check for Secret availability
110110
id: secret-check
111-
if: ${{ contains(fromJSON('["3.9"]'), matrix.python) || contains(fromJSON('["3.13"]'), matrix.python) }}
111+
if: ${{ contains(fromJSON('["3.10"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python) }}
112112
# perform secret check & put boolean result as an output
113113
shell: bash
114114
run: |
@@ -124,17 +124,48 @@ jobs:
124124
echo "synapse_pat_available=true" >> $GITHUB_OUTPUT;
125125
fi
126126
127+
- name: Download Failed Tests from Previous Attempt
128+
if: ${{ github.run_attempt > 1 && (contains(fromJSON('["3.10"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true'}}
129+
uses: actions/download-artifact@v4
130+
with:
131+
name: failed-tests-${{ matrix.os }}-${{ matrix.python }}
132+
continue-on-error: true
133+
127134
# run integration tests iff the decryption keys for the test configuration are available.
128135
# they will not be available in pull requests from forks.
129136
# run integration tests on the oldest and newest supported versions of python.
130137
# we don't run on the entire matrix to avoid a 3xN set of concurrent tests against
131138
# the target server where N is the number of supported python versions.
132139
- name: run-integration-tests
140+
id: integration_tests
133141
shell: bash
134142

135143
# keep versions consistent with the first and last from the strategy matrix
136-
if: ${{ (contains(fromJSON('["3.9"]'), matrix.python) || contains(fromJSON('["3.13"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true'}}
144+
if: ${{ (contains(fromJSON('["3.10"]'), matrix.python) || contains(fromJSON('["3.14"]'), matrix.python)) && steps.secret-check.outputs.secrets_available == 'true'}}
137145
run: |
146+
# Set SYNAPSE_PROFILE based on OS and Python version
147+
if [ "${{ startsWith(matrix.os, 'ubuntu') }}" == "true" ]; then
148+
if [ "${{ matrix.python }}" == "3.10" ]; then
149+
export SYNAPSE_PROFILE="TestUbuntuMinimumPython"
150+
elif [ "${{ matrix.python }}" == "3.14" ]; then
151+
export SYNAPSE_PROFILE="TestUbuntuMaximumPython"
152+
fi
153+
elif [ "${{ startsWith(matrix.os, 'windows') }}" == "true" ]; then
154+
if [ "${{ matrix.python }}" == "3.10" ]; then
155+
export SYNAPSE_PROFILE="TestWindowsMinimumPython"
156+
elif [ "${{ matrix.python }}" == "3.14" ]; then
157+
export SYNAPSE_PROFILE="TestWindowsMaximumPython"
158+
fi
159+
elif [ "${{ startsWith(matrix.os, 'macos') }}" == "true" ]; then
160+
if [ "${{ matrix.python }}" == "3.10" ]; then
161+
export SYNAPSE_PROFILE="TestMacosMinimumPython"
162+
elif [ "${{ matrix.python }}" == "3.14" ]; then
163+
export SYNAPSE_PROFILE="TestMacosMaximumPython"
164+
fi
165+
fi
166+
167+
echo "Using SYNAPSE_PROFILE: $SYNAPSE_PROFILE"
168+
138169
# decrypt the encrypted test synapse configuration
139170
openssl aes-256-cbc -K ${{ secrets.encrypted_d17283647768_key }} -iv ${{ secrets.encrypted_d17283647768_iv }} -in test.synapseConfig.enc -out test.synapseConfig -d
140171
mv test.synapseConfig ~/.synapseConfig
@@ -170,21 +201,96 @@ jobs:
170201
# Setup ignore patterns based on Python version
171202
IGNORE_FLAGS="--ignore=tests/integration/synapseclient/test_command_line_client.py"
172203
173-
if [ "${{ matrix.python }}" == "3.9" ]; then
174-
# For min Python version, ignore async tests
175-
IGNORE_FLAGS="$IGNORE_FLAGS --ignore=tests/integration/synapseclient/models/async/"
176-
echo "Running integration tests for Min Python version (3.9) - ignoring async tests"
177-
elif [ "${{ matrix.python }}" == "3.13" ]; then
178-
# For max Python version, ignore synchronous tests
179-
IGNORE_FLAGS="$IGNORE_FLAGS --ignore=tests/integration/synapseclient/models/synchronous/"
180-
echo "Running integration tests for Max Python version (3.13) - ignoring synchronous tests"
181-
fi
204+
# Check if we should run only failed tests from previous attempt
205+
if [[ -f failed_tests.txt && -s failed_tests.txt ]]; then
206+
echo "::notice::Retry attempt ${{ github.run_attempt }} detected - running only previously failed tests"
207+
cat failed_tests.txt
182208
183-
# use loadscope to avoid issues running tests concurrently that share scoped fixtures
184-
pytest -sv --reruns 3 --cov-append --cov=. --cov-report xml tests/integration -n 8 $IGNORE_FLAGS --dist loadscope
209+
# Run only the failed tests
210+
pytest -sv --reruns 3 --cov-append --cov=. --cov-report xml \
211+
--junit-xml=test-results.xml \
212+
-n 8 --dist loadscope \
213+
$(cat failed_tests.txt | tr '\n' ' ')
214+
else
215+
echo "::notice::First attempt or no previous failures - running full integration test suite"
216+
217+
# use loadscope to avoid issues running tests concurrently that share scoped fixtures
218+
pytest -sv --reruns 3 --cov-append --cov=. --cov-report xml \
219+
--junit-xml=test-results.xml \
220+
tests/integration -n 8 $IGNORE_FLAGS --dist loadscope
221+
fi
185222
186223
# Execute the CLI tests in a non-dist way because they were causing some test instability when being run concurrently
187224
pytest -sv --reruns 3 --cov-append --cov=. --cov-report xml tests/integration/synapseclient/test_command_line_client.py
225+
226+
- name: Extract Failed Tests
227+
if: always() && steps.integration_tests.outcome == 'failure'
228+
shell: bash
229+
run: |
230+
python -c "
231+
import xml.etree.ElementTree as ET
232+
import os
233+
tree = ET.parse('test-results.xml')
234+
root = tree.getroot()
235+
failed = []
236+
for testcase in root.iter('testcase'):
237+
if testcase.find('failure') is not None or testcase.find('error') is not None:
238+
classname = testcase.get('classname')
239+
name = testcase.get('name')
240+
file_attr = testcase.get('file')
241+
242+
# Use the file attribute if available, otherwise convert classname
243+
if file_attr:
244+
# file attribute is already in the correct format
245+
test_path = f'{file_attr}::{classname.split(\".\")[-1]}::{name}'
246+
else:
247+
# Convert classname from dot notation to file path
248+
# e.g., 'tests.integration.foo.test_bar.TestClass' -> 'tests/integration/foo/test_bar.py::TestClass'
249+
parts = classname.split('.')
250+
# Find the test file (usually starts with 'test_')
251+
module_parts = []
252+
class_parts = []
253+
found_test_file = False
254+
for part in parts:
255+
if not found_test_file:
256+
module_parts.append(part)
257+
if part.startswith('test_'):
258+
found_test_file = True
259+
else:
260+
class_parts.append(part)
261+
262+
file_path = '/'.join(module_parts) + '.py'
263+
if class_parts:
264+
test_path = f'{file_path}::{\"::\".join(class_parts)}::{name}'
265+
else:
266+
test_path = f'{file_path}::{name}'
267+
268+
failed.append(test_path)
269+
270+
with open('failed_tests.txt', 'w') as f:
271+
f.write('\n'.join(failed))
272+
print(f'Found {len(failed)} failed tests')
273+
for test in failed:
274+
print(f' - {test}')
275+
print(f'Current attempt: ${{ github.run_attempt }}')
276+
"
277+
278+
- name: Upload Failed Tests for Next Attempt
279+
if: always() && steps.integration_tests.outcome == 'failure' && github.run_attempt < 3
280+
uses: actions/upload-artifact@v4
281+
with:
282+
name: failed-tests-${{ matrix.os }}-${{ matrix.python }}
283+
path: failed_tests.txt
284+
retention-days: 2
285+
overwrite: true
286+
287+
- name: Fail job if integration tests failed after all retries
288+
if: always() && steps.integration_tests.outcome == 'failure'
289+
shell: bash
290+
run: |
291+
echo "::error::Integration tests failed after ${{ github.run_attempt }} attempt(s)"
292+
exit 1
293+
188294
- name: Upload coverage report
189295
id: upload_coverage_report
190296
uses: actions/upload-artifact@v4
@@ -201,12 +307,12 @@ jobs:
201307
steps:
202308
- uses: actions/checkout@v4
203309
with:
204-
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
310+
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
205311
- name: Check coverage-report artifact existence
206312
id: check_coverage_report
207313
uses: LIT-Protocol/artifact-exists-action@v0
208314
with:
209-
name: "coverage-report"
315+
name: 'coverage-report'
210316
- name: Download coverage report
211317
uses: actions/download-artifact@v4
212318
if: steps.check_coverage_report.outputs.exists == 'true'
@@ -216,21 +322,21 @@ jobs:
216322
id: check_coverage_xml
217323
uses: andstor/file-existence-action@v3
218324
with:
219-
files: "coverage.xml"
325+
files: 'coverage.xml'
220326
# This is a workaround described in https://community.sonarsource.com/t/sonar-on-github-actions-with-python-coverage-source-issue/36057
221327
- name: Override Coverage Source Path for Sonar
222328
if: steps.check_coverage_xml.outputs.files_exists == 'true'
223329
run: sed -i "s/<source>\/home\/runner\/work\/synapsePythonClient<\/source>/<source>\/github\/workspace<\/source>/g" coverage.xml
224330
- name: SonarCloud Scan
225-
uses: SonarSource/sonarcloud-github-action@master
331+
uses: SonarSource/sonarqube-scan-action@v5.3.1
226332
if: ${{ always() }}
227333
env:
228334
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
229335
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
230336

231337
# on a GitHub release, build the pip package and upload it as a GitHub release asset
232338
package:
233-
needs: [test,pre-commit]
339+
needs: [test, pre-commit]
234340

235341
runs-on: ubuntu-22.04
236342

@@ -245,7 +351,7 @@ jobs:
245351

246352
- uses: actions/setup-python@v5
247353
with:
248-
python-version: 3.9
354+
python-version: 3.10
249355

250356
- name: set-release-env
251357
shell: bash
@@ -342,7 +448,6 @@ jobs:
342448
# asset_path: dist/${{ steps.build-package.outputs.bdist-package-name }}
343449
# asset_content_type: application/zip
344450

345-
346451
# build standalone desktop client artifacts for Windows and macOS on release
347452
build-electron-desktop-clients:
348453
needs: [test, pre-commit]
@@ -482,7 +587,7 @@ jobs:
482587
os: [ubuntu-24.04, macos-13, windows-2022]
483588

484589
# python versions should be consistent with the strategy matrix and the runs-integration-tests versions
485-
python: ['3.9', '3.10', '3.11', '3.12', '3.13']
590+
python: ['3.10', '3.11', '3.12', '3.13', '3.14']
486591

487592
runs-on: ${{ matrix.os }}
488593

.github/workflows/test-cleanup.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@ jobs:
1313
permissions:
1414
contents: read
1515

16+
strategy:
17+
matrix:
18+
synapse_profile:
19+
- "TestUbuntuMinimumPython"
20+
- "TestUbuntuMaximumPython"
21+
- "TestWindowsMinimumPython"
22+
- "TestWindowsMaximumPython"
23+
- "TestMacosMinimumPython"
24+
- "TestMacosMaximumPython"
25+
- "" # Empty string for default profile (no SYNAPSE_PROFILE set)
26+
1627
steps:
1728
- name: Checkout repository
1829
uses: actions/checkout@v4
@@ -67,17 +78,33 @@ jobs:
6778
mv test.synapseConfig ~/.synapseConfig
6879
6980
- name: Run evaluation deletion script
81+
shell: bash
7082
run: |
83+
if [ -n "${{ matrix.synapse_profile }}" ]; then
84+
export SYNAPSE_PROFILE="${{ matrix.synapse_profile }}"
85+
fi
7186
python .github/scripts/delete_evaluations.py
7287
7388
- name: Run project deletion script
89+
shell: bash
7490
run: |
91+
if [ -n "${{ matrix.synapse_profile }}" ]; then
92+
export SYNAPSE_PROFILE="${{ matrix.synapse_profile }}"
93+
fi
7594
python .github/scripts/delete_projects.py
7695
7796
- name: Run team deletion script
97+
shell: bash
7898
run: |
99+
if [ -n "${{ matrix.synapse_profile }}" ]; then
100+
export SYNAPSE_PROFILE="${{ matrix.synapse_profile }}"
101+
fi
79102
python .github/scripts/delete_teams.py
80103
81104
- name: Run empty trash script
105+
shell: bash
82106
run: |
107+
if [ -n "${{ matrix.synapse_profile }}" ]; then
108+
export SYNAPSE_PROFILE="${{ matrix.synapse_profile }}"
109+
fi
83110
python .github/scripts/empty_trash.py

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ virtualenvs
66
examples_temp
77
.DS_Store
88
deploy.sh
9+
.venv/
910

1011
junk/
1112
nose.cfg
@@ -33,6 +34,7 @@ coverage.xml
3334
.ipynb_checkpoints
3435
*.ipynb
3536
.env
37+
test.synapseConfig
3638
*.spec
3739

3840
synapse-electron/node_modules

0 commit comments

Comments
 (0)