<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/pysim/+/23594">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">utils.py: Add more type annotations<br><br>Change-Id: I50a0a07132890af0817f4ff0ce9fec53b7512522<br>---<br>M pySim/utils.py<br>1 file changed, 36 insertions(+), 31 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/94/23594/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/pySim/utils.py b/pySim/utils.py</span><br><span>index 75106d8..8acc0bf 100644</span><br><span>--- a/pySim/utils.py</span><br><span>+++ b/pySim/utils.py</span><br><span>@@ -3,7 +3,9 @@</span><br><span> """ pySim: various utilities</span><br><span> """</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#</span><br><span style="color: hsl(120, 100%, 40%);">+from typing import Optional, List, Dict, Any, Tuple</span><br><span style="color: hsl(120, 100%, 40%);">+from pySim.transport import LinkBase</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> # Copyright (C) 2009-2010  Sylvain Munaut <tnt@246tNt.com></span><br><span> #</span><br><span> # This program is free software: you can redistribute it and/or modify</span><br><span>@@ -20,40 +22,42 @@</span><br><span> # along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span> #</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+# just to differentiate strings of hex nibbles from everything else</span><br><span style="color: hsl(120, 100%, 40%);">+Hexstr = str</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def h2b(s: str) -> bytearray:</span><br><span style="color: hsl(120, 100%, 40%);">+def h2b(s:Hexstr) -> bytearray:</span><br><span>       """convert from a string of hex nibbles to a sequence of bytes"""</span><br><span>      return bytearray.fromhex(s)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def b2h(b: bytearray) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def b2h(b:bytearray) -> str:</span><br><span>     """convert from a sequence of bytes to a string of hex nibbles"""</span><br><span>      return ''.join(['%02x'%(x) for x in b])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def h2i(s:str):</span><br><span style="color: hsl(120, 100%, 40%);">+def h2i(s:Hexstr) -> List[int]:</span><br><span>       """convert from a string of hex nibbles to a list of integers"""</span><br><span>       return [(int(x,16)<<4)+int(y,16) for x,y in zip(s[0::2], s[1::2])]</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def i2h(s) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def i2h(s:List[int]) -> str:</span><br><span>   """convert from a list of integers to a string of hex nibbles"""</span><br><span>       return ''.join(['%02x'%(x) for x in s])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def h2s(s:str) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def h2s(s:Hexstr) -> str:</span><br><span>   """convert from a string of hex nibbles to an ASCII string"""</span><br><span>  return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2])</span><br><span>                                                       if int(x + y, 16) != 0xff])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def s2h(s:str) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def s2h(s:str) -> Hexstr:</span><br><span>         """convert from an ASCII string to a string of hex nibbles"""</span><br><span>  b = bytearray()</span><br><span>      b.extend(map(ord, s))</span><br><span>        return b2h(b)</span><br><span> </span><br><span> # List of bytes to string</span><br><span style="color: hsl(0, 100%, 40%);">-def i2s(s) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def i2s(s:List[int]) -> str:</span><br><span>         """convert from a list of integers to an ASCII string"""</span><br><span>       return ''.join([chr(x) for x in s])</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def swap_nibbles(s:str) -> str:</span><br><span style="color: hsl(120, 100%, 40%);">+def swap_nibbles(s:Hexstr) -> Hexstr:</span><br><span>  """swap the nibbles in a hex string"""</span><br><span>         return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])</span><br><span> </span><br><span>@@ -104,7 +108,7 @@</span><br><span>     ei = '%02x' % l + swap_nibbles('%01x%s' % ((oe<<3)|1, rpad(imsi, 15)))</span><br><span>         return ei</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_imsi(ef):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_imsi(ef:Hexstr) -> Optional[str]:</span><br><span>         """Converts an EF value to the imsi string representation"""</span><br><span>   if len(ef) < 4:</span><br><span>           return None</span><br><span>@@ -122,10 +126,10 @@</span><br><span>  imsi = swapped[1:]</span><br><span>   return imsi</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_iccid(ef):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_iccid(ef:Hexstr) -> str:</span><br><span>       return swap_nibbles(ef).strip('f')</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def enc_iccid(iccid):</span><br><span style="color: hsl(120, 100%, 40%);">+def enc_iccid(iccid:str) -> Hexstr:</span><br><span>  return swap_nibbles(rpad(iccid, 20))</span><br><span> </span><br><span> def enc_plmn(mcc, mnc):</span><br><span>@@ -151,7 +155,7 @@</span><br><span>    return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ]</span><br><span> </span><br><span> # Accepts hex string representing three bytes</span><br><span style="color: hsl(0, 100%, 40%);">-def dec_mcc_from_plmn(plmn):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_mcc_from_plmn(plmn) -> int:</span><br><span>   ia = h2i(plmn)</span><br><span>       digit1 = ia[0] & 0x0F               # 1st byte, LSB</span><br><span>      digit2 = (ia[0] & 0xF0) >> 4  # 1st byte, MSB</span><br><span>@@ -160,7 +164,7 @@</span><br><span>                return 0xFFF # 4095</span><br><span>  return derive_mcc(digit1, digit2, digit3)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_mnc_from_plmn(plmn):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_mnc_from_plmn(plmn) -> int:</span><br><span>    ia = h2i(plmn)</span><br><span>       digit1 = ia[2] & 0x0F               # 3rd byte, LSB</span><br><span>      digit2 = (ia[2] & 0xF0) >> 4  # 3rd byte, MSB</span><br><span>@@ -169,7 +173,7 @@</span><br><span>                return 0xFFF # 4095</span><br><span>  return derive_mnc(digit1, digit2, digit3)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_act(twohexbytes):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_act(twohexbytes:Hexstr) -> List[str]:</span><br><span>     act_list = [</span><br><span>                 {'bit': 15, 'name': "UTRAN"},</span><br><span>              {'bit': 14, 'name': "E-UTRAN"},</span><br><span>@@ -186,7 +190,7 @@</span><br><span>                      sel.append(a['name'])</span><br><span>        return sel</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_xplmn_w_act(fivehexbytes):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_xplmn_w_act(fivehexbytes:Hexstr) -> Dict[str,Any]:</span><br><span>      res = {'mcc': 0, 'mnc': 0, 'act': []}</span><br><span>        plmn_chars = 6</span><br><span>       act_chars = 4</span><br><span>@@ -238,7 +242,7 @@</span><br><span>  res['status'] = h2i(hexstr[34:36])</span><br><span>   return res</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_xplmn(threehexbytes):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_xplmn(threehexbytes:Hexstr) -> dict:</span><br><span>         res = {'mcc': 0, 'mnc': 0, 'act': []}</span><br><span>        plmn_chars = 6</span><br><span>       plmn_str = threehexbytes[:plmn_chars]                           # first three bytes (six ascii hex chars)</span><br><span>@@ -246,7 +250,7 @@</span><br><span>      res['mnc'] = dec_mnc_from_plmn(plmn_str)</span><br><span>     return res</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def format_xplmn(hexstr):</span><br><span style="color: hsl(120, 100%, 40%);">+def format_xplmn(hexstr:Hexstr) -> str:</span><br><span>  s = ""</span><br><span>     for rec_data in hexstr_to_Nbytearr(hexstr, 3):</span><br><span>               rec_info = dec_xplmn(rec_data)</span><br><span>@@ -257,7 +261,7 @@</span><br><span>                 s += "\t%s # %s\n" % (rec_data, rec_str)</span><br><span>   return s</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def derive_milenage_opc(ki_hex, op_hex):</span><br><span style="color: hsl(120, 100%, 40%);">+def derive_milenage_opc(ki_hex:Hexstr, op_hex:Hexstr) -> Hexstr:</span><br><span>    """</span><br><span>   Run the milenage algorithm to calculate OPC from Ki and OP</span><br><span>   """</span><br><span>@@ -272,7 +276,7 @@</span><br><span>     opc_bytes = aes.encrypt(op_bytes)</span><br><span>    return b2h(strxor(opc_bytes, op_bytes))</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def calculate_luhn(cc):</span><br><span style="color: hsl(120, 100%, 40%);">+def calculate_luhn(cc) ->int:</span><br><span>         """</span><br><span>   Calculate Luhn checksum used in e.g. ICCID and IMEI</span><br><span>  """</span><br><span>@@ -280,7 +284,7 @@</span><br><span>     check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10</span><br><span>       return 0 if check_digit == 10 else check_digit</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def mcc_from_imsi(imsi):</span><br><span style="color: hsl(120, 100%, 40%);">+def mcc_from_imsi(imsi:str) -> Optional[str]:</span><br><span>         """</span><br><span>   Derive the MCC (Mobile Country Code) from the first three digits of an IMSI</span><br><span>  """</span><br><span>@@ -292,7 +296,7 @@</span><br><span>     else:</span><br><span>                return None</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def mnc_from_imsi(imsi, long=False):</span><br><span style="color: hsl(120, 100%, 40%);">+def mnc_from_imsi(imsi:str, long=False) -> Optional[str]:</span><br><span>    """</span><br><span>   Derive the MNC (Mobile Country Code) from the 4th to 6th digit of an IMSI</span><br><span>    """</span><br><span>@@ -307,7 +311,7 @@</span><br><span>     else:</span><br><span>                return None</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def derive_mcc(digit1, digit2, digit3):</span><br><span style="color: hsl(120, 100%, 40%);">+def derive_mcc(digit1:int, digit2:int, digit3:int) -> int:</span><br><span>        """</span><br><span>   Derive decimal representation of the MCC (Mobile Country Code)</span><br><span>       from three given digits.</span><br><span>@@ -324,7 +328,7 @@</span><br><span> </span><br><span>   return mcc</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def derive_mnc(digit1, digit2, digit3=0x0f):</span><br><span style="color: hsl(120, 100%, 40%);">+def derive_mnc(digit1:int, digit2:int, digit3:int=0x0f) -> int:</span><br><span>       """</span><br><span>   Derive decimal representation of the MNC (Mobile Network Code)</span><br><span>       from two or (optionally) three given digits.</span><br><span>@@ -344,7 +348,7 @@</span><br><span> </span><br><span>       return mnc</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_msisdn(ef_msisdn):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_msisdn(ef_msisdn) -> Optional[Tuple[int,int,Optional[str]]]:</span><br><span>    """</span><br><span>   Decode MSISDN from EF.MSISDN or EF.ADN (same structure).</span><br><span>     See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.</span><br><span>@@ -385,7 +389,7 @@</span><br><span> </span><br><span>    return (npi, ton, msisdn)</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def enc_msisdn(msisdn, npi=0x01, ton=0x03):</span><br><span style="color: hsl(120, 100%, 40%);">+def enc_msisdn(msisdn:str, npi:int=0x01, ton:int=0x03) -> Hexstr:</span><br><span>       """</span><br><span>   Encode MSISDN as LHV so it can be stored to EF.MSISDN.</span><br><span>       See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.</span><br><span>@@ -411,7 +415,7 @@</span><br><span> </span><br><span>    return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def dec_st(st, table="sim"):</span><br><span style="color: hsl(120, 100%, 40%);">+def dec_st(st, table="sim") -> str:</span><br><span>     """</span><br><span>   Parses the EF S/U/IST and prints the list of available services in EF S/U/IST</span><br><span>        """</span><br><span>@@ -599,7 +603,7 @@</span><br><span> </span><br><span>         return s</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def is_hex(string, minlen=2, maxlen=None) -> bool:</span><br><span style="color: hsl(120, 100%, 40%);">+def is_hex(string:str, minlen:int=2, maxlen:Optional[int]=None) -> bool:</span><br><span>       """</span><br><span>   Check if a string is a valid hexstring</span><br><span>       """</span><br><span>@@ -621,7 +625,7 @@</span><br><span>     except:</span><br><span>              return False</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def sanitize_pin_adm(pin_adm, pin_adm_hex = None):</span><br><span style="color: hsl(120, 100%, 40%);">+def sanitize_pin_adm(pin_adm, pin_adm_hex = None) -> Hexstr:</span><br><span>  """</span><br><span>   The ADM pin can be supplied either in its hexadecimal form or as</span><br><span>     ascii string. This function checks the supplied opts parameter and</span><br><span>@@ -650,10 +654,11 @@</span><br><span> </span><br><span>       return pin_adm</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-def init_reader(opts):</span><br><span style="color: hsl(120, 100%, 40%);">+def init_reader(opts) -> Optional[LinkBase]:</span><br><span>    """</span><br><span>   Init card reader driver</span><br><span>      """</span><br><span style="color: hsl(120, 100%, 40%);">+    sl:Optional[LinkBase] = None</span><br><span>         try:</span><br><span>                 if opts.pcsc_dev is not None:</span><br><span>                        print("Using PC/SC reader interface")</span><br><span>@@ -819,7 +824,7 @@</span><br><span>        return sw_masked == pattern</span><br><span> </span><br><span> def tabulate_str_list(str_list, width:int = 79, hspace:int = 2, lspace:int = 1,</span><br><span style="color: hsl(0, 100%, 40%);">-                                        align_left:bool = True):</span><br><span style="color: hsl(120, 100%, 40%);">+                                      align_left:bool = True) -> str:</span><br><span>         """Pretty print a list of strings into a tabulated form.</span><br><span> </span><br><span>  Args:</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/pysim/+/23594">change 23594</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/pysim/+/23594"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: pysim </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I50a0a07132890af0817f4ff0ce9fec53b7512522 </div>
<div style="display:none"> Gerrit-Change-Number: 23594 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>