added support for python 3.12

This commit is contained in:
Tobias Wellnitz, DH1TW 2023-12-28 21:02:41 +01:00
parent e549f416e8
commit 6a152760c5
24 changed files with 289 additions and 313 deletions

View file

@ -4,14 +4,59 @@ on: [push, pull_request]
jobs:
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 latest - Python ${{ matrix.python-version }}"
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:
USING_COVERAGE: '3.11'
strategy:
matrix:
python-version: ["2.7", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "pypy2.7", "pypy3.7", "pypy3.8", "pypy3.9"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.7", "pypy3.8", "pypy3.9", "pypy3.10"]
redis-version: [6]
steps:
@ -49,8 +94,13 @@ jobs:
# of concurrent API calls on Clublog and QRZ.com when all CI jobs execute simultaneously
run: |
sleep $[ ( $RANDOM % 10 ) + 1 ]s
pytest --cov=./
if [[ $PYTHON_VERSION == 3.11 ]]; then codecov; fi
if [[ $PYTHON_VERSION == 3.11 ]]
then
pytest --cov=test/
codecov
else
pytest test/
fi
cd docs && make html
# publish_package:
@ -64,18 +114,58 @@ jobs:
# user: __token__
# password: ${{ secrets.PYPI_API_TOKEN }}
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 }}"
strategy:
matrix:
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "pypy3.8", "pypy3.9", "pypy3.10"]
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
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: shogo82148/actions-setup-redis@v1.31.1
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 ]
pytest ./test
test_windows:
runs-on: "windows-latest"
name: "Windows latest - Python ${{ matrix.python-version }}"
strategy:
matrix:
# lxml support for windows/python3.11 still missing (Dec 2022)
# https://github.com/lxml/lxml/pull/360
# python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
# python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
# disable python 3.6 on windows due to lxml / bs4 problems on Github Actions
python-version: ["3.7", "3.8", "3.9", "3.10"]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: "actions/checkout@v3"
@ -94,24 +184,27 @@ jobs:
python -m pip install -r requirements-pytest.txt
python -m pip install -r requirements-docs.txt
- name: Setup redis
# We have to download and install a non-official redis windows port
# since there is no official redis version for windows.
# 5.0 is good enough for our purposes. After installing the msi,
# redis will startup as a service.
# There are no github-actions supporting redis on windows.
# Github Actions Container services are also not available for windows.
# We have to download and install a non-official redis windows port
# 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/tporadowski/redis/releases/download/v5.0.14.1/Redis-x64-5.0.14.1.msi
msiexec /quiet /i Redis-x64-5.0.14.1.msi
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
net start Redis
- 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 1-20sec to reduce the
# give redis service time to startup and
# delay the execution randomly by 5-20sec to reduce the
# amount of concurrent API calls on Clublog and QRZ.com
# when all CI jobs execute simultaneously
run: |
start-sleep -Seconds (1..10 | get-random)
start-sleep -Seconds (5..20 | get-random)
pytest

View file

