added qrz.com and callsign exception file

This commit is contained in:
dh1tw 2015-04-06 20:00:30 +02:00
parent c037bcee71
commit 63eb9a2447
31 changed files with 1061 additions and 233 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 28550054b902e31426622d239c737bb6
config: 7a49ae1f4a901a2bfa6bcbedb16df815
tags: 645f666f9bcd5a90fca523b33c5a78b7

View file

@ -7,7 +7,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Index &mdash; pyhamtools 0.4.1 documentation</title>
<title>Index &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -15,7 +15,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,7 +24,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="index.html" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="index.html" />
</head>
<body>
<div class="related">
@ -36,7 +36,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -61,33 +61,33 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.locator.calculate_distance">calculate_distance() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.calculate_distance">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.calculate_distance">calculate_distance() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.locator.calculate_distance_longpath">calculate_distance_longpath() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.calculate_distance_longpath">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.calculate_distance_longpath">calculate_distance_longpath() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.locator.calculate_heading">calculate_heading() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.calculate_heading">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.calculate_heading">calculate_heading() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.locator.calculate_heading_longpath">calculate_heading_longpath() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.calculate_heading_longpath">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.calculate_heading_longpath">calculate_heading_longpath() (in module pyhamtools.locator)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.locator.calculate_sunrise_sunset">calculate_sunrise_sunset() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.calculate_sunrise_sunset">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.calculate_sunrise_sunset">calculate_sunrise_sunset() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo">Callinfo (class in pyhamtools.callinfo)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo">Callinfo (class in pyhamtools.callinfo)</a>
</dt>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.copy_data_in_redis">copy_data_in_redis() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.copy_data_in_redis">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.copy_data_in_redis">copy_data_in_redis() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
</dl></td>
@ -102,7 +102,7 @@
<dd><dl>
<dt><a href="reference.html#pyhamtools.utils.freq_to_band">(in module pyhamtools.utils)</a>, <a href="utils.html#pyhamtools.utils.freq_to_band">[1]</a>, <a href="frequency.html#pyhamtools.utils.freq_to_band">[2]</a>
<dt><a href="reference.html#pyhamtools.utils.freq_to_band">(in module pyhamtools.utils)</a>
</dt>
</dl></dd>
@ -113,37 +113,45 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_adif_id">get_adif_id() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_adif_id">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_adif_id">get_adif_id() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_all">get_all() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_all">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_all">get_all() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_continent">get_continent() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_continent">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_continent">get_continent() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_country_name">get_country_name() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_country_name">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_country_name">get_country_name() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_cqz">get_cqz() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_cqz">get_cqz() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_cqz">[1]</a>
<dt><a href="reference.html#pyhamtools.qsl.get_eqsl_users">get_eqsl_users() (in module pyhamtools.qsl)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_homecall">get_homecall() (pyhamtools.callinfo.Callinfo static method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_homecall">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_homecall">get_homecall() (pyhamtools.callinfo.Callinfo static method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_ituz">get_ituz() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_ituz">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_ituz">get_ituz() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_lat_long">get_lat_long() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.get_lat_long">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.get_lat_long">get_lat_long() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.qsl.get_lotw_users">get_lotw_users() (in module pyhamtools.qsl)</a>
</dt>
</dl></td>
@ -153,13 +161,13 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.is_invalid_operation">is_invalid_operation() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.is_invalid_operation">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.is_invalid_operation">is_invalid_operation() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.is_valid_callsign">is_valid_callsign() (pyhamtools.callinfo.Callinfo method)</a>, <a href="callinfo.html#pyhamtools.callinfo.Callinfo.is_valid_callsign">[1]</a>
<dt><a href="reference.html#pyhamtools.callinfo.Callinfo.is_valid_callsign">is_valid_callsign() (pyhamtools.callinfo.Callinfo method)</a>
</dt>
</dl></td>
@ -169,33 +177,33 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.locator.latlong_to_locator">latlong_to_locator() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.latlong_to_locator">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.latlong_to_locator">latlong_to_locator() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.locator.locator_to_latlong">locator_to_latlong() (in module pyhamtools.locator)</a>, <a href="locator.html#pyhamtools.locator.locator_to_latlong">[1]</a>
<dt><a href="reference.html#pyhamtools.locator.locator_to_latlong">locator_to_latlong() (in module pyhamtools.locator)</a>
</dt>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_callsign">lookup_callsign() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.lookup_callsign">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_callsign">lookup_callsign() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_entity">lookup_entity() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.lookup_entity">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_entity">lookup_entity() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_prefix">lookup_prefix() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.lookup_prefix">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_prefix">lookup_prefix() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_zone_exception">lookup_zone_exception() (pyhamtools.lookuplib.LookupLib method)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib.lookup_zone_exception">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib.lookup_zone_exception">lookup_zone_exception() (pyhamtools.lookuplib.LookupLib method)</a>
</dt>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib">LookupLib (class in pyhamtools.lookuplib)</a>, <a href="lookupLib.html#pyhamtools.lookuplib.LookupLib">[1]</a>
<dt><a href="reference.html#pyhamtools.lookuplib.LookupLib">LookupLib (class in pyhamtools.lookuplib)</a>
</dt>
</dl></td>
@ -205,7 +213,7 @@
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#module-pyhamtools.callinfo">pyhamtools.callinfo (module)</a>, <a href="callinfo.html#module-pyhamtools.callinfo">[1]</a>
<dt><a href="reference.html#module-pyhamtools.callinfo">pyhamtools.callinfo (module)</a>
</dt>
@ -213,17 +221,21 @@
</dt>
<dt><a href="reference.html#module-pyhamtools.locator">pyhamtools.locator (module)</a>, <a href="reference.html#module-pyhamtools.locator">[1]</a>, <a href="locator.html#module-pyhamtools.locator">[2]</a>
<dt><a href="reference.html#module-pyhamtools.locator">pyhamtools.locator (module)</a>, <a href="reference.html#module-pyhamtools.locator">[1]</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="reference.html#module-pyhamtools.lookuplib">pyhamtools.lookuplib (module)</a>, <a href="lookupLib.html#module-pyhamtools.lookuplib">[1]</a>
<dt><a href="reference.html#module-pyhamtools.lookuplib">pyhamtools.lookuplib (module)</a>
</dt>
<dt><a href="reference.html#module-pyhamtools.utils">pyhamtools.utils (module)</a>, <a href="utils.html#module-pyhamtools.utils">[1]</a>, <a href="frequency.html#module-pyhamtools.utils">[2]</a>
<dt><a href="reference.html#module-pyhamtools.qsl">pyhamtools.qsl (module)</a>, <a href="reference.html#module-pyhamtools.qsl">[1]</a>
</dt>
<dt><a href="reference.html#module-pyhamtools.utils">pyhamtools.utils (module)</a>
</dt>
</dl></td>
@ -265,7 +277,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

View file

@ -6,7 +6,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>help &mdash; pyhamtools 0.4.1 documentation</title>
<title>help &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -14,7 +14,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -23,7 +23,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="index.html" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="index.html" />
</head>
<body>
<div class="related">
@ -35,7 +35,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -86,7 +86,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

View file

