Browse Source

AddrIdxList: cleanups, new `id_str` property

The MMGen Project 2 years ago
parent
commit
d9a2e0cfd1
3 changed files with 71 additions and 30 deletions
  1. 43 26
      mmgen/addrlist.py
  2. 4 4
      test/objtest_py_d/ot_btc_mainnet.py
  3. 24 0
      test/unit_tests_d/ut_addrlist.py

+ 43 - 26
mmgen/addrlist.py

@@ -31,35 +31,52 @@ def dmsg_sc(desc,data):
 	if g.debug_addrlist:
 		Msg(f'sc_debug_{desc}: {data}')
 
-class AddrIdxList(list,InitErrors,MMGenObject):
+class AddrIdxList(tuple,InitErrors,MMGenObject):
+
 	max_len = 1000000
-	def __init__(self,fmt_str=None,idx_list=None,sep=','):
+
+	def __new__(cls,fmt_str=None,idx_list=None,sep=','):
 		try:
-			if idx_list:
-				return list.__init__(self,sorted({AddrIdx(i) for i in idx_list}))
-			elif fmt_str:
-				ret = []
-				for i in (fmt_str.split(sep)):
-					j = i.split('-')
-					if len(j) == 1:
-						idx = AddrIdx(i)
-						if not idx:
-							break
-						ret.append(idx)
-					elif len(j) == 2:
-						beg = AddrIdx(j[0])
-						if not beg:
-							break
-						end = AddrIdx(j[1])
-						if not beg or (end < beg):
-							break
-						ret.extend([AddrIdx(x) for x in range(beg,end+1)])
-					else: break
-				else:
-					return list.__init__(self,sorted(set(ret))) # fell off end of loop - success
-				raise ValueError(f'{i!r}: invalid range')
+			if fmt_str:
+				def gen():
+					for i in (fmt_str.split(sep)):
+						j = [int(x) for x in i.split('-')]
+						if len(j) == 1:
+							yield j[0]
+						elif len(j) == 2:
+							if j[0] > j[1]:
+								raise ValueError(f'{i}: invalid range')
+							for k in range(j[0], j[1] + 1):
+								yield k
+						else:
+							raise ValueError(f'{i}: invalid range')
+				idx_list = tuple(gen())
+			return tuple.__new__(cls,sorted({AddrIdx(i) for i in (idx_list or [])}))
 		except Exception as e:
-			return type(self).init_fail(e,idx_list or fmt_str)
+			return cls.init_fail(e,idx_list or fmt_str)
+
+	@property
+	def id_str(self):
+
+		def gen():
+			i_save = self[0]
+			yield f'{i_save}'
+			in_range = False
+
+			for i in self[1:]:
+				if i - i_save == 1:
+					in_range = True
+				else:
+					if in_range:
+						in_range = False
+						yield f'-{i_save}'
+					yield f',{i}'
+				i_save = i
+
+			if in_range:
+				yield f'-{i_save}'
+
+		return ''.join(gen()) if self else ''
 
 class AddrListEntryBase(MMGenListItem):
 	invalid_attrs = {'proto'}

+ 4 - 4
test/objtest_py_d/ot_btc_mainnet.py

@@ -57,11 +57,11 @@ tests = {
 	},
 	'AddrIdxList': {
 		'arg1': 'fmt_str',
-		'bad':  ('x','5,9,1-2-3','8,-11','66,3-2'),
+		'bad':  ('x','5,9,1-2-3','8,-11','66,3-2','0-3'),
 		'good': (
-			('3,2,2',[2,3]),
-			('101,1,3,5,2-7,99',[1,2,3,4,5,6,7,99,101]),
-			({'idx_list':AddrIdxList('1-5')},[1,2,3,4,5])
+			('3,2,2',(2,3)),
+			('101,1,3,5,2-7,99',(1,2,3,4,5,6,7,99,101)),
+			({'idx_list':AddrIdxList('1-5')},(1,2,3,4,5))
 		)
 	},
 	'SubSeedIdxRange': {

+ 24 - 0
test/unit_tests_d/ut_addrlist.py

@@ -55,6 +55,30 @@ def do_test(list_type,chksum,idx_spec=None,pw_id_str=None,add_kwargs=None):
 
 class unit_tests:
 
+	def idxlist(self,name,ut):
+		for i,o in (
+				('99,88-102,1-3,4,9,818,444-445,816',        '1-4,9,88-102,444-445,816,818'),
+				('99,88-99,100,102,4-7,9,818,444-445,816,1', '1,4-7,9,88-100,102,444-445,816,818'),
+				('8',             '8'),
+				('2-4',           '2-4'),
+				('1,2-4',         '1-4'),
+				('2-4,1-9,9,1,8', '1-9'),
+				('2-4,1',         '1-4'),
+				('2-2',           '2'),
+				('2,2',           '2'),
+				('2-3',           '2-3'),
+				('2,3',           '2-3'),
+				('3,2',           '2-3'),
+				('2,4',           '2,4'),
+				('',              ''),
+			):
+			l = AddrIdxList(i)
+			if opt.verbose:
+				msg('list: {}\nin:   {}\nout:  {}\n'.format(list(l),i,o))
+			assert l.id_str == o, f'{l.id_str} != {o}'
+
+		return True
+
 	def addr(self,name,ut):
 		return (
 			do_test(AddrList,'BCE8 082C 0973 A525','1-3') and