From 624cea394223b2866cfd2e88df95eb8d58a94c53 Mon Sep 17 00:00:00 2001 From: dh1tw Date: Wed, 30 Apr 2014 08:56:08 +0200 Subject: [PATCH] Added documentation for class Callinfo --- docs/build/doctrees/Callinfo.doctree | Bin 6629 -> 71011 bytes docs/build/doctrees/environment.pickle | Bin 9293 -> 10461 bytes docs/build/doctrees/lookuplib.doctree | Bin 55615 -> 55583 bytes docs/build/html/Callinfo.html | 346 ++++++++++++++++++++++++- docs/build/html/genindex.html | 38 ++- docs/build/html/lookuplib.html | 8 +- docs/build/html/objects.inv | 6 +- docs/build/html/searchindex.js | 2 +- pyhamtools/__init__.py | 1 - pyhamtools/callinfo.py | 239 +++++++++++++++-- pyhamtools/consts.py | 22 +- pyhamtools/dxcluster.py | 60 +++++ pyhamtools/logging.ini | 22 ++ pyhamtools/lookuplib.py | 24 +- pyhamtools/utils.py | 135 ++++++++++ setup.py | 16 +- test/conftest.py | 7 - test/test_utils_freq_to_band.py | 81 ++++++ tox.ini | 13 + 19 files changed, 965 insertions(+), 55 deletions(-) create mode 100644 pyhamtools/dxcluster.py create mode 100644 pyhamtools/logging.ini create mode 100644 pyhamtools/utils.py create mode 100644 test/test_utils_freq_to_band.py create mode 100644 tox.ini diff --git a/docs/build/doctrees/Callinfo.doctree b/docs/build/doctrees/Callinfo.doctree index 13b3186072a378f8055b06503f40e3d38e4503df..2cf843111b292e9366d8c5ff0f9b16cd8ba15d49 100644 GIT binary patch literal 71011 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