@ -6,7 +6,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>PyHamTools &mdash; pyhamtools 0.4.1 documentation</title>
<title>PyHamTools &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -14,7 +14,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -23,7 +23,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="#" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="#" />
<link rel="next" title="Reference" href="reference.html" />
</head>
<body>
@ -39,7 +39,7 @@
<li class="right" >
<a href="reference.html" title="Reference"
accesskey="N">next</a> |</li>
<li><a href="#">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="#">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -54,11 +54,11 @@
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field-odd field"><th class="field-name">Version:</th><td class="field-body">0.4.1</td>
<tr class="field-odd field"><th class="field-name">Version:</th><td class="field-body">0.4.2</td>
</tr>
<tr class="field-even field"><th class="field-name">Code:</th><td class="field-body"><a class="reference external" href="https://github.com/dh1tw/pyhamtools">https://github.com/dh1tw/pyhamtools</a></td>
</tr>
<tr class="field-odd field"><th class="field-name">License:</th><td class="field-body">MIT; see LICENSE file</td>
<tr class="field-odd field"><th class="field-name">License:</th><td class="field-body">MIT; see <a class="reference internal" href="license.html"><em>license</em></a> file</td>
</tr>
<tr class="field-even field"><th class="field-name">Issues:</th><td class="field-body"><a class="reference external" href="https://github.com/dh1tw/pyhamtools/issues">https://github.com/dh1tw/pyhamtools/issues</a></td>
</tr>
@ -85,6 +85,7 @@ with some modules and classes which are frequently needed:</p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="reference.html">Reference</a><ul>
<li class="toctree-l2"><a class="reference internal" href="reference.html#module-pyhamtools.locator">pyhamtools.locator</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#module-pyhamtools.qsl">pyhamtools.qsl</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#module-pyhamtools.frequency">pyhamtools.frequency</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#module-pyhamtools.callinfo">pyhamtools.callinfo</a></li>
<li class="toctree-l2"><a class="reference internal" href="reference.html#module-pyhamtools.lookuplib">pyhamtools.lookuplib</a></li>
@ -95,10 +96,11 @@ with some modules and classes which are frequently needed:</p>
<li class="toctree-l2"><a class="reference internal" href="examples.html#calculate-shortpath-and-longpath-heading-between-two-locators">Calculate Shortpath and Longpath Heading between two locators</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#calculate-distance-between-two-wgs84-coordinates">Calculate Distance between two WGS84 Coordinates</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#calculate-sunrise-and-sunset-for-jn48qm-on-the-1-january-2015">Calculate Sunrise and Sunset for JN48QM on the 1. January 2015</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#decode-a-callsign-and-get-country-itu-zone-cq-zone-latitude-longitude">Decode a Callsign and get Country, ITU Zone, CQ Zone, Latitude &amp; Longitude</a></li>
<li class="toctree-l2"><a class="reference internal" href="examples.html#decode-a-callsign-and-get-country-name-adif-id-latitude-longitude">Decode a Callsign and get Country name, ADIF ID, Latitude &amp; Longitude</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="changelog.html">Changelog</a><ul>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#pyhamtools-0-4-2">PyHamTools 0.4.2</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#pyhamtools-0-4-1">PyHamTools 0.4.1</a></li>
<li class="toctree-l2"><a class="reference internal" href="changelog.html#pyhamtools-0-4-0">PyHamTools 0.4.0</a></li>
</ul>
@ -167,7 +169,7 @@ with some modules and classes which are frequently needed:</p>
<li class="right" >
<a href="reference.html" title="Reference"
>next</a> |</li>
<li><a href="#">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="#">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

View file

@ -6,7 +6,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>license &mdash; pyhamtools 0.4.1 documentation</title>
<title>license &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -14,7 +14,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -23,7 +23,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="index.html" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="index.html" />
</head>
<body>
<div class="related">
@ -35,7 +35,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -112,7 +112,7 @@ SOFTWARE.</p>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

Binary file not shown.

View file

@ -6,7 +6,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Python Module Index &mdash; pyhamtools 0.4.1 documentation</title>
<title>Python Module Index &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -14,7 +14,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -23,7 +23,7 @@
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="index.html" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="index.html" />
@ -38,7 +38,7 @@
<li class="right" >
<a href="#" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -87,7 +87,12 @@
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="utils.html#module-pyhamtools.utils"><tt class="xref">pyhamtools.utils</tt></a></td><td>
<a href="reference.html#module-pyhamtools.qsl"><tt class="xref">pyhamtools.qsl</tt></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&nbsp;&nbsp;&nbsp;
<a href="reference.html#module-pyhamtools.utils"><tt class="xref">pyhamtools.utils</tt></a></td><td>
<em></em></td></tr>
</table>
@ -123,7 +128,7 @@
<li class="right" >
<a href="#" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

View file

@ -6,7 +6,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Search &mdash; pyhamtools 0.4.1 documentation</title>
<title>Search &mdash; pyhamtools 0.4.2 documentation</title>
<link rel="stylesheet" href="_static/default.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -14,7 +14,7 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
VERSION: '0.4.2',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
@ -24,7 +24,7 @@
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="top" title="pyhamtools 0.4.1 documentation" href="index.html" />
<link rel="top" title="pyhamtools 0.4.2 documentation" href="index.html" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
@ -43,7 +43,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
@ -94,7 +94,7 @@
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li><a href="index.html">pyhamtools 0.4.1 documentation</a> &raquo;</li>
<li><a href="index.html">pyhamtools 0.4.2 documentation</a> &raquo;</li>
</ul>
</div>
<div class="footer">

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,26 @@
Changelog
---------
PyHamTools 0.5.0
================
5. April 2015
* implemented QRZ.com interface into LookupLib [LookupLib]
* changed and unified all output to Unicode
* corrected Longitude to General Standard (-180...0° West, 0...180° East) [LookupLib]
* improved callsign decoding alogrithm [CallInfo]
* added special case to decode location of VK9 callsigns [CallInfo]
* added ValueError when LOTW data from file contains too many errors [qsl]
* added handling of special callsigns which can't be decoded properly inside a separate
callsign exception file (e.g. 7QAA)
PyHamTools 0.4.2
================

View file

@ -7,6 +7,7 @@ import pytz
from pyhamtools.consts import LookupConventions as const
from pyhamtools.callsign_exceptions import callsign_exceptions
UTC = pytz.UTC
timestamp_now = datetime.utcnow().replace(tzinfo=UTC)
@ -80,6 +81,10 @@ class Callinfo(object):
def _iterate_prefix(self, callsign, timestamp=timestamp_now):
"""truncate call until it corresponds to a Prefix in the database"""
prefix = callsign
if re.search('(VK|AX|VI)9[A-Z]{3}', callsign): #special rule for VK9 calls
if timestamp > datetime(2006,1,1, tzinfo=UTC):
prefix = callsign[0:3]+callsign[4:5]
while len(prefix) > 0:
try:
@ -139,7 +144,7 @@ class Callinfo(object):
appendix = re.search('/[A-Z0-9]{2,4}$', callsign)
appendix = re.sub('/', '', appendix.group(0))
self._logger.debug("appendix: " + appendix)
if appendix == 'MM': # special case Martime Mobile
#self._mm = True
return {
@ -173,6 +178,10 @@ class Callinfo(object):
elif appendix == "LH": # Filter all Lighthouses
callsign = re.sub('/LH', '', callsign)
return self._iterate_prefix(callsign, timestamp)
elif re.search('[A-Z]{3}', appendix): #case of US county(?) contest N3HBX/UAL
callsign = re.sub('/[A-Z]{3}$', '', callsign)
return self._iterate_prefix(callsign, timestamp)
else:
# check if the appendix is a valid country prefix
return self._iterate_prefix(re.sub('/', '', appendix), timestamp)
@ -205,10 +214,17 @@ class Callinfo(object):
elif re.search('^[A-Z0-9]{1,4}/', entire_callsign):
pfx = re.search('^[A-Z0-9]{1,4}/', entire_callsign)
pfx = re.sub('/', '', pfx.group(0))
return self._iterate_prefix(pfx)
#make sure that the remaining part is actually a callsign (avoid: OZ/JO81)
rest = re.search('/[A-Z0-9]+', entire_callsign)
rest = re.sub('/', '', rest.group(0))
if re.match('^[\d]{0,1}[A-Z]{1,2}\d([A-Z]{1,4}|\d{3,3}|\d{1,3}[A-Z])[A-Z]{0,5}$', rest):
return self._iterate_prefix(pfx)
if entire_callsign in callsign_exceptions:
return self._iterate_prefix(callsign_exceptions[entire_callsign])
self._logger.debug("Could not decode " + callsign)
raise KeyError
raise KeyError("Callsign could not be decoded")
def _lookup_callsign(self, callsign, timestamp=timestamp_now):
@ -241,7 +257,7 @@ class Callinfo(object):
'longitude': 0.0
}
# Check if a dedicated entry exists for the callsign
# Check if a dedicated entry/exception exists for the callsign
try:
data = self._lookuplib.lookup_callsign(callsign, timestamp).copy()
if self.check_if_beacon(callsign):

View file

@ -0,0 +1,6 @@
callsign_exceptions={
'7QAA' : '7Q',
'2SZ' : 'G0'
}

View file

