Skip to content

Commit 41b56be

Browse files
authored
Merge pull request #335 from JamesParrott/pyshp-3.0.0-alpha-return-of-the-type-hints
Add Speed test. Return of the type hints
2 parents 4f0bbdf + 5e40f2e commit 41b56be

File tree

4 files changed

+356
-99
lines changed

4 files changed

+356
-99
lines changed

.github/actions/test/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ runs:
7272
name: PyShp_wheel_and_sdist
7373
path: dist
7474

75-
- name: Install PyShp from the wheel (built in prev step)
75+
- name: Install PyShp from the wheel (downloaded in prev step)
7676
shell: bash
7777
working-directory: dist/
7878
run: |

.github/workflows/speed_test.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
name: Run the speed tests
3+
4+
on:
5+
push:
6+
pull_request:
7+
workflow_dispatch:
8+
9+
jobs:
10+
11+
12+
build_wheel_and_sdist:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- uses: actions/setup-python@v5
17+
- name: Build wheel from the project repo
18+
uses: ./.github/actions/build_wheel_and_sdist
19+
20+
run_speed_tests:
21+
needs: build_wheel_and_sdist
22+
strategy:
23+
fail-fast: false
24+
matrix:
25+
python-version: [
26+
"3.9",
27+
"3.13",
28+
]
29+
os: [
30+
"windows-latest",
31+
"ubuntu-24.04",
32+
]
33+
34+
35+
runs-on: ${{ matrix.os }}
36+
steps:
37+
- uses: actions/setup-python@v5
38+
with:
39+
python-version: ${{ matrix.python-version }}
40+
41+
- name: Download wheel and sdist (built in previous job)
42+
uses: actions/download-artifact@v4
43+
with:
44+
name: PyShp_wheel_and_sdist
45+
path: dist
46+
47+
- name: Install PyShp + test deps from the wheel (downloaded in prev step)
48+
shell: bash
49+
working-directory: dist/
50+
run: |
51+
WHEEL_NAME=$(ls pyshp-*py3-none-any.whl)
52+
python -m pip install $WHEEL_NAME[test]
53+
54+
- uses: actions/checkout@v4
55+
with:
56+
path: ./Pyshp
57+
58+
- name: Checkout shapefiles and zip file artefacts repo
59+
uses: actions/checkout@v4
60+
with:
61+
repository: JamesParrott/PyShp_test_shapefile
62+
path: ./PyShp_test_shapefile
63+
64+
- name: Run Speed tests.
65+
env:
66+
PYSHP_TEST_REPO: ./PyShp_test_shapefile
67+
run: python ./Pyshp/run_benchmarks.py
68+
69+
70+

run_benchmarks.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Based on Taneli Hukkinen's https://github.com/hukkin/tomli-w/blob/master/benchmark/run.py
2+
3+
from __future__ import annotations
4+
5+
import functools
6+
import os
7+
import timeit
8+
from collections.abc import Callable
9+
from pathlib import Path
10+
from typing import Union
11+
12+
import shapefile as shp
13+
14+
# For shapefiles from https://github.com/JamesParrott/PyShp_test_shapefile
15+
DEFAULT_PYSHP_TEST_REPO = (
16+
rf"{os.getenv('USERPROFILE')}\Coding\repos\PyShp_test_shapefile"
17+
)
18+
PYSHP_TEST_REPO = Path(os.getenv("PYSHP_TEST_REPO", DEFAULT_PYSHP_TEST_REPO))
19+
REPO_ROOT = Path(__file__).parent
20+
21+
22+
blockgroups_file = REPO_ROOT / "shapefiles" / "blockgroups.shp"
23+
edit_file = REPO_ROOT / "shapefiles" / "test" / "edit.shp"
24+
merge_file = REPO_ROOT / "shapefiles" / "test" / "merge.shp"
25+
states_provinces_file = PYSHP_TEST_REPO / "ne_10m_admin_1_states_provinces.shp"
26+
tiny_countries_file = PYSHP_TEST_REPO / "ne_110m_admin_0_tiny_countries.shp"
27+
gis_osm_natural_file = PYSHP_TEST_REPO / "gis_osm_natural_a_free_1.zip"
28+
29+
30+
def benchmark(
31+
name: str,
32+
run_count: int,
33+
func: Callable,
34+
col_width: tuple,
35+
compare_to: float | None = None,
36+
) -> float:
37+
placeholder = "Running..."
38+
print(f"{name:>{col_width[0]}} | {placeholder}", end="", flush=True)
39+
time_taken = timeit.timeit(func, number=run_count)
40+
print("\b" * len(placeholder), end="")
41+
time_suffix = " s"
42+
print(f"{time_taken:{col_width[1]-len(time_suffix)}.3g}{time_suffix}", end="")
43+
print()
44+
return time_taken
45+
46+
47+
def open_shapefile_with_PyShp(target: Union[str, os.PathLike]):
48+
with shp.Reader(target) as r:
49+
for shapeRecord in r.iterShapeRecords():
50+
pass
51+
52+
53+
READER_TESTS = {
54+
"Blockgroups": blockgroups_file,
55+
"Edit": edit_file,
56+
"Merge": merge_file,
57+
"States_35MB": states_provinces_file,
58+
"Tiny Countries": tiny_countries_file,
59+
"GIS_OSM_zip_10MB": gis_osm_natural_file,
60+
}
61+
62+
63+
def run(run_count: int) -> None:
64+
col_width = (21, 10)
65+
col_head = ("parser", "exec time", "performance (more is better)")
66+
# Load files to avoid one off delays that only affect first disk seek
67+
for file_path in READER_TESTS.values():
68+
file_path.read_bytes()
69+
print(f"Running benchmarks {run_count} times:")
70+
print("-" * col_width[0] + "---" + "-" * col_width[1])
71+
print(f"{col_head[0]:>{col_width[0]}} | {col_head[1]:>{col_width[1]}}")
72+
print("-" * col_width[0] + "-+-" + "-" * col_width[1])
73+
for test_name, target in READER_TESTS.items():
74+
benchmark(
75+
f"Read {test_name}",
76+
run_count,
77+
functools.partial(open_shapefile_with_PyShp, target=target),
78+
col_width,
79+
)
80+
81+
82+
if __name__ == "__main__":
83+
run(1)

0 commit comments

Comments
 (0)