def __format__(self, specifier, context=None, _localeconv=None): if self.is_nan(): amount = '–' elif specifier in ('', 'f',): amount = self.quantize(self._cents).__format__(specifier) else: amount = Decimal.__format__(self, specifier) vals = dict(code=self._currency_code, symbol=self._currency[2], currency=self._currency[3], amount=amount) return self.MONEY_FORMAT.format(**vals)
def __format__(self, specifier, context=None, _localeconv=None): vals = self._get_format_values() if self.is_nan(): amount = '–' # mdash elif specifier in ( '', 'f', ): amount = Decimal.quantize(self, self._cents).__format__(specifier) else: amount = Decimal.__format__(self, specifier) if settings.USE_L10N: lang, use_l10n = get_language(), True else: lang, use_l10n = None, False # handle grouping use_grouping = settings.USE_L10N and settings.USE_THOUSAND_SEPARATOR decimal_sep = get_format('DECIMAL_SEPARATOR', lang, use_l10n=use_l10n) grouping = get_format('NUMBER_GROUPING', lang, use_l10n=use_l10n) thousand_sep = get_format('THOUSAND_SEPARATOR', lang, use_l10n=use_l10n) # minus sign for negative amounts if amount[0] == '-': vals.update(minus='-') amount = amount[1:] # decimal part if '.' in amount: int_part, dec_part = amount.split('.') else: int_part, dec_part = amount, '' if dec_part: dec_part = decimal_sep + dec_part # grouping if use_grouping and grouping > 0: int_part_gd = '' for cnt, digit in enumerate(int_part[::-1]): if cnt and not cnt % grouping: int_part_gd += thousand_sep[::-1] int_part_gd += digit int_part = int_part_gd[::-1] # recombine parts vals.update(amount=int_part + dec_part) return self.MONEY_FORMAT.format(**vals)
def __format__(self, specifier, context=None, _localeconv=None): vals = self._get_format_values() if self.is_nan(): amount = '–' # mdash elif specifier in ('', 'f',): amount = self.quantize(self._cents).__format__(specifier) else: amount = Decimal.__format__(self, specifier) if settings.USE_L10N: lang, use_l10n = get_language(), True else: lang, use_l10n = None, False # handle grouping use_grouping = settings.USE_L10N and settings.USE_THOUSAND_SEPARATOR decimal_sep = get_format('DECIMAL_SEPARATOR', lang, use_l10n=use_l10n) grouping = get_format('NUMBER_GROUPING', lang, use_l10n=use_l10n) thousand_sep = get_format('THOUSAND_SEPARATOR', lang, use_l10n=use_l10n) # minus sign for negative amounts if amount[0] == '-': vals.update(minus='-') amount = amount[1:] # decimal part if '.' in amount: int_part, dec_part = amount.split('.') else: int_part, dec_part = amount, '' if dec_part: dec_part = decimal_sep + dec_part # grouping if use_grouping: int_part_gd = '' for cnt, digit in enumerate(int_part[::-1]): if cnt and not cnt % grouping: int_part_gd += thousand_sep[::-1] int_part_gd += digit int_part = int_part_gd[::-1] # recombine parts vals.update(amount=int_part + dec_part) return self.MONEY_FORMAT.format(**vals)
class Decibel(object): @classmethod def from_factor(cls, gain_factor, context=pcontext): """Create a Decibel object give the gain factor. >>> Decibel.from_factor(1) Decibel('0.000000') >>> Decibel.from_factor(3) Decibel('4.771213') """ return cls(mwatt2db(gain_factor)) @classmethod def from_10ths_db(cls, inval): """ >>> dB = Decibel.from_10ths_db(22) >>> str(dB) '2.20' >>> dB = Decibel.from_10ths_db(None) >>> str(dB) 'None' """ if inval is None or inval == "None": dB = None else: dB = Decibel(inval).dB / D(10) return cls(dB) @classmethod def from_100ths_db(cls, inval): """ >>> dB = Decibel.from_100ths_db(202) >>> str(dB) '2.02' >>> dB = Decibel.from_10ths_db(None) >>> str(dB) 'None' """ if inval is None or inval == "None": dB = None else: dB = D(inval) / D(100) return cls(dB) def __init__(self, dB): if dB is None or (is_str(dB) and dB == "None"): self.dB = None else: try: dB = dB.replace('dB', '') except AttributeError: pass if isinstance(dB, Decibel): self.dB = dB.dB else: self.dB = Decimal(dB).quantize(SIXPLACES, rounding=ROUND_HALF_EVEN) def __repr__(self): """ >>> Decibel(1) Decibel('1.000000') >>> Decibel(.01) Decibel('0.010000') >>> Decibel(None) Decibel(None) >>> Decibel("None") Decibel(None) """ if self.dB is None: return "Decibel(None)" return "Decibel('{}')".format(self.dB) def __hash__(self): return self.dB.__hash__() def __float__(self): return float(self.dB) def __format__(self, format_spec): # pylint: disable=W0221 """ >>> str("{:+2.2f}".format(Decibal(100))) '+100.00' >>> str("{:+2.2f}".format(Decibal(0))) '+0.00' >>> str("{:+2.2f}".format(Decibal(None))) 'None' """ if self.dB is None: # XXX really want to format this. return "None" return self.dB.__format__(format_spec) def __str__(self): # pylint: disable=W0222 """ >>> str(Decibel(0)) '0.00' >>> str(Decibel(3.141596)) '3.14' >>> str(Decibel(-3.999)) '-4.00' >>> str(Decibel(None)) 'None' """ if self.dB is None: return "None" else: return "{:.2f}".format(self.dB) def __abs__(self): if self.dB is None: return Decibel(None) elif self.dB < 0: return Decibel(self.dB.__neg__()) else: return Decibel(self.dB) def __neg__(self): # pylint: disable=W0222 """ >>> str(-Decibel(1)) '-1.00' >>> str(-Decibel(-1)) '1.00' """ if self.dB is None: return Decibel(None) return Decibel(self.dB.__neg__()) def __add__(self, add_atten): # pylint: disable=W0221 """ >>> Decibel(1) + Decibel(3) Decibel('4.000000') >>> Decibel(-1) + 3 Decibel('2.000000') """ if hasattr(add_atten, "dB"): return Decibel(self.dB + add_atten.dB) else: return Decibel(self.dB + add_atten) def __sub__(self, sub_atten): # pylint: disable=W0221 """ >>> Decibel(1) - Decibel(3) Decibel('-2.000000') >>> Decibel(2) - 1 Decibel('1.000000') """ if hasattr(sub_atten, "dB"): return Decibel(self.dB - sub_atten.dB) else: return Decibel(self.dB - sub_atten) def __mul__(self, other): # pylint: disable=W0222 """ >>> Decibel(.5) * 20 Decibel('10.000000') """ if self.dB is None or other is None: return Decibel(None) if hasattr(other, "dB") and other.dB is None: return Decibel(None) return Decibel(self.dB * other) __rmul__ = __mul__ def __lt__(self, other): """ >>> Gain(0) > Gain(.1) False >>> Gain(.1) > Gain(0) True >>> Gain(0) < Gain(.1) True >>> Gain(.1) < Gain(0) False >>> Gain(0) == Gain(0) True >>> Gain(.1) == Gain(.1) True >>> Gain(0) != Gain(None) True >>> Gain(0) == Gain(None) False >>> Gain(None) == Gain(None) True >>> Gain(None) >= Gain(-50) False >>> Gain(None) < Gain(-50) True >>> Gain(None) <= Gain(-50) True """ if self.dB is None: if other is None or other == "None": return False if hasattr(other, "dB") and other.dB is None: return False # other is not None so it's greater return True elif other is None or other == "None" or (hasattr(other, "dB") and other.dB is None): # self is not None other is so False return False return float(self.dB) < float(other) def __eq__(self, other): if self.dB is None: if other is None or other == "None": return True if hasattr(other, "dB") and other.dB is None: return True return False elif other is None or other == "None" or (hasattr(other, "dB") and other.dB is None): return self.dB is None return float(self.dB) == float(other) def gain_factor(self): """Convert gain value to mwatt for multiplying >>> Decibel(0).gain_factor() Decimal('1.000000') >>> Decibel(13).gain_factor() Decimal('19.952623') """ # # Gain: x dB = 10 * log10(multiplier) # 10 ^ (x dB / 10) = 10^(log10(multiplier)) # 10 ^ (x dB / 10) = multiplier # rv = Decimal(10 ** (self.dB / 10), pcontext) rv = rv.quantize(SIXPLACES, rounding=ROUND_HALF_EVEN) return rv mwatt_ratio = gain_factor def ase(self, nf, for_osnr=False): """Calculate ASE generated by amplification >>> Gain(23).ase(5.5) Power('-3.461412') """ # Pase = hv(G -1) * NF * B0 if not for_osnr: B0 = D('5.00e+12') # all c-band (for .5nm) else: B0 = D('1.25e+10') # @0.1nm resolution v = D('1.93e+14') # speed of light h = D('6.63e-34') # planck's constant nf = db2mwatt(nf) # convert noise figure from dB to mwatts ase_watts = D(nf) * B0 * h * v * (self.mwatt_ratio() - 1) return Power.from_mwatt(ase_watts * 1000) def osnr(self, nf, powerin): """Calculate OSNR for .1nm signal >>> Gain(16).osnr(7.9, Power(-20)) Decibel('30.170675') """ # Psig = Pin * G # Pase = hv(G - 1) * NF * B0.1nm # OSNR = Psig / Pase psig = powerin + self pase = self.ase(nf, True) return psig - pase
class Power(object): """Optical power value act's mostly like a float""" @classmethod def from_xml(cls, entry, xpath=None): if entry is not None and xpath is not None: entry = entry.find(xpath) if entry is None: return Power(None) try: return Power(entry.text) except ValueError: return Power(None) @classmethod def from_10uwatt(cls, mwatt): return cls.from_mwatt(D(mwatt) / 10000) @classmethod def from_10ths_dbm(cls, inval): dB = D(inval) / D(10) return cls(dB) from_10ths_db = from_10ths_dbm @classmethod def from_100ths_dbm(cls, inval): dB = D(inval) / D(100) return cls(dB) from_100ths_db = from_100ths_dbm @classmethod def from_mwatt(cls, mwatt): """ >>> Power.from_mwatt(D(0)) Power(None) >>> Power.from_mwatt(2) Power('3.010300') >>> Power.from_mwatt(1) Power('0.000000') >>> Power.from_mwatt(.5) Power('-3.010300') """ if mwatt is None: return cls(None) if not mwatt: return cls(None) try: # Try and convert to float first to catch '0.00' case if not float(mwatt): return cls(None) except ValueError: pass dBm = D(10, pcontext) * D(mwatt).log10(pcontext) dBm = dBm.quantize(SIXPLACES, rounding=ROUND_HALF_EVEN) return cls(dBm) def __init__(self, dBm, context=pcontext): # pylint: disable=W0222 """ >>> Power(20).mwatt() Decimal('100.000000') >>> Power(10).mwatt() Decimal('10.000000') >>> Power(3).mwatt() Decimal('1.995262') >>> Power(1).mwatt() Decimal('1.258925') >>> Power(0).mwatt() Decimal('1.000000') >>> Power(None).mwatt() 0 >>> Power('None').mwatt() 0 """ if dBm is None or (is_str(dBm) and dBm == "None"): self.dBm = None else: try: if dBm.endswith('dBm'): dBm = dBm.replace('dBm', '') except AttributeError: pass if isinstance(dBm, Power): self.dBm = dBm.dBm else: self.dBm = Decimal(dBm, context).quantize(SIXPLACES, rounding=ROUND_HALF_EVEN) def mwatt(self): if self.dBm is None: return 0 # XXX get context from us not global rv = Decimal(10 ** (self.dBm / 10), pcontext) rv = rv.quantize(SIXPLACES, rounding=ROUND_HALF_EVEN) return rv def __hash__(self): return self.dBm.__hash__() def __format__(self, format_spec): # pylint: disable=W0221 """ >>> str("{:+2.2f}".format(Power(100))) '+100.00' >>> str("{:+2.2f}".format(Power(0))) '+0.00' >>> str("{:+2.2f}".format(Power(None))) 'None' """ if self.dBm is None: return "None" return self.dBm.__format__(format_spec) def __bool__(self): return self.dBm is not None def __nonzero__(self): return self.dBm is not None def __add__(self, gain): # pylint: disable=W0221 """ >>> Power(0) + Gain(1) Power('1.000000') """ if hasattr(gain, "dBm"): raise TypeError("unsupported operand type(s) for +: 'Power' and 'Power'") else: return self.add_gain(gain) def __sub__(self, power_or_gain): # pylint: disable=W0221 """ >>> Power(0) - Gain(1) Power('-1.000000') >>> Power(0) - Power(2) Decibel('-2.000000') >>> Power(3) - Power(0) Decibel('3.000000') """ try: dBm = power_or_gain.dBm return Gain(self.dBm - dBm) except AttributeError: return self.add_gain(-power_or_gain) def __lt__(self, other): """ >>> Power(0) > Power(.1) False >>> Power(.1) > Power(0) True >>> Power(0) < Power(.1) True >>> Power(.1) < Power(0) False >>> Power(0) == Power(0) True >>> Power(.1) == Power(.1) True >>> Power(0) != Power(None) True >>> Power(0) == Power(None) False >>> Power(None) == Power(None) True >>> Power(None) >= Power(-50) False >>> Power(None) < Power(-50) True >>> Power(None) <= Power(-50) True >>> Power(0) == None False >>> Power(None) == None True >>> Power(0) != None True >>> Power(None) == None True >>> Power(0) is None False >>> Power(None) is None False >>> Power(0) is not None True >>> Power(None) is not None True """ # Either we are None (not less than) or more than None. if other is None: return False mwatt = self.mwatt() try: return mwatt < other.mwatt() except AttributeError: return mwatt < Power(D(other)).mwatt() def __eq__(self, other): if other is None: return self.dBm is None mwatt = self.mwatt() try: return mwatt == other.mwatt() except AttributeError: return mwatt == Power(D(other)).mwatt() def __repr__(self): """ >>> Power(0) Power('0.000000') >>> Power(.01) Power('0.010000') >>> Power(None) Power(None) >>> Power("None") Power(None) """ if self.dBm is None: return "Power(None)" return "Power('{}')".format(str(self.dBm)) def __str__(self): """ >>> str(Power(0)) '0.00' """ if self.dBm is None: return "None" else: return "{:.2f}".format(self.dBm) def __truediv__(self, other): # pylint: disable=W0221 return self.__div__(other) def __floordiv__(self, other): # pylint: disable=W0221 return self.__div__(other) def __div__(self, divisor): """ >>> Power(0) / 16 / 6 Power('-19.822712') >>> Power(0) / 10 Power('-10.000000') >>> Power(0) / 8 Power('-9.030900') >>> Power(0) / 6 Power('-7.781513') >>> Power(0) / 4 Power('-6.020600') >>> Power(0) / 2 Power('-3.010300') >>> Power(3) / 2 Power('-0.010301') """ return Power.from_mwatt(self.mwatt() / divisor) def __mul__(self, multiplier): return Power.from_mwatt(self.mwatt() * multiplier) def __or__(self, other): """ # Check str() here it's very different >>> Power(0) | Power(0) Power('3.010300') """ return Power.from_mwatt(self.mwatt() + other.mwatt()) def add_gain(self, gain): # XXX hmm not sure about adding None to power. if self.dBm is None or gain is None: return Power(None) return Power(self.dBm + gain.dB) def get_delta(self, other): if self.dBm is None or other is None: return Gain(None) return Gain(other.dBm - self.dBm)