@ -4,69 +4,110 @@ class LookupConventions:
""" This class defines the constants used within the pyhamtools package """
# Mostly specific to Clublog XML File
CALLSIGN = "callsign"
COUNTRY = "country"
PREFIX = "prefix"
ADIF = "adif"
CQZ = "cqz"
ITUZ = "ituz"
CONTINENT = "continent"
LATITUDE = "latitude"
LONGITUDE = "longitude"
START = "start"
END = "end"
WHITELIST = "whitelist"
WHITELIST_START = "whitelist_start"
WHITELIST_END = "whitelist_end"
DELETED = "deleted"
MARITIME_MOBILE = "mm"
AIRCRAFT_MOBILE = "am"
LOCATOR = "locator"
BEACON = "beacon"
CALLSIGN = u"callsign"
COUNTRY = u"country"
PREFIX = u"prefix"
ADIF = u"adif"
CQZ = u"cqz"
ITUZ = u"ituz"
CONTINENT = u"continent"
LATITUDE = u"latitude"
LONGITUDE = u"longitude"
START = u"start"
END = u"end"
WHITELIST = u"whitelist"
WHITELIST_START = u"whitelist_start"
WHITELIST_END = u"whitelist_end"
DELETED = u"deleted"
MARITIME_MOBILE = u"mm"
AIRCRAFT_MOBILE = u"am"
LOCATOR = u"locator"
BEACON = u"beacon"
#CQ / DIGITAL Skimmer specific
SKIMMER = "skimmer"
FS = "fs" #fieldstrength
WPM = "wpm" #words / bytes per second
CQ = "cq"
NCDXF = "ncdxf"
SKIMMER = u"skimmer"
FS = u"fs" #fieldstrength
WPM = u"wpm" #words / bytes per second
CQ = u"cq"
NCDXF = u"ncdxf"
# Modes
CW = "CW"
USB = "USB"
LSB = "LSB"
DIGITAL = "DIGITAL"
FM = "FM"
CW = u"CW"
USB = u"USB"
LSB = u"LSB"
DIGITAL = u"DIGITAL"
FM = u"FM"
#DX Spot
SPOTTER = "spotter"
DX = "dx"
FREQUENCY = "frequency"
COMMENT = "comment"
TIME = "time"
BAND = "band"
MODE = "mode"
SPOTTER = u"spotter"
DX = u"dx"
FREQUENCY = u"frequency"
COMMENT = u"comment"
TIME = u"time"
BAND = u"band"
MODE = u"mode"
#DX Spider specific
ORIGIN_NODE = "node"
HOPS = "hops"
RAW_SPOT = "raw"
IP = "ip"
ROUTE = "route"
TEXT = "text"
SYSOP_FLAG = "sysop_flag"
WX_FLAG = "wx_flag"
ORIGIN_NODE = u"node"
HOPS = u"hops"
RAW_SPOT = u"raw"
IP = u"ip"
ROUTE = u"route"
TEXT = u"text"
SYSOP_FLAG = u"sysop_flag"
WX_FLAG = u"wx_flag"
#WWV & WCY
STATION = "station"
R = "r"
K = "k"
EXPK = "expk"
SFI = "sfi"
A = "a"
AURORA = "aurora"
SA = "sa"
GMF = "gmf"
FORECAST = "forecast"
STATION = u"station"
R = u"r"
K = u"k"
EXPK = u"expk"
SFI = u"sfi"
A = u"a"
AURORA = u"aurora"
SA = u"sa"
GMF = u"gmf"
FORECAST = u"forecast"
#QRZ.com
XREF = u"xref"
ALIASES = u"aliases"
FNAME = u"fname"
NAME = u"name"
ADDR1 = u"addr1"
ADDR2 = u"addr2"
STATE = u"state"
ZIPCODE = u"zipcode"
CCODE = u"ccode"
COUNTY = u"county"
FIPS = u"fips"
LAND = u"land"
EFDATE = u"efdate"
EXPDATE = u"expdate"
P_CALL = u"p_call"
LICENSE_CLASS = u"license_class"
CODES = u"codes"
QSLMGR = u"qslmgr"
EMAIL = u"email"
URL = u"url"
U_VIEWS = u"u_views"
BIO = u"bio"
BIODATE = u"biodate"
IMAGE = u"image"
IMAGE_INFO = u"imageinfo"
SERIAL = u"serial"
MODDATE = u"moddate"
MSA = "msa"
AREACODE = "areacode"
TIMEZONE = "timezone"
GMTOFFSET = "gmtoffset"
DST = "dst"
EQSL = "eqsl"
MQSL = "mqsl"
LOTW = "lotw"
BORN = "born"
USER_MGR = "user"
IOTA = "iota"
GEOLOC = "geoloc"

38
pyhamtools/logparser.py Normal file
View file

@ -0,0 +1,38 @@
import os
import re
from datetime import datetime
def import_cabrillo(filename):
log = None;
log_import = None
with open(filename, 'r') as f:
log_import = f.read()
log = []
log_import = log_import.split("\r\n")
for qso in log_import:
if re.match("^QSO", qso):
freq = int(qso[4:11])
mode = qso[11:13]
time = datetime.strptime(qso[14:29], "%Y-%m-%d %H%M")
frm = qso[30:44].strip()
sent_rst = int(qso[44:47])
sent_exchange = qso[48:55].strip()
qso_partner = qso[55:68].strip()
rcvd_rst = int(qso[69:72])
rcvd_exchange = qso[73:79].strip()
station = int(qso[80])
log.append({
"freq": freq,
"mode":mode,
"time":time,
"from": frm,
"sent_rst":sent_rst,
"sent_exchange": sent_exchange,
"qso_partner": qso_partner,
"rcvd_rst": rcvd_rst,
"rcvd_exchange": rcvd_exchange,
"station": station
})
return log

View file

