Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/netaddr/eui/__init__.py: 24%

369 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:45 +0000

1#----------------------------------------------------------------------------- 

2# Copyright (c) 2008 by David P. D. Moss. All rights reserved. 

3# 

4# Released under the BSD license. See the LICENSE file for details. 

5#----------------------------------------------------------------------------- 

6""" 

7Classes and functions for dealing with MAC addresses, EUI-48, EUI-64, OUI, IAB 

8identifiers. 

9""" 

10 

11from netaddr.core import NotRegisteredError, AddrFormatError, DictDotLookup 

12from netaddr.strategy import eui48 as _eui48, eui64 as _eui64 

13from netaddr.strategy.eui48 import mac_eui48 

14from netaddr.strategy.eui64 import eui64_base 

15from netaddr.ip import IPAddress 

16from netaddr.compat import _importlib_resources, _is_int, _is_str 

17 

18 

19class BaseIdentifier(object): 

20 """Base class for all IEEE identifiers.""" 

21 __slots__ = ('_value', '__weakref__') 

22 

23 def __init__(self): 

24 self._value = None 

25 

26 def __int__(self): 

27 """:return: integer value of this identifier""" 

28 return self._value 

29 

30 def __long__(self): 

31 """:return: integer value of this identifier""" 

32 return self._value 

33 

34 def __oct__(self): 

35 """:return: octal string representation of this identifier.""" 

36 # Python 2.x only. 

37 if self._value == 0: 

38 return '0' 

39 return '0%o' % self._value 

40 

41 def __hex__(self): 

42 """:return: hexadecimal string representation of this identifier.""" 

43 # Python 2.x only. 

44 return '0x%x' % self._value 

45 

46 def __index__(self): 

47 """ 

48 :return: return the integer value of this identifier when passed to 

49 hex(), oct() or bin(). 

50 """ 

51 # Python 3.x only. 

52 return self._value 

53 

54 

55class OUI(BaseIdentifier): 

56 """ 

57 An individual IEEE OUI (Organisationally Unique Identifier). 

58 

59 For online details see - http://standards.ieee.org/regauth/oui/ 

60 

61 """ 

62 __slots__ = ('records',) 

63 

64 def __init__(self, oui): 

65 """ 

66 Constructor 

67 

68 :param oui: an OUI string ``XX-XX-XX`` or an unsigned integer. \ 

69 Also accepts and parses full MAC/EUI-48 address strings (but not \ 

70 MAC/EUI-48 integers)! 

71 """ 

72 super(OUI, self).__init__() 

73 

74 # Lazy loading of IEEE data structures. 

75 from netaddr.eui import ieee 

76 

77 self.records = [] 

78 

79 if isinstance(oui, str): 

80 #TODO: Improve string parsing here. 

81 #TODO: Accept full MAC/EUI-48 addressses as well as XX-XX-XX 

82 #TODO: and just take /16 (see IAB for details) 

83 self._value = int(oui.replace('-', ''), 16) 

84 elif _is_int(oui): 

85 if 0 <= oui <= 0xffffff: 

86 self._value = oui 

87 else: 

88 raise ValueError('OUI int outside expected range: %r' % (oui,)) 

89 else: 

90 raise TypeError('unexpected OUI format: %r' % (oui,)) 

91 

92 # Discover offsets. 

93 if self._value in ieee.OUI_INDEX: 

94 fh = _importlib_resources.open_binary(__package__, 'oui.txt') 

95 for (offset, size) in ieee.OUI_INDEX[self._value]: 

96 fh.seek(offset) 

97 data = fh.read(size).decode('UTF-8') 

98 self._parse_data(data, offset, size) 

99 fh.close() 

100 else: 

101 raise NotRegisteredError('OUI %r not registered!' % (oui,)) 

102 

103 def __hash__(self): 

104 return hash(self._value) 

105 

106 def __eq__(self, other): 

107 if not isinstance(other, OUI): 

108 try: 

109 other = self.__class__(other) 

110 except Exception: 

111 return NotImplemented 

112 return self._value == other._value 

113 

114 def __ne__(self, other): 

115 if not isinstance(other, OUI): 

116 try: 

117 other = self.__class__(other) 

118 except Exception: 

119 return NotImplemented 

120 return self._value != other._value 

121 

122 def __getstate__(self): 

123 """:returns: Pickled state of an `OUI` object.""" 

124 return self._value, self.records 

125 

