From 5ec3461d033df73919823588573023e79e07454a Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sat, 1 Jun 2024 00:33:10 +0200 Subject: [PATCH 01/12] support for 4, 6, 8 char precision maidenhead locator conversions # fixes bug report #30 --- docs/source/changelog.rst | 8 ++ pyhamtools/locator.py | 120 +++++++++++++++++------- pyhamtools/version.py | 2 +- requirements-pytest.txt | 1 + test/test_locator_distances.py | 7 +- test/test_locator_latlong_to_locator.py | 12 ++- test/test_locator_locator_to_latlong.py | 85 +++++++++++++++-- 7 files changed, 188 insertions(+), 47 deletions(-) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index cc88197..fb93872 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,6 +1,14 @@ Changelog --------- +PyHamtools 0.10.0 +================ + +01. June 2024 + +* full support for 4, 6, 8 characters Maidenhead locator conversions + + PyHamtools 0.9.1 ================ diff --git a/pyhamtools/locator.py b/pyhamtools/locator.py index 2f0872a..dc963d5 100644 --- a/pyhamtools/locator.py +++ b/pyhamtools/locator.py @@ -3,12 +3,13 @@ from datetime import datetime, timezone import ephem -def latlong_to_locator (latitude, longitude): +def latlong_to_locator (latitude, longitude, precision=6): """converts WGS84 coordinates into the corresponding Maidenhead Locator Args: latitude (float): Latitude longitude (float): Longitude + precision (int): 4,6,8 chars (default 6) Returns: string: Maidenhead locator @@ -32,35 +33,54 @@ def latlong_to_locator (latitude, longitude): """ + if precision < 4 or precision ==5 or precision == 7 or precision > 8: + return ValueError + if longitude >= 180 or longitude <= -180: raise ValueError if latitude >= 90 or latitude <= -90: raise ValueError - longitude += 180; - latitude +=90; + longitude +=180 + latitude +=90 - locator = chr(ord('A') + int(longitude / 20)) - locator += chr(ord('A') + int(latitude / 10)) - locator += chr(ord('0') + int((longitude % 20) / 2)) - locator += chr(ord('0') + int(latitude % 10)) - locator += chr(ord('A') + int((longitude - int(longitude / 2) * 2) / (2 / 24))) - locator += chr(ord('A') + int((latitude - int(latitude / 1) * 1 ) / (1 / 24))) + # copied & adapted from github.com/space-physics/maidenhead + A = ord('A') + a = divmod(longitude, 20) + b = divmod(latitude, 10) + locator = chr(A + int(a[0])) + chr(A + int(b[0])) + lon = a[1] / 2.0 + lat = b[1] + i = 1 + + while i < precision/2: + i += 1 + a = divmod(lon, 1) + b = divmod(lat, 1) + if not (i % 2): + locator += str(int(a[0])) + str(int(b[0])) + lon = 24 * a[1] + lat = 24 * b[1] + else: + locator += chr(A + int(a[0])) + chr(A + int(b[0])) + lon = 10 * a[1] + lat = 10 * b[1] return locator -def locator_to_latlong (locator): +def locator_to_latlong (locator, center=True): """converts Maidenhead locator in the corresponding WGS84 coordinates Args: - locator (string): Locator, either 4 or 6 characters + locator (string): Locator, either 4, 6 or 8 characters + center (bool): Center of (sub)square. By default True. If False, the south/western corner will be returned Returns: tuple (float, float): Latitude, Longitude Raises: - ValueError: When called with wrong or invalid input arg + ValueError: When called with wrong or invalid Maidenhead locator string TypeError: When arg is not a string Example: @@ -79,7 +99,7 @@ def locator_to_latlong (locator): locator = locator.upper() - if len(locator) == 5 or len(locator) < 4: + if len(locator) < 4 or len(locator) == 5 or len(locator) == 7: raise ValueError if ord(locator[0]) > ord('R') or ord(locator[0]) < ord('A'): @@ -100,23 +120,44 @@ def locator_to_latlong (locator): if ord (locator[5]) > ord('X') or ord(locator[5]) < ord('A'): raise ValueError + if len(locator) == 8: + if ord(locator[6]) > ord('9') or ord(locator[6]) < ord('0'): + raise ValueError + if ord (locator[7]) > ord('9') or ord(locator[7]) < ord('0'): + raise ValueError + longitude = (ord(locator[0]) - ord('A')) * 20 - 180 latitude = (ord(locator[1]) - ord('A')) * 10 - 90 longitude += (ord(locator[2]) - ord('0')) * 2 - latitude += (ord(locator[3]) - ord('0')) + latitude += (ord(locator[3]) - ord('0')) * 1 - if len(locator) == 6: - longitude += ((ord(locator[4])) - ord('A')) * (2 / 24) - latitude += ((ord(locator[5])) - ord('A')) * (1 / 24) + if len(locator) == 4: - # move to center of subsquare - longitude += 1 / 24 - latitude += 0.5 / 24 + if center: + longitude += 2 / 2 + latitude += 1.0 / 2 + + elif len(locator) == 6: + longitude += (ord(locator[4]) - ord('A')) * 5.0 / 60 + latitude += (ord(locator[5]) - ord('A')) * 2.5 / 60 + + if center: + longitude += 5.0 / 60 / 2 + latitude += 2.5 / 60 / 2 + + elif len(locator) == 8: + longitude += (ord(locator[4]) - ord('A')) * 5.0 / 60 + latitude += (ord(locator[5]) - ord('A')) * 2.5 / 60 + + longitude += int(locator[6]) * 5.0 / 600 + latitude += int(locator[7]) * 2.5 / 600 + + if center: + longitude += 5.0 / 600 / 2 + latitude += 2.5 / 600 / 2 else: - # move to center of square - longitude += 1; - latitude += 0.5; + raise ValueError return latitude, longitude @@ -125,14 +166,14 @@ def calculate_distance(locator1, locator2): """calculates the (shortpath) distance between two Maidenhead locators Args: - locator1 (string): Locator, either 4 or 6 characters - locator2 (string): Locator, either 4 or 6 characters + locator1 (string): Locator, either 4, 6 or 8 characters + locator2 (string): Locator, either 4, 6 or 8 characters Returns: float: Distance in km Raises: - ValueError: When called with wrong or invalid input arg + ValueError: When called with wrong or invalid maidenhead locator strings AttributeError: When args are not a string Example: @@ -142,6 +183,9 @@ def calculate_distance(locator1, locator2): >>> calculate_distance("JN48QM", "QF67bf") 16466.413 + Note: + Distances is calculated between the centers of the (sub) squares + """ R = 6371 #earh radius @@ -160,15 +204,15 @@ def calculate_distance(locator1, locator2): c = 2 * atan2(sqrt(a), sqrt(1-a)) d = R * c #distance in km - return d; + return d def calculate_distance_longpath(locator1, locator2): """calculates the (longpath) distance between two Maidenhead locators Args: - locator1 (string): Locator, either 4 or 6 characters - locator2 (string): Locator, either 4 or 6 characters + locator1 (string): Locator, either 4, 6 or 8 characters + locator2 (string): Locator, either 4, 6 or 8 characters Returns: float: Distance in km @@ -184,6 +228,8 @@ def calculate_distance_longpath(locator1, locator2): >>> calculate_distance_longpath("JN48QM", "QF67bf") 23541.5867 + Note: + Distance is calculated between the centers of the (sub) squares """ c = 40008 #[km] earth circumference @@ -196,8 +242,8 @@ def calculate_heading(locator1, locator2): """calculates the heading from the first to the second locator Args: - locator1 (string): Locator, either 4 or 6 characters - locator2 (string): Locator, either 4 or 6 characters + locator1 (string): Locator, either 4, 6 or 8 characters + locator2 (string): Locator, either 4, 6 or 6 characters Returns: float: Heading in deg @@ -213,6 +259,9 @@ def calculate_heading(locator1, locator2): >>> calculate_heading("JN48QM", "QF67bf") 74.3136 + Note: + Heading is calculated between the centers of the (sub) squares + """ lat1, long1 = locator_to_latlong(locator1) @@ -236,8 +285,8 @@ def calculate_heading_longpath(locator1, locator2): """calculates the heading from the first to the second locator (long path) Args: - locator1 (string): Locator, either 4 or 6 characters - locator2 (string): Locator, either 4 or 6 characters + locator1 (string): Locator, either 4, 6 or 8 characters + locator2 (string): Locator, either 4, 6 or 8 characters Returns: float: Long path heading in deg @@ -253,6 +302,9 @@ def calculate_heading_longpath(locator1, locator2): >>> calculate_heading_longpath("JN48QM", "QF67bf") 254.3136 + Note: + Distance is calculated between the centers of the (sub) squares + """ heading = calculate_heading(locator1, locator2) @@ -265,7 +317,7 @@ def calculate_sunrise_sunset(locator, calc_date=None): """calculates the next sunset and sunrise for a Maidenhead locator at a give date & time Args: - locator1 (string): Maidenhead Locator, either 4 or 6 characters + locator1 (string): Maidenhead Locator, either 4, 6 or 8 characters calc_date (datetime, optional): Starting datetime for the calculations (UTC) Returns: diff --git a/pyhamtools/version.py b/pyhamtools/version.py index 3408010..8aeb2b4 100644 --- a/pyhamtools/version.py +++ b/pyhamtools/version.py @@ -1,3 +1,3 @@ -VERSION = (0, 9, 1) +VERSION = (0, 10, 0) __release__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:] __version__ = '.'.join((str(VERSION[0]), str(VERSION[1]))) diff --git a/requirements-pytest.txt b/requirements-pytest.txt index c086f37..995a5fa 100644 --- a/requirements-pytest.txt +++ b/requirements-pytest.txt @@ -3,3 +3,4 @@ pytest==4.6.11; python_version=='3.6' pytest-blockage>=0.2.2 pytest-localserver>=0.5 pytest-cov>=2.12 +maidenhead==1.7.0 \ No newline at end of file diff --git a/test/test_locator_distances.py b/test/test_locator_distances.py index a53a765..79cf801 100644 --- a/test/test_locator_distances.py +++ b/test/test_locator_distances.py @@ -14,7 +14,12 @@ class Test_calculate_distance(): assert abs(calculate_distance("JN48QM", "FN44AB") - 5965) < 1 assert abs(calculate_distance("FN44AB", "JN48QM") - 5965) < 1 - assert abs(calculate_distance("JN48QM", "QF67bf") - 16467) < 1 + assert abs(calculate_distance("JN48QM", "QF67BF") - 16467) < 1 + assert abs(calculate_distance("JN48QM84", "QF67BF84") - 16467) < 1 + assert abs(calculate_distance("JN48QM84", "QF67BF") - 16464) < 1 + assert abs(calculate_distance("JN48QM84", "QF67") - 16506) < 1 + assert abs(calculate_distance("JN48QM", "QF67") - 16508) < 1 + assert abs(calculate_distance("JN48", "QF67") - 16535) < 1 def test_calculate_distance_invalid_inputs(self): with pytest.raises(AttributeError): diff --git a/test/test_locator_latlong_to_locator.py b/test/test_locator_latlong_to_locator.py index f34028a..0d1c970 100644 --- a/test/test_locator_latlong_to_locator.py +++ b/test/test_locator_latlong_to_locator.py @@ -8,10 +8,20 @@ class Test_latlong_to_locator(): assert latlong_to_locator(-89.97916, -179.95833) == "AA00AA" assert latlong_to_locator(89.97916, 179.9583) == "RR99XX" - def test_latlong_to_locator_normal_case(self): + def test_latlong_to_locator_4chars_precision(self): + + assert latlong_to_locator(48.52083, 9.3750000, precision=4) == "JN48" + assert latlong_to_locator(39.222916, -86.45416, 4) == "EM69" + + def test_latlong_to_locator_6chars_precision(self): assert latlong_to_locator(48.52083, 9.3750000) == "JN48QM" assert latlong_to_locator(48.5, 9.0) == "JN48MM" #center of the square + assert latlong_to_locator(39.222916, -86.45416, 6) == "EM69SF" + + def test_latlong_to_locator_8chars_precision(self): + assert latlong_to_locator(48.51760, 9.40345, precision=8) == "JN48QM84" + assert latlong_to_locator(39.222916, -86.45416, 4) == "EM69SF53" def test_latlong_to_locator_invalid_characters(self): diff --git a/test/test_locator_locator_to_latlong.py b/test/test_locator_locator_to_latlong.py index 22740c5..a5cf1d2 100644 --- a/test/test_locator_locator_to_latlong.py +++ b/test/test_locator_locator_to_latlong.py @@ -1,10 +1,12 @@ import pytest +import maidenhead from pyhamtools.locator import locator_to_latlong from pyhamtools.consts import LookupConventions as const + class Test_locator_to_latlong(): - def test_locator_to_latlong_edge_cases(self): + def test_locator_to_latlong_min_max_cases(self): latitude, longitude = locator_to_latlong("AA00AA") assert abs(latitude + 89.97916) < 0.00001 assert abs(longitude +179.95833) < 0.0001 @@ -13,23 +15,71 @@ class Test_locator_to_latlong(): assert abs(latitude - 89.97916) < 0.00001 assert abs(longitude - 179.9583) < 0.0001 - def test_locator_to_latlong_normal_case(self): - - latitude, longitude = locator_to_latlong("JN48QM") - assert abs(latitude - 48.52083) < 0.00001 - assert abs(longitude - 9.3750000) < 0.0001 + def test_locator_to_latlong_4chars_precision(self): latitude, longitude = locator_to_latlong("JN48") - assert abs(latitude - 48.5) < 0.001 - assert abs(longitude - 9.000) < 0.001 + assert abs(latitude - 48.5) < 0.1 + assert abs(longitude - 9.0) < 0.1 - def test_locator_to_latlong_mixed_signs(self): + latitude, longitude = locator_to_latlong("JN48", center=False) + assert abs(latitude - 48) < 0.1 + assert abs(longitude - 8) < 0.1 + + def test_locator_to_latlong_6chars_precision(self): + latitude, longitude = locator_to_latlong("JN48QM") + assert abs(latitude - 48.52083) < 0.00001 + assert abs(longitude - 9.37500) < 0.00001 + + def test_locator_to_latlong_8chars(self): + + latitude, longitude = locator_to_latlong("JN48QM84") + assert abs(latitude - 48.51875) < 0.00001 + assert abs(longitude - 9.40416) < 0.00001 + + latitude, longitude = locator_to_latlong("EM69SF53") + assert abs(latitude - 39.222916) < 0.00001 + assert abs(longitude + 86.45416) < 0.00001 + + def test_locator_to_latlong_consistency_checks_6chars_lower_left_corner(self): + + latitude_4, longitude_4 = locator_to_latlong("JN48", center=False) + latitude_6, longitude_6 = locator_to_latlong("JN48AA", center=False) + + assert latitude_4 == latitude_6 + assert longitude_4 == longitude_6 + + def test_locator_to_latlong_consistency_checks_8chars_lower_left_corner(self): + + latitude_6, longitude_6 = locator_to_latlong("JN48AA", center=False) + latitude_8, longitude_8 = locator_to_latlong("JN48AA00", center=False) + + assert latitude_6 == latitude_8 + assert longitude_6 == longitude_8 + + def test_locator_to_latlong_consistency_checks_against_maidenhead(self): + + locs = ["JN48", "EM69", "JN48QM", "EM69SF", "AA00AA", "RR99XX", "JN48QM84", "EM69SF53"] + + # lower left (south/east) corner + for loc in locs: + lat, lon = locator_to_latlong(loc, center=False) + lat_m, lon_m = maidenhead.to_location(loc) + assert abs(lat - lat_m) < 0.00001 + assert abs(lon - lon_m) < 0.00001 + + # center of square + for loc in locs: + lat, lon = locator_to_latlong(loc) # default: center=True + lat_m, lon_m = maidenhead.to_location(loc, center=True) + assert abs(lat - lat_m) < 0.1 + assert abs(lon - lon_m) < 0.1 + + def test_locator_to_latlong_upper_lower_chars(self): latitude, longitude = locator_to_latlong("Jn48qM") assert abs(latitude - 48.52083) < 0.00001 assert abs(longitude - 9.3750000) < 0.0001 - def test_locator_to_latlong_wrong_amount_of_characters(self): with pytest.raises(ValueError): @@ -43,12 +93,27 @@ class Test_locator_to_latlong(): with pytest.raises(ValueError): latitude, longitude = locator_to_latlong("JN8Q") + + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("JN8QM1") def test_locator_to_latlong_invalid_characters(self): with pytest.raises(ValueError): latitude, longitude = locator_to_latlong("21XM99") + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("48") + + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("JNJN") + + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("JN4848") + + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("JN48QMaa") + with pytest.raises(ValueError): latitude, longitude = locator_to_latlong("****") From 1c3536396d9f80eaa85e301f8ced2c54d53eb50d Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sat, 1 Jun 2024 00:39:04 +0200 Subject: [PATCH 02/12] skip LOTW download test until LOTW is again recovered --- test/test_lotw.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_lotw.py b/test/test_lotw.py index afd676c..5e541c4 100644 --- a/test/test_lotw.py +++ b/test/test_lotw.py @@ -29,6 +29,7 @@ class Test_lotw_methods: execfile(os.path.join(fix_dir,"lotw_fixture.py"), namespace) assert get_lotw_users(url=httpserver.url) == namespace['lotw_fixture'] + @pytest.mark.skip("ARRL has been hacked in May 2024; skipping until LOTW is again up") def test_download_lotw_list_and_check_types(self): data = get_lotw_users() From 17117b1c20cd50b6fb87b46f2642495822bf22ca Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sat, 1 Jun 2024 00:45:57 +0200 Subject: [PATCH 03/12] fixed lat/long unittest --- requirements-pytest.txt | 2 +- test/test_locator_latlong_to_locator.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-pytest.txt b/requirements-pytest.txt index 995a5fa..f0acaa0 100644 --- a/requirements-pytest.txt +++ b/requirements-pytest.txt @@ -3,4 +3,4 @@ pytest==4.6.11; python_version=='3.6' pytest-blockage>=0.2.2 pytest-localserver>=0.5 pytest-cov>=2.12 -maidenhead==1.7.0 \ No newline at end of file +maidenhead==1.6.0 \ No newline at end of file diff --git a/test/test_locator_latlong_to_locator.py b/test/test_locator_latlong_to_locator.py index 0d1c970..0b5dd25 100644 --- a/test/test_locator_latlong_to_locator.py +++ b/test/test_locator_latlong_to_locator.py @@ -21,7 +21,7 @@ class Test_latlong_to_locator(): def test_latlong_to_locator_8chars_precision(self): assert latlong_to_locator(48.51760, 9.40345, precision=8) == "JN48QM84" - assert latlong_to_locator(39.222916, -86.45416, 4) == "EM69SF53" + assert latlong_to_locator(39.222916, -86.45416, 8) == "EM69SF53" def test_latlong_to_locator_invalid_characters(self): From ac444fa36ba1896768e1df1dd3845108715a3ad6 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sat, 1 Jun 2024 01:30:20 +0200 Subject: [PATCH 04/12] CI: fixed redis dependency on windows --- .github/workflows/test.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 84f3389..bfa2430 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -190,9 +190,10 @@ jobs: # since there is no official redis version for windows. # Redis is then installed an run as a service run: | - C:\msys64\usr\bin\wget.exe https://github.com/redis-windows/redis-windows/releases/download/7.0.14/Redis-7.0.14-Windows-x64-with-Service.tar.gz - C:\msys64\usr\bin\tar.exe -xvzf Redis-7.0.14-Windows-x64-with-Service.tar.gz - sc.exe create Redis binpath=D:\a\pyhamtools\pyhamtools\Redis-7.0.14-Windows-x64-with-Service\RedisService.exe start= auto + C:\msys64\usr\bin\wget.exe https://github.com/redis-windows/redis-windows/releases/download/7.0.14/Redis-7.0.14-Windows-x64-msys2-with-Service.zip + C:\msys64\usr\bin\pacman.exe -S --noconfirm unzip + C:\msys64\usr\bin\unzip.exe Redis-7.0.14-Windows-x64-msys2-with-Service.zip + sc.exe create Redis binpath=D:\a\pyhamtools\pyhamtools\Redis-7.0.14-Windows-x64-msys2-with-Service\RedisService.exe start= auto net start Redis - name: "Run tests for ${{ matrix.python-version }}" From 940c0f072ccac86b88d55a7982ae021c54433926 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sun, 2 Mar 2025 00:07:00 +0100 Subject: [PATCH 05/12] added support for python 3.13 --- .github/workflows/test.yml | 96 +++++++++++++++---------------- docs/source/changelog.rst | 7 +++ pyhamtools/version.py | 2 +- setup.py | 2 +- test/test_callinfo.py | 22 +++---- test/test_lookuplib_clublogxml.py | 10 ++-- 6 files changed, 73 insertions(+), 66 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bfa2430..de1a9fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,52 +3,52 @@ name: Linux on: [push, pull_request] jobs: + test_linux_legacy: + # Ubuntu 20.04 is still required for python 3.6; this doesn't work on Ubuntu 22.04 anymore + runs-on: "ubuntu-20.04" + name: "Ubuntu 20.04 - Python ${{ matrix.python-version }}" + strategy: + matrix: + python-version: ["3.6"] + redis-version: [6] + + steps: + - uses: "actions/checkout@v3" + - uses: "actions/setup-python@v4" + with: + python-version: "${{ matrix.python-version }}" + cache: "pip" + cache-dependency-path: | + **/setup.py + **/requirements*.txt + + - name: "Install dependencies" + run: | + set -xe + sudo apt-get install -y libxml2-dev libxslt-dev + python -VV + python -m pip install --upgrade pip setuptools + python -m pip install -e . + python -m pip install -r requirements-pytest.txt + + - name: Start Redis + uses: supercharge/redis-github-action@1.2.0 + with: + redis-version: ${{ matrix.redis-version }} + + - name: "Run tests for ${{ matrix.python-version }}" + env: + CLUBLOG_APIKEY: ${{ secrets.CLUBLOG_APIKEY }} + QRZ_USERNAME: ${{ secrets.QRZ_USERNAME }} + QRZ_PWD: ${{ secrets.QRZ_PWD }} + PYTHON_VERSION: ${{ matrix.python-version }} + # delay the execution randomly by a couple of seconds to reduce the amount + # of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously + run: | + sleep $[ ( $RANDOM % 10 ) + 1 ]s + pytest ./test + test_linux: - # Ubuntu 20.04 is still required for python 3.6; this doesn't work on Ubuntu 22.04 anymore - runs-on: "ubuntu-20.04" - name: "Ubuntu 20.04 - Python ${{ matrix.python-version }}" - strategy: - matrix: - python-version: ["3.6"] - redis-version: [6] - - steps: - - uses: "actions/checkout@v3" - - uses: "actions/setup-python@v4" - with: - python-version: "${{ matrix.python-version }}" - cache: "pip" - cache-dependency-path: | - **/setup.py - **/requirements*.txt - - - name: "Install dependencies" - run: | - set -xe - sudo apt-get install -y libxml2-dev libxslt-dev - python -VV - python -m pip install --upgrade pip setuptools - python -m pip install -e . - python -m pip install -r requirements-pytest.txt - - - name: Start Redis - uses: supercharge/redis-github-action@1.2.0 - with: - redis-version: ${{ matrix.redis-version }} - - - name: "Run tests for ${{ matrix.python-version }}" - env: - CLUBLOG_APIKEY: ${{ secrets.CLUBLOG_APIKEY }} - QRZ_USERNAME: ${{ secrets.QRZ_USERNAME }} - QRZ_PWD: ${{ secrets.QRZ_PWD }} - PYTHON_VERSION: ${{ matrix.python-version }} - # delay the execution randomly by a couple of seconds to reduce the amount - # of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously - run: | - sleep $[ ( $RANDOM % 10 ) + 1 ]s - pytest ./test - - test_linux_ubuntu_22: runs-on: "ubuntu-22.04" name: "Ubuntu 22.04 - Python ${{ matrix.python-version }}" env: @@ -56,7 +56,7 @@ jobs: strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.7", "pypy3.8", "pypy3.9", "pypy3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] redis-version: [6] steps: @@ -121,7 +121,7 @@ jobs: name: "MacOS 12 - Python ${{ matrix.python-version }}" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8", "pypy3.9", "pypy3.10"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] redis-version: [6] steps: @@ -165,7 +165,7 @@ jobs: strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: "actions/checkout@v3" diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index fb93872..25a83c5 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,6 +1,13 @@ Changelog --------- +PyHamtools 0.11.0 +================ + +02. March 2025 + +* added support for Python 3.13 + PyHamtools 0.10.0 ================ diff --git a/pyhamtools/version.py b/pyhamtools/version.py index 8aeb2b4..b3e6bed 100644 --- a/pyhamtools/version.py +++ b/pyhamtools/version.py @@ -1,3 +1,3 @@ -VERSION = (0, 10, 0) +VERSION = (0, 11, 0) __release__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:] __version__ = '.'.join((str(VERSION[0]), str(VERSION[1]))) diff --git a/setup.py b/setup.py index 68ade0f..b12e880 100755 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ setup(name='pyhamtools', "requests>=2.21.0", "ephem>=4.1.3", "beautifulsoup4>=4.7.1", - "lxml>=4.8.0,<5.0.0", + "lxml>=5.0.0", "redis>=2.10.6", ], **kw diff --git a/test/test_callinfo.py b/test/test_callinfo.py index 2d20541..3c7c672 100644 --- a/test/test_callinfo.py +++ b/test/test_callinfo.py @@ -90,12 +90,12 @@ response_prefix_VK9DWX_clublog = { } response_prefix_VK9DLX_clublog = { - u'adif': 147, + u'adif': 189, u'continent': u'OC', - u'country': u'LORD HOWE ISLAND', - u'cqz': 30, - u'latitude': -31.6, - u'longitude': 159.1 + u'country': u'NORFOLK ISLAND', + u'cqz': 32, + u'latitude': -29.0, + u'longitude': 168.0 } response_prefix_TA7I_clublog = { @@ -126,13 +126,13 @@ response_prefix_V26K_clublog = { } response_prefix_VK9DLX_countryfile = { - u'adif': 147, + u'adif': 189, u'continent': u'OC', - u'country': u'Lord Howe Island', - u'cqz': 30, + u'country': u'Norfolk Island', + u'cqz': 32, u'ituz': 60, - u'latitude': -31.55, - u'longitude': 159.08 + u'latitude': -29.03, + u'longitude': 167.93 } response_prefix_VK9GMW_clublog = { @@ -195,7 +195,7 @@ response_Exception_VK9XO_with_start_date = { 'country': 'CHRISTMAS ISLAND', 'continent': 'OC', 'latitude': -10.48, - 'longitude': 105.71, + 'longitude': 105.62, 'cqz': 29 } diff --git a/test/test_lookuplib_clublogxml.py b/test/test_lookuplib_clublogxml.py index 5241729..3e32afb 100644 --- a/test/test_lookuplib_clublogxml.py +++ b/test/test_lookuplib_clublogxml.py @@ -25,8 +25,8 @@ response_Exception_KC6MM_1990 = { 'adif': 22, 'country': u'PALAU', 'continent': u'OC', - 'latitude': 9.50, - 'longitude': 138.20, + 'latitude': 9.52, + 'longitude': 138.21, 'cqz': 27, } @@ -34,8 +34,8 @@ response_Exception_KC6MM_1992 = { 'adif': 22, 'country': u'PALAU', 'continent': u'OC', - 'latitude': 9.50, - 'longitude': 138.20, + 'latitude': 9.52, + 'longitude': 138.21, 'cqz': 27, } @@ -53,7 +53,7 @@ response_Exception_VK9XO_with_start_date = { 'country': u'CHRISTMAS ISLAND', 'continent': u'OC', 'latitude': -10.48, - 'longitude': 105.71, + 'longitude': 105.62, 'cqz': 29, } From 4bdaf8d3357c4830780e3d48f31c599f70a04d3f Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Sun, 2 Mar 2025 00:10:44 +0100 Subject: [PATCH 06/12] updated readme & license --- LICENSE | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index 8ddf036..041d2a9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Tobias Wellnitz +Copyright (c) 2025 Tobias Wellnitz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b02b2bb..78edca3 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,14 @@ This Library is used in production at the [DXHeat.com DX Cluster](https://dxheat Pyhamtools is compatible with Python >=3.6. We check compatibility on OSX, Windows, and Linux with the following Python versions: -* Python 3.6 (will be deprecated in 2024) -* Python 3.7 (will be deprecated in 2024) +* Python 3.6 (will be deprecated in 2025) +* Python 3.7 (will be deprecated in 2025) * Python 3.8 * Python 3.9 * Python 3.10 * Python 3.11 * Python 3.12 -* [pypy3.7](https://pypy.org/) (will be deprecated in 2024) +* Python 3.13 * [pypy3.8](https://pypy.org/) * [pypy3.9](https://pypy.org/) * [pypy3.10](https://pypy.org/) From 1a79467db189bba33b8d1fa853c48d59c9a658fc Mon Sep 17 00:00:00 2001 From: Dawid Date: Mon, 9 Jun 2025 23:21:27 +0200 Subject: [PATCH 07/12] Add higher uWave bands and 10 char locators support (#32) --- pyhamtools/frequency.py | 16 +++++++++++++-- pyhamtools/locator.py | 26 ++++++++++++++++++++++--- test/test_locator_latlong_to_locator.py | 4 ++++ test/test_locator_locator_to_latlong.py | 15 ++++++++++++-- 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/pyhamtools/frequency.py b/pyhamtools/frequency.py index 51ad88b..5f7583f 100644 --- a/pyhamtools/frequency.py +++ b/pyhamtools/frequency.py @@ -182,7 +182,7 @@ def freq_to_band(freq): elif ((freq >= 1200000) and (freq <= 1300000)): band = 0.23 #23cm mode = None - elif ((freq >= 2390000) and (freq <= 2450000)): + elif ((freq >= 2300000) and (freq <= 2450000)): band = 0.13 #13cm mode = None elif ((freq >= 3300000) and (freq <= 3500000)): @@ -200,7 +200,19 @@ def freq_to_band(freq): elif ((freq >= 47000000) and (freq <= 47200000)): band = 0.0063 #6,3mm mode = None + elif ((freq >= 75500000) and (freq <= 81500000)): + band = 0.004 #4mm + mode = None + elif ((freq >= 122250000) and (freq <= 123000000)): + band = 0.0025 #2.5mm + mode = None + elif ((freq >= 134000000) and (freq <= 141000000)): + band = 0.002 #2mm + mode = None + elif ((freq >= 241000000) and (freq <= 250000000)): + band = 0.001 #1mm + mode = None else: raise KeyError - return {"band": band, "mode": mode} \ No newline at end of file + return {"band": band, "mode": mode} diff --git a/pyhamtools/locator.py b/pyhamtools/locator.py index dc963d5..a37c7ea 100644 --- a/pyhamtools/locator.py +++ b/pyhamtools/locator.py @@ -9,7 +9,7 @@ def latlong_to_locator (latitude, longitude, precision=6): Args: latitude (float): Latitude longitude (float): Longitude - precision (int): 4,6,8 chars (default 6) + precision (int): 4,6,8,10 chars (default 6) Returns: string: Maidenhead locator @@ -33,7 +33,7 @@ def latlong_to_locator (latitude, longitude, precision=6): """ - if precision < 4 or precision ==5 or precision == 7 or precision > 8: + if precision < 4 or precision == 5 or precision == 7 or precision == 9 or precision > 10: return ValueError if longitude >= 180 or longitude <= -180: @@ -99,7 +99,7 @@ def locator_to_latlong (locator, center=True): locator = locator.upper() - if len(locator) < 4 or len(locator) == 5 or len(locator) == 7: + if len(locator) < 4 or len(locator) == 5 or len(locator) == 7 or len(locator) == 9: raise ValueError if ord(locator[0]) > ord('R') or ord(locator[0]) < ord('A'): @@ -126,6 +126,12 @@ def locator_to_latlong (locator, center=True): if ord (locator[7]) > ord('9') or ord(locator[7]) < ord('0'): raise ValueError + if len(locator) == 10: + if ord(locator[8]) > ord('X') or ord(locator[8]) < ord('A'): + raise ValueError + if ord (locator[9]) > ord('X') or ord(locator[9]) < ord('A'): + raise ValueError + longitude = (ord(locator[0]) - ord('A')) * 20 - 180 latitude = (ord(locator[1]) - ord('A')) * 10 - 90 longitude += (ord(locator[2]) - ord('0')) * 2 @@ -156,6 +162,20 @@ def locator_to_latlong (locator, center=True): longitude += 5.0 / 600 / 2 latitude += 2.5 / 600 / 2 + elif len(locator) == 10: + longitude += (ord(locator[4]) - ord('A')) * 5.0 / 60 + latitude += (ord(locator[5]) - ord('A')) * 2.5 / 60 + + longitude += int(locator[6]) * 5.0 / 600 + latitude += int(locator[7]) * 2.5 / 600 + + longitude += (ord(locator[8]) - ord('A')) * 1.0 / 2880 + latitude += (ord(locator[9]) - ord('A')) * 1.0 / 5760 + + if center: + longitude += 1.0 / 2880 / 2 + latitude += 1.0 / 5760 / 2 + else: raise ValueError diff --git a/test/test_locator_latlong_to_locator.py b/test/test_locator_latlong_to_locator.py index 0b5dd25..85b357a 100644 --- a/test/test_locator_latlong_to_locator.py +++ b/test/test_locator_latlong_to_locator.py @@ -23,6 +23,10 @@ class Test_latlong_to_locator(): assert latlong_to_locator(48.51760, 9.40345, precision=8) == "JN48QM84" assert latlong_to_locator(39.222916, -86.45416, 8) == "EM69SF53" + def test_latlong_to_locator_10chars_precision(self): + assert latlong_to_locator(45.835677, 68.525173, precision=10) == "MN45GU30AN" + assert latlong_to_locator(51.124913, 16.941840, 10) == "JO81LC39AX" + def test_latlong_to_locator_invalid_characters(self): # throws ValueError in Python2 and TypeError in Python3 diff --git a/test/test_locator_locator_to_latlong.py b/test/test_locator_locator_to_latlong.py index a5cf1d2..a35ad55 100644 --- a/test/test_locator_locator_to_latlong.py +++ b/test/test_locator_locator_to_latlong.py @@ -30,8 +30,7 @@ class Test_locator_to_latlong(): assert abs(latitude - 48.52083) < 0.00001 assert abs(longitude - 9.37500) < 0.00001 - def test_locator_to_latlong_8chars(self): - + def test_locator_to_latlong_8chars_precision(self): latitude, longitude = locator_to_latlong("JN48QM84") assert abs(latitude - 48.51875) < 0.00001 assert abs(longitude - 9.40416) < 0.00001 @@ -40,6 +39,15 @@ class Test_locator_to_latlong(): assert abs(latitude - 39.222916) < 0.00001 assert abs(longitude + 86.45416) < 0.00001 + def test_locator_to_latlong_10chars_precision(self): + latitude, longitude = locator_to_latlong("JO81LC39AX") + assert abs(latitude - 51.124913) < 0.000001 + assert abs(longitude - 16.941840) < 0.000001 + + latitude, longitude = locator_to_latlong("MN45GU30AN") + assert abs(latitude - 45.835677) < 0.000001 + assert abs(longitude - 68.525173) < 0.000001 + def test_locator_to_latlong_consistency_checks_6chars_lower_left_corner(self): latitude_4, longitude_4 = locator_to_latlong("JN48", center=False) @@ -97,6 +105,9 @@ class Test_locator_to_latlong(): with pytest.raises(ValueError): latitude, longitude = locator_to_latlong("JN8QM1") + with pytest.raises(ValueError): + latitude, longitude = locator_to_latlong("JN8QM1AA") + def test_locator_to_latlong_invalid_characters(self): with pytest.raises(ValueError): From a12616ceca4bb6c8b5587ef4c1dad7ea68ecfdc6 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Mon, 9 Jun 2025 23:29:42 +0200 Subject: [PATCH 08/12] added missing packages for requirements-pytest --- requirements-pytest.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/requirements-pytest.txt b/requirements-pytest.txt index f0acaa0..998390f 100644 --- a/requirements-pytest.txt +++ b/requirements-pytest.txt @@ -3,4 +3,8 @@ pytest==4.6.11; python_version=='3.6' pytest-blockage>=0.2.2 pytest-localserver>=0.5 pytest-cov>=2.12 -maidenhead==1.6.0 \ No newline at end of file +maidenhead==1.6.0 +requests==2.32.2 +bs4==4.13.3 +redis==5.2.1 +ephem==4.2 \ No newline at end of file From b51b32e5752ef14e2193c33f0ce26ec5c9a5cd31 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Tue, 10 Jun 2025 01:32:11 +0200 Subject: [PATCH 09/12] updated CI build system --- .github/workflows/test.yml | 77 +++++++++----------------------------- requirements-pytest.txt | 7 ++-- 2 files changed, 20 insertions(+), 64 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de1a9fe..bf03d3c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,61 +3,17 @@ name: Linux on: [push, pull_request] jobs: - test_linux_legacy: - # Ubuntu 20.04 is still required for python 3.6; this doesn't work on Ubuntu 22.04 anymore - runs-on: "ubuntu-20.04" - name: "Ubuntu 20.04 - Python ${{ matrix.python-version }}" - strategy: - matrix: - python-version: ["3.6"] - redis-version: [6] - - steps: - - uses: "actions/checkout@v3" - - uses: "actions/setup-python@v4" - with: - python-version: "${{ matrix.python-version }}" - cache: "pip" - cache-dependency-path: | - **/setup.py - **/requirements*.txt - - - name: "Install dependencies" - run: | - set -xe - sudo apt-get install -y libxml2-dev libxslt-dev - python -VV - python -m pip install --upgrade pip setuptools - python -m pip install -e . - python -m pip install -r requirements-pytest.txt - - - name: Start Redis - uses: supercharge/redis-github-action@1.2.0 - with: - redis-version: ${{ matrix.redis-version }} - - - name: "Run tests for ${{ matrix.python-version }}" - env: - CLUBLOG_APIKEY: ${{ secrets.CLUBLOG_APIKEY }} - QRZ_USERNAME: ${{ secrets.QRZ_USERNAME }} - QRZ_PWD: ${{ secrets.QRZ_PWD }} - PYTHON_VERSION: ${{ matrix.python-version }} - # delay the execution randomly by a couple of seconds to reduce the amount - # of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously - run: | - sleep $[ ( $RANDOM % 10 ) + 1 ]s - pytest ./test test_linux: - runs-on: "ubuntu-22.04" - name: "Ubuntu 22.04 - Python ${{ matrix.python-version }}" + runs-on: "ubuntu-24.04" + name: "Ubuntu 24.04 - Python ${{ matrix.python-version }}" env: USING_COVERAGE: '3.11' strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] - redis-version: [6] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] + redis-version: [7] steps: - uses: "actions/checkout@v3" @@ -93,7 +49,7 @@ jobs: # delay the execution randomly by a couple of seconds to reduce the amount # of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously run: | - sleep $[ ( $RANDOM % 10 ) + 1 ]s + sleep $[ ( $RANDOM % 60 ) + 1 ]s if [[ $PYTHON_VERSION == 3.11 ]] then pytest --cov=test/ @@ -116,13 +72,12 @@ jobs: test_macos: - # Ubuntu 20.04 is still required for python 3.6; this doesn't work on Ubuntu 22.04 anymore - runs-on: "macos-12" - name: "MacOS 12 - Python ${{ matrix.python-version }}" + runs-on: "macos-15" + name: "MacOS 15 - Python ${{ matrix.python-version }}" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] - redis-version: [6] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "pypy3.8", "pypy3.9", "pypy3.10"] + redis-version: [7.2] steps: - uses: "actions/checkout@v3" @@ -143,7 +98,7 @@ jobs: python -m pip install -r requirements-pytest.txt - name: Start Redis - uses: shogo82148/actions-setup-redis@v1.31.1 + uses: shogo82148/actions-setup-redis@v1 with: redis-version: ${{ matrix.redis-version }} @@ -156,16 +111,16 @@ jobs: # delay the execution randomly by a couple of seconds to reduce the amount # of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously run: | - sleep $[ ( $RANDOM % 10 ) + 1 ] + sleep $[ ( $RANDOM % 60 ) + 1 ] pytest ./test test_windows: - runs-on: "windows-latest" + runs-on: "windows-2022" name: "Windows latest - Python ${{ matrix.python-version }}" strategy: matrix: - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: "actions/checkout@v3" @@ -193,8 +148,10 @@ jobs: C:\msys64\usr\bin\wget.exe https://github.com/redis-windows/redis-windows/releases/download/7.0.14/Redis-7.0.14-Windows-x64-msys2-with-Service.zip C:\msys64\usr\bin\pacman.exe -S --noconfirm unzip C:\msys64\usr\bin\unzip.exe Redis-7.0.14-Windows-x64-msys2-with-Service.zip - sc.exe create Redis binpath=D:\a\pyhamtools\pyhamtools\Redis-7.0.14-Windows-x64-msys2-with-Service\RedisService.exe start= auto + sc.exe create Redis binpath=${{ github.workspace }}\Redis-7.0.14-Windows-x64-msys2-with-Service\RedisService.exe start= auto + echo "Redis service created, now starting it" net start Redis + echo "Redis service started" - name: "Run tests for ${{ matrix.python-version }}" env: @@ -207,5 +164,5 @@ jobs: # amount of concurrent API calls on Clublog and QRZ.com # when all CI jobs execute simultaneously run: | - start-sleep -Seconds (5..20 | get-random) + start-sleep -Seconds (5..60 | get-random) pytest \ No newline at end of file diff --git a/requirements-pytest.txt b/requirements-pytest.txt index 998390f..a5c2fa7 100644 --- a/requirements-pytest.txt +++ b/requirements-pytest.txt @@ -1,10 +1,9 @@ -pytest>=7.0.0; python_version>='3.7' -pytest==4.6.11; python_version=='3.6' +pytest>=7.0.0 pytest-blockage>=0.2.2 pytest-localserver>=0.5 pytest-cov>=2.12 maidenhead==1.6.0 -requests==2.32.2 -bs4==4.13.3 +requests>=2.32.4 +beautifulsoup4==4.13.4 redis==5.2.1 ephem==4.2 \ No newline at end of file From 9c61f75c284b8182a4d68b179f5a1b07b2734c85 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Tue, 10 Jun 2025 01:34:16 +0200 Subject: [PATCH 10/12] release version 0.12.0 --- README.md | 8 +++++--- docs/source/changelog.rst | 12 ++++++++++++ pyhamtools/version.py | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78edca3..316610e 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,6 @@ This Library is used in production at the [DXHeat.com DX Cluster](https://dxheat Pyhamtools is compatible with Python >=3.6. We check compatibility on OSX, Windows, and Linux with the following Python versions: -* Python 3.6 (will be deprecated in 2025) -* Python 3.7 (will be deprecated in 2025) * Python 3.8 * Python 3.9 * Python 3.10 @@ -46,7 +44,11 @@ We check compatibility on OSX, Windows, and Linux with the following Python vers * [pypy3.9](https://pypy.org/) * [pypy3.10](https://pypy.org/) -The support for Python 2.7 and 3.5 has been deprecated at the end of 2023. The last version which supports Python 2.7 and Python 3.5 is 0.8.7. +### depreciated: Python 2.7 & Python 3.5 +The support for Python 2.7 and 3.5 has been deprecated at the end of 2023. The last version which supports Python 2.7 and Python 3.5 is 0.8.7. + +### depricated: Python 3.6 & Python 3.7 +Support for Python 3.6 and Python 3.7 has been deprecated in June 2025. The last version which support Python 3.6 and Python 3.7 is 0.11.0. ## Documentation diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 25a83c5..804559f 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -1,6 +1,18 @@ Changelog --------- +PyHamtools 0.12.0 +================ + +09. June 2025 + +* deprecated support for Python 3.6 +* deprecated support for Python 3.7 +* added support for higher Microwave bands (tnx @sq6emm) +* added support for 10 characters Maidenhead locators (tnx @sq6emm) +* updated CI pipeline + + PyHamtools 0.11.0 ================ diff --git a/pyhamtools/version.py b/pyhamtools/version.py index b3e6bed..8f63cd8 100644 --- a/pyhamtools/version.py +++ b/pyhamtools/version.py @@ -1,3 +1,3 @@ -VERSION = (0, 11, 0) +VERSION = (0, 12, 0) __release__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:] __version__ = '.'.join((str(VERSION[0]), str(VERSION[1]))) From 8ef752e3ad4c40bbb767e7932e3103f5ccf02dbd Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Wed, 30 Jul 2025 00:49:38 +0200 Subject: [PATCH 11/12] added unittest for frequency conversion (2.4GHz - 13cm) --- test/test_utils_freq_to_band.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_utils_freq_to_band.py b/test/test_utils_freq_to_band.py index 1373f0c..1672c3f 100644 --- a/test/test_utils_freq_to_band.py +++ b/test/test_utils_freq_to_band.py @@ -65,6 +65,7 @@ class Test_utils_freq_to_band(): assert freq_to_band(1200000) == {"band" : 0.23, "mode":None} def test_shf_frequencies(self): + assert freq_to_band(2320200) == {"band" : 0.13, "mode":None} assert freq_to_band(2390000) == {"band" : 0.13, "mode":None} assert freq_to_band(3300000) == {"band" : 0.09, "mode":None} From 8c15ab8c2c15858a0e0eeabf004c292cfd803b20 Mon Sep 17 00:00:00 2001 From: "Tobias Wellnitz, DH1TW" Date: Wed, 10 Sep 2025 23:21:34 +0200 Subject: [PATCH 12/12] changed documents theme to readthedocs --- docs/source/conf.py | 5 ++++- readthedocs-pip-requirements.txt | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6356823..cb9fd69 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,6 +25,7 @@ from pyhamtools.version import __version__, __release__ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', + 'sphinx_rtd_dark_mode', ] # Add any paths that contain templates here, relative to this directory. @@ -95,7 +96,9 @@ pygments_style = 'sphinx' # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'default' +# html_theme = 'default' +html_theme = 'sphinx_rtd_theme' +# html_theme = 'sphinx_material' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/readthedocs-pip-requirements.txt b/readthedocs-pip-requirements.txt index 8bfee76..3a5e4ea 100644 --- a/readthedocs-pip-requirements.txt +++ b/readthedocs-pip-requirements.txt @@ -1,3 +1,5 @@ sphinx>=1.8.5 sphinxcontrib-napoleon>=0.7 -beautifulsoup4>=4.7.1 \ No newline at end of file +beautifulsoup4>=4.7.1 +sphinx_rtd_theme>=0.5.2 +sphinx_rtd_dark_mode>=0.1.2 \ No newline at end of file