@ -9,12 +9,14 @@ 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
import version
from consts import LookupConventions as const
from exceptions import APIKeyMissingError
@ -54,6 +56,9 @@ class LookupLib(object):
Args:
lookuptype (str) : "clublogxml" or "clublogapi" or "countryfile" or "redis"
apikey (str): Clublog API Key
username (str): QRZ.com username
pwd (str): QRZ.com password
apiv (str, optional): QRZ.com API Version
filename (str, optional): Filename for Clublog XML or Country-files.com cty.plist file. When a local file is
used, no Internet connection not API Key is necessary.
logger (logging.getLogger(__name__), optional): Python logger
@ -62,7 +67,7 @@ class LookupLib(object):
"""
def __init__(self, lookuptype = "countryfile", apikey=None, filename=None, logger=None, redis_instance=None, redis_prefix=None):
def __init__(self, lookuptype = "countryfile", apikey=None, apiv="1.3.3", filename=None, logger=None, username=None, pwd=None, redis_instance=None, redis_prefix=None):
self._logger = None
if logger:
@ -75,10 +80,13 @@ class LookupLib(object):
self._logger.addHandler(logging.NullHandler())
self._apikey = apikey
self._apiv = apiv
self._download = True
self._lib_filename = filename
self._redis = redis_instance
self._redis_prefix = redis_prefix
self._username = username
self._pwd = pwd
if self._lib_filename:
self._download = False
@ -101,8 +109,36 @@ class LookupLib(object):
pass
elif self._lookuptype == "redis":
import redis
elif self._lookuptype == "qrz":
self._apikey = self._get_qrz_session_key(self._username, self._pwd)
else:
raise AttributeError("Lookup type missing")
def _get_qrz_session_key(self, username, pwd):
qrz_api_version = "1.3.3"
url = "https://xmldata.qrz.com/xml/" + qrz_api_version + "/"
agent = "PyHT"+version.__version__
params = {"username" : username,
"password" : pwd,
"agent" : agent
}
encodeurl = url + "?" + urllib.urlencode(params)
response = requests.get(encodeurl, timeout=5)
doc = BeautifulSoup(response.text)
session_key = None
if doc.session.key:
session_key = doc.session.key.text
else:
if doc.session.error:
raise ValueError(doc.session.error.text)
else:
raise ValueError("Could not retrieve Session Key from QRZ.com")
return session_key
def copy_data_in_redis(self, redis_prefix, redis_instance):
"""
@ -135,8 +171,8 @@ class LookupLib(object):
>>> my_lookuplib.lookup_callsign("3D2RI")
{
u'adif': 460,
u'continent': 'OC',
u'country': 'Rotuma Island',
u'continent': u'OC',
u'country': u'Rotuma Island',
u'cqz': 32,
u'ituz': 56,
u'latitude': -12.48,
@ -217,12 +253,12 @@ class LookupLib(object):
>>> print my_lookuplib.lookup_entity(273)
{
'deleted': False,
'country': 'TURKMENISTAN',
'country': u'TURKMENISTAN',
'longitude': -58.4,
'cqz': 17,
'prefix': 'EZ',
'prefix': u'EZ',
'latitude': 38.0,
'continent': 'AS'
'continent': u'AS'
}
@ -241,16 +277,18 @@ class LookupLib(object):
raise KeyError
elif self._lookuptype == "redis":
if self._redis_prefix is None:
raise KeyError ("redis_prefix is missing")
#entity = str(entity)
json_data = self._redis.get(self._redis_prefix + "_entity_" + str(entity))
if json_data is not None:
my_dict = self._deserialize_data(json_data)
return self._strip_metadata(my_dict)
elif self._lookuptype == "qrz":
result = self._lookup_qrz_dxcc(entity, self._apikey)
return result
# no matching case
raise KeyError
@ -297,12 +335,12 @@ class LookupLib(object):
>>> timestamp = datetime(year=1962, month=7, day=7, tzinfo=pytz.UTC)
>>> print my_lookuplib.lookup_callsign("VK9XO", timestamp)
{
'country': 'CHRISTMAS ISLAND',
'country': u'CHRISTMAS ISLAND',
'longitude': -105.7,
'cqz': 29,
'adif': 35,
'latitude': -10.5,
'continent': 'OC'
'continent': u'OC'
}
Note:
@ -311,8 +349,10 @@ class LookupLib(object):
- clublogxml
- clublogapi
- countryfile
- qrz.com
- redis
"""
callsign = callsign.strip().upper()
@ -333,7 +373,10 @@ class LookupLib(object):
return self._check_data_for_date(callsign, timestamp, data_dict, index)
# no matching case
raise KeyError
elif self._lookuptype == "qrz":
return self._lookup_qrz_callsign(callsign, self._apikey, self._apiv)
raise KeyError("unknown Callsign")
def _get_dicts_from_redis(self, name, index_name, redis_prefix, item):
"""
@ -454,12 +497,12 @@ class LookupLib(object):
>>> print myLookupLib.lookup_prefix("DH")
{
'adif': 230,
'country': 'Fed. Rep. of Germany',
'country': u'Fed. Rep. of Germany',
'longitude': -10.0,
'cqz': 14,
'ituz': 28,
'latitude': 51.0,
'continent': 'EU'
'continent': u'EU'
}
Note:
@ -644,17 +687,243 @@ class LookupLib(object):
lookup = {}
for item in jsonLookup:
if item == "Name": lookup[const.COUNTRY] = str(jsonLookup["Name"])
if item == "Name": lookup[const.COUNTRY] = jsonLookup["Name"]
elif item == "DXCC": lookup[const.ADIF] = int(jsonLookup["DXCC"])
elif item == "Lon": lookup[const.LONGITUDE] = float(jsonLookup["Lon"])
elif item == "Lat": lookup[const.LATITUDE] = float(jsonLookup["Lat"])
elif item == "CQZ": lookup[const.CQZ] = int(jsonLookup["CQZ"])
elif item == "Continent": lookup[const.CONTINENT] = str(jsonLookup["Continent"])
elif item == "Continent": lookup[const.CONTINENT] = jsonLookup["Continent"]
if lookup[const.ADIF] == 0:
raise KeyError
else:
return lookup
def _request_callsign_info_from_qrz(self, callsign, apikey, apiv="1.3.3"):
qrz_api_version = apiv
url = "https://xmldata.qrz.com/xml/" + qrz_api_version + "/"
params = {
"s": apikey,
"callsign" : callsign,
}
encodeurl = url + "?" + urllib.urlencode(params)
response = requests.get(encodeurl, timeout=5)
return response
def _request_dxcc_info_from_qrz(self, dxcc_or_callsign, apikey, apiv="1.3.3"):
qrz_api_version = apiv
url = "https://xmldata.qrz.com/xml/" + qrz_api_version + "/"
params = {
"s": apikey,
"dxcc" : str(dxcc_or_callsign),
}
encodeurl = url + "?" + urllib.urlencode(params)
response = requests.get(encodeurl, timeout=5)
return response
def _lookup_qrz_dxcc(self, dxcc_or_callsign, apikey, apiv="1.3.3"):
""" Performs the dxcc lookup against the QRZ.com XML API:
"""
response = self._request_dxcc_info_from_qrz(dxcc_or_callsign, apikey, apiv=apiv)
root = BeautifulSoup(response.text)
lookup = {}
if root.error: #try to get a new session key and try to request again
if re.search('No DXCC Information for', root.error.text, re.I): #No data available for callsign
raise KeyError(root.error.text)
elif re.search('Session Timeout', root.error.text, re.I): # Get new session key
self._apikey = apikey = self._get_qrz_session_key(self._username, self._pwd)
response = self._request_dxcc_info_from_qrz(dxcc_or_callsign, apikey)
root = BeautifulSoup(response.text)
else:
raise AttributeError("Session Key Missing") #most likely session key missing or invalid
if root.dxcc is None:
raise ValueError
if root.dxcc.dxcc:
lookup[const.ADIF] = int(root.dxcc.dxcc.text)
if root.dxcc.cc:
lookup['cc'] = root.dxcc.cc.text
if root.dxcc.cc:
lookup['ccc'] = root.dxcc.ccc.text
if root.find('name'):
lookup[const.COUNTRY] = root.find('name').get_text()
if root.dxcc.continent:
lookup[const.CONTINENT] = root.dxcc.continent.text
if root.dxcc.ituzone:
lookup[const.ITUZ] = int(root.dxcc.ituzone.text)
if root.dxcc.cqzone:
lookup[const.CQZ] = int(root.dxcc.cqzone.text)
if root.dxcc.timezone:
lookup['timezone'] = float(root.dxcc.timezone.text)
if root.dxcc.lat:
lookup[const.LATITUDE] = float(root.dxcc.lat.text)
if root.dxcc.lon:
lookup[const.LONGITUDE] = float(root.dxcc.lon.text)
return lookup
def _lookup_qrz_callsign(self, callsign=None, apikey=None, apiv="1.3.3"):
""" Performs the callsign lookup against the QRZ.com XML API:
"""
if apikey is None:
raise AttributeError("Session Key Missing")
callsign = callsign.upper()
response = self._request_callsign_info_from_qrz(callsign, apikey, apiv)
root = BeautifulSoup(response.text)
lookup = {}
if root.error: #try to get a new session key and try to request again
if re.search('Not found', root.error.text, re.I): #No data available for callsign
raise KeyError(root.error.text)
elif re.search('Session Timeout', root.error.text, re.I): # Get new session key
self._apikey = apikey = self._get_qrz_session_key(self._username, self._pwd)
response = self._request_callsign_info_from_qrz(callsign, apikey)
root = BeautifulSoup(response.text)
else:
raise AttributeError(root.error.text) #most likely session key missing or invalid
if root.callsign is None:
raise ValueError
if root.callsign.call:
lookup[const.CALLSIGN] = root.callsign.call.text
if root.callsign.xref:
lookup[const.XREF] = root.callsign.xref.text
if root.callsign.aliases:
lookup[const.ALIASES] = root.callsign.aliases.text.split(',')
if root.callsign.dxcc:
lookup[const.ADIF] = int(root.callsign.dxcc.text)
if root.callsign.fname:
lookup[const.FNAME] = root.callsign.fname.text
if root.callsign.find("name"):
lookup[const.NAME] = root.callsign.find('name').get_text()
if root.callsign.addr1:
lookup[const.ADDR1] = root.callsign.addr1.text
if root.callsign.addr2:
lookup[const.ADDR2] = root.callsign.addr2.text
if root.callsign.state:
lookup[const.STATE] = root.callsign.state.text
if root.callsign.zip:
lookup[const.ZIPCODE] = root.callsign.zip.text
if root.callsign.country:
lookup[const.COUNTRY] = root.callsign.country.text
if root.callsign.ccode:
lookup[const.CCODE] = int(root.callsign.ccode.text)
if root.callsign.lat:
lookup[const.LATITUDE] = float(root.callsign.lat.text)
if root.callsign.lon:
lookup[const.LONGITUDE] = float(root.callsign.lon.text)
if root.callsign.grid:
lookup[const.LOCATOR] = root.callsign.grid.text
if root.callsign.county:
lookup[const.COUNTY] = root.callsign.county.text
if root.callsign.fips:
lookup[const.FIPS] = int(root.callsign.fips.text) # check type
if root.callsign.land:
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)
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)
except ValueError:
self._logger.debug("[QRZ.com] expdate: Invalid DateTime; " + callsign + " " + root.callsign.expdate.text)
if root.callsign.p_call:
lookup[const.P_CALL] = root.callsign.p_call.text
if root.callsign.find('class'):
lookup[const.LICENSE_CLASS] = root.callsign.find('class').get_text()
if root.callsign.codes:
lookup[const.CODES] = root.callsign.codes.text
if root.callsign.qslmgr:
lookup[const.QSLMGR] = root.callsign.qslmgr.text
if root.callsign.email:
lookup[const.EMAIL] = root.callsign.email.text
if root.callsign.url:
lookup[const.URL] = root.callsign.url.text
if root.callsign.u_views:
lookup[const.U_VIEWS] = int(root.callsign.u_views.text)
if root.callsign.bio:
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)
except ValueError:
self._logger.warning("[QRZ.com] biodate: Invalid DateTime; " + callsign)
if root.callsign.image:
lookup[const.IMAGE] = root.callsign.image.text
if root.callsign.imageinfo:
lookup[const.IMAGE_INFO] = root.callsign.imageinfo.text
if root.callsign.serial:
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)
except ValueError:
self._logger.warning("[QRZ.com] moddate: Invalid DateTime; " + callsign)
if root.callsign.MSA:
lookup[const.MSA] = int(root.callsign.MSA.text)
if root.callsign.AreaCode:
lookup[const.AREACODE] = int(root.callsign.AreaCode.text)
if root.callsign.TimeZone:
lookup[const.TIMEZONE] = int(root.callsign.TimeZone.text)
if root.callsign.GMTOffset:
lookup[const.GMTOFFSET] = float(root.callsign.GMTOffset.text)
if root.callsign.DST:
if root.callsign.DST.text == "Y":
lookup[const.DST] = True
else:
lookup[const.DST] = False
if root.callsign.eqsl:
if root.callsign.eqsl.text == "1":
lookup[const.EQSL] = True
else:
lookup[const.EQSL] = False
if root.callsign.mqsl:
if root.callsign.mqsl.text == "1":
lookup[const.MQSL] = True
else:
lookup[const.MQSL] = False
if root.callsign.cqzone:
lookup[const.CQZ] = int(root.callsign.cqzone.text)
if root.callsign.ituzone:
lookup[const.ITUZ] = int(root.callsign.ituzone.text)
if root.callsign.born:
lookup[const.BORN] = int(root.callsign.born.text)
if root.callsign.user:
lookup[const.USER_MGR] = root.callsign.user.text
if root.callsign.lotw:
if root.callsign.lotw.text == "1":
lookup[const.LOTW] = True
else:
lookup[const.LOTW] = False
if root.callsign.iota:
lookup[const.IOTA] = root.callsign.iota.text
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,
url="https://secure.clublog.org/cty.php",
@ -866,44 +1135,49 @@ class LookupLib(object):
#retrieve ADIF Country Entities
cty_entities = cty_tree.find("entities")
self._logger.debug("total entities: " + str(len(cty_entities)))
if len(cty_entities) > 1:
for cty_entity in cty_entities:
entity = {}
for item in cty_entity:
if item.tag == "name":
entity[const.COUNTRY] = str(item.text)
elif item.tag == "prefix":
entity[const.PREFIX] = str(item.text)
elif item.tag == "deleted":
if item.text == "TRUE":
entity[const.DELETED] = True
else:
entity[const.DELETED] = False
elif item.tag == "cqz":
entity[const.CQZ] = int(item.text)
elif item.tag == "cont":
entity[const.CONTINENT] = str(item.text)
elif item.tag == "long":
entity[const.LONGITUDE] = float(item.text)*(-1)
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)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.END] = dt.replace(tzinfo=UTC)
elif item.tag == "whitelist":
if item.text == "TRUE":
entity[const.WHITELIST] = True
else:
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)
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)
try:
entity = {}
for item in cty_entity:
if item.tag == "name":
entity[const.COUNTRY] = unicode(item.text)
self._logger.debug(unicode(item.text))
elif item.tag == "prefix":
entity[const.PREFIX] = unicode(item.text)
elif item.tag == "deleted":
if item.text == "TRUE":
entity[const.DELETED] = True
else:
entity[const.DELETED] = False
elif item.tag == "cqz":
entity[const.CQZ] = int(item.text)
elif item.tag == "cont":
entity[const.CONTINENT] = unicode(item.text)
elif item.tag == "long":
entity[const.LONGITUDE] = float(item.text)*(-1)
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)
elif item.tag == "end":
dt = datetime.strptime(item.text[:19], '%Y-%m-%dT%H:%M:%S')
entity[const.END] = dt.replace(tzinfo=UTC)
elif item.tag == "whitelist":
if item.text == "TRUE":
entity[const.WHITELIST] = True
else:
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)
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)
except AttributeError:
self._logger.error("Error while processing: ")
entities[int(cty_entity[0].text)] = entity
self._logger.debug(str(len(entities))+" Entities added")
else:
@ -922,13 +1196,13 @@ class LookupLib(object):
else:
call_exceptions_index[call] = [int(cty_exception.attrib["record"])]
elif item.tag == "entity":
call_exception[const.COUNTRY] = str(item.text)
call_exception[const.COUNTRY] = unicode(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] = str(item.text)
call_exception[const.CONTINENT] = unicode(item.text)
elif item.tag == "long":
call_exception[const.LONGITUDE] = float(item.text)*(-1)
elif item.tag == "lat":
@ -963,13 +1237,13 @@ class LookupLib(object):
else:
prefixes_index[call] = [int(cty_prefix.attrib["record"])]
if item.tag == "entity":
prefix[const.COUNTRY] = str(item.text)
prefix[const.COUNTRY] = unicode(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] = str(item.text)
prefix[const.CONTINENT] = unicode(item.text)
elif item.tag == "long":
prefix[const.LONGITUDE] = float(item.text)*(-1)
elif item.tag == "lat":
@ -1086,12 +1360,12 @@ class LookupLib(object):
for item in cty_list:
entry = {}
call = str(item)
entry[const.COUNTRY] = str(cty_list[item]["Country"])
entry[const.COUNTRY] = unicode(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] = str(cty_list[item]["Continent"])
entry[const.CONTINENT] = unicode(cty_list[item]["Continent"])
entry[const.LATITUDE] = float(cty_list[item]["Latitude"])
entry[const.LONGITUDE] = float(cty_list[item]["Longitude"])
@ -1193,7 +1467,7 @@ class LookupLib(object):
elif item == const.WHITELIST:
my_dict[item] = self._str_to_bool(my_dict[item])
else:
my_dict[item] = str(my_dict[item])
my_dict[item] = unicode(my_dict[item])
return my_dict

