Skip to content

Commit 288986c

Browse files
authored
test model dump and fix, add tests to pr workflow (#101)
* test model dump and fix, add tests to pr workflow * use composite action for setup
1 parent 82063e9 commit 288986c

File tree

10 files changed

+264
-69
lines changed

10 files changed

+264
-69
lines changed

.github/actions/setup/action.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name: "Setup Python"
2+
description: "Setup Python and dependencies"
3+
runs:
4+
using: "composite"
5+
steps:
6+
- name: Setup Python
7+
uses: actions/setup-python@v5
8+
with:
9+
python-version: '>=3.11'
10+
11+
- name: Install dependencies
12+
shell: bash
13+
run: pip install -r requirements.txt

.github/workflows/issue_to_pr.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,7 @@ jobs:
3131
uses: actions/checkout@v4
3232

3333
- name: Setup Python
34-
uses: actions/setup-python@v5
35-
with:
36-
python-version: 3.x
37-
38-
- name: Install dependencies
39-
run: pip install -r requirements.txt
34+
uses: ./.github/actions/setup
4035

4136
- name: Read and validate properties txt file
4237
id: parseProps
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: Pull Request Test Update Workflow
2+
on:
3+
pull_request:
4+
types:
5+
- opened
6+
- synchronize
7+
- reopened
8+
9+
jobs:
10+
test_run:
11+
name: Test that update contributions workflow runs
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout sources
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Python
18+
uses: ./.github/actions/setup
19+
20+
- name: run unit tests
21+
run: pytest
22+
23+
- name: fetch updates on contributions
24+
run: python -u scripts/fetch_updates.py
25+
26+
- name: write contribs.txt file
27+
run: python -u scripts/to_contribs_txt.py
28+
29+
- name: write source json files
30+
run: python -u scripts/to_sources_jsons.py

.github/workflows/update_contributions.yml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ jobs:
1515
uses: actions/checkout@v4
1616

1717
- name: Setup Python
18-
uses: actions/setup-python@v5
19-
with:
20-
python-version: '>=3.11'
21-
22-
- name: Install dependencies
23-
run: pip install -r requirements.txt
18+
uses: ./.github/actions/setup
2419

2520
- name: fetch updates and edit database
2621
run: |

scripts/add_new_contribution_to_yaml.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,31 @@
88

99
from ruamel.yaml import YAML
1010

11+
12+
def split_categories(categories):
13+
categories = sorted(categories.replace('"', '').split(','))
14+
categories = [category.strip() for category in categories]
15+
return categories
16+
17+
18+
def postprocess_properties(properties_dict):
19+
if 'categories' in properties_dict and properties_dict['categories']:
20+
properties_dict['categories'] = split_categories(properties_dict['categories'])
21+
else:
22+
properties_dict['categories'] = None
23+
24+
# add download
25+
if 'download' not in properties_dict:
26+
properties_dict['download'] = properties_dict['source'][:properties_dict['source'].rfind('.')] + '.zip'
27+
28+
1129
if __name__ == "__main__":
1230
if len(argv) < 2:
1331
print("script takes json string as argument.\nStopping...")
1432
raise ValueError
1533

1634
props = json.loads(argv[1])
17-
# process category list
18-
if 'categories' in props and props['categories']:
19-
props['categories'] = sorted(props['categories'].replace('"', '').split(','))
20-
props['categories'] = [category.strip() for category in props['categories']]
21-
else:
22-
props['categories'] = None
23-
24-
# add download
25-
if 'download' not in props:
26-
props['download'] = props['source'][:props['source'].rfind('.')] + '.zip'
35+
postprocess_properties(props)
2736

2837
# open database
2938
database_file = pathlib.Path(__file__).parent.parent / 'contributions.yaml'

scripts/fetch_updates.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ def process_contribution(item):
7878
return index, contribution
7979

8080

81+
def process_all(contributions_list):
82+
total = len(contributions_list)
83+
completed = 0
84+
print(f"Starting processing of {total} contributions...")
85+
86+
with Pool(processes=256) as pool:
87+
for index, contribution in pool.imap_unordered(process_contribution, enumerate(contributions_list)):
88+
contributions_list[index] = contribution
89+
completed += 1
90+
print(f"Progress: {completed}/{total} ({(completed / total * 100):.1f}%)")
91+
92+
8193
if __name__ == "__main__":
8294
parser = argparse.ArgumentParser()
8395
parser.add_argument('--index')
@@ -97,16 +109,7 @@ def process_contribution(item):
97109
contributions_list = data['contributions']
98110

99111
if index == 'all':
100-
total = len(contributions_list)
101-
completed = 0
102-
print(f"Starting processing of {total} contributions...")
103-
104-
with Pool(processes=256) as pool:
105-
for index, contribution in pool.imap_unordered(process_contribution, enumerate(contributions_list)):
106-
contributions_list[index] = contribution
107-
completed += 1
108-
print(f"Progress: {completed}/{total} ({(completed/total*100):.1f}%)")
109-
112+
process_all(contributions_list)
110113
print("All processing complete")
111114
else:
112115
# update only contribution with id==index

scripts/parse_and_validate_properties_txt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,19 @@ def validate_existing(properties_dict):
7575
# validation on existing contribution is weaker
7676
properties = PropertiesExisting.model_validate(properties_dict)
7777

78-
return properties.model_dump(exclude_unset=True)
78+
return properties.model_dump()
7979

8080
def validate_new(properties_dict):
8181
# new contribution has stronger validation
8282
properties = PropertiesBase.model_validate(properties_dict)
8383

84-
return properties.model_dump(exclude_unset=True)
84+
return properties.model_dump()
8585

8686
def validate_new_library(properties_dict):
8787
# new contribution has stronger validation
8888
properties = LibraryPropertiesNew.model_validate(properties_dict)
8989

90-
return properties.model_dump(exclude_unset=True)
90+
return properties.model_dump()
9191

9292
def set_output(output_object):
9393
with open(os.environ['GITHUB_OUTPUT'],'a') as f:

scripts/to_contribs_txt.py

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pathlib
77
import shutil
88
from collections import defaultdict
9+
from typing import List
910

1011
from utils import get_valid_contributions
1112

@@ -45,6 +46,40 @@ def read_contribs_text(filepath):
4546
return contribs_list
4647

4748

49+
def preprocess_contributions() -> List:
50+
all_contributions = get_valid_contributions()
51+
52+
# sort contributions list by type
53+
def sort_key(d):
54+
return type_list.index(d['type'])
55+
all_contributions = sorted(all_contributions, key=sort_key)
56+
57+
return all_contributions
58+
59+
60+
def write_contribs(all_contributions, fh):
61+
for contribution in all_contributions:
62+
fh.write(contribution['type'] + '\n')
63+
for field in contribs_fields_list:
64+
if field in contribution:
65+
if field == 'id':
66+
fh.write(f'{field}={contribution[field]:03}\n')
67+
elif field == 'categories':
68+
if contribution['type'] == 'library':
69+
fh.write(f'{field}={",".join(contribution[field]) if contribution[field] else ""}\n')
70+
else:
71+
# categories are only relevant for libraries, except for examples with "Books" as category
72+
if contribution[field] and 'Books' in contribution[field]:
73+
fh.write(f'{field}={",".join(contribution[field]) if contribution[field] else ""}\n')
74+
else:
75+
fh.write(f'{field}=\n')
76+
elif field == 'compatibleModesList':
77+
fh.write(f'modes={contribution[field]}\n')
78+
else:
79+
fh.write(f'{field}={"" if contribution[field] is None else contribution[field]}\n')
80+
fh.write('\n')
81+
82+
4883
if __name__ == "__main__":
4984
pde_folder = pathlib.Path(__file__).parent.parent / 'pde/'
5085
# remove sources folder if it already exists
@@ -54,34 +89,10 @@ def read_contribs_text(filepath):
5489

5590
contribs_text_file = pde_folder / 'contribs.txt'
5691

57-
contributions_list = get_valid_contributions()
58-
59-
# sort contributions list by type
60-
def sort_key(d):
61-
return type_list.index(d['type'])
62-
contributions_list = sorted(contributions_list, key=sort_key)
92+
contributions_list = preprocess_contributions()
6393

6494
# write contribs.txt file
6595
with open(contribs_text_file, 'w+') as f:
66-
for contribution in contributions_list:
67-
f.write(contribution['type']+'\n')
68-
for field in contribs_fields_list:
69-
if field in contribution:
70-
if field == 'id':
71-
f.write(f'{field}={contribution[field]:03}\n')
72-
elif field == 'categories':
73-
if contribution['type'] == 'library':
74-
f.write(f'{field}={",".join(contribution[field]) if contribution[field] else ""}\n')
75-
else:
76-
# categories are only relevant for libraries, except for examples with "Books" as category
77-
if contribution[field] and 'Books' in contribution[field]:
78-
f.write(f'{field}={",".join(contribution[field]) if contribution[field] else ""}\n')
79-
else:
80-
f.write(f'{field}=\n')
81-
elif field == 'compatibleModesList':
82-
f.write(f'modes={contribution[field]}\n')
83-
else:
84-
f.write(f'{field}={"" if contribution[field] is None else contribution[field]}\n')
85-
f.write('\n')
96+
write_contribs(contributions_list, f)
8697

8798

scripts/to_sources_jsons.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ def to_sources_dict(contribution_dict):
6363
return sources_dict
6464

6565

66+
def write_json_for_each_contribution_in_list(all_contributions, folder_path):
67+
for contribution in all_contributions:
68+
if 'name' in contribution:
69+
# output zero padded string for id
70+
contribution['id'] = f"{contribution['id']:03}"
71+
filename = contribution['name'].replace(':', '').replace('/', '').replace(' ', '_') + '.json'
72+
this_filepath = folder_path / filename
73+
with open(this_filepath, 'w') as f:
74+
json.dump(to_sources_dict(contribution), f, indent=2)
75+
76+
6677
if __name__ == "__main__":
6778
sources_folder = pathlib.Path(__file__).parent.parent / 'sources/'
6879

@@ -74,11 +85,4 @@ def to_sources_dict(contribution_dict):
7485
sources_folder.mkdir(parents=True, exist_ok=True)
7586

7687
# create a json file in the sources folder for each contribution
77-
for contribution in contributions_list:
78-
if 'name' in contribution:
79-
# output zero padded string for id
80-
contribution['id'] = f"{contribution['id']:03}"
81-
filename = contribution['name'].replace(':','').replace('/','').replace(' ','_') + '.json'
82-
this_filepath = sources_folder / filename
83-
with open(this_filepath, 'w') as f:
84-
json.dump(to_sources_dict(contribution),f,indent=2)
88+
write_json_for_each_contribution_in_list(contributions_list, sources_folder)

0 commit comments

Comments
 (0)