@ -4,7 +4,7 @@
[![codecov](https://codecov.io/gh/dh1tw/pyhamtools/branch/master/graph/badge.svg)](https://codecov.io/gh/dh1tw/pyhamtools)
[![PyPI version](https://badge.fury.io/py/pyhamtools.svg)](https://badge.fury.io/py/pyhamtools)
Pyhamtools is a set of functions and classes for Amateur Radio purpose.
Pyhamtools is a set of functions and classes for Amateur Radio purposes.
Currently, the core part is the Callsign Lookup which decodes any amateur radio
callsign string and provides the corresponding information (Country, DXCC
entity, CQ Zone...etc). This basic functionality is needed for Logbooks,
@ -31,22 +31,22 @@ This Library is used in production at the [DXHeat.com DX Cluster](https://dxheat
## Compatibility
Pyhamtools is compatible with Python 2.7 and Python >=3.6.
We check compatibility on OSX, Windows, and Linux with the following Python
versions:
Pyhamtools is compatible with Python >=3.6.
We check compatibility on OSX, Windows, and Linux with the following Python versions:
* Python 2.7 (will be deprecated in 2023)
* Python 3.5 (has been deprecated in 2022)
* Python 3.6 (will be deprecated in 2023)
* Python 3.7
* Python 3.6 (will be deprecated in 2024)
* Python 3.7 (will be deprecated in 2024)
* Python 3.8
* Python 3.9
* Python 3.10
* Python 3.11
* [pypy2](https://pypy.org/) (Python 2)
* [pypy3.7](https://pypy.org/)
* Python 3.12
* [pypy3.7](https://pypy.org/) (will be deprecated in 2024)
* [pypy3.8](https://pypy.org/)
* [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.
## Documentation

View file

@ -1,6 +1,18 @@
Changelog
---------
PyHamtools 0.9.0
================
28. December 2023
* Deprecated support for Python 2.7 and Python 3.5
* Added Support for Python 3.12
* Replaced pytz with datetime.timezone
* Added Continous Integration Jobs for MacOS (now supported by Github Actions)
PyHamtools 0.8.7
================

View file

@ -12,19 +12,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
from pyhamtools.version import __version__, __release__
sys.path.insert(0,"/Users/user/projects/pyhamtools/pyhamtools")
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
@ -52,7 +41,7 @@ master_doc = 'index'
# General information about the project.
project = u'pyhamtools'
copyright = u'2019, Tobias Wellnitz, DH1TW'
copyright = u'2024, Tobias Wellnitz, DH1TW'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the

View file

@ -1,22 +1,11 @@
import re
import logging
from datetime import datetime
import sys
import pytz
from datetime import datetime, timezone
from pyhamtools.consts import LookupConventions as const
from pyhamtools.callsign_exceptions import callsign_exceptions
UTC = pytz.UTC
if sys.version_info < (2, 7, ):
class NullHandler(logging.Handler):
def emit(self, record):
pass
class Callinfo(object):
"""
The purpose of this class is to return data (country, latitude, longitude, CQ Zone...etc) for an
@ -37,10 +26,7 @@ class Callinfo(object):
self._logger = logger
else:
self._logger = logging.getLogger(__name__)
if sys.version_info[:2] == (2, 6):
self._logger.addHandler(NullHandler())
else:
self._logger.addHandler(logging.NullHandler())
self._logger.addHandler(logging.NullHandler())
self._lookuplib = lookuplib
self._callsign_info = None
@ -81,10 +67,10 @@ class Callinfo(object):
"""truncate call until it corresponds to a Prefix in the database"""
prefix = callsign
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if re.search('(VK|AX|VI)9[A-Z]{3}', callsign): #special rule for VK9 calls
if timestamp > datetime(2006,1,1, tzinfo=UTC):
if timestamp > datetime(2006,1,1, tzinfo=timezone.utc):
prefix = callsign[0:3]+callsign[4:5]
while len(prefix) > 0:
@ -115,7 +101,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Raises:
KeyError: Callsign could not be identified
@ -124,7 +110,7 @@ class Callinfo(object):
"""
entire_callsign = callsign.upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if re.search('[/A-Z0-9\\-]{3,15}', entire_callsign): # make sure the call has at least 3 characters
@ -230,7 +216,7 @@ class Callinfo(object):
def _lookup_callsign(self, callsign, timestamp=None):
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
# Check if operation is invalid
invalid = False
@ -278,7 +264,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
dict: Dictionary containing the callsign specific data
@ -315,7 +301,7 @@ class Callinfo(object):
callsign = callsign.upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
callsign_data = self._lookup_callsign(callsign, timestamp)
@ -332,7 +318,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
bool: True / False
@ -348,7 +334,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
try:
if self.get_all(callsign, timestamp):
@ -361,7 +347,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
dict: Containing Latitude and Longitude
@ -388,7 +374,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
callsign_data = self.get_all(callsign, timestamp=timestamp)
return {
@ -401,7 +387,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
int: containing the callsign's CQ Zone
@ -411,7 +397,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
return self.get_all(callsign, timestamp)[const.CQZ]
@ -420,7 +406,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
int: containing the callsign's CQ Zone
@ -433,7 +419,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
return self.get_all(callsign, timestamp)[const.ITUZ]
@ -442,7 +428,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
str: name of the Country
@ -460,7 +446,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
return self.get_all(callsign, timestamp)[const.COUNTRY]
@ -469,7 +455,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
int: containing the country ADIF id
@ -479,7 +465,7 @@ class Callinfo(object):
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
return self.get_all(callsign, timestamp)[const.ADIF]
@ -488,7 +474,7 @@ class Callinfo(object):
Args:
callsign (str): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
str: continent identified
@ -508,6 +494,6 @@ class Callinfo(object):
- AN: Antarctica
"""
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
return self.get_all(callsign, timestamp)[const.CONTINENT]

View file

@ -1,37 +1,30 @@
__author__ = 'dh1tw'
from datetime import datetime
from datetime import datetime, timezone
from time import strptime, mktime
import re
import pytz
from pyhamtools.consts import LookupConventions as const
UTC = pytz.UTC
def decode_char_spot(raw_string):
"""Chop Line from DX-Cluster into pieces and return a dict with the spot data"""
data = {}
# Spotter callsign
if re.match('[A-Za-z0-9\/]+[:$]', raw_string[6:15]):
data[const.SPOTTER] = re.sub(':', '', re.match('[A-Za-z0-9\/]+[:$]', raw_string[6:15]).group(0))
if re.match(r'[A-Za-z0-9\/]+[:$]', raw_string[6:15]):
data[const.SPOTTER] = re.sub(':', '', re.match(r'[A-Za-z0-9\/]+[:$]', raw_string[6:15]).group(0))
else:
raise ValueError
if re.search('[0-9\.]{5,12}', raw_string[10:25]):
data[const.FREQUENCY] = float(re.search('[0-9\.]{5,12}', raw_string[10:25]).group(0))
if re.search(r'[0-9\.]{5,12}', raw_string[10:25]):
data[const.FREQUENCY] = float(re.search(r'[0-9\.]{5,12}', raw_string[10:25]).group(0))
else:
raise ValueError
data[const.DX] = re.sub('[^A-Za-z0-9\/]+', '', raw_string[26:38])
data[const.COMMENT] = re.sub('[^\sA-Za-z0-9\.,;\#\+\-!\?\$\(\)@\/]+', ' ', raw_string[39:69]).strip()
data[const.TIME] = datetime.now().replace(tzinfo=UTC)
data[const.DX] = re.sub(r'[^A-Za-z0-9\/]+', '', raw_string[26:38])
data[const.COMMENT] = re.sub(r'[^\sA-Za-z0-9\.,;\#\+\-!\?\$\(\)@\/]+', ' ', raw_string[39:69]).strip()
data[const.TIME] = datetime.now(timezone.utc)
return data

View file

@ -1,12 +1,8 @@
from __future__ import division
from math import pi, sin, cos, atan2, sqrt, radians, log, tan, degrees
from datetime import datetime
from datetime import datetime, timezone
import pytz
import ephem
UTC = pytz.UTC
def latlong_to_locator (latitude, longitude):
"""converts WGS84 coordinates into the corresponding Maidenhead Locator
@ -283,16 +279,14 @@ def calculate_sunrise_sunset(locator, calc_date=None):
The following calculates the next sunrise & sunset for JN48QM on the 1./Jan/2014
>>> from pyhamtools.locator import calculate_sunrise_sunset
>>> from datetime import datetime
>>> import pytz
>>> UTC = pytz.UTC
>>> myDate = datetime(year=2014, month=1, day=1, tzinfo=UTC)
>>> from datetime import datetime, timezone
>>> myDate = datetime(year=2014, month=1, day=1, tzinfo=timezone.utc)
>>> calculate_sunrise_sunset("JN48QM", myDate)
{
'morning_dawn': datetime.datetime(2014, 1, 1, 6, 36, 51, 710524, tzinfo=<UTC>),
'sunset': datetime.datetime(2014, 1, 1, 16, 15, 23, 31016, tzinfo=<UTC>),
'evening_dawn': datetime.datetime(2014, 1, 1, 15, 38, 8, 355315, tzinfo=<UTC>),
'sunrise': datetime.datetime(2014, 1, 1, 7, 14, 6, 162063, tzinfo=<UTC>)
'morning_dawn': datetime.datetime(2014, 1, 1, 6, 36, 51, 710524, tzinfo=datetime.timezone.utc),
'sunset': datetime.datetime(2014, 1, 1, 16, 15, 23, 31016, tzinfo=datetime.timezone.utc),
'evening_dawn': datetime.datetime(2014, 1, 1, 15, 38, 8, 355315, tzinfo=datetime.timezone.utc),
'sunrise': datetime.datetime(2014, 1, 1, 7, 14, 6, 162063, tzinfo=datetime.timezone.utc)
}
"""
@ -304,7 +298,7 @@ def calculate_sunrise_sunset(locator, calc_date=None):
latitude, longitude = locator_to_latlong(locator)
if calc_date is None:
calc_date = datetime.utcnow()
calc_date = datetime.now(timezone.utc)
if type(calc_date) != datetime:
raise ValueError
@ -350,11 +344,11 @@ def calculate_sunrise_sunset(locator, calc_date=None):
result['sunset'] = sunset
if morning_dawn:
result['morning_dawn'] = morning_dawn.replace(tzinfo=UTC)
result['morning_dawn'] = morning_dawn.replace(tzinfo=timezone.utc)
if sunrise:
result['sunrise'] = sunrise.replace(tzinfo=UTC)
result['sunrise'] = sunrise.replace(tzinfo=timezone.utc)
if evening_dawn:
result['evening_dawn'] = evening_dawn.replace(tzinfo=UTC)
result['evening_dawn'] = evening_dawn.replace(tzinfo=timezone.utc)
if sunset:
result['sunset'] = sunset.replace(tzinfo=UTC)
result['sunset'] = sunset.replace(tzinfo=timezone.utc)
return result

View file

@ -1,38 +1,24 @@
from __future__ import unicode_literals
import os
import logging
import logging.config
import re
import random, string
from datetime import datetime
from datetime import datetime, timezone
import xml.etree.ElementTree as ET
import urllib
import json
import copy
import sys
import unicodedata
import requests
from requests.exceptions import ConnectionError, HTTPError, Timeout
from bs4 import BeautifulSoup
import pytz
from . import version
from .consts import LookupConventions as const
from .exceptions import APIKeyMissingError
UTC = pytz.UTC
REDIS_LUA_DEL_SCRIPT = "local keys = redis.call('keys', ARGV[1]) \n for i=1,#keys,20000 do \n redis.call('del', unpack(keys, i, math.min(i+19999, #keys))) \n end \n return keys"
if sys.version_info < (2, 7,):
class NullHandler(logging.Handler):
def emit(self, record):
pass
if sys.version_info.major == 3:
unicode = str
class LookupLib(object):
"""
@ -80,10 +66,7 @@ class LookupLib(object):
self._logger = logger
else:
self._logger = logging.getLogger(__name__)
if sys.version_info[:2] == (2, 6):
self._logger.addHandler(NullHandler())
else:
self._logger.addHandler(logging.NullHandler())
self._logger.addHandler(logging.NullHandler())
self._apikey = apikey
self._apiv = apiv
@ -131,10 +114,7 @@ class LookupLib(object):
"agent" : agent
}
if sys.version_info.major == 3:
encodeurl = url + "?" + urllib.parse.urlencode(params)
else:
encodeurl = url + "?" + urllib.urlencode(params)
encodeurl = url + "?" + urllib.parse.urlencode(params)
response = requests.get(encodeurl, timeout=10)
doc = BeautifulSoup(response.text, "xml")
session_key = None
@ -334,7 +314,7 @@ class LookupLib(object):
Args:
callsign (string): Amateur radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
dict: Dictionary containing the country specific data of the callsign
@ -347,10 +327,9 @@ class LookupLib(object):
The following code queries the the online Clublog API for the callsign "VK9XO" on a specific date.
>>> from pyhamtools import LookupLib
>>> from datetime import datetime
>>> import pytz
>>> from datetime import datetime, timezone
>>> my_lookuplib = LookupLib(lookuptype="clublogapi", apikey="myapikey")
>>> timestamp = datetime(year=1962, month=7, day=7, tzinfo=pytz.UTC)
>>> timestamp = datetime(year=1962, month=7, day=7, tzinfo=timezone.utc)
>>> print my_lookuplib.lookup_callsign("VK9XO", timestamp)
{
'country': u'CHRISTMAS ISLAND',
@ -374,7 +353,7 @@ class LookupLib(object):
"""
callsign = callsign.strip().upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if self._lookuptype == "clublogapi":
callsign_data = self._lookup_clublogAPI(callsign=callsign, timestamp=timestamp, apikey=self._apikey)
@ -499,7 +478,7 @@ class LookupLib(object):
Args:
prefix (string): Prefix of a Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
dict: Dictionary containing the country specific data of the Prefix
@ -536,7 +515,7 @@ class LookupLib(object):
prefix = prefix.strip().upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if self._lookuptype == "clublogxml" or self._lookuptype == "countryfile":
@ -556,7 +535,7 @@ class LookupLib(object):
Args:
callsign (string): Amateur Radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
bool: True if a record exists for this callsign (at the given time)
@ -569,13 +548,12 @@ class LookupLib(object):
The following code checks the Clublog XML database if the operation is valid for two dates.
>>> from pyhamtools import LookupLib
>>> from datetime import datetime
>>> import pytz
>>> from datetime import datetime, timezone
>>> my_lookuplib = LookupLib(lookuptype="clublogxml", apikey="myapikey")
>>> print my_lookuplib.is_invalid_operation("5W1CFN")
True
>>> try:
>>> timestamp = datetime(year=2012, month=1, day=31).replace(tzinfo=pytz.UTC)
>>> timestamp = datetime(year=2012, month=1, day=31, tzinfo=timezone.utc)
>>> my_lookuplib.is_invalid_operation("5W1CFN", timestamp)
>>> except KeyError:
>>> print "Seems to be invalid operation before 31.1.2012"
@ -591,7 +569,7 @@ class LookupLib(object):
callsign = callsign.strip().upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if self._lookuptype == "clublogxml":
@ -645,7 +623,7 @@ class LookupLib(object):
Args:
callsign (string): Amateur radio callsign
timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC)
timestamp (datetime, optional): datetime in UTC (tzinfo=timezone.utc)
Returns:
int: Value of the the CQ Zone exception which exists for this callsign (at the given time)
@ -675,7 +653,7 @@ class LookupLib(object):
callsign = callsign.strip().upper()
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if self._lookuptype == "clublogxml":
@ -704,12 +682,9 @@ class LookupLib(object):
}
if timestamp is None:
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
if sys.version_info.major == 3:
encodeurl = url + "?" + urllib.parse.urlencode(params)
else:
encodeurl = url + "?" + urllib.urlencode(params)
encodeurl = url + "?" + urllib.parse.urlencode(params)
response = requests.get(encodeurl, timeout=5)
if not self._check_html_response(response):
@ -740,10 +715,7 @@ class LookupLib(object):
"callsign" : callsign,
}
if sys.version_info.major == 3:
encodeurl = url + "?" + urllib.parse.urlencode(params)
else:
encodeurl = url + "?" + urllib.urlencode(params)
encodeurl = url + "?" + urllib.parse.urlencode(params)
response = requests.get(encodeurl, timeout=5)
return response
@ -756,10 +728,7 @@ class LookupLib(object):
"dxcc" : str(dxcc_or_callsign),
}
if sys.version_info.major == 3:
encodeurl = url + "?" + urllib.parse.urlencode(params)
else:
encodeurl = url + "?" + urllib.urlencode(params)
encodeurl = url + "?" + urllib.parse.urlencode(params)
response = requests.get(encodeurl, timeout=5)
return response
@ -890,12 +859,12 @@ class LookupLib(object):
lookup[const.LAND] = root.Callsign.land.text
if root.Callsign.efdate:
try:
lookup[const.EFDATE] = datetime.strptime(root.Callsign.efdate.text, '%Y-%m-%d').replace(tzinfo=UTC)
lookup[const.EFDATE] = datetime.strptime(root.Callsign.efdate.text, '%Y-%m-%d').replace(tzinfo=timezone.utc)
except ValueError:
self._logger.debug("[QRZ.com] efdate: Invalid DateTime; " + callsign + " " + root.Callsign.efdate.text)
if root.Callsign.expdate:
try:
lookup[const.EXPDATE] = datetime.strptime(root.Callsign.expdate.text, '%Y-%m-%d').replace(tzinfo=UTC)
lookup[const.EXPDATE] = datetime.strptime(root.Callsign.expdate.text, '%Y-%m-%d').replace(tzinfo=timezone.utc)
except ValueError:
self._logger.debug("[QRZ.com] expdate: Invalid DateTime; " + callsign + " " + root.Callsign.expdate.text)
if root.Callsign.p_call:
@ -916,7 +885,7 @@ class LookupLib(object):
lookup[const.BIO] = root.Callsign.bio.text
if root.Callsign.biodate:
try:
lookup[const.BIODATE] = datetime.strptime(root.Callsign.biodate.text, '%Y-%m-%d %H:%M:%S').replace(tzinfo=UTC)
lookup[const.BIODATE] = datetime.strptime(root.Callsign.biodate.text, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
except ValueError:
self._logger.warning("[QRZ.com] biodate: Invalid DateTime; " + callsign)
if root.Callsign.image:
@ -927,7 +896,7 @@ class LookupLib(object):
lookup[const.SERIAL] = long(root.Callsign.serial.text)
if root.Callsign.moddate:
try:
lookup[const.MODDATE] = datetime.strptime(root.Callsign.moddate.text, '%Y-%m-%d %H:%M:%S').replace(tzinfo=UTC)
lookup[const.MODDATE] = datetime.strptime(root.Callsign.moddate.text, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
except ValueError:
self._logger.warning("[QRZ.com] moddate: Invalid DateTime; " + callsign)
if root.Callsign.MSA:
@ -971,10 +940,6 @@ class LookupLib(object):
if root.Callsign.geoloc:
lookup[const.GEOLOC] = root.Callsign.geoloc.text
# if sys.version_info >= (2,):
# for item in lookup:
# if isinstance(lookup[item], unicode):
# print item, repr(lookup[item])
return lookup
def _load_clublogXML(self,
@ -1135,7 +1100,7 @@ class LookupLib(object):
if cty_date:
cty_date = cty_date.group(0).replace("date=", "").replace("'", "")
cty_date = datetime.strptime(cty_date[:19], '%Y-%m-%dT%H:%M:%S')
cty_date.replace(tzinfo=UTC)
cty_date.replace(tzinfo=timezone.utc)
cty_header["Date"] = cty_date
cty_ns = re.search("xmlns='.+[']", raw_header)
@ -1215,10 +1180,10 @@ class LookupLib(object):
entity = {}
for item in cty_entity:
if item.tag == "name":
entity[const.COUNTRY] = unicode(item.text)
self._logger.debug(unicode(item.text))
entity[const.COUNTRY] = str(item.text)
self._logger.debug(str(item.text))
elif item.tag == "prefix":
entity[const.PREFIX] = unicode(item.text)
entity[const.PREFIX] = str(item.text)
elif item.tag == "deleted":
if item.text == "TRUE":
entity[const.DELETED] = True
@ -1227,17 +1192,17 @@ class LookupLib(object):
elif item.tag == "cqz":
entity[const.CQZ] = int(item.text)
elif item.tag == "cont":
entity[const.CONTINENT] = unicode(item.text)
entity[const.CONTINENT] = str(item.text)
elif item.tag == "long":
entity[const.LONGITUDE] = float(item.text)
elif item.tag == "lat":
entity[const.LATITUDE] = float(item.text)
elif item.tag == "start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.START] = dt.replace(tzinfo=UTC)
entity[const.START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.END] = dt.replace(tzinfo=UTC)
entity[const.END] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "whitelist":
if item.text == "TRUE":
entity[const.WHITELIST] = True
@ -1245,10 +1210,10 @@ class LookupLib(object):
entity[const.WHITELIST] = False
elif item.tag == "whitelist_start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.WHITELIST_START] = dt.replace(tzinfo=UTC)
entity[const.WHITELIST_START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "whitelist_end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.WHITELIST_END] = dt.replace(tzinfo=UTC)
entity[const.WHITELIST_END] = dt.replace(tzinfo=timezone.utc)
except AttributeError:
self._logger.error("Error while processing: ")
entities[int(cty_entity[0].text)] = entity
@ -1269,23 +1234,23 @@ class LookupLib(object):
else:
call_exceptions_index[call] = [int(cty_exception.attrib["record"])]
elif item.tag == "entity":
call_exception[const.COUNTRY] = unicode(item.text)
call_exception[const.COUNTRY] = str(item.text)
elif item.tag == "adif":
call_exception[const.ADIF] = int(item.text)
elif item.tag == "cqz":
call_exception[const.CQZ] = int(item.text)
elif item.tag == "cont":
call_exception[const.CONTINENT] = unicode(item.text)
call_exception[const.CONTINENT] = str(item.text)
elif item.tag == "long":
call_exception[const.LONGITUDE] = float(item.text)
elif item.tag == "lat":
call_exception[const.LATITUDE] = float(item.text)
elif item.tag == "start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
call_exception[const.START] = dt.replace(tzinfo=UTC)
call_exception[const.START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
call_exception[const.END] = dt.replace(tzinfo=UTC)
call_exception[const.END] = dt.replace(tzinfo=timezone.utc)
call_exceptions[int(cty_exception.attrib["record"])] = call_exception
self._logger.debug(str(len(call_exceptions))+" Exceptions added")
@ -1310,23 +1275,23 @@ class LookupLib(object):
else:
prefixes_index[call] = [int(cty_prefix.attrib["record"])]
if item.tag == "entity":
prefix[const.COUNTRY] = unicode(item.text)
prefix[const.COUNTRY] = str(item.text)
elif item.tag == "adif":
prefix[const.ADIF] = int(item.text)
elif item.tag == "cqz":
prefix[const.CQZ] = int(item.text)
elif item.tag == "cont":
prefix[const.CONTINENT] = unicode(item.text)
prefix[const.CONTINENT] = str(item.text)
elif item.tag == "long":
prefix[const.LONGITUDE] = float(item.text)
elif item.tag == "lat":
prefix[const.LATITUDE] = float(item.text)
elif item.tag == "start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
prefix[const.START] = dt.replace(tzinfo=UTC)
prefix[const.START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
prefix[const.END] = dt.replace(tzinfo=UTC)
prefix[const.END] = dt.replace(tzinfo=timezone.utc)
prefixes[int(cty_prefix.attrib["record"])] = prefix
self._logger.debug(str(len(prefixes))+" Prefixes added")
@ -1349,10 +1314,10 @@ class LookupLib(object):
elif item.tag == "start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
invalid_operation[const.START] = dt.replace(tzinfo=UTC)
invalid_operation[const.START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
invalid_operation[const.END] = dt.replace(tzinfo=UTC)
invalid_operation[const.END] = dt.replace(tzinfo=timezone.utc)
invalid_operations[int(cty_inv_operation.attrib["record"])] = invalid_operation
self._logger.debug(str(len(invalid_operations))+" Invalid Operations added")
@ -1378,10 +1343,10 @@ class LookupLib(object):
zoneException[const.CQZ] = int(item.text)
elif item.tag == "start":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
zoneException[const.START] = dt.replace(tzinfo=UTC)
zoneException[const.START] = dt.replace(tzinfo=timezone.utc)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
zoneException[const.END] = dt.replace(tzinfo=UTC)
zoneException[const.END] = dt.replace(tzinfo=timezone.utc)
zone_exceptions[int(cty_zone_exception.attrib["record"])] = zoneException
self._logger.debug(str(len(zone_exceptions))+" Zone Exceptions added")
@ -1437,12 +1402,12 @@ class LookupLib(object):
for item in cty_list:
entry = {}
call = str(item)
entry[const.COUNTRY] = unicode(cty_list[item]["Country"])
entry[const.COUNTRY] = str(cty_list[item]["Country"])
if mapping:
entry[const.ADIF] = int(mapping[cty_list[item]["Country"]])
entry[const.CQZ] = int(cty_list[item]["CQZone"])
entry[const.ITUZ] = int(cty_list[item]["ITUZone"])
entry[const.CONTINENT] = unicode(cty_list[item]["Continent"])
entry[const.CONTINENT] = str(cty_list[item]["Continent"])
entry[const.LATITUDE] = float(cty_list[item]["Latitude"])
entry[const.LONGITUDE] = float(cty_list[item]["Longitude"])*(-1)
@ -1534,17 +1499,17 @@ class LookupLib(object):
elif item == const.LONGITUDE:
my_dict[item] = float(my_dict[item])
elif item == const.START:
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=UTC)
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=timezone.utc)
elif item == const.END:
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=UTC)
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=timezone.utc)
elif item == const.WHITELIST_START:
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=UTC)
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=timezone.utc)
elif item == const.WHITELIST_END:
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=UTC)
my_dict[item] = datetime.strptime(my_dict[item], '%Y-%m-%d%H:%M:%S').replace(tzinfo=timezone.utc)
elif item == const.WHITELIST:
my_dict[item] = self._str_to_bool(my_dict[item])
else:
my_dict[item] = unicode(my_dict[item])
my_dict[item] = str(my_dict[item])
return my_dict

View file

@ -1,4 +1,3 @@
from future.utils import iteritems
from datetime import datetime
import re
@ -125,7 +124,7 @@ def get_clublog_users(**kwargs):
error_count = 0
for call, call_data in iteritems(cl_data):
for call, call_data in cl_data.items():
try:
data = {}
if "firstqso" in call_data:

View file

@ -1,3 +1,3 @@
VERSION = (0, 8, 7)
VERSION = (0, 9, 0)
__release__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:]
__version__ = '.'.join((str(VERSION[0]), str(VERSION[1])))

View file

@ -1,5 +1,5 @@
pytest>=7.0.0; python_version>='3.7'
pytest==4.6.11; python_version<='3.6' and python_version>='2.7'
pytest==4.6.11; python_version=='3.6'
pytest-blockage>=0.2.2
pytest-localserver>=0.5
pytest-cov>=2.12

View file

@ -1,5 +1,4 @@
#!/usr/bin/env python
import sys
import os
from distutils.core import setup
@ -16,12 +15,10 @@ setup(name='pyhamtools',
package_data={'': ['countryfilemapping.json']},
packages=['pyhamtools'],
install_requires=[
"pytz>=2019.1",
"requests>=2.21.0",
"ephem>=4.1.3",
"beautifulsoup4>=4.7.1",
"lxml>=4.8.0",
"future>=0.18.2",
"redis>=2.10.6",
],
**kw

View file

@ -1,14 +1,10 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from datetime import datetime, timezone
import pytest
import pytz
from pyhamtools.consts import LookupConventions as const
UTC = pytz.UTC
response_prefix_DH_clublog = {
'country': 'FEDERAL REPUBLIC OF GERMANY',
'adif': 230,
@ -198,8 +194,8 @@ response_Exception_VK9XO_with_start_date = {
'adif': 35,
'country': 'CHRISTMAS ISLAND',
'continent': 'OC',
'latitude': -10.50,
'longitude': 105.70,
'latitude': -10.48,
'longitude': 105.71,
'cqz': 29
}
@ -389,7 +385,7 @@ class Test_callinfo_methods:
if fix_callinfo._lookuplib._lookuptype == "clublogxml" or fix_callinfo._lookuplib._lookuptype == "clublogapi":
assert fix_callinfo.get_all("DH1TW") == response_prefix_DH_clublog
assert fix_callinfo.get_all("ci8aw") == response_zone_exception_ci8aw
timestamp = datetime(year=2016, month=1, day=20, tzinfo=UTC)
timestamp = datetime(year=2016, month=1, day=20, tzinfo=timezone.utc)
assert fix_callinfo.get_all("VP8STI", timestamp) == response_Exception_VP8STI_with_start_and_stop_date
elif fix_callinfo._lookuplib._lookuptype == "countryfile":

View file

@ -1,15 +1,9 @@
import os
import sys
import datetime
import pytest
from future.utils import iteritems
from pyhamtools.qsl import get_clublog_users
if sys.version_info.major == 3:
unicode = str
test_dir = os.path.dirname(os.path.abspath(__file__))
fix_dir = os.path.join(test_dir, 'fixtures')
@ -26,8 +20,8 @@ class Test_clublog_methods:
data = get_clublog_users()
assert isinstance(data, dict)
for key, value in iteritems(data):
assert isinstance(key, unicode)
for key, value in data.items():
assert isinstance(key, str)
assert isinstance(value, dict)
def test_with_invalid_url(self):

View file

@ -1,15 +1,9 @@
import pytest
from datetime import datetime
import pytz
from datetime import datetime, timezone
from pyhamtools.consts import LookupConventions as const
from pyhamtools.dxcluster import decode_char_spot, decode_pc11_message, decode_pc61_message
UTC = pytz.UTC
fix_spot1 = "DX de CT3FW: 21004.8 HC2AO 599 TKS(CW)QSL READ,QRZ.COM 2132Z"
fix_spot1_broken_spotter_call = "DX de $QRM: 21004.8 HC2AO 599 TKS(CW)QSL READ,QRZ.COM 2132Z"
@ -34,7 +28,7 @@ response_spot1 = {
const.BAND: 15,
const.MODE: "CW",
const.COMMENT: "599 TKS(CW)QSL READ,QRZ.COM",
const.TIME: datetime.utcnow().replace( hour=21, minute=32, second=0, microsecond = 0, tzinfo=UTC)
const.TIME: datetime.now(timezone.utc).replace(hour=21, minute=32, second=0, microsecond = 0)
}

View file

@ -1,15 +1,10 @@
from .execfile import execfile
import os
import sys
import datetime
import pytest
from pyhamtools.qsl import get_eqsl_users
if sys.version_info.major == 3:
unicode = str
test_dir = os.path.dirname(os.path.abspath(__file__))
fix_dir = os.path.join(test_dir, 'fixtures')
class Test_eqsl_methods:
@ -26,7 +21,7 @@ class Test_eqsl_methods:
data = get_eqsl_users()
assert isinstance(data, list)
for el in data:
assert isinstance(el, unicode)
assert isinstance(el, str)
assert len(data) > 1000
def test_with_invalid_url(self):

View file

@ -1,12 +1,9 @@
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
import pytest
import pytz
from pyhamtools.locator import calculate_sunrise_sunset
UTC = pytz.UTC
class Test_calculate_sunrise_sunset_normal_case():
def test_calculate_sunrise_sunset(self):
@ -14,11 +11,11 @@ class Test_calculate_sunrise_sunset_normal_case():
time_margin = timedelta(minutes=1)
locator = "JN48QM"
test_time = datetime(year=2014, month=1, day=1, tzinfo=UTC)
result_JN48QM_1_1_2014_evening_dawn = datetime(2014, 1, 1, 15, 38, tzinfo=UTC)
result_JN48QM_1_1_2014_morning_dawn = datetime(2014, 1, 1, 6, 36, tzinfo=UTC)
result_JN48QM_1_1_2014_sunrise = datetime(2014, 1, 1, 7, 14, tzinfo=UTC)
result_JN48QM_1_1_2014_sunset = datetime(2014, 1, 1, 16, 15, 23, 31016, tzinfo=UTC)
test_time = datetime(year=2014, month=1, day=1, tzinfo=timezone.utc)
result_JN48QM_1_1_2014_evening_dawn = datetime(2014, 1, 1, 15, 38, tzinfo=timezone.utc)
result_JN48QM_1_1_2014_morning_dawn = datetime(2014, 1, 1, 6, 36, tzinfo=timezone.utc)
result_JN48QM_1_1_2014_sunrise = datetime(2014, 1, 1, 7, 14, tzinfo=timezone.utc)
result_JN48QM_1_1_2014_sunset = datetime(2014, 1, 1, 16, 15, 23, 31016, tzinfo=timezone.utc)
assert calculate_sunrise_sunset(locator, test_time)['morning_dawn'] - result_JN48QM_1_1_2014_morning_dawn < time_margin
assert calculate_sunrise_sunset(locator, test_time)['evening_dawn'] - result_JN48QM_1_1_2014_evening_dawn < time_margin
@ -33,7 +30,7 @@ class Test_calculate_sunrise_sunset_normal_case():
# The sun never rises in winter time close to the north pole (e.g. at Jan Mayen)
# Therefore we expect no sunrise or sunset.
test_time = datetime(year=2021, month=12, day=15, tzinfo=UTC)
test_time = datetime(year=2021, month=12, day=15, tzinfo=timezone.utc)
assert calculate_sunrise_sunset(locator, test_time)['morning_dawn'] == None
assert calculate_sunrise_sunset(locator, test_time)['evening_dawn'] == None
@ -48,7 +45,7 @@ class Test_calculate_sunrise_sunset_normal_case():
# The sun never sets at the south pole during arctic summer
# Therefore we expect no sunrise or sunset.
test_time = datetime(year=2014, month=1, day=1, tzinfo=UTC)
test_time = datetime(year=2014, month=1, day=1, tzinfo=timezone.utc)
assert calculate_sunrise_sunset(locator, test_time)['morning_dawn'] == None
assert calculate_sunrise_sunset(locator, test_time)['evening_dawn'] == None

View file

@ -1,13 +1,8 @@
from __future__ import unicode_literals
import pytest
import sys
from pyhamtools.lookuplib import LookupLib
from pyhamtools.exceptions import APIKeyMissingError
if sys.version_info.major == 3:
unicode = str
@pytest.fixture(scope="function", params=[5, -5, "", "foo bar", 11.5, {}, [], None, ("foo", "bar")])
def fixAnyValue(request):
return request.param
@ -41,5 +36,5 @@ class TestlookupLibHelper:
with pytest.raises(TypeError):
fixClublogApi._generate_random_word()
assert type(fixClublogApi._generate_random_word(5)) is unicode
assert type(fixClublogApi._generate_random_word(5)) is str
assert len(fixClublogApi._generate_random_word(5)) == 5

View file

@ -1,5 +1,5 @@
import pytest
from datetime import datetime
from datetime import datetime, timezone
from pyhamtools.lookuplib import LookupLib
@ -84,7 +84,7 @@ class TestclublogApi_Getters:
def test_lookup_callsign(self, fixClublogApi):
assert fixClublogApi.lookup_callsign("DH1TW") == response_Exception_DH1TW
assert fixClublogApi.lookup_callsign("VU9KV") == response_Exception_VU9KV
d = datetime.utcnow().replace(year=1971, month=4, day=14)
d = datetime.now(timezone.utc).replace(year=1971, month=4, day=14)
assert fixClublogApi.lookup_callsign("VU9KV", d) == response_Exception_VU9KV_with_Date
assert fixClublogApi.lookup_callsign("DH1TW/MM") == response_Exception_DH1TW_MM
assert fixClublogApi.lookup_callsign("DH1TW/AM") == response_Exception_DH1TW_AM

View file

@ -1,13 +1,10 @@
import pytest
from datetime import datetime
import pytz
from datetime import datetime, timezone
import os
from pyhamtools.lookuplib import LookupLib
from pyhamtools.exceptions import APIKeyMissingError
UTC = pytz.UTC
#Fixtures
#===========================================================
@ -55,8 +52,8 @@ response_Exception_VK9XO_with_start_date = {
'adif': 35,
'country': u'CHRISTMAS ISLAND',
'continent': u'OC',
'latitude': -10.50,
'longitude': 105.70,
'latitude': -10.48,
'longitude': 105.71,
'cqz': 29,
}
@ -142,40 +139,40 @@ class TestclublogXML_Getters:
#===============================
def test_lookup_callsign_same_callsign_different_exceptions(self, fixClublogXML):
timestamp = datetime(year=1990, month=10, day=12, tzinfo=UTC)
timestamp = datetime(year=1990, month=10, day=12, tzinfo=timezone.utc)
assert fixClublogXML.lookup_callsign("kc6mm", timestamp) == response_Exception_KC6MM_1990
timestamp = datetime(year=1992, month=3, day=8, tzinfo=UTC)
timestamp = datetime(year=1992, month=3, day=8, tzinfo=timezone.utc)
assert fixClublogXML.lookup_callsign("kc6mm", timestamp) == response_Exception_KC6MM_1992
def test_lookup_callsign_exception_only_with_start_date(self, fixClublogXML):
#timestamp > startdate
timestamp = datetime(year=1962, month=7, day=7, tzinfo=UTC)
timestamp = datetime(year=1962, month=7, day=7, tzinfo=timezone.utc)
assert fixClublogXML.lookup_callsign("vk9xo", timestamp) == response_Exception_VK9XO_with_start_date
assert fixClublogXML.lookup_callsign("vk9xo") == response_Exception_VK9XO_with_start_date
#timestamp < startdate
timestamp = datetime(year=1962, month=7, day=5, tzinfo=UTC)
timestamp = datetime(year=1962, month=7, day=5, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_callsign("vk9xo", timestamp)
def test_lookup_callsign_exception_only_with_end_date(self, fixClublogXML):
#timestamp < enddate
timestamp = datetime(year=1975, month=9, day=14, tzinfo=UTC)
timestamp = datetime(year=1975, month=9, day=14, tzinfo=timezone.utc)
assert fixClublogXML.lookup_callsign("vk9xx", timestamp) == response_Exception_VK9XX_with_end_date
# timestamp > enddate
with pytest.raises(KeyError):
fixClublogXML.lookup_callsign("vk9xx")
timestamp = datetime(year=1975, month=9, day=16, tzinfo=UTC)
timestamp = datetime(year=1975, month=9, day=16, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_callsign("vk9xx", timestamp)
def test_lookup_callsign_exception_no_start_nor_end_date(self, fixClublogXML):
timestamp = datetime(year=1975, month=9, day=14, tzinfo=UTC)
timestamp = datetime(year=1975, month=9, day=14, tzinfo=timezone.utc)
assert fixClublogXML.lookup_callsign("ax9nyg", timestamp) == response_Exception_AX9NYG
assert fixClublogXML.lookup_callsign("ax9nyg" ) == response_Exception_AX9NYG
@ -196,29 +193,29 @@ class TestclublogXML_Getters:
def test_lookup_prefix_with_changing_entities(self, fixClublogXML):
#return old entity (PAPUA TERR)
timestamp = datetime(year=1975, month=9, day=14).replace(tzinfo=UTC)
timestamp = datetime(year=1975, month=9, day=14, tzinfo=timezone.utc)
assert fixClublogXML.lookup_prefix("VK9", timestamp) == response_Prefix_VK9_until_1975
#return empty dict - Prefix was not assigned at that time
timestamp = datetime(year=1975, month=9, day=16).replace(tzinfo=UTC)
timestamp = datetime(year=1975, month=9, day=16, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_prefix("VK9", timestamp)
#return new entity (Norfolk Island)
timestamp = datetime.utcnow().replace(tzinfo=UTC)
timestamp = datetime.now(timezone.utc)
assert fixClublogXML.lookup_prefix("VK9", timestamp ) == response_Prefix_VK9_starting_1976
def test_lookup_prefix_with_entities_having_start_and_stop(self, fixClublogXML):
timestamp_before = datetime(year=1964, month=11, day=1).replace(tzinfo=UTC)
timestamp_before = datetime(year=1964, month=11, day=1, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_prefix("ZD5", timestamp_before)
timestamp_valid = datetime(year=1964, month=12, day=2).replace(tzinfo=UTC)
timestamp_valid = datetime(year=1964, month=12, day=2, tzinfo=timezone.utc)
assert fixClublogXML.lookup_prefix("ZD5", timestamp_valid) == response_Prefix_ZD5_1964_to_1971
timestamp_after = datetime(year=1971, month=8, day=1).replace(tzinfo=UTC)
timestamp_after = datetime(year=1971, month=8, day=1, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_prefix("ZD5", timestamp_after)
@ -234,8 +231,8 @@ class TestclublogXML_Getters:
fixClublogXML.is_invalid_operation("dh1tw")
#Invalid Operation with start and end date
timestamp_before = datetime(year=1993, month=12, day=30).replace(tzinfo=UTC)
timestamp = datetime(year=1994, month=12, day=30).replace(tzinfo=UTC)
timestamp_before = datetime(year=1993, month=12, day=30, tzinfo=timezone.utc)
timestamp = datetime(year=1994, month=12, day=30, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.is_invalid_operation("vk0mc")
@ -246,7 +243,7 @@ class TestclublogXML_Getters:
#Invalid Operation with start date
assert fixClublogXML.is_invalid_operation("5W1CFN")
timestamp_before = datetime(year=2012, month=1, day=31).replace(tzinfo=UTC)
timestamp_before = datetime(year=2012, month=1, day=31, tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.is_invalid_operation("5W1CFN", timestamp_before)
@ -264,9 +261,9 @@ class TestclublogXML_Getters:
assert fixClublogXML.lookup_zone_exception("dp0gvn") == 38
#zone exception with start and end date
timestamp = datetime(year=1992, month=10, day=2).replace(tzinfo=UTC)
timestamp_before = datetime(year=1992, month=9, day=30).replace(tzinfo=UTC)
timestamp_after = datetime(year=1993, month=3, day=1).replace(tzinfo=UTC)
timestamp = datetime(year=1992, month=10, day=2, tzinfo=timezone.utc)
timestamp_before = datetime(year=1992, month=9, day=30, tzinfo=timezone.utc)
timestamp_after = datetime(year=1993, month=3, day=1, tzinfo=timezone.utc)
assert fixClublogXML.lookup_zone_exception("dl1kvc/p", timestamp) == 38
with pytest.raises(KeyError):
@ -276,6 +273,6 @@ class TestclublogXML_Getters:
fixClublogXML.lookup_zone_exception("dl1kvc/p", timestamp_after)
#zone exception with start date
timestamp_before = datetime(year=2013, month=12, day=26).replace(tzinfo=UTC)
timestamp_before = datetime(year=2013, month=12, day=26,tzinfo=timezone.utc)
with pytest.raises(KeyError):
fixClublogXML.lookup_zone_exception("dh1hb/p", timestamp_before)

View file

@ -1,11 +1,4 @@
from __future__ import unicode_literals
import pytest
import tempfile
import os
import sys
if sys.version_info.major == 3:
unicode = str
from datetime import datetime
@ -58,13 +51,13 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
count = 0
for attr in entity:
if attr == "country":
assert type(entity[attr] is unicode)
assert type(entity[attr] is str)
count +=1
if attr == "continent":
assert type(entity[attr] is unicode)
assert type(entity[attr] is str)
count +=1
if attr == "prefix":
assert type(entity[attr] is unicode)
assert type(entity[attr] is str)
count +=1
if attr == "deleted":
assert type(entity[attr] is bool)
@ -114,10 +107,10 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
assert type(ex[attr]) is float
count +=1
elif attr == "country":
assert type(ex[attr]) is unicode
assert type(ex[attr]) is str
count +=1
elif attr == "continent":
assert type(ex[attr]) is unicode
assert type(ex[attr]) is str
count +=1
elif attr == "cqz":
assert type(ex[attr]) is int
@ -150,7 +143,7 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
count = 0
for attr in prefix:
if attr == "country":
assert type(prefix[attr]) is unicode
assert type(prefix[attr]) is str
count +=1
elif attr == "adif":
assert type(prefix[attr]) is int
@ -162,7 +155,7 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
assert type(prefix[attr]) is int
count +=1
elif attr == "continent":
assert type(prefix[attr]) is unicode
assert type(prefix[attr]) is str
count +=1
elif attr == "latitude":
assert type(prefix[attr]) is float

View file

@ -1,16 +1,12 @@
import os
import pytest
from datetime import datetime
from datetime import datetime, timezone
from pyhamtools.lookuplib import LookupLib
from pyhamtools.exceptions import APIKeyMissingError
from pyhamtools.consts import LookupConventions as const
import pytz
UTC = pytz.UTC
try:
QRZ_USERNAME = str(os.environ['QRZ_USERNAME'])
QRZ_PWD = str(os.environ['QRZ_PWD'])
@ -21,10 +17,10 @@ except Exception:
#===========================================================
response_1A1AB = {
u'biodate': datetime(2018, 9, 7, 21, 17, 7, tzinfo=UTC),
u'biodate': datetime(2018, 9, 7, 21, 17, 7, tzinfo=timezone.utc),
u'bio': u'0',
u'license_class': u'C',
u'moddate': datetime(2008, 11, 2, 15, 0, 38, tzinfo=UTC),
u'moddate': datetime(2008, 11, 2, 15, 0, 38, tzinfo=timezone.utc),
u'locator': u'JN61fw',
u'callsign': u'1A1AB',
u'addr2': u'00187 Rome',

View file

@ -1,15 +1,11 @@
import pytest
import json
from datetime import datetime
from datetime import datetime, timezone
import pytz
import redis
from pyhamtools import LookupLib, Callinfo
UTC = pytz.UTC
r = redis.Redis()
@ -44,7 +40,7 @@ class TestStoreDataInRedis:
with pytest.raises(KeyError):
fix_redis.is_invalid_operation("VK0MC")
timestamp = datetime(year=1994, month=12, day=30).replace(tzinfo=UTC)
timestamp = datetime(year=1994, month=12, day=30, tzinfo=timezone.utc)
assert fix_redis.is_invalid_operation("VK0MC", timestamp)
with pytest.raises(KeyError):
@ -61,7 +57,7 @@ class TestStoreDataInRedis:
assert lib.lookup_prefix("DH") == fixCountryFile.lookup_prefix("DH")
def test_redis_lookup(self, fixClublogXML, fix_redis):
timestamp = datetime(year=2016, month=1, day=20, tzinfo=UTC)
timestamp = datetime(year=2016, month=1, day=20, tzinfo=timezone.utc)
ci = Callinfo(fix_redis)
assert ci.get_all("VP8STI", timestamp) == response_Exception_VP8STI_with_start_and_stop_date
assert ci.get_all("tu5pct") == response_TU5PCT

View file

@ -1,9 +1,7 @@
import os
import sys
import datetime
from .execfile import execfile
from future.utils import iteritems
import pytest
def execfile(filepath, globals=None, locals=None):
@ -19,9 +17,6 @@ def execfile(filepath, globals=None, locals=None):
from pyhamtools.qsl import get_lotw_users
if sys.version_info.major == 3:
unicode = str
test_dir = os.path.dirname(os.path.abspath(__file__))
fix_dir = os.path.join(test_dir, 'fixtures')
@ -38,8 +33,8 @@ class Test_lotw_methods:
data = get_lotw_users()
assert isinstance(data, dict)
for key, value in iteritems(data):
assert isinstance(key, unicode)
for key, value in data.items():
assert isinstance(key, str)
assert isinstance(value, datetime.datetime )
assert len(data) > 1000