View file

@ -5,7 +5,6 @@ import requests
import redis
from requests.exceptions import ConnectionError, HTTPError, Timeout
def get_lotw_users(**kwargs):
"""Download the latest inoffical list of `ARRL Logbook of the World (LOTW)`__ users which is provided on a weekly basis by HB9BZA_. Dates of the users last upload is added by WD5EAE_.
@ -17,6 +16,7 @@ def get_lotw_users(**kwargs):
Raises:
IOError: When network is unavailable, file can't be downloaded or processed
ValueError: Raised when data from file can't be read
Example:
The following example downloads the LOTW user list and check when DH1TW has made his last LOTW upload:
@ -30,7 +30,9 @@ def get_lotw_users(**kwargs):
.. _HB9BZA: http://www.hb9bza.net/lotw-users-list
.. _WD5EAE: http://www.wd5eae.org/HB9BZA_LoTWUsersList.html
__ ARRL_
"""
"""
url = ""
lotw = {}
@ -46,14 +48,21 @@ def get_lotw_users(**kwargs):
except (ConnectionError, HTTPError, Timeout) as e:
raise IOError(e)
error_count = 0
if result.status_code == requests.codes.ok:
for el in result.text.split():
data = el.split(",")
lotw[data[0]] = datetime.strptime(data[1], '%Y-%m-%d')
# print call
try:
lotw[data[0]] = datetime.strptime(data[1], '%Y-%m-%d')
except ValueError as e:
error_count += 1
if error_count > 10:
raise ValueError("more than 10 wrongly formatted datasets " + str(e))
else:
raise IOError("HTTP Error: " + str(result.status_code))
return lotw
def get_eqsl_users(**kwargs):

View file

@ -1,4 +1,4 @@
#VERSION = (0, 5, 0, 'dev')
VERSION = (0, 4, 2)
VERSION = (0, 5, 0)
__release__ = ''.join(['-.'[type(x) == int]+str(x) for x in VERSION])[1:]
__version__ = '.'.join((str(VERSION[0]), str(VERSION[1])))

View file

@ -0,0 +1,58 @@
1A0C,20-07-29
1A0KM,20-02-08
1A3A,20-09-12
1A4A,20-09-16
2A/DJ6AU,20-01-04
2A0APF,20-11-23
2A0APF/P,20-11-23
2A0BQI,0000-10-03
2A0BQI/P,20-10-03
2A0BSM,20-12-31
2A0MAV,20-11-23
2C0TKX,20-05-15
2C3SFC,2014-06-26
2D0EBV/P,2006-10-26
2D0YLX,2014-07-27
2E0ADK,2014-02-18
2E0ATS,2004-02-25
2E0BBA,2010-08-19
2E0BPP,2014-09-30
2E0BXD,2011-12-29
2E0BXO,2012-07-09
2E0CAX,2006-07-11
2E0CAX/P,2006-07-07
2E0CHS,2008-12-05
2E0CMD,2012-11-25
2E0CMD/P,2012-11-25
2E0CPJ,2013-03-22
2E0CPT,2011-04-19
2E0CQB,2014-06-14
2E0CRY,2013-06-10
2E0CXF,2014-05-24
2E0DDG,2012-04-15
2E0EBM,2014-07-21
2E0EBV,2008-02-10
2E0EBV/P,2006-07-03
2E0EDL,2014-09-28
2E0EET,2013-01-14
2E0ETN,2012-06-06
2E0ETT,2011-04-23
2E0FAS,2014-08-31
2E0FFQ,2008-12-10
2E0FNG,2011-12-14
2E0FSM,2014-09-19
2E0GBC,2013-10-28
2E0GBK,2014-07-31
2E0GOL,2013-01-08
2E0GSW,2013-12-28
2E0GYC,2011-12-11
2E0HEF,2014-08-26
2E0HYE,2013-10-03
2E0IAF,2014-09-28
2E0IAF/P,2011-06-12
2E0IFC,2014-09-28
2E0IKW,2010-02-28
2E0INV,2014-09-25
2E0JAX,2013-05-01
2E0JCA,2010-04-09
2E0JCQ,2013-10-15

View file

@ -47,7 +47,65 @@ response_prefix_C6A_countryfile = {
'ituz': 11
}
response_prefix_VK9NDX_countryfile = {
u'adif': 189,
u'continent': u'OC',
u'country': u'Norfolk Island',
u'cqz': 32,
u'ituz': 60,
u'latitude': -29.03,
u'longitude': -167.93
}
response_prefix_VK9DNX_clublog = {
u'adif': 189,
u'continent': u'OC',
u'country': u'NORFOLK ISLAND',
u'cqz': 32,
u'latitude': -29.0,
u'longitude': -168.0
}
response_prefix_VK9DWX_clublog = {
u'adif': 303,
u'continent': u'OC',
u'country': u'WILLIS ISLAND',
u'cqz': 30,
u'latitude': -16.2,
u'longitude': -150.0
}
response_prefix_VK9DLX_clublog = {
u'adif': 147,
u'continent': u'OC',
u'country': u'LORD HOWE ISLAND',
u'cqz': 30,
u'latitude': -31.6,
u'longitude': -159.1
}
response_prefix_VK9DLX_countryfile = {
u'adif': 147,
u'continent': u'OC',
u'country': u'Lord Howe Island',
u'cqz': 30,
u'ituz': 60,
u'latitude': -31.55,
u'longitude': -159.08
}
response_prefix_VK9GMW_clublog = {
u'adif': 171,
u'continent': u'OC',
u'country': u'MELLISH REEF',
u'cqz': 30,
u'latitude': -17.6,
u'longitude': -155.8
}
response_Exception_VK9XO_with_start_date = {
'adif': 35,
'country': 'CHRISTMAS ISLAND',
@ -89,6 +147,18 @@ response_aircraft_mobile = {
'longitude': 0.0
}
response_callsign_exceptions_7QAA_clublog = {
u'adif': 440,
u'continent': u'AF',
u'country': u'MALAWI',
u'cqz': 37,
u'latitude': -14.9,
u'longitude': -34.4
}
class Test_callinfo_methods:
def test_callinfo_iterate_prefix(self, fix_callinfo):
@ -126,7 +196,7 @@ class Test_callinfo_methods:
def test_dismantle_callsign(self, fix_callinfo):
if fix_callinfo._lookuplib._lookuptype == "clublogxml":
#assert fix_callinfo._dismantle_callsign("DH1TW/BCN")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/BCN")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/QRP") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/QRPP") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/LH") == response_prefix_DH_clublog
@ -134,28 +204,51 @@ class Test_callinfo_methods:
assert fix_callinfo._dismantle_callsign("DH1TW/P") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/5") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/M") == response_prefix_DH_clublog
#assert fix_callinfo._dismantle_callsign("DH1TW/B")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/B")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DL/HC2AO") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("9H5A/C6A") == response_prefix_C6A_clublog
assert fix_callinfo._dismantle_callsign("C6A/9H5A") == response_prefix_C6A_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/UNI") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/BUX") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("DH1TW/NOT") == response_prefix_DH_clublog
assert fix_callinfo._dismantle_callsign("VK9DLX/NOT") == response_prefix_VK9DLX_clublog
assert fix_callinfo._dismantle_callsign("7QAA") == response_callsign_exceptions_7QAA_clublog
with pytest.raises(KeyError):
fix_callinfo._dismantle_callsign("OZ/JO85")
if fix_callinfo._lookuplib._lookuptype == "countryfile":
assert fix_callinfo._dismantle_callsign("DH1TW/QRP") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("DH1TW/QRPP") == response_prefix_DH_countryfile
#assert fix_callinfo._dismantle_callsign("DH1TW/BCN")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/BCN")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/LH") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("HC2AO/DL") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("DH1TW/P") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("DH1TW/5") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("DH1TW/M") == response_prefix_DH_countryfile
#assert fix_callinfo._dismantle_callsign("DH1TW/B")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW/B")[const.BEACON]
assert fix_callinfo._dismantle_callsign("DH1TW") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("DL/HC2AO") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("9H5A/C6A") == response_prefix_C6A_countryfile
assert fix_callinfo._dismantle_callsign("C6A/9H5A") == response_prefix_C6A_countryfile
assert fix_callinfo._dismantle_callsign("DH1TW/NOT") == response_prefix_DH_countryfile
assert fix_callinfo._dismantle_callsign("VK9DLX/NOT") == response_prefix_VK9DLX_countryfile
with pytest.raises(KeyError):
fix_callinfo._dismantle_callsign("OZ/JO85")
def test_dismantle_callsign_with_VK9_special_suffixes(self, fix_callinfo):
if fix_callinfo._lookuplib._lookuptype == "clublog":
assert fix_callinfo._dismantle_callsign("VK9DNX") == response_prefix_VK9DNX_clublog
assert fix_callinfo._dismantle_callsign("VK9DLX") == response_prefix_VK9DLX_clublog
assert fix_callinfo._dismantle_callsign("VK9GMX") == response_prefix_VK9GMW_clublog
assert fix_callinfo._dismantle_callsign("VK9DWX") == response_prefix_VK9DWX_clublog
def test_lookup_callsign(selfself, fix_callinfo):
def test_lookup_callsign(self, fix_callinfo):
assert fix_callinfo._lookup_callsign("DH1TW/MM") == response_maritime_mobile
assert fix_callinfo._lookup_callsign("DH1TW/AM") == response_aircraft_mobile

View file

@ -7,7 +7,6 @@ from pyhamtools.qsl import get_eqsl_users
class Test_eqsl_methods:
def test_check_content_with_mocked_http_server(self, httpserver):
httpserver.serve_content(open('./fixtures/eqsl_data.html').read(), headers={'content-type': 'text/plain; charset=ISO-8859-1'})

View file

@ -10,8 +10,8 @@ from pyhamtools.exceptions import APIKeyMissingError
response_Exception_DH1TW = {
'adif': 230,
'country': 'FEDERAL REPUBLIC OF GERMANY',
'continent': 'EU',
'country': u'FEDERAL REPUBLIC OF GERMANY',
'continent': u'EU',
'latitude': 51.0,
'longitude': -10.0,
'cqz': 14
@ -19,8 +19,8 @@ response_Exception_DH1TW = {
response_Exception_VU9KV = {
'adif': 324,
'country': 'INDIA',
'continent': 'AS',
'country': u'INDIA',
'continent': u'AS',
'latitude': 22.0,
'longitude': -80.0,
'cqz': 22
@ -29,8 +29,8 @@ response_Exception_VU9KV = {
response_Exception_VU9KV_with_Date = {
'adif': 11,
'country': 'ANDAMAN & NICOBAR ISLANDS',
'continent': 'AS',
'country': u'ANDAMAN & NICOBAR ISLANDS',
'continent': u'AS',
'latitude': 11.70,
'longitude': -92.80,
'cqz': 26
@ -39,8 +39,8 @@ response_Exception_VU9KV_with_Date = {
response_Exception_DH1TW_MM = {
'adif': 999,
'country': 'MARITIME MOBILE',
'continent': '',
'country': u'MARITIME MOBILE',
'continent': u'',
'latitude': 0.0,
'longitude': 0.0,
'cqz': 0
@ -48,8 +48,8 @@ response_Exception_DH1TW_MM = {
response_Exception_DH1TW_AM = {
'adif': 998,
'country': 'AIRCRAFT MOBILE',
'continent': '',
'country': u'AIRCRAFT MOBILE',
'continent': u'',
'longitude': 0.0,
'latitude': 0.0,
'cqz': 0

View file

@ -15,19 +15,19 @@ UTC = pytz.UTC
response_Entity_230 = {
'country': 'FEDERAL REPUBLIC OF GERMANY',
'continent': 'EU',
'country': u'FEDERAL REPUBLIC OF GERMANY',
'continent': u'EU',
'latitude': 51.0,
'longitude': -10.0,
'cqz': 14,
'prefix' : 'DL',
'prefix' : u'DL',
'deleted' : False,
}
response_Exception_KC6MM_1990 = {
'adif': 22,
'country': 'PALAU',
'continent': 'OC',
'country': u'PALAU',
'continent': u'OC',
'latitude': 9.50,
'longitude': -138.20,
'cqz': 27,
@ -35,8 +35,8 @@ response_Exception_KC6MM_1990 = {
response_Exception_KC6MM_1992 = {
'adif': 22,
'country': 'PALAU',
'continent': 'OC',
'country': u'PALAU',
'continent': u'OC',
'latitude': 9.50,
'longitude': -138.20,
'cqz': 27,
@ -45,8 +45,8 @@ response_Exception_KC6MM_1992 = {
response_Exception_VK9XX_with_end_date = {
'adif': 35,
'country': 'CHRISTMAS ISLAND',
'continent': 'OC',
'country': u'CHRISTMAS ISLAND',
'continent': u'OC',
'latitude': -10.50,
'longitude': -105.70,
'cqz': 29,
@ -54,8 +54,8 @@ response_Exception_VK9XX_with_end_date = {
response_Exception_VK9XO_with_start_date = {
'adif': 35,
'country': 'CHRISTMAS ISLAND',
'continent': 'OC',
'country': u'CHRISTMAS ISLAND',
'continent': u'OC',
'latitude': -10.50,
'longitude': -105.70,
'cqz': 29,
@ -63,44 +63,44 @@ response_Exception_VK9XO_with_start_date = {
response_Exception_AX9NYG = {
'adif': 38,
'country': 'COCOS (KEELING) ISLAND',
'continent': 'OC',
'country': u'COCOS (KEELING) ISLAND',
'continent': u'OC',
'latitude': -12.20,
'longitude': -96.80,
'cqz': 29,
}
response_Prefix_DH = {
'country': 'FEDERAL REPUBLIC OF GERMANY',
'country': u'FEDERAL REPUBLIC OF GERMANY',
'adif' : 230,
'continent': 'EU',
'continent': u'EU',
'latitude': 51.0,
'longitude': -10.0,
'cqz': 14,
}
response_Prefix_VK9_until_1975 = {
'country': 'PAPUA TERR',
'country': u'PAPUA TERR',
'adif' : 198,
'continent': 'OC',
'continent': u'OC',
'latitude': -9.40,
'longitude': -147.10,
'cqz': 28,
}
response_Prefix_VK9_starting_1976 = {
'country': 'NORFOLK ISLAND',
'country': u'NORFOLK ISLAND',
'adif' : 189,
'continent': 'OC',
'continent': u'OC',
'latitude': -29.00,
'longitude': -168.00,
'cqz': 32,
}
response_Prefix_ZD5_1964_to_1971 = {
'country': 'SWAZILAND',
'country': u'SWAZILAND',
'adif' : 468,
'continent': 'AF',
'continent': u'AF',
'latitude': -26.30,
'longitude': -31.10,
'cqz': 38,

View file

@ -53,13 +53,13 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
count = 0
for attr in entity:
if attr == "country":
assert type(entity[attr] is str)
assert type(entity[attr] is unicode)
count +=1
if attr == "continent":
assert type(entity[attr] is str)
assert type(entity[attr] is unicode)
count +=1
if attr == "prefix":
assert type(entity[attr] is str)
assert type(entity[attr] is unicode)
count +=1
if attr == "deleted":
assert type(entity[attr] is bool)
@ -109,10 +109,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 str
assert type(ex[attr]) is unicode
count +=1
elif attr == "continent":
assert type(ex[attr]) is str
assert type(ex[attr]) is unicode
count +=1
elif attr == "cqz":
assert type(ex[attr]) is int
@ -145,7 +145,7 @@ class Test_Getter_Setter_Api_Types_for_all_sources:
count = 0
for attr in prefix:
if attr == "country":
assert type(prefix[attr]) is str
assert type(prefix[attr]) is unicode
count +=1
elif attr == "adif":
assert type(prefix[attr]) is int
@ -157,7 +157,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 str
assert type(prefix[attr]) is unicode
count +=1
elif attr == "latitude":
assert type(prefix[attr]) is float

242
test/test_lookuplib_qrz.py Normal file
View file

@ -0,0 +1,242 @@
import pytest
from datetime import datetime
from apikey import QRZ_USERNAME, QRZ_PWD
from pyhamtools.lookuplib import LookupLib
from pyhamtools.exceptions import APIKeyMissingError
from pyhamtools.consts import LookupConventions as const
import pytz
UTC = pytz.UTC
#Fixtures
#===========================================================
response_XX1XX = {
# 'u_views': u'17495',
u'biodate': datetime(2015, 2, 4, 17, 50, 32, tzinfo=UTC),
u'image': u'http://files.qrz.com/x/xx1xx/DSC_0094.png',
u'locator': u'KF05nx',
u'addr2': u'TEST CALLSIGN CITY',
u'addr1': u'DO NOT QSL',
u'aliases': [u'YY1YY'],
u'codes': u'TPS',
u'zipcode': u'010101',
u'lotw': True,
u'state': u'JC',
u'callsign': u'XX1XX',
u'fname': u'James W.',
u'latitude': -34.010735,
u'longitude': 21.164476,
u'email': u'trucker2345@easymail.com',
u'qslmgr': u'NO QSL - TEST CALLSIGN',
u'bio': u'10415',
u'ccode': 120,
u'geoloc': u'user',
u'eqsl': True,
u'mqsl': True,
u'adif': 134,
u'moddate': datetime(2015, 2, 4, 17, 53, 2, tzinfo=UTC),
u'license_class': u'z',
u'land': u'Kingman Reef',
u'imageinfo': u'425:640:425545',
u'name': 'Smith',
u'born': 2002,
u'country': u'Iceland',
u'user': u'XX1XX'
}
response_XX2XX = {
u'bio': u'93',
u'land': u'NON-DXCC',
u'adif': 0,
u'zipcode': u'23232',
u'country': u'Anguilla',
u'user': u'XX2XX',
u'moddate': datetime(2015, 3, 20, 23, 20, 37, tzinfo=UTC),
u'lotw': False,
u'ccode': 9,
u'geoloc': u'dxcc',
u'state': u'GA',
u'eqsl': False,
u'addr2': u'Las Vegas',
# 'u_views': u'23',
u'fname': u'NO',
u'addr1': u'123 Main Stod\u00DFer',
u'callsign': u'XX2XX',
u'mqsl': False,
u'biodate': datetime(2015, 2, 19, 22, 30, 2, tzinfo=UTC),
u'image': u'http://files.qrz.com/x/xx2xx/oval_bumper_sticker4.png',
u'imageinfo': u'285:500:44218'
}
response_XX3XX = {
# 'u_views': u'4698',
u'biodate': datetime(2014, 8, 13, 15, 34, 57, tzinfo=UTC),
u'image': u'http://files.qrz.com/x/xx3xx/IMG_8813.JPG',
u'locator': u'FO51sj',
u'addr2': u'Shady Circle Roads',
u'addr1': u'1234 Main St.3',
u'aliases': [u'XX3XX/W7'],
u'zipcode': u'00033',
u'lotw': False,
u'state': u'JJ',
u'callsign': u'XX3XX',
u'fname': u'TEST\xc3\x9c\xc3\x9f\xc3\xb8x',
u'latitude': 51.396953,
u'email': u'fred@qrz.com',
u'qslmgr': u'Via BURO or AA7BQ',
u'bio': u'2420',
u'ccode': 130,
u'geoloc': u'user',
u'eqsl': False,
u'user': u'KF7WIS',
u'adif': 79,
u'moddate': datetime(2014, 6, 6, 23, 0, 45, tzinfo=UTC),
u'license_class': u'3',
u'land': u'Guadeloupe',
u'imageinfo': u'540:799:101014',
u'name': u'CALLSIGN3',
u'born': 2010,
u'country': u'Jamaica',
u'longitude': -68.41959,
u'mqsl': False
}
response_XX4XX = {
# 'u_views': u'7980',
u'biodate': datetime(2014, 9, 17, 19, 46, 54, tzinfo=UTC),
u'image': u'http://files.qrz.com/x/xx4xx/IMG_0032.JPG',
u'locator': u'DM79mp',
u'addr2': u'Getamap and Findit',
u'addr1': u'Test Callsign for QRZ',
u'imageinfo': u'1200:1600:397936',
u'lotw': False,
u'state': u'ZZ',
u'callsign': u'XX4XX',
u'fname': u'Arthur',
u'latitude': 39.645,
u'iota': u'NA-075',
u'qslmgr': u'NO QSL - TEST CALLSIGN',
u'bio': u'785',
u'ccode': 34,
u'geoloc': u'user',
u'eqsl': False,
u'user': u'XX2XX',
u'adif': 64,
u'moddate': datetime(2014, 3, 28, 20, 29, 42, tzinfo=UTC),
u'name': u'Fay',
u'land': u'Bermuda',
u'zipcode': u'12345',
u'country': u'Bermuda',
u'longitude': -104.96,
u'mqsl': False
}
response_333 = {
const.COUNTRY: u'Iraq',
u'cc': u'IQ',
const.LONGITUDE: 44.362793,
const.CQZ: 21,
const.ITUZ: 39,
const.LATITUDE: 33.358062,
u'timezone': 3.0,
const.ADIF: 333,
const.CONTINENT: u'AS',
u'ccc': u'IRQ'
}
#TESTS
#===========================================================
class TestQrzConstructur:
def test_get_session_key(self):
lib = LookupLib(lookuptype="qrz", username=QRZ_USERNAME, pwd=QRZ_PWD)
assert len(lib._apikey) == 32
def test_get_session_key_with_invalid_username(self):
with pytest.raises(ValueError):
lib = LookupLib(lookuptype="qrz", username="hello", pwd=QRZ_PWD)
def test_get_session_key_with_invalid_password(self):
with pytest.raises(ValueError):
lib = LookupLib(lookuptype="qrz", username=QRZ_USERNAME, pwd="hello")
def test_get_session_key_with_empty_username_and_password(self):
with pytest.raises(ValueError):
lib = LookupLib(lookuptype="qrz", username="", pwd="")
class TestQrz_Callsign_Lookup:
def test_lookup_callsign(self, fix_qrz):
data = fix_qrz._lookup_qrz_callsign("xx1xx", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX1XX #check content
assert len(data) == len(response_XX1XX) #ensure all fields are included
data = fix_qrz._lookup_qrz_callsign("XX1XX", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX1XX
data = fix_qrz._lookup_qrz_callsign("XX2XX", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX2XX
assert len(data) == len(response_XX2XX)
data = fix_qrz._lookup_qrz_callsign("XX3XX", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX3XX
assert len(data) == len(response_XX3XX)
data = fix_qrz._lookup_qrz_callsign("XX4XX", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX4XX
assert len(data) == len(response_XX4XX)
def test_lookup_callsign_with_unicode_escaping(self, fix_qrz):
data = fix_qrz._lookup_qrz_callsign("XX2XX", fix_qrz._apikey)
data.pop('u_views', None)
assert data == response_XX2XX
def test_lookup_callsign_does_not_exist(self, fix_qrz):
with pytest.raises(KeyError):
fix_qrz._lookup_qrz_callsign("XX8XX", fix_qrz._apikey)
def test_lookup_callsign_with_empty_input(self, fix_qrz):
with pytest.raises(ValueError):
fix_qrz._lookup_qrz_callsign("", fix_qrz._apikey)
def test_lookup_callsign_with_invalid_input(self, fix_qrz):
with pytest.raises(AttributeError):
fix_qrz._lookup_qrz_callsign(3, fix_qrz._apikey)
class TestQrz_DXCC_Lookup:
def test_lookup_dxcc_with_int(self, fix_qrz):
data = fix_qrz._lookup_qrz_dxcc(333, fix_qrz._apikey)
assert data == response_333 #check content
assert len(data) == len(response_333) #ensure all fields are included
def test_lookup_dxcc_with_string(self, fix_qrz):
data = fix_qrz._lookup_qrz_dxcc("333", fix_qrz._apikey)
assert data == response_333 #check content
assert len(data) == len(response_333) #ensure all fields are included
def test_lookup_dxcc_does_not_exist(self, fix_qrz):
with pytest.raises(KeyError):
fix_qrz._lookup_qrz_dxcc('854', fix_qrz._apikey)
def test_lookup_dxcc_wrong_input(self, fix_qrz):
with pytest.raises(ValueError):
fix_qrz._lookup_qrz_dxcc('', fix_qrz._apikey)
def test_lookup_dxcc(self, fix_qrz):
data = fix_qrz.lookup_entity(333)
assert data == response_333 #check content

View file

@ -26,4 +26,11 @@ class Test_lotw_methods:
with pytest.raises(IOError):
get_lotw_users(url="http://wd5eae.org/LoTW_Data_XXXXX.txt")
def test_with_more_than_10_invalid_dates(self, httpserver):
httpserver.serve_content(open('./fixtures/lotw_data_with_errors.html').read())
with pytest.raises(ValueError):
get_lotw_users(url=httpserver.url)

View file

@ -7,6 +7,7 @@
envlist = py26,py27,pypy
[testenv]
#deps=-rtox_requirements.txt
deps=pytest
commands =
py.test \

5
tox_requirements.txt Normal file
View file

@ -0,0 +1,5 @@
pyephem (3.7.5.3)
Pygments (1.6)
pytz (2014.2)
redis (2.10.3)
requests (2.2.1)