126 def __setstate__(self, state): 

127 """:param state: data used to unpickle a pickled `OUI` object.""" 

128 self._value, self.records = state 

129 

130 def _parse_data(self, data, offset, size): 

131 """Returns a dict record from raw OUI record data""" 

132 record = { 

133 'idx': 0, 

134 'oui': '', 

135 'org': '', 

136 'address': [], 

137 'offset': offset, 

138 'size': size, 

139 } 

140 

141 for line in data.split("\n"): 

142 line = line.strip() 

143 if not line: 

144 continue 

145 

146 if '(hex)' in line: 

147 record['idx'] = self._value 

148 record['org'] = line.split(None, 2)[2] 

149 record['oui'] = str(self) 

150 elif '(base 16)' in line: 

151 continue 

152 else: 

153 record['address'].append(line) 

154 

155 self.records.append(record) 

156 

157 @property 

158 def reg_count(self): 

159 """Number of registered organisations with this OUI""" 

160 return len(self.records) 

161 

162 def registration(self, index=0): 

163 """ 

164 The IEEE registration details for this OUI. 

165 

166 :param index: the index of record (may contain multiple registrations) 

167 (Default: 0 - first registration) 

168 

169 :return: Objectified Python data structure containing registration 

170 details. 

171 """ 

172 return DictDotLookup(self.records[index]) 

173 

174 def __str__(self): 

175 """:return: string representation of this OUI""" 

176 int_val = self._value 

177 return "%02X-%02X-%02X" % ( 

178 (int_val >> 16) & 0xff, 

179 (int_val >> 8) & 0xff, 

180 int_val & 0xff) 

181 

182 def __repr__(self): 

183 """:return: executable Python string to recreate equivalent object.""" 

184 return "OUI('%s')" % self 

185 

186 

187class IAB(BaseIdentifier): 

188 IAB_EUI_VALUES = (0x0050c2, 0x40d855) 

189 

190 """ 

191 An individual IEEE IAB (Individual Address Block) identifier. 

192 

193 For online details see - http://standards.ieee.org/regauth/oui/ 

194 

195 """ 

196 __slots__ = ('record',) 

197 

198 @classmethod 

199 def split_iab_mac(cls, eui_int, strict=False): 

200 """ 

201 :param eui_int: a MAC IAB as an unsigned integer. 

202 

203 :param strict: If True, raises a ValueError if the last 12 bits of 

204 IAB MAC/EUI-48 address are non-zero, ignores them otherwise. 

205 (Default: False) 

206 """ 

207 if (eui_int >> 12) in cls.IAB_EUI_VALUES: 

208 return eui_int, 0 

209 

210 user_mask = 2 ** 12 - 1 

211 iab_mask = (2 ** 48 - 1) ^ user_mask 

212 iab_bits = eui_int >> 12 

213 user_bits = (eui_int | iab_mask) - iab_mask 

214 

215 if (iab_bits >> 12) in cls.IAB_EUI_VALUES: 

216 if strict and user_bits != 0: 

217 raise ValueError('%r is not a strict IAB!' % hex(user_bits)) 

218 else: 

219 raise ValueError('%r is not an IAB address!' % hex(eui_int)) 

220 

221 return iab_bits, user_bits 

222 

223 def __init__(self, iab, strict=False): 

224 """ 

225 Constructor 

226 

227 :param iab: an IAB string ``00-50-C2-XX-X0-00`` or an unsigned \ 

228 integer. This address looks like an EUI-48 but it should not \ 

229 have any non-zero bits in the last 3 bytes. 

230 

231 :param strict: If True, raises a ValueError if the last 12 bits \ 

232 of IAB MAC/EUI-48 address are non-zero, ignores them otherwise. \ 

233 (Default: False) 

234 """ 

235 super(IAB, self).__init__() 

236 

237 # Lazy loading of IEEE data structures. 

238 from netaddr.eui import ieee 

239 

240 self.record = { 

241 'idx': 0, 

242 'iab': '', 

243 'org': '', 

244 'address': [], 

245 'offset': 0, 

246 'size': 0, 

247 } 

248 

249 if isinstance(iab, str): 

250 #TODO: Improve string parsing here. 

251 #TODO: '00-50-C2' is actually invalid. 

252 #TODO: Should be '00-50-C2-00-00-00' (i.e. a full MAC/EUI-48) 

253 int_val = int(iab.replace('-', ''), 16) 