^m<~YZ}>C3j9boA6p!o3{tx5 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 diff --git a/docs/build/doctrees/environment.pickle b/docs/build/doctrees/environment.pickle index 516b185c8670e9766c4dab38c1e3464df3a730b6..fc4a825157004ec5978a40b98a9d035a0e43cd27 100644 GIT binary patch literal 10461 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 diff --git a/docs/build/doctrees/lookuplib.doctree b/docs/build/doctrees/lookuplib.doctree index c788d025378b4c2c1ef60196095733e14b80f8a6..eea2d5b92b899f17b80839e0a28a0d7c9a6da9cf 100644 GIT binary patch literal 55583 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 N8Aq*-Yq7QA{{tEiyxjl* literal 55615 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 diff --git a/docs/build/html/Callinfo.html b/docs/build/html/Callinfo.html index 43e6330..6107d45 100644 --- a/docs/build/html/Callinfo.html +++ b/docs/build/html/Callinfo.html @@ -60,12 +60,348 @@

-class pyhamtools.callinfo.Callinfo(lookuplib)
-

This is going to going to return information for a callsign

+class pyhamtools.callinfo.Callinfo(lookuplib, logger=None) +

The purpose of this class is to return data (country, latitude, longitude, CQ Zone...etc) for an +Amateur Radio callsign. The class can be used with any lookup database, +provided through an Instance of LookupLib. +An instance of Lookuplib has to be injected on object construction.

+ +++ + + + +
Parameters:
    +
  • lookuplib (LookupLib) – instance of LookupLib
  • +
  • logger (logging.getLogger(__name__), optional) – Python logger
  • +
+
-
-getHomeCall(callsign)
-

verify call and strip off any /ea1 vp5/ /qrp etc

+
+get_adif_id(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Returns ADIF id of a callsign’s country

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

containing the country ADIF id

+
Return type:

int

+
Raises:

KeyError – +No Country found for callsign

+
+
+ +
+
+get_all(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Lookup a callsign and return all data available from the underlying database

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

Dictionary containing the callsign specific data

+
Return type:

dict

+
Raises:

KeyError – +Callsign could not be identified

+
+

Example

+

The following code returns all available information from the country-files.com database for the +callsign “DH1TW”

+
>>> from pyhamtools import LookupLib, Callinfo
+>>> my_lookuplib = LookupLib(lookuptype="countryfile")
+>>> cic = Callinfo(my_lookuplib)
+>>> cic.get_all("DH1TW")
+{
+     'country': 'Fed. Rep. of Germany',
+     'adif': 230,
+     'continent': 'EU',
+     'latitude': 51.0,
+     'longitude': -10.0,
+     'cqz': 14,
+     'ituz': 28
+}
+
+
+
+

Note

+

The content of the returned data depends entirely on the injected +LookupLib (and the used database). While the country-files.com provides +for example the ITU Zone, Clublog doesn’t. Consequently, the item “ituz” +would be missing with Clublog (API or XML) LookupLib.

+
+
+ +
+
+get_continent(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Returns the continent Identifier of a callsign

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

continent identified

+
Return type:

str

+
Raises:

KeyError – +No Continent found for callsign

+
+
+

Note

+

The following continent identifiers are used:

+
    +
  • EU: Europe
  • +
  • NA: North America
  • +
  • SA: South America
  • +
  • AS: Asia
  • +
  • AF: Africa
  • +
  • OC: Oceania
  • +
  • AN: Antarctica
  • +
+
+
+ +
+
+get_country_name(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Returns the country name where the callsign is located

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

name of the Country

+
Return type:

str

+
Raises:

KeyError – +No Country found for callsign

+
+
+

Note

+

Don’t rely on the country name when working with several instances of +:Callinfo. Clublog and Country-files.org use slightly different names +for countrys. Example: +Country-files.com: “Fed. Rep. of Germany” +Clublog: “FEDERAL REPUBLIC OF GERMANY”

+
+
+ +
+
+get_cqz(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Returns CQ Zone of a callsign

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

containing the callsign’s CQ Zone

+
Return type:

int

+
Raises:

KeyError – +no CQ Zone found for callsign

+
+
+ +
+
+get_homecall(callsign)
+

Strips off country prefixes (HC2/**DH1TW) and activity suffixes (DH1TW/P**).

+ +++ + + + + + + + + + +
Parameters:callsign (str) – Amateur Radio callsign
Returns:callsign without country/activity pre/suffixes
Return type:str
Raises:ValueError – +No callsign found in string
+

Example

+

The following code retrieves the home call for “HC2/DH1TW/P”

+
>>> from pyhamtools import LookupLib, Callinfo
+>>> my_lookuplib = LookupLib(lookuptype="countryfile")
+>>> cic = Callinfo(my_lookuplib)
+>>> cic.get_homecall("HC2/DH1TW/P")
+DH1TW
+
+
+
+ +
+
+get_ituz(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Returns ITU Zone of a callsign

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

containing the callsign’s CQ Zone

+
Return type:

int

+
Raises:

KeyError – +No ITU Zone found for callsign

+
+
+

Note

+

Currently, only Country-files.com lookup database contains ITU Zones

+
+
+ +
+
+get_lat_long(callsign)
+

Returns Latitude and Longitude for a callsign

+ +++ + + + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

Containing Latitude and Longitude

+
Return type:

dict

+
Raises:

KeyError – +No data found for callsign

+
+

Example

+

The following code returns Latitude & Longitude for “DH1TW”

+
>>> from pyhamtools import LookupLib, Callinfo
+>>> my_lookuplib = LookupLib(lookuptype="countryfile")
+>>> cic = Callinfo(my_lookuplib)
+>>> cic.get_lat_long("DH1TW")
+{
+   'latitude': 51.0,
+   'longitude': -10.0
+}
+
+
+
+

Note

+

Unfortunately, in most cases the returned Latitude and Longitude are not very precise. +Clublog and Country-files.com use the country’s capital coordinates in most cases, if no +dedicated entry in the database exists.

+
+
+ +
+
+is_valid_callsign(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 22, 14, 671563, tzinfo=<UTC>))
+

Checks if a callsign is valid

+ +++ + + + + + + + +
Parameters:
    +
  • callsign (str) – Amateur Radio callsign
  • +
  • timestamp (datetime, optional) – datetime in UTC (tzinfo=pytz.UTC)
  • +
+
Returns:

True / False

+
Return type:

bool

+
+

Example

+

The following checks if “DH1TW” is a valid callsign

+
>>> from pyhamtools import LookupLib, Callinfo
+>>> my_lookuplib = LookupLib(lookuptype="countryfile")
+>>> cic = Callinfo(my_lookuplib)
+>>> cic.is_valid_callsign("DH1TW")
+True
+
+
diff --git a/docs/build/html/genindex.html b/docs/build/html/genindex.html index c353f6e..3dc6e40 100644 --- a/docs/build/html/genindex.html +++ b/docs/build/html/genindex.html @@ -70,7 +70,37 @@ + @@ -83,6 +113,12 @@
is_invalid_operation() (pyhamtools.lookuplib.LookupLib method)
+ +
-
getHomeCall() (pyhamtools.callinfo.Callinfo method) +
get_adif_id() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_all() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_continent() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_country_name() (pyhamtools.callinfo.Callinfo method) +
+ +
+ +
get_cqz() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_homecall() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_ituz() (pyhamtools.callinfo.Callinfo method) +
+ + +
get_lat_long() (pyhamtools.callinfo.Callinfo method)
+ +
is_valid_callsign() (pyhamtools.callinfo.Callinfo method) +
+
diff --git a/docs/build/html/lookuplib.html b/docs/build/html/lookuplib.html index 8bf869a..1fd8fd5 100644 --- a/docs/build/html/lookuplib.html +++ b/docs/build/html/lookuplib.html @@ -85,7 +85,7 @@ lookup against the Clublog API.

-is_invalid_operation(callsign, timestamp=datetime.datetime(2014, 4, 25, 22, 19, 33, 219680, tzinfo=<UTC>))
+is_invalid_operation(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 1, 27, 518550, tzinfo=<UTC>))

Returns True if an operations is known as invalid

@@ -140,7 +140,7 @@ API Key for Clublog missing or incorrect
-lookup_callsign(callsign=None, timestamp=datetime.datetime(2014, 4, 25, 22, 19, 33, 219601, tzinfo=<UTC>))
+lookup_callsign(callsign=None, timestamp=datetime.datetime(2014, 4, 29, 13, 1, 27, 518519, tzinfo=<UTC>))

Returns lookup data if an exception exists for a callsign

@@ -244,7 +244,7 @@ the id 273.

-lookup_prefix(prefix, timestamp=datetime.datetime(2014, 4, 25, 22, 19, 33, 219601, tzinfo=<UTC>))
+lookup_prefix(prefix, timestamp=datetime.datetime(2014, 4, 29, 13, 1, 27, 518519, tzinfo=<UTC>))

Returns lookup data of a Prefix

@@ -301,7 +301,7 @@ database (default database).

-lookup_zone_exception(callsign, timestamp=datetime.datetime(2014, 4, 25, 22, 19, 33, 219687, tzinfo=<UTC>))
+lookup_zone_exception(callsign, timestamp=datetime.datetime(2014, 4, 29, 13, 1, 27, 518556, tzinfo=<UTC>))

Returns a CQ Zone if an exception exists for the given callsign

Args: callsign (string): Amateur radio callsign diff --git a/docs/build/html/objects.inv b/docs/build/html/objects.inv index 122f8d0..479e5aa 100644 --- a/docs/build/html/objects.inv +++ b/docs/build/html/objects.inv @@ -2,5 +2,7 @@ # Project: pyhamtools # Version: 0.1 # The remainder of this file is compressed using zlib. -xڭn0D|rU\PJoU^+6UCpBVpxZNפ - 33^&ze5+ФDzPm٤ƨhxS5,\(Kb;emg;;,"l)9Z*"'fok"9;hU@` k^Qˇ $=El!r-T#kZt~#e asg1 \ No newline at end of file +xڭSAj0j\sBJZՒW4qj f43VZA(@l\ T Ц{E􃎊D YO i&*ظ&iki,bI?c Yv.Bk%M#8GNjRl{4ˢ&.9/QqrЈd'̊EVˢ%Wx +K +Kj +ER ocYIpJӮ%ysmKKBcV+<d \ No newline at end of file diff --git a/docs/build/html/searchindex.js b/docs/build/html/searchindex.js index 53333c6..c8bb064 100644 --- a/docs/build/html/searchindex.js +++ b/docs/build/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:42,terms:{oper:4,all:[4,3],code:[0,4],identifi:4,show:4,illustr:[],text:[],obtain:[4,3],myapikei:4,prefix:4,radio:[0,4],invalid:4,permiss:3,follow:[0,4,3],lookup:4,apikeymissingerror:4,entiti:4,xml:4,content:[],clublogxml:4,depend:4,copyright:3,also:4,"true":4,explain:[],tobia:3,except:4,should:[],tort:3,other:3,dict:4,ituz:4,queri:4,tzinfo:4,aris:3,logger:4,therefor:4,local:4,match:4,merchant:3,applic:0,lookup_ent:4,sourc:4,"return":[1,4],string:4,variou:4,countryfil:4,python:[0,4],timestamp:4,express:3,dai:4,"import":4,veri:[],liabl:3,month:4,associ:3,requir:4,warranti:3,like:0,specif:4,complic:[],"try":4,provid:[4,3],stuff:[],necessari:[0,4],contain:[0,4],found:4,readthedoc:0,page:0,impli:3,right:3,deal:3,example_gener:[],replac:4,some:0,see:0,callsign:[0,1,4],connect:[4,3],arg:4,download:4,germani:4,event:3,librari:[0,4],out:3,even:4,index:0,lookuptyp:4,turkmenistan:4,lookup_prefix:4,databas:4,rep:4,publish:3,lookup_zone_except:4,current:0,delet:4,written:[],version:0,inject:4,action:3,internet:4,print:4,condit:3,irc:0,bla:[],method:4,str:4,kei:4,longitud:4,given:4,free:3,dictionari:4,locat:4,come:0,lookup_callsign:4,valu:4,christma:4,search:0,fit:3,island:4,cty:4,against:4,datetim:4,instanc:4,doctest:[],permit:3,fals:4,countri:4,typic:4,dh1tw:[0,2,3],com:[0,4],assign:4,frequent:0,"default":4,vp5:1,softwar:3,adif:4,directli:4,modul:[],damag:3,three:4,qrp:1,filenam:4,api:4,strip:1,ea1:1,noresult:[],miss:4,merg:3,liabil:3,differ:4,from:[4,3],log:4,wai:[],cqz:4,modifi:3,etc:1,contact:[],two:4,wrapper:4,github:0,avail:4,whom:3,station:4,interfac:4,includ:3,paramet:4,call:1,daili:4,type:4,more:4,"function":[],amateur:[0,4],option:4,copi:3,keyerror:4,notic:3,is_invalid_oper:4,pytz:4,pars:0,callinfo:[],particular:3,known:4,herebi:3,holder:3,utc:4,kind:3,whether:3,access:[],structur:[],exampl:4,aim:4,record:4,contin:4,limit:3,can:4,abov:3,webirc:0,otherwis:3,hamtest:0,purpos:3,latitud:4,claim:3,file:[0,4,3],creat:0,"int":4,descript:[],year:4,my_lookuplib:4,ani:[1,3],dp0gvn:4,antarctica:4,inform:[1,4],exist:4,contract:3,substanti:3,onlin:4,seem:4,deltaxrai:0,plist:4,sell:3,vk9xo:4,mylookuplib:4,date:4,author:3,perform:4,apikei:4,when:4,detail:4,same:4,check:4,note:[],how:4,valid:4,bool:4,which:[0,4],none:4,verifi:1,you:0,subject:3,mit:[0,3],lookuplib:[],updat:4,incorrect:4,"5w1cfn":4,http:[0,4],clublog:4,shall:3,org:[0,4],fed:4,restrict:3,befor:4,zone:4,rais:4,distribut:3,sublicens:3,bsd:[],data:4,"class":[0,1,4],charg:3,homogen:4,noninfring:3,infrequ:4,off:1,faster:0,"__name__":4,grant:3,clublogapi:4,wellnitz:3,without:3,issu:0,person:3,portion:3,getter:[],gethomecal:1,getlogg:4,thi:[1,4,3],time:4,format:[],hello:[],furnish:3},objtypes:{"0":"py:module","1":"py:method","2":"py:class"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","class","Python class"]},filenames:["index","Callinfo","help","license","LookupLib"],titles:["PyHamTools","Callinfo","help","license","LookupLib"],objects:{pyhamtools:{callinfo:[1,0,0,"-"],lookuplib:[4,0,0,"-"]},"pyhamtools.callinfo.Callinfo":{getHomeCall:[1,1,1,""]},"pyhamtools.lookuplib":{LookupLib:[4,2,1,""]},"pyhamtools.lookuplib.LookupLib":{lookup_prefix:[4,1,1,""],lookup_entity:[4,1,1,""],lookup_zone_exception:[4,1,1,""],lookup_callsign:[4,1,1,""],is_invalid_operation:[4,1,1,""]},"pyhamtools.callinfo":{Callinfo:[1,2,1,""]}},titleterms:{help:2,anoth:[],licens:3,clase:0,simpl:[],indic:0,content:[],header:[],contact:3,tabl:0,pyhamtool:0,document:[],callinfo:1,modul:0,lookuplib:4,welcom:[]}}) \ No newline at end of file +Search.setIndex({envversion:42,terms:{vp5:[],all:[1,4,3],code:[0,1,4],identifi:[1,4],show:4,illustr:[],text:[],obtain:[4,3],damag:3,myapikei:4,prefix:[1,4],get_contin:1,publish:3,permiss:3,follow:[0,1,4,3],itu:1,apikeymissingerror:4,entiti:4,xml:[1,4],content:[],onli:1,clublogxml:4,depend:[1,4],copyright:3,also:4,adif:[1,4],"true":[1,4],explain:[],tobia:3,except:4,should:[],tort:3,other:3,dict:[1,4],ituz:[1,4],queri:4,tzinfo:[1,4],aris:3,logger:[1,4],therefor:4,local:4,match:4,merchant:3,applic:0,lookup_ent:4,sourc:4,"return":[1,4],string:[1,4],variou:4,format:[],python:[0,1,4],timestamp:[1,4],express:3,dai:4,feder:1,"import":[1,4],veri:1,liabl:3,month:4,geo:[],requir:4,name:1,warranti:3,like:0,specif:[1,4],descript:[],complic:[],"try":4,whether:3,republ:1,stuff:[],necessari:[0,4],contain:[0,1,4],found:[1,4],readthedoc:0,where:1,page:0,get_cqz:1,impli:3,right:3,deal:3,replac:4,some:0,consequ:1,see:0,callsign:[0,1,4],connect:[4,3],arg:4,download:4,home:1,event:3,librari:[0,4],out:3,even:4,index:0,oceania:1,lookuptyp:[1,4],turkmenistan:4,item:1,lookup_prefix:4,databas:[1,4],rep:[1,4],asia:1,lookup_zone_except:4,current:[0,1],delet:4,written:[],version:0,inject:[1,4],internet:4,print:4,condit:3,irc:0,bla:[],method:4,provid:[1,4,3],str:[1,4],kei:4,longitud:[1,4],differ:[1,4],free:3,entir:1,dictionari:[1,4],europ:1,come:0,lookup_callsign:4,valu:4,christma:4,hc2:1,sell:3,search:0,perform:4,fit:3,most:1,germani:[1,4],island:4,could:1,slightli:1,cty:4,against:4,unfortun:1,precis:1,datetim:[1,4],instanc:[1,4],doctest:[],permit:3,fals:[1,4],countri:[1,4],typic:4,dh1tw:[0,1,2,3],com:[0,1,4],assign:4,frequent:0,oper:4,softwar:3,get_ituz:1,suffix:1,directli:4,activ:1,modul:[],africa:1,three:4,qrp:[],filenam:4,api:[1,4],wrapper:4,strip:1,ea1:[],noresult:[],miss:[1,4],fed:[1,4],merg:3,liabil:3,given:4,latitud:[1,4],from:[1,4,3],log:[1,4],wai:[],cqz:[1,4],modifi:3,daili:4,etc:1,contact:[],two:4,construct:1,github:0,avail:[1,4],whom:3,reli:1,station:4,interfac:4,includ:3,paramet:[1,4],call:1,underli:1,locat:[1,4],type:[1,4],valueerror:1,more:4,"function":[],plist:4,capit:1,through:1,option:[1,4],copi:3,keyerror:[1,4],notic:3,lookup:[1,4],is_invalid_oper:4,pytz:[1,4],pars:0,callinfo:[],particular:3,known:4,off:1,herebi:3,holder:3,cic:1,utc:[1,4],kind:3,dedic:1,retriev:1,"default":4,access:[],none:[1,4],structur:[],exampl:[1,4],aim:4,record:4,"while":1,contin:[1,4],limit:3,can:[1,4],abov:3,webirc:0,otherwis:3,hamtest:0,purpos:[1,3],radio:[0,1,4],associ:3,pre:1,claim:3,would:1,file:[0,1,4,3],creat:0,"int":[1,4],get_homecal:1,year:4,my_lookuplib:[1,4],ani:[1,3],doesn:1,dp0gvn:4,"case":1,antarctica:[1,4],inform:[1,4],exist:[1,4],contract:3,substanti:3,onlin:4,seem:4,deltaxrai:0,action:3,sever:1,incorrect:4,vk9xo:4,mylookuplib:4,date:4,author:3,check:[1,4],get_country_nam:1,apikei:4,when:[1,4],detail:4,same:4,get_lat_long:1,note:[],how:4,amateur:[0,1,4],valid:[1,4],bool:[1,4],which:[0,4],get_adif_id:1,verifi:[],you:0,subject:3,mit:[0,3],lookuplib:[],updat:4,furnish:3,example_gener:[],"5w1cfn":4,http:[0,4],clublog:[1,4],shall:3,org:[0,1,4],object:1,restrict:3,invalid:4,befor:4,zone:[1,4],rais:[1,4],countryfil:[1,4],work:1,distribut:3,sublicens:3,bsd:[],america:1,data:[1,4],"class":[0,1,4],charg:3,is_valid_callsign:1,homogen:4,noninfring:3,infrequ:4,don:1,faster:0,coordin:1,entri:1,"__name__":[1,4],grant:3,clublogapi:4,wellnitz:3,without:[1,3],issu:0,person:3,portion:3,getter:[],gethomecal:[],south:1,thi:[1,4,3],time:4,north:1,get_al:1,hello:[],getlogg:[1,4]},objtypes:{"0":"py:module","1":"py:method","2":"py:class"},objnames:{"0":["py","module","Python module"],"1":["py","method","Python method"],"2":["py","class","Python class"]},filenames:["index","Callinfo","help","license","LookupLib"],titles:["PyHamTools","Callinfo","help","license","LookupLib"],objects:{pyhamtools:{callinfo:[1,0,0,"-"],lookuplib:[4,0,0,"-"]},"pyhamtools.callinfo.Callinfo":{get_continent:[1,1,1,""],get_cqz:[1,1,1,""],get_homecall:[1,1,1,""],get_country_name:[1,1,1,""],get_all:[1,1,1,""],get_lat_long:[1,1,1,""],is_valid_callsign:[1,1,1,""],get_adif_id:[1,1,1,""],get_ituz:[1,1,1,""]},"pyhamtools.lookuplib":{LookupLib:[4,2,1,""]},"pyhamtools.lookuplib.LookupLib":{lookup_prefix:[4,1,1,""],lookup_entity:[4,1,1,""],lookup_zone_exception:[4,1,1,""],lookup_callsign:[4,1,1,""],is_invalid_operation:[4,1,1,""]},"pyhamtools.callinfo":{Callinfo:[1,2,1,""]}},titleterms:{help:2,anoth:[],licens:3,clase:0,simpl:[],indic:0,content:[],header:[],contact:3,tabl:0,pyhamtool:0,document:[],callinfo:1,modul:0,lookuplib:4,welcom:[]}}) \ No newline at end of file diff --git a/pyhamtools/__init__.py b/pyhamtools/__init__.py index ce01da8..10baab5 100644 --- a/pyhamtools/__init__.py +++ b/pyhamtools/__init__.py @@ -1,4 +1,3 @@ from pyhamtools.lookuplib import LookupLib from pyhamtools.callinfo import Callinfo - diff --git a/pyhamtools/callinfo.py b/pyhamtools/callinfo.py index 90542ea..02abd69 100644 --- a/pyhamtools/callinfo.py +++ b/pyhamtools/callinfo.py @@ -1,6 +1,7 @@ import re import logging from datetime import datetime +import sys import pytz @@ -13,26 +14,61 @@ from pyhamtools.consts import LookupConventions as const UTC = pytz.UTC timestamp_now = datetime.utcnow().replace(tzinfo=UTC) +if sys.version_info < (2, 7, ): + class NullHandler(logging.Handler): + def emit(self, record): + pass class Callinfo(object): """ - This is going to going to return information for a callsign + The purpose of this class is to return data (country, latitude, longitude, CQ Zone...etc) for an + Amateur Radio callsign. The class can be used with any lookup database, + provided through an Instance of :py:class:`LookupLib`. + An instance of :py:class:`Lookuplib` has to be injected on object construction. + + Args: + lookuplib (:py:class:`LookupLib`) : instance of :py:class:`LookupLib` + logger (logging.getLogger(__name__), optional): Python logger + """ - def __init__(self, lookuplib=LookupLib(), logger=None): + def __init__(self, lookuplib, logger=None): self._logger = None if logger: self._logger = logger else: self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) + if sys.version_info[:2] == (2, 6): + self._logger.addHandler(NullHandler()) + else: + self._logger.addHandler(logging.NullHandler()) self._lookuplib = lookuplib self._callsign_info = None def get_homecall(self, callsign): - """verify call and strip off any /ea1 vp5/ /qrp etc""" + """Strips off country prefixes (**HC2/**DH1TW) and activity suffixes (DH1TW**/P**). + + Args: + callsign (str): Amateur Radio callsign + + Returns: + str: callsign without country/activity pre/suffixes + + Raises: + ValueError: No callsign found in string + + Example: + The following code retrieves the home call for "HC2/DH1TW/P" + + >>> from pyhamtools import LookupLib, Callinfo + >>> my_lookuplib = LookupLib(lookuptype="countryfile") + >>> cic = Callinfo(my_lookuplib) + >>> cic.get_homecall("HC2/DH1TW/P") + DH1TW + + """ callsign = callsign.upper() homecall = re.search('[\d]{0,1}[A-Z]{1,2}\d([A-Z]{1,4}|\d{3,3}|\d{1,3}[A-Z])[A-Z]{0,5}', callsign) @@ -40,7 +76,8 @@ class Callinfo(object): homecall = homecall.group(0) return homecall else: - return + raise ValueError + def _iterate_prefix(self, callsign, timestamp=timestamp_now): """truncate call until it corresponds to a Prefix in the database""" @@ -55,7 +92,17 @@ class Callinfo(object): raise KeyError def _dismantle_callsign(self, callsign, timestamp=timestamp_now): + """ try to identify the callsign's identity by analyzing it in the following order: + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Raises: + KeyError: Callsign could not be identified + + + """ entire_callsign = callsign.upper() if re.search('[/A-Z0-9\-]{3,15}', entire_callsign): # make sure the call has at least 3 characters @@ -150,7 +197,43 @@ class Callinfo(object): def get_all(self, callsign, timestamp=timestamp_now): + """ Lookup a callsign and return all data available from the underlying database + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + dict: Dictionary containing the callsign specific data + + Raises: + KeyError: Callsign could not be identified + + Example: + The following code returns all available information from the country-files.com database for the + callsign "DH1TW" + + >>> from pyhamtools import LookupLib, Callinfo + >>> my_lookuplib = LookupLib(lookuptype="countryfile") + >>> cic = Callinfo(my_lookuplib) + >>> cic.get_all("DH1TW") + { + 'country': 'Fed. Rep. of Germany', + 'adif': 230, + 'continent': 'EU', + 'latitude': 51.0, + 'longitude': -10.0, + 'cqz': 14, + 'ituz': 28 + } + + Note: + The content of the returned data depends entirely on the injected + :py:class:`LookupLib` (and the used database). While the country-files.com provides + for example the ITU Zone, Clublog doesn't. Consequently, the item "ituz" + would be missing with Clublog (API or XML) :py:class:`LookupLib`. + + """ callsign_data = self._lookup_callsign(callsign, timestamp_now) try: @@ -159,18 +242,65 @@ class Callinfo(object): except KeyError: pass - print callsign_data - return callsign_data def is_valid_callsign(self, callsign, timestamp=timestamp_now): + """ Checks if a callsign is valid + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + bool: True / False + + Example: + The following checks if "DH1TW" is a valid callsign + + >>> from pyhamtools import LookupLib, Callinfo + >>> my_lookuplib = LookupLib(lookuptype="countryfile") + >>> cic = Callinfo(my_lookuplib) + >>> cic.is_valid_callsign("DH1TW") + True + + """ try: if self.get_all(callsign, timestamp): return True - except: + except KeyError: return False def get_lat_long(self, callsign): + """ Returns Latitude and Longitude for a callsign + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + dict: Containing Latitude and Longitude + + Raises: + KeyError: No data found for callsign + + Example: + The following code returns Latitude & Longitude for "DH1TW" + + >>> from pyhamtools import LookupLib, Callinfo + >>> my_lookuplib = LookupLib(lookuptype="countryfile") + >>> cic = Callinfo(my_lookuplib) + >>> cic.get_lat_long("DH1TW") + { + 'latitude': 51.0, + 'longitude': -10.0 + } + + Note: + Unfortunately, in most cases the returned Latitude and Longitude are not very precise. + Clublog and Country-files.com use the country's capital coordinates in most cases, if no + dedicated entry in the database exists. + + """ callsign_data = self.get_all(callsign, timestamp=timestamp_now) return { const.LATITUDE : callsign_data[const.LATITUDE], @@ -178,30 +308,101 @@ class Callinfo(object): } def get_cqz(self, callsign, timestamp=timestamp_now): + """ Returns CQ Zone of a callsign + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + int: containing the callsign's CQ Zone + + Raises: + KeyError: no CQ Zone found for callsign + + """ return self.get_all(callsign, timestamp)[const.CQZ] def get_ituz(self, callsign, timestamp=timestamp_now): + """ Returns ITU Zone of a callsign + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + int: containing the callsign's CQ Zone + + Raises: + KeyError: No ITU Zone found for callsign + + Note: + Currently, only Country-files.com lookup database contains ITU Zones + + """ return self.get_all(callsign, timestamp)[const.ITUZ] def get_country_name(self, callsign, timestamp=timestamp_now): + """ Returns the country name where the callsign is located + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + str: name of the Country + + Raises: + KeyError: No Country found for callsign + + Note: + Don't rely on the country name when working with several instances of + :Callinfo. Clublog and Country-files.org use slightly different names + for countrys. Example: + Country-files.com: "Fed. Rep. of Germany" + Clublog: "FEDERAL REPUBLIC OF GERMANY" + + """ return self.get_all(callsign, timestamp)[const.COUNTRY] def get_adif_id(self, callsign, timestamp=timestamp_now): + """ Returns ADIF id of a callsign's country + + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + + Returns: + int: containing the country ADIF id + + Raises: + KeyError: No Country found for callsign + + """ return self.get_all(callsign, timestamp)[const.ADIF] def get_continent(self, callsign, timestamp=timestamp_now): - return self.get_all(callsign, timestamp)[const.CONTINENT] + """ Returns the continent Identifier of a callsign -if __name__ == "__main__": - import logging.config - logging.config.fileConfig("logging.ini") - logger = logging.getLogger(__name__) + Args: + callsign (str): Amateur Radio callsign + timestamp (datetime, optional): datetime in UTC (tzinfo=pytz.UTC) + Returns: + str: continent identified - from pyhamtools import LookupLib - apikey = "67547d6ce7a37276373b0568e3e52c1d3e2cb0e5" - l = LookupLib("clublogxml", apikey=apikey) - c = Callinfo(l) - print c._iterate_prefix("DH1TW") - print c._iterate_prefix("QRM") + Raises: + KeyError: No Continent found for callsign + Note: + The following continent identifiers are used: + + - EU: Europe + - NA: North America + - SA: South America + - AS: Asia + - AF: Africa + - OC: Oceania + - AN: Antarctica + """ + return self.get_all(callsign, timestamp)[const.CONTINENT] \ No newline at end of file diff --git a/pyhamtools/consts.py b/pyhamtools/consts.py index 9210ada..965497d 100644 --- a/pyhamtools/consts.py +++ b/pyhamtools/consts.py @@ -17,4 +17,24 @@ class LookupConventions: WHITELIST = "whitelist" WHITELIST_START = "whitelist_start" WHITELIST_END = "whitelist_end" - DELETED = "deleted" \ No newline at end of file + DELETED = "deleted" + +class Modes: + """ Constants for Operating modes """ + + CW = "CW" + USB = "USB" + LSB = "LSB" + DIGITAL = "DIGITAL" + FM = "FM" + +class DXSpot: + """ Constants used for DX Spots """ + + SPOTTER = "spotter" + DX = "dx" + FREQUENCY = "frequency" + COMMENT = "comment" + TIME = "time" + BAND = "band" + MODE = "mode" \ No newline at end of file diff --git a/pyhamtools/dxcluster.py b/pyhamtools/dxcluster.py new file mode 100644 index 0000000..9e35737 --- /dev/null +++ b/pyhamtools/dxcluster.py @@ -0,0 +1,60 @@ +__author__ = 'dh1tw' + +from datetime import datetime +import re + + +import pytz + +UTC = pytz.UTC + +from pyhamtools.utils import freq_to_band +from pyhamtools.consts import Modes as mode +from pyhamtools.consts import DXSpot as dxspot + + +def decode_spot(raw_string): + """Chop Line from DX-Cluster into pieces and return a dict with the spot data""" + + spotter_call = None + dx_call = None + frequency = None + comment = None + spot_time = None + band = None + mode = None + bandmode = None + + # Spotter callsign + if re.match('[A-Za-z0-9\/]+[:$]', raw_string[6:15]): + spotter_call = re.sub(':', '', re.match('[A-Za-z0-9\/]+[:$]', raw_string[6:15]).group(0)) + else: + raise ValueError + + if re.search('[0-9\.]{5,12}', raw_string[10:25]): + frequency = float(re.search('[0-9\.]{5,12}', raw_string[10:25]).group(0)) + else: + raise ValueError + + dx_call = re.sub('[^A-Za-z0-9\/]+', '', raw_string[26:38]) + comment = re.sub('[^\sA-Za-z0-9\.,;\#\+\-!\?\$\(\)@\/]+', ' ', raw_string[39:69]) + spot_time_ = re.sub('[^0-9]+', '', raw_string[70:74]) + spot_time = datetime(hour=int(spot_time_[0:2]), minute=int(spot_time_[2:4]), second=0, microsecond = 0, tzinfo=UTC) + + try: + bandmode = freq_to_band(frequency) + band = bandmode["band"] + mode = bandmode["mode"] + except KeyError: + raise ValueError + + data = { + dxspot.SPOTTER: spotter_call, + dxspot.DX: dx_call, + dxspot.BAND: band, + dxspot.MODE: mode, + dxspot.COMMENT: comment, + dxspot.TIME: spot_time + } + + return data diff --git a/pyhamtools/logging.ini b/pyhamtools/logging.ini new file mode 100644 index 0000000..4c8fca4 --- /dev/null +++ b/pyhamtools/logging.ini @@ -0,0 +1,22 @@ +[loggers] +keys=root + +[handlers] +keys=consoleHandler + +[formatters] +keys=simpleFormatter + +[logger_root] +level=DEBUG +handlers=consoleHandler + +[handler_consoleHandler] +class=StreamHandler +level=DEBUG +formatter=simpleFormatter +args=(sys.stdout,) + +[formatter_simpleFormatter] +format=%(asctime)s - %(name)s - %(levelname)s - %(message)s +datefmt= \ No newline at end of file diff --git a/pyhamtools/lookuplib.py b/pyhamtools/lookuplib.py index dc514e0..408064f 100644 --- a/pyhamtools/lookuplib.py +++ b/pyhamtools/lookuplib.py @@ -8,7 +8,7 @@ import xml.etree.ElementTree as ET import urllib import json import copy - +import sys import requests from requests.exceptions import ConnectionError, HTTPError, Timeout @@ -21,6 +21,10 @@ from exceptions import APIKeyMissingError UTC = pytz.UTC timestamp_now = datetime.utcnow().replace(tzinfo=UTC) +if sys.version_info < (2, 7,): + class NullHandler(logging.Handler): + def emit(self, record): + pass class LookupLib(object): """ @@ -55,7 +59,10 @@ class LookupLib(object): self._logger = logger else: self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) + if sys.version_info[:2] == (2, 6): + self._logger.addHandler(NullHandler()) + else: + self._logger.addHandler(logging.NullHandler()) self._apikey = apikey self._download = True @@ -201,7 +208,6 @@ class LookupLib(object): if self._callsign_exceptions[item][const.START] < timestamp: callsign_data = copy.deepcopy(self._callsign_exceptions[item]) del callsign_data[const.START] - print callsign + ": " + "here1" return callsign_data # enddate > timestamp @@ -209,7 +215,6 @@ class LookupLib(object): if self._callsign_exceptions[item][const.END] > timestamp: callsign_data = copy.deepcopy(self._callsign_exceptions[item]) del callsign_data[const.END] - print callsign + ": " + "here2" return callsign_data # startdate > timestamp > enddate @@ -219,15 +224,12 @@ class LookupLib(object): callsign_data = copy.deepcopy(self._callsign_exceptions[item]) del callsign_data[const.START] del callsign_data[const.END] - print callsign + ": " + "here3" return callsign_data # no startdate or enddate available elif not const.START in self._callsign_exceptions[item] and not const.END in self._callsign_exceptions[item]: - print callsign + ": " + "here4" return self._callsign_exceptions[item] - print callsign + ": " + "here5" # no matching case raise KeyError @@ -588,11 +590,15 @@ class LookupLib(object): # unzip file, if gz if os.path.splitext(download_file_path)[1][1:] == "gz": - with gzip.open(download_file_path, "r") as download_file: + + download_file = gzip.open(download_file_path, "r") + try: cty_file_path = os.path.join(os.path.splitext(download_file_path)[0]) with open(cty_file_path, "w") as cty_file: cty_file.write(download_file.read()) - self._logger.debug(str(cty_file_path) + " successfully extracted") + self._logger.debug(str(cty_file_path) + " successfully extracted") + finally: + download_file.close() else: cty_file_path = download_file_path diff --git a/pyhamtools/utils.py b/pyhamtools/utils.py new file mode 100644 index 0000000..b2e8f14 --- /dev/null +++ b/pyhamtools/utils.py @@ -0,0 +1,135 @@ +from pyhamtools.consts import Modes as const + + +def freq_to_band(freq): + """converts a frequency [kHz] into the band and looks up the mode""" + band = None + mode = None + if ((freq >= 135) and (freq <= 138)): + band = 2190 + mode = const.CW + elif ((freq >= 1800) and (freq <= 2000)): + band = 160 + if ((freq >= 1800) and (freq < 1838)): + mode = const.CW + elif ((freq >= 1838) and (freq < 1840)): + mode = const.DIGITAL + elif ((freq >= 1840) and (freq < 2000)): + mode = const.LSB + elif ((freq >= 3500) and (freq <= 4000)): + band = 80 + if ((freq >= 3500) and (freq < 3580)): + mode = const.CW + elif ((freq >= 3580) and (freq < 3600)): + mode = const.DIGITAL + elif ((freq >= 3600) and (freq < 4000)): + mode = const.LSB + elif ((freq >= 5000) and (freq <= 5500)): + band = 60 + elif ((freq >= 7000) and (freq <= 7300)): + band = 40 + if ((freq >= 7000) and (freq < 7040)): + mode = const.CW + elif ((freq >= 7040) and (freq < 7050)): + mode = const.DIGITAL + elif ((freq >= 7050) and (freq < 7300)): + mode = const.LSB + elif ((freq >= 10100) and (freq <= 10150)): + band = 30 + if ((freq >= 10100) and (freq < 10140)): + mode = const.CW + elif ((freq >= 10140) and (freq < 10150)): + mode = const.DIGITAL + elif ((freq >= 14000) and (freq <= 14350)): + band = 20 + if ((freq >= 14000) and (freq < 14070)): + mode = const.CW + elif ((freq >= 14070) and (freq < 14099)): + mode = const.DIGITAL + elif ((freq >= 14100) and (freq < 14350)): + mode = const.USB + elif ((freq >= 18068) and (freq <= 18268)): + band = 17 + if ((freq >= 18068) and (freq < 18095)): + mode = const.CW + elif ((freq >= 18095) and (freq < 18110)): + mode = const.DIGITAL + elif ((freq >= 18110) and (freq < 18268)): + mode = const.USB + elif ((freq >= 21000) and (freq <= 21450)): + band = 15 + if ((freq >= 21000) and (freq < 21070)): + mode = const.CW + elif ((freq >= 21070) and (freq < 21150)): + mode = const.DIGITAL + elif ((freq >= 21150) and (freq < 21450)): + mode = const.USB + elif ((freq >= 24890) and (freq <= 24990)): + band = 12 + if ((freq >= 24890) and (freq < 24915)): + mode = const.CW + elif ((freq >= 24915) and (freq < 24930)): + mode = const.DIGITAL + elif ((freq >= 24930) and (freq < 24990)): + mode = const.USB + elif ((freq >= 28000) and (freq <= 29700)): + band = 10 + if ((freq >= 28000) and (freq < 28070)): + mode = const.CW + elif ((freq >= 28070) and (freq < 28190)): + mode = const.DIGITAL + elif ((freq >= 28300) and (freq < 29700)): + mode = const.USB + elif ((freq >= 50000) and (freq <= 54000)): + band = 6 + if ((freq >= 50000) and (freq < 50100)): + mode = const.CW + elif ((freq >= 50100) and (freq < 50500)): + mode = const.USB + elif ((freq >= 50500) and (freq < 51000)): + mode = const.DIGITAL + elif ((freq >= 70000) and (freq <= 71000)): + band = 4 + mode = None + elif ((freq >= 144000) and (freq <= 148000)): + band = 2 + if ((freq >= 144000) and (freq < 144150)): + mode = const.CW + elif ((freq >= 144150) and (freq < 144400)): + mode = const.USB + elif ((freq >= 144400) and (freq < 148000)): + mode = None + elif ((freq >= 220000) and (freq <= 226000)): + band = 1.25 #1.25m + mode = None + elif ((freq >= 420000) and (freq <= 470000)): + band = 0.7 #70cm + mode = None + elif ((freq >= 902000) and (freq <= 928000)): + band = 0.33 #33cm US + mode = None + elif ((freq >= 1200000) and (freq <= 1300000)): + band = 0.23 #23cm + mode = None + elif ((freq >= 2390000) and (freq <= 2450000)): + band = 0.13 #13cm + mode = None + elif ((freq >= 3300000) and (freq <= 3500000)): + band = 0.09 #9cm + mode = None + elif ((freq >= 5650000) and (freq <= 5850000)): + band = 0.053 #5.3cm + mode = None + elif ((freq >= 10000000) and (freq <= 10500000)): + band = 0.03 #3cm + mode = None + elif ((freq >= 24000000) and (freq <= 24050000)): + band = 0.0125 #1,25cm + mode = None + elif ((freq >= 47000000) and (freq <= 47200000)): + band = 0.0063 #6,3mm + mode = None + else: + raise KeyError + + return {"band": band, "mode": mode} \ No newline at end of file diff --git a/setup.py b/setup.py index a49a534..e012857 100755 --- a/setup.py +++ b/setup.py @@ -1,16 +1,22 @@ #!/usr/bin/env python - +import sys from distutils.core import setup +kw = {} + +if sys.version_info >= (3,): + kw['use_2to3'] = True + setup(name='pyhamtools', - version='0.1', - description='Amateur Radio Callsign Lookup', + version='0.1.1', + description='Collection of Tools for Amateur Radio developers', author='Tobias Wellnitz, DH1TW', author_email='Tobias@dh1tw.de', - url='http://github.com/dh1tw', + url='http://github.com/dh1tw/pyhamtools', packages=['pyhamtools'], install_requires=[ "pytz", "requests", - ] + ], + **kw ) diff --git a/test/conftest.py b/test/conftest.py index bfaecf2..0452e52 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -4,13 +4,6 @@ import os from apikey import APIKEY -# -# @pytest.fixture() -# def cleandir(): -# newpath = tempfile.mkdtemp() -# os.chdir(newpath) -# - from pyhamtools import LookupLib from pyhamtools import Callinfo diff --git a/test/test_utils_freq_to_band.py b/test/test_utils_freq_to_band.py new file mode 100644 index 0000000..74885a4 --- /dev/null +++ b/test/test_utils_freq_to_band.py @@ -0,0 +1,81 @@ +import pytest +from pyhamtools.utils import freq_to_band +from pyhamtools.consts import Modes as mode + +class Test_utils_freq_to_band(): + + def test_hf_frequencies(self): + assert freq_to_band(137) == {"band" : 2190, "mode":mode.CW} + + assert freq_to_band(1805) == {"band" : 160, "mode":mode.CW} + assert freq_to_band(1838) == {"band" : 160, "mode":mode.DIGITAL} + assert freq_to_band(1870) == {"band" : 160, "mode":mode.LSB} + + assert freq_to_band(3500) == {"band" : 80, "mode":mode.CW} + assert freq_to_band(3580) == {"band" : 80, "mode":mode.DIGITAL} + assert freq_to_band(3799) == {"band" : 80, "mode":mode.LSB} + + assert freq_to_band(5200) == {"band" : 60, "mode":None} + + assert freq_to_band(7000) == {"band" : 40, "mode":mode.CW} + assert freq_to_band(7044) == {"band" : 40, "mode":mode.DIGITAL} + assert freq_to_band(7139) == {"band" : 40, "mode":mode.LSB} + + assert freq_to_band(10100) == {"band" : 30, "mode":mode.CW} + assert freq_to_band(10141) == {"band" : 30, "mode":mode.DIGITAL} + + assert freq_to_band(14000) == {"band" : 20, "mode":mode.CW} + assert freq_to_band(14070) == {"band" : 20, "mode":mode.DIGITAL} + assert freq_to_band(14349) == {"band" : 20, "mode":mode.USB} + + assert freq_to_band(18068) == {"band" : 17, "mode":mode.CW} + assert freq_to_band(18096) == {"band" : 17, "mode":mode.DIGITAL} + assert freq_to_band(18250) == {"band" : 17, "mode":mode.USB} + + assert freq_to_band(21000) == {"band" : 15, "mode":mode.CW} + assert freq_to_band(21070) == {"band" : 15, "mode":mode.DIGITAL} + assert freq_to_band(21449) == {"band" : 15, "mode":mode.USB} + + assert freq_to_band(24890) == {"band" : 12, "mode":mode.CW} + assert freq_to_band(24916) == {"band" : 12, "mode":mode.DIGITAL} + assert freq_to_band(24965) == {"band" : 12, "mode":mode.USB} + + assert freq_to_band(28000) == {"band" : 10, "mode":mode.CW} + assert freq_to_band(28070) == {"band" : 10, "mode":mode.DIGITAL} + assert freq_to_band(28500) == {"band" : 10, "mode":mode.USB} + + assert freq_to_band(50000) == {"band" : 6, "mode":mode.CW} + assert freq_to_band(50100) == {"band" : 6, "mode":mode.USB} + assert freq_to_band(50500) == {"band" : 6, "mode":mode.DIGITAL} + + def test_vhf_frequencies(self): + assert freq_to_band(70001) == {"band" : 4, "mode":None} + + assert freq_to_band(144000) == {"band" : 2, "mode":mode.CW} + assert freq_to_band(144150) == {"band" : 2, "mode":mode.USB} + assert freq_to_band(144400) == {"band" : 2, "mode":None} + + assert freq_to_band(220000) == {"band" : 1.25, "mode":None} + + def test_uhf_frequencies(self): + assert freq_to_band(420000) == {"band" : 0.7, "mode":None} + + assert freq_to_band(902000) == {"band" : 0.33, "mode":None} + + assert freq_to_band(1200000) == {"band" : 0.23, "mode":None} + + def test_shf_frequencies(self): + assert freq_to_band(2390000) == {"band" : 0.13, "mode":None} + + assert freq_to_band(3300000) == {"band" : 0.09, "mode":None} + + assert freq_to_band(5650000) == {"band" : 0.053, "mode":None} + + assert freq_to_band(10000000) == {"band" : 0.03, "mode":None} + + assert freq_to_band(24000000) == {"band" : 0.0125, "mode":None} + + assert freq_to_band(47000000) == {"band" : 0.0063, "mode":None} + + with pytest.raises(KeyError): + freq_to_band(16304) \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..8f93aa7 --- /dev/null +++ b/tox.ini @@ -0,0 +1,13 @@ +# Tox (http://tox.testrun.org/) is a tool for running tests +# in multiple virtualenvs. This configuration file will run the +# test suite on all supported python versions. To use it, "pip install tox" +# and then run "tox" from this directory. + +[tox] +envlist = py26,py27,pypy + +[testenv] +deps=pytest +commands = + py.test \ + {posargs}