[wireless-regdb] [PATCH v2 2/2] wireless-regdb: make scripts compatible with Python 3
Matthias Schiffer
mschiffer at universe-factory.net
Thu Mar 22 07:44:00 PDT 2018
On 03/22/2018 03:05 PM, Seth Forshee wrote:
> On Sun, Feb 04, 2018 at 12:36:54AM +0100, Matthias Schiffer wrote:
>> When playing with the generation scripts for OpenWrt development, I noticed
>> that these scripts still required Python 2. Future-proof them by replacing
>> deprecated functions with new Python 3 compatible variants. The result
>> works with both Python 2.7 and Python 3.x; older Python 2.x releases are
>> not supported anymore.
>>
>> regulatory.db and regulatory.bin are unchanged and reproducible across
>> Python versions. Note that there is no stable release of m2crypto for
>> Python 3 yet; I used the current development branch for testing.
>
> I can't say I'm all that knowledgable about Python 2 to Python 3
> conversion, but as far as I can tell this looks okay. It does seem to
> work for me running with both Python 2 and Python 3.
>
> One question below though, mostly just to satisfy my curiousity.
>
>> Signed-off-by: Matthias Schiffer <mschiffer at universe-factory.net>
>> ---
>>
>> v2: explicitly open input file with UTF-8 encoding; otherwise the scripts
>> will fail without a UTF-8 locale set in the environment
>>
>>
>> db2bin.py | 22 ++++++++---------
>> db2fw.py | 28 +++++++++++-----------
>> dbparse.py | 81 +++++++++++++++++++++++++++++++++++++-------------------------
>> 3 files changed, 74 insertions(+), 57 deletions(-)
>>
>> diff --git a/db2bin.py b/db2bin.py
>> index ae5f064..28cd7d2 100755
>> --- a/db2bin.py
>> +++ b/db2bin.py
>> @@ -1,6 +1,6 @@
>> #!/usr/bin/env python
>>
>> -from cStringIO import StringIO
>> +from io import BytesIO, open
>> import struct
>> import hashlib
>> from dbparse import DBParser
>> @@ -10,21 +10,21 @@ MAGIC = 0x52474442
>> VERSION = 19
>>
>> if len(sys.argv) < 3:
>> - print 'Usage: %s output-file input-file [key-file]' % sys.argv[0]
>> + print('Usage: %s output-file input-file [key-file]' % sys.argv[0])
>> sys.exit(2)
>>
>> def create_rules(countries):
>> result = {}
>> - for c in countries.itervalues():
>> + for c in countries.values():
>> for rule in c.permissions:
>> result[rule] = 1
>> - return result.keys()
>> + return list(result)
>
> Here and elsewhere, to get a list of the keys from a dictionary, we use
> list(dict). Experimentally I find this works, but I haven't been able to
> find anything which actually tells me that this is the defined behavior,
> and examples seem to prefer list(dict.keys()). I'm curious why this is
> guaranteed to provide a lsit of dictionary keys, and why you've done
> that rather than list(dict.keys()) (I'll grant that the scripts
> elsewhere use list(dict), so maybe you were just being consistent with
> that).
list(dict) is the recommended syntax in
http://python-future.org/compatible_idioms.html#dict-keys-values-items-as-a-list
.
Regards,
Matthias
>
>> def create_collections(countries):
>> result = {}
>> - for c in countries.itervalues():
>> + for c in countries.values():
>> result[c.permissions] = 1
>> - return result.keys()
>> + return list(result)
>>
>>
>> def be32(output, val):
>> @@ -49,9 +49,9 @@ class PTR(object):
>> return self._offset
>>
>> p = DBParser()
>> -countries = p.parse(file(sys.argv[2]))
>> +countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8'))
>>
>> -countrynames = countries.keys()
>> +countrynames = list(countries)
>> countrynames.sort()
>>
>> power = []
>> @@ -67,7 +67,7 @@ rules.sort()
>> collections = create_collections(countries)
>> collections.sort()
>>
>> -output = StringIO()
>> +output = BytesIO()
>>
>> # struct regdb_file_header
>> be32(output, MAGIC)
>> @@ -118,7 +118,7 @@ reg_country_ptr.set()
>> for alpha2 in countrynames:
>> coll = countries[alpha2]
>> # struct regdb_file_reg_country
>> - output.write(struct.pack('>ccxBI', str(alpha2[0]), str(alpha2[1]), coll.dfs_region, reg_rules_collections[coll.permissions]))
>> + output.write(struct.pack('>BBxBI', alpha2[0], alpha2[1], coll.dfs_region, reg_rules_collections[coll.permissions]))
>>
>>
>> if len(sys.argv) > 3:
>> @@ -143,5 +143,5 @@ if len(sys.argv) > 3:
>> else:
>> siglen.set(0)
>>
>> -outfile = open(sys.argv[1], 'w')
>> +outfile = open(sys.argv[1], 'wb')
>> outfile.write(output.getvalue())
>> diff --git a/db2fw.py b/db2fw.py
>> index 630e4d6..91b88d3 100755
>> --- a/db2fw.py
>> +++ b/db2fw.py
>> @@ -1,6 +1,6 @@
>> #!/usr/bin/env python
>>
>> -from cStringIO import StringIO
>> +from io import BytesIO, open
>> import struct
>> import hashlib
>> from dbparse import DBParser
>> @@ -10,21 +10,21 @@ MAGIC = 0x52474442
>> VERSION = 20
>>
>> if len(sys.argv) < 3:
>> - print 'Usage: %s output-file input-file' % sys.argv[0]
>> + print('Usage: %s output-file input-file' % sys.argv[0])
>> sys.exit(2)
>>
>> def create_rules(countries):
>> result = {}
>> - for c in countries.itervalues():
>> + for c in countries.values():
>> for rule in c.permissions:
>> result[rule] = 1
>> - return result.keys()
>> + return list(result)
>>
>> def create_collections(countries):
>> result = {}
>> - for c in countries.itervalues():
>> + for c in countries.values():
>> result[(c.permissions, c.dfs_region)] = 1
>> - return result.keys()
>> + return list(result)
>>
>>
>> def be32(output, val):
>> @@ -58,26 +58,26 @@ class PTR(object):
>> return self._written
>>
>> p = DBParser()
>> -countries = p.parse(file(sys.argv[2]))
>> +countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8'))
>> rules = create_rules(countries)
>> rules.sort()
>> collections = create_collections(countries)
>> collections.sort()
>>
>> -output = StringIO()
>> +output = BytesIO()
>>
>> # struct regdb_file_header
>> be32(output, MAGIC)
>> be32(output, VERSION)
>>
>> country_ptrs = {}
>> -countrynames = countries.keys()
>> +countrynames = list(countries)
>> countrynames.sort()
>> for alpha2 in countrynames:
>> coll = countries[alpha2]
>> - output.write(struct.pack('>cc', str(alpha2[0]), str(alpha2[1])))
>> + output.write(struct.pack('>BB', alpha2[0], alpha2[1]))
>> country_ptrs[alpha2] = PTR(output)
>> -output.write('\x00' * 4)
>> +output.write(b'\x00' * 4)
>>
>> reg_rules = {}
>> flags = 0
>> @@ -104,8 +104,8 @@ for reg_rule in rules:
>> cac_timeout = 0
>> if cac_timeout:
>> rule_len += 2
>> - output.write(struct.pack('>BBHIII', rule_len, flags, power_rule.max_eirp * 100,
>> - freq_range.start * 1000, freq_range.end * 1000, freq_range.maxbw * 1000,
>> + output.write(struct.pack('>BBHIII', rule_len, flags, int(power_rule.max_eirp * 100),
>> + int(freq_range.start * 1000), int(freq_range.end * 1000), int(freq_range.maxbw * 1000),
>> ))
>> if cac_timeout:
>> output.write(struct.pack('>H', cac_timeout))
>> @@ -129,5 +129,5 @@ for coll in collections:
>> for alpha2 in countrynames:
>> assert country_ptrs[alpha2].written
>>
>> -outfile = open(sys.argv[1], 'w')
>> +outfile = open(sys.argv[1], 'wb')
>> outfile.write(output.getvalue())
>> diff --git a/dbparse.py b/dbparse.py
>> index b735b6a..d73d1bd 100755
>> --- a/dbparse.py
>> +++ b/dbparse.py
>> @@ -1,5 +1,7 @@
>> #!/usr/bin/env python
>>
>> +from builtins import bytes
>> +from functools import total_ordering
>> import sys, math
>>
>> # must match <linux/nl80211.h> enum nl80211_reg_rule_flags
>> @@ -25,6 +27,7 @@ dfs_regions = {
>> 'DFS-JP': 3,
>> }
>>
>> + at total_ordering
>> class FreqBand(object):
>> def __init__(self, start, end, bw, comments=None):
>> self.start = start
>> @@ -32,41 +35,49 @@ class FreqBand(object):
>> self.maxbw = bw
>> self.comments = comments or []
>>
>> - def __cmp__(self, other):
>> - s = self
>> - o = other
>> - if not isinstance(o, FreqBand):
>> - return False
>> - return cmp((s.start, s.end, s.maxbw), (o.start, o.end, o.maxbw))
>> + def _as_tuple(self):
>> + return (self.start, self.end, self.maxbw)
>> +
>> + def __eq__(self, other):
>> + return (self._as_tuple() == other._as_tuple())
>> +
>> + def __ne__(self, other):
>> + return not (self == other)
>> +
>> + def __lt__(self, other):
>> + return (self._as_tuple() < other._as_tuple())
>>
>> def __hash__(self):
>> - s = self
>> - return hash((s.start, s.end, s.maxbw))
>> + return hash(self._as_tuple())
>>
>> def __str__(self):
>> return '<FreqBand %.3f - %.3f @ %.3f>' % (
>> self.start, self.end, self.maxbw)
>>
>> + at total_ordering
>> class PowerRestriction(object):
>> def __init__(self, max_ant_gain, max_eirp, comments = None):
>> self.max_ant_gain = max_ant_gain
>> self.max_eirp = max_eirp
>> self.comments = comments or []
>>
>> - def __cmp__(self, other):
>> - s = self
>> - o = other
>> - if not isinstance(o, PowerRestriction):
>> - return False
>> - return cmp((s.max_ant_gain, s.max_eirp),
>> - (o.max_ant_gain, o.max_eirp))
>> + def _as_tuple(self):
>> + return (self.max_ant_gain, self.max_eirp)
>>
>> - def __str__(self):
>> - return '<PowerRestriction ...>'
>> + def __eq__(self, other):
>> + return (self._as_tuple() == other._as_tuple())
>> +
>> + def __ne__(self, other):
>> + return not (self == other)
>> +
>> + def __lt__(self, other):
>> + return (self._as_tuple() < other._as_tuple())
>>
>> def __hash__(self):
>> - s = self
>> - return hash((s.max_ant_gain, s.max_eirp))
>> + return hash(self._as_tuple())
>> +
>> + def __str__(self):
>> + return '<PowerRestriction ...>'
>>
>> class DFSRegionError(Exception):
>> def __init__(self, dfs_region):
>> @@ -76,6 +87,7 @@ class FlagError(Exception):
>> def __init__(self, flag):
>> self.flag = flag
>>
>> + at total_ordering
>> class Permission(object):
>> def __init__(self, freqband, power, flags):
>> assert isinstance(freqband, FreqBand)
>> @@ -92,10 +104,14 @@ class Permission(object):
>> def _as_tuple(self):
>> return (self.freqband, self.power, self.flags)
>>
>> - def __cmp__(self, other):
>> - if not isinstance(other, Permission):
>> - return False
>> - return cmp(self._as_tuple(), other._as_tuple())
>> + def __eq__(self, other):
>> + return (self._as_tuple() == other._as_tuple())
>> +
>> + def __ne__(self, other):
>> + return not (self == other)
>> +
>> + def __lt__(self, other):
>> + return (self._as_tuple() < other._as_tuple())
>>
>> def __hash__(self):
>> return hash(self._as_tuple())
>> @@ -104,12 +120,12 @@ class Country(object):
>> def __init__(self, dfs_region, permissions=None, comments=None):
>> self._permissions = permissions or []
>> self.comments = comments or []
>> - self.dfs_region = 0
>> + self.dfs_region = 0
>>
>> - if dfs_region:
>> - if not dfs_region in dfs_regions:
>> - raise DFSRegionError(dfs_region)
>> - self.dfs_region = dfs_regions[dfs_region]
>> + if dfs_region:
>> + if not dfs_region in dfs_regions:
>> + raise DFSRegionError(dfs_region)
>> + self.dfs_region = dfs_regions[dfs_region]
>>
>> def add(self, perm):
>> assert isinstance(perm, Permission)
>> @@ -248,6 +264,7 @@ class DBParser(object):
>> for cname in cnames:
>> if len(cname) != 2:
>> self._warn("country '%s' not alpha2" % cname)
>> + cname = bytes(cname, 'ascii')
>> if not cname in self._countries:
>> self._countries[cname] = Country(dfs_region, comments=self._comments)
>> self._current_countries[cname] = self._countries[cname]
>> @@ -304,9 +321,9 @@ class DBParser(object):
>> p = self._power[pname]
>> try:
>> perm = Permission(b, p, flags)
>> - except FlagError, e:
>> + except FlagError as e:
>> self._syntax_error("Invalid flag '%s'" % e.flag)
>> - for cname, c in self._current_countries.iteritems():
>> + for cname, c in self._current_countries.items():
>> if perm in c:
>> self._warn('Rule "%s, %s" added to "%s" twice' % (
>> bname, pname, cname))
>> @@ -360,7 +377,7 @@ class DBParser(object):
>>
>> countries = self._countries
>> bands = {}
>> - for k, v in self._bands.iteritems():
>> + for k, v in self._bands.items():
>> if k in self._bands_used:
>> bands[self._banddup[k]] = v
>> continue
>> @@ -369,7 +386,7 @@ class DBParser(object):
>> self._lineno = self._bandline[k]
>> self._warn('Unused band definition "%s"' % k)
>> power = {}
>> - for k, v in self._power.iteritems():
>> + for k, v in self._power.items():
>> if k in self._power_used:
>> power[self._powerdup[k]] = v
>> continue
>> --
>> 2.16.1
>>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/wireless-regdb/attachments/20180322/4bb80d3a/attachment-0001.sig>
More information about the wireless-regdb
mailing list