254 iab_int, user_int = self.split_iab_mac(int_val, strict=strict) 

255 self._value = iab_int 

256 elif _is_int(iab): 

257 iab_int, user_int = self.split_iab_mac(iab, strict=strict) 

258 self._value = iab_int 

259 else: 

260 raise TypeError('unexpected IAB format: %r!' % (iab,)) 

261 

262 # Discover offsets. 

263 if self._value in ieee.IAB_INDEX: 

264 fh = _importlib_resources.open_binary(__package__, 'iab.txt') 

265 (offset, size) = ieee.IAB_INDEX[self._value][0] 

266 self.record['offset'] = offset 

267 self.record['size'] = size 

268 fh.seek(offset) 

269 data = fh.read(size).decode('UTF-8') 

270 self._parse_data(data, offset, size) 

271 fh.close() 

272 else: 

273 raise NotRegisteredError('IAB %r not unregistered!' % (iab,)) 

274 

275 def __eq__(self, other): 

276 if not isinstance(other, IAB): 

277 try: 

278 other = self.__class__(other) 

279 except Exception: 

280 return NotImplemented 

281 return self._value == other._value 

282 

283 def __ne__(self, other): 

284 if not isinstance(other, IAB): 

285 try: 

286 other = self.__class__(other) 

287 except Exception: 

288 return NotImplemented 

289 return self._value != other._value 

290 

291 def __getstate__(self): 

292 """:returns: Pickled state of an `IAB` object.""" 

293 return self._value, self.record 

294 

295 def __setstate__(self, state): 

296 """:param state: data used to unpickle a pickled `IAB` object.""" 

297 self._value, self.record = state 

298 

299 def _parse_data(self, data, offset, size): 

300 """Returns a dict record from raw IAB record data""" 

301 for line in data.split("\n"): 

302 line = line.strip() 

303 if not line: 

304 continue 

305 

306 if '(hex)' in line: 

307 self.record['idx'] = self._value 

308 self.record['org'] = line.split(None, 2)[2] 

309 self.record['iab'] = str(self) 

310 elif '(base 16)' in line: 

311 continue 

312 else: 

313 self.record['address'].append(line) 

314 

315 def registration(self): 

316 """The IEEE registration details for this IAB""" 

317 return DictDotLookup(self.record) 

318 

319 def __str__(self): 

320 """:return: string representation of this IAB""" 

321 int_val = self._value << 4 

322 

323 return "%02X-%02X-%02X-%02X-%02X-00" % ( 

324 (int_val >> 32) & 0xff, 

325 (int_val >> 24) & 0xff, 

326 (int_val >> 16) & 0xff, 

327 (int_val >> 8) & 0xff, 

328 int_val & 0xff) 

329 

330 def __repr__(self): 

331 """:return: executable Python string to recreate equivalent object.""" 

332 return "IAB('%s')" % self 

333 

334 

335class EUI(BaseIdentifier): 

336 """ 

337 An IEEE EUI (Extended Unique Identifier). 

338 

339 Both EUI-48 (used for layer 2 MAC addresses) and EUI-64 are supported. 

340 

341 Input parsing for EUI-48 addresses is flexible, supporting many MAC 

342 variants. 

343 

344 """ 

345 __slots__ = ('_module', '_dialect') 

346 

347 def __init__(self, addr, version=None, dialect=None): 

348 """ 

349 Constructor. 

350 

351 :param addr: an EUI-48 (MAC) or EUI-64 address in string format or \ 

352 an unsigned integer. May also be another EUI object (copy \ 

353 construction). 

354 

355 :param version: (optional) the explicit EUI address version, either \ 

356 48 or 64. Mainly used to distinguish EUI-48 and EUI-64 identifiers \ 

357 specified as integers which may be numerically equivalent. 

358 

359 :param dialect: (optional) the mac_* dialect to be used to configure \ 

360 the formatting of EUI-48 (MAC) addresses. 

361 """ 

362 super(EUI, self).__init__() 

363 

364 self._module = None 

365 

366 if isinstance(addr, EUI): 

367 # Copy constructor. 

368 if version is not None and version != addr._module.version: 

369 raise ValueError('cannot switch EUI versions using ' 

370 'copy constructor!') 

371 self._module = addr._module 

372 self._value = addr._value 

373 self.dialect = addr.dialect 

374 return 

375 

376 if version is not None: 

377 if version == 48: 

378 self._module = _eui48 

379 elif version == 64: 

380 self._module = _eui64 

381 else: 

382 raise ValueError('unsupported EUI version %r' % version) 

383 else: 

384 # Choose a default version when addr is an integer and version is 

385 # not specified. 

386 if _is_int(addr): 

387 if 0 <= addr <= 0xffffffffffff: 

388 self._module = _eui48 

389 elif 0xffffffffffff < addr <= 0xffffffffffffffff: 

390 self._module = _eui64 

391 

392 self.value = addr 

393 

394 # Choose a dialect for MAC formatting. 

395 self.dialect = dialect 

396 

397 def __getstate__(self): 

398 """:returns: Pickled state of an `EUI` object.""" 

399 return self._value, self._module.version, self.dialect 

400 

401 def __setstate__(self, state): 

402 """ 

403 :param state: data used to unpickle a pickled `EUI` object. 

404 

405 """ 

406 value, version, dialect = state 

407 

408 self._value = value 

409 

410 if version == 48: 

411 self._module = _eui48 

412 elif version == 64: 

413 self._module = _eui64 

414 else: 

415 raise ValueError('unpickling failed for object state: %s' \ 

416 % (state,)) 

417 

418 self.dialect = dialect 

419 

420 def _get_value(self): 

421 return self._value 

422 

423 def _set_value(self, value): 

424 if self._module is None: 

425 # EUI version is implicit, detect it from value. 

426 for module in (_eui48, _eui64): 

427 try: 

428 self._value = module.str_to_int(value) 

429 self._module = module 

430 break 

431 except AddrFormatError: 

432 try: 

433 if 0 <= int(value) <= module.max_int: 

434 self._value = int(value) 

435 self._module = module 

436 break 

437 except ValueError: 

438 pass 

439 

440 if self._module is None: 

441 raise AddrFormatError('failed to detect EUI version: %r' 

442 % (value,)) 

443 else: 

444 # EUI version is explicit. 

445 if _is_str(value): 

446 try: 

447 self._value = self._module.str_to_int(value) 

448 except AddrFormatError: 

449 raise AddrFormatError('address %r is not an EUIv%d' 

450 % (value, self._module.version)) 

451 else: 

452 if 0 <= int(value) <= self._module.max_int: 

453 self._value = int(value) 

454 else: 

455 raise AddrFormatError('bad address format: %r' % (value,)) 

456 

457 value = property(_get_value, _set_value, None, 

458 'a positive integer representing the value of this EUI indentifier.') 

459 

460 def _get_dialect(self): 

461 return self._dialect 

462 

463 def _validate_dialect(self, value): 

464 if value is None: 

465 if self._module is _eui64: 

466 return eui64_base 

467 else: 

468 return mac_eui48 

469 else: 

470 if hasattr(value, 'word_size') and hasattr(value, 'word_fmt'): 

471 return value 

472 else: 

473 raise TypeError('custom dialects should subclass mac_eui48!') 

474 

475 def _set_dialect(self, value): 

476 self._dialect = self._validate_dialect(value) 

477 

478 dialect = property(_get_dialect, _set_dialect, None, 

479 "a Python class providing support for the interpretation of " 

480 "various MAC\n address formats.") 

481 

482 @property 

483 def oui(self): 

484 """The OUI (Organisationally Unique Identifier) for this EUI.""" 

485 if self._module == _eui48: 

486 return OUI(self.value >> 24) 

487 elif self._module == _eui64: 

488 return OUI(self.value >> 40) 

489 

490 @property 

491 def ei(self): 

492 """The EI (Extension Identifier) for this EUI""" 

493 if self._module == _eui48: 

494 return '%02X-%02X-%02X' % tuple(self[3:6]) 

495 elif self._module == _eui64: 

496 return '%02X-%02X-%02X-%02X-%02X' % tuple(self[3:8]) 

497 

498 def is_iab(self): 

499 """:return: True if this EUI is an IAB address, False otherwise""" 

500 return (self._value >> 24) in IAB.IAB_EUI_VALUES 

501 

502 @property 

503 def iab(self): 

504 """ 

505 If is_iab() is True, the IAB (Individual Address Block) is returned, 

506 ``None`` otherwise. 

507 """ 

508 if self.is_iab(): 

509 return IAB(self._value >> 12) 

510 

511 @property 

512 def version(self): 

513 """The EUI version represented by this EUI object.""" 

514 return self._module.version 

515 

516 def __getitem__(self, idx): 

517 """ 

518 :return: The integer value of the word referenced by index (both \ 

519 positive and negative). Raises ``IndexError`` if index is out \ 

520 of bounds. Also supports Python list slices for accessing \ 

521 word groups. 

522 """ 

523 if _is_int(idx): 

524 # Indexing, including negative indexing goodness. 

525 num_words = self._dialect.num_words 

526 if not (-num_words) <= idx <= (num_words - 1): 

527 raise IndexError('index out range for address type!') 

528 return self._module.int_to_words(self._value, self._dialect)[idx] 

529 elif isinstance(idx, slice): 

530 words = self._module.int_to_words(self._value, self._dialect) 

531 return [words[i] for i in range(*idx.indices(len(words)))] 

532 else: 

533 raise TypeError('unsupported type %r!' % (idx,)) 

534 

535 def __setitem__(self, idx, value): 

536 """Set the value of the word referenced by index in this address""" 

537 if isinstance(idx, slice): 

538 # TODO - settable slices. 

539 raise NotImplementedError('settable slices are not supported!') 

540 

541 if not _is_int(idx): 

542 raise TypeError('index not an integer!') 

543 

544 if not 0 <= idx <= (self._dialect.num_words - 1): 

545 raise IndexError('index %d outside address type boundary!' % (idx,)) 

546 

547 if not _is_int(value): 

548 raise TypeError('value not an integer!') 

549 

550 if not 0 <= value <= self._dialect.max_word: 

551 raise IndexError('value %d outside word size maximum of %d bits!' 

552 % (value, self._dialect.word_size)) 

553 

554 words = list(self._module.int_to_words(self._value, self._dialect)) 

555 words[idx] = value 

556 self._value = self._module.words_to_int(words) 

557 

558 def __hash__(self): 

559 """:return: hash of this EUI object suitable for dict keys, sets etc""" 

560 return hash((self.version, self._value)) 

561 

562 def __eq__(self, other): 

563 """ 

564 :return: ``True`` if this EUI object is numerically the same as other, \ 

565 ``False`` otherwise. 

566 """ 

567 if not isinstance(other, EUI): 

568 try: 

569 other = self.__class__(other) 

570 except Exception: 

571 return NotImplemented 

572 return (self.version, self._value) == (other.version, other._value) 

573 

574 def __ne__(self, other): 

575 """ 

576 :return: ``True`` if this EUI object is numerically the same as other, \ 

577 ``False`` otherwise. 

578 """ 

579 if not isinstance(other, EUI): 

580 try: 

581 other = self.__class__(other) 

582 except Exception: 

583 return NotImplemented 

584 return (self.version, self._value) != (other.version, other._value) 

585 

586 def __lt__(self, other): 

587 """ 

588 :return: ``True`` if this EUI object is numerically lower in value than \ 

589 other, ``False`` otherwise. 

590 """ 

591 if not isinstance(other, EUI): 

592 try: 

593 other = self.__class__(other) 

594 except Exception: 

595 return NotImplemented 

596 return (self.version, self._value) < (other.version, other._value) 

597 

598 def __le__(self, other): 

599 """ 

600 :return: ``True`` if this EUI object is numerically lower or equal in \ 

601 value to other, ``False`` otherwise. 

602 """ 

603 if not isinstance(other, EUI): 

604 try: 

605 other = self.__class__(other) 

606 except Exception: 

607 return NotImplemented 

608 return (self.version, self._value) <= (other.version, other._value) 

609 

610 def __gt__(self, other): 

611 """ 

612 :return: ``True`` if this EUI object is numerically greater in value \ 

613 than other, ``False`` otherwise. 

614 """ 

615 if not isinstance(other, EUI): 

616 try: 

617 other = self.__class__(other) 

618 except Exception: 

619 return NotImplemented 

620 return (self.version, self._value) > (other.version, other._value) 

621 

622 def __ge__(self, other): 

623 """ 

624 :return: ``True`` if this EUI object is numerically greater or equal \ 

625 in value to other, ``False`` otherwise. 

626 """ 

627 if not isinstance(other, EUI): 

628 try: 

629 other = self.__class__(other) 

630 except Exception: 

631 return NotImplemented 

632 return (self.version, self._value) >= (other.version, other._value) 

633 

634 def bits(self, word_sep=None): 

635 """ 

636 :param word_sep: (optional) the separator to insert between words. \ 

637 Default: None - use default separator for address type. 

638 

639 :return: human-readable binary digit string of this address. 

640 """ 

641 return self._module.int_to_bits(self._value, word_sep) 

642 

643 @property 

644 def packed(self): 

645 """The value of this EUI address as a packed binary string.""" 

646 return self._module.int_to_packed(self._value) 

647 

648 @property 

649 def words(self): 

650 """A list of unsigned integer octets found in this EUI address.""" 

651 return self._module.int_to_words(self._value) 

652 

653 @property 

654 def bin(self): 

655 """ 

656 The value of this EUI adddress in standard Python binary 

657 representational form (0bxxx). A back port of the format provided by 

658 the builtin bin() function found in Python 2.6.x and higher. 

659 """ 

660 return self._module.int_to_bin(self._value) 

661 

662 def eui64(self): 

663 """ 

664 - If this object represents an EUI-48 it is converted to EUI-64 \ 

665 as per the standard. 

666 - If this object is already an EUI-64, a new, numerically \ 

667 equivalent object is returned instead. 

668 

669 :return: The value of this EUI object as a new 64-bit EUI object. 

670 """ 

671 if self.version == 48: 

672 # Convert 11:22:33:44:55:66 into 11:22:33:FF:FE:44:55:66. 

673 first_three = self._value >> 24 

674 last_three = self._value & 0xffffff 

675 new_value = (first_three << 40) | 0xfffe000000 | last_three 

676 else: 

677 # is already a EUI64 

678 new_value = self._value 

679 return self.__class__(new_value, version=64) 

680 

681 def modified_eui64(self): 

682 """ 

683 - create a new EUI object with a modified EUI-64 as described in RFC 4291 section 2.5.1 

684 

685 :return: a new and modified 64-bit EUI object. 

686 """ 

687 # Modified EUI-64 format interface identifiers are formed by inverting 

688 # the "u" bit (universal/local bit in IEEE EUI-64 terminology) when 

689 # forming the interface identifier from IEEE EUI-64 identifiers. In 

690 # the resulting Modified EUI-64 format, the "u" bit is set to one (1) 

691 # to indicate universal scope, and it is set to zero (0) to indicate 

692 # local scope. 

693 eui64 = self.eui64() 

694 eui64._value ^= 0x00000000000000000200000000000000 

695 return eui64 

696 

697 def ipv6(self, prefix): 

698 """ 

699 .. note:: This poses security risks in certain scenarios. \ 

700 Please read RFC 4941 for details. Reference: RFCs 4291 and 4941. 

701 

702 :param prefix: ipv6 prefix 

703 

704 :return: new IPv6 `IPAddress` object based on this `EUI` \ 

705 using the technique described in RFC 4291. 

706 """ 

707 int_val = int(prefix) + int(self.modified_eui64()) 

708 return IPAddress(int_val, version=6) 

709 

710 def ipv6_link_local(self): 

711 """ 

712 .. note:: This poses security risks in certain scenarios. \ 

713 Please read RFC 4941 for details. Reference: RFCs 4291 and 4941. 

714 

715 :return: new link local IPv6 `IPAddress` object based on this `EUI` \ 

716 using the technique described in RFC 4291. 

717 """ 

718 return self.ipv6(0xfe800000000000000000000000000000) 

719 

720 @property 

721 def info(self): 

722 """ 

723 A record dict containing IEEE registration details for this EUI 

724 (MAC-48) if available, None otherwise. 

725 """ 

726 data = {'OUI': self.oui.registration()} 

727 if self.is_iab(): 

728 data['IAB'] = self.iab.registration() 

729 

730 return DictDotLookup(data) 

731 

732 def format(self, dialect=None): 

733 """ 

734 Format the EUI into the representational format according to the given 

735 dialect 

736 

737 :param dialect: the mac_* dialect defining the formatting of EUI-48 \ 

738 (MAC) addresses. 

739 

740 :return: EUI in representational format according to the given dialect 

741 """ 

742 validated_dialect = self._validate_dialect(dialect) 

743 return self._module.int_to_str(self._value, validated_dialect) 

744 

745 def __str__(self): 

746 """:return: EUI in representational format""" 

747 return self._module.int_to_str(self._value, self._dialect) 

748 

749 def __repr__(self): 

750 """:return: executable Python string to recreate equivalent object.""" 

751 return "EUI('%s')" % self 

752