- e=DateTime('US/Eastern')
- # returns current date/time, represented in US/Eastern.
-
- x=DateTime('1997/3/9 1:45pm')
- # returns specified time, represented in local machine zone.
-
- y=DateTime('Mar 9, 1997 13:45:00')
- # y is equal to x
-
-
- The date component consists of year, month, and day
- values. The year value must be a one-, two-, or
- four-digit integer. If a one- or two-digit year is
- used, the year is assumed to be in the twentieth
- century. The month may be an integer, from 1 to 12, a
- month name, or a month abreviation, where a period may
- optionally follow the abreviation. The day must be an
- integer from 1 to the number of days in the month. The
- year, month, and day values may be separated by
- periods, hyphens, forward, shashes, or spaces. Extra
- spaces are permitted around the delimiters. Year,
- month, and day values may be given in any order as long
- as it is possible to distinguish the components. If all
- three components are numbers that are less than 13,
- then a a month-day-year ordering is assumed.
-
- The time component consists of hour, minute, and second
- values separated by colons. The hour value must be an
- integer between 0 and 23 inclusively. The minute value
- must be an integer between 0 and 59 inclusively. The
- second value may be an integer value between 0 and
- 59.999 inclusively. The second value or both the minute
- and second values may be ommitted. The time may be
- followed by am or pm in upper or lower case, in which
- case a 12-hour clock is assumed.
-
- New in Zope 2.4:
- The DateTime constructor automatically detects and handles
- ISO8601 compliant dates (YYYY-MM-DDThh:ss:mmTZD).
-
- New in Zope 2.9.6:
- The existing ISO8601 parser was extended to support almost
- the whole ISO8601 specification. New formats includes:
-
-
- y=DateTime('1993-045')
- # returns the 45th day from 1993, which is 14th February
-
- w=DateTime('1993-W06-7')
- # returns the 7th day from the 6th week from 1993, which
- # is also 14th February
-
-
- See http://en.wikipedia.org/wiki/ISO_8601 for full specs.
-
- Note that the Zope DateTime parser assumes timezone naive ISO
- strings to be in UTC rather than local time as specified.
-
- - If the DateTime function is invoked with a single Numeric
- argument, the number is assumed to be a floating point value
- such as that returned by time.time().
-
- A DateTime object is returned that represents the GMT value
- of the time.time() float represented in the local machine's
- timezone.
-
- - If the DateTime function is invoked with a single argument
- that is a DateTime instane, a copy of the passed object will
- be created.
-
- - New in 2.11:
- The DateTime function may now be invoked with a single argument
- that is a datetime.datetime instance. DateTimes may be converted
- back to datetime.datetime objects with asdatetime().
- DateTime instances may be converted to a timezone naive
- datetime.datetime in UTC with utcdatetime().
-
- - If the function is invoked with two numeric arguments, then
- the first is taken to be an integer year and the second
- argument is taken to be an offset in days from the beginning
- of the year, in the context of the local machine timezone.
-
- The date-time value returned is the given offset number of
- days from the beginning of the given year, represented in
- the timezone of the local machine. The offset may be positive
- or negative.
-
- Two-digit years are assumed to be in the twentieth
- century.
-
- - If the function is invoked with two arguments, the first
- a float representing a number of seconds past the epoch
- in gmt (such as those returned by time.time()) and the
- second a string naming a recognized timezone, a DateTime
- with a value of that gmt time will be returned, represented
- in the given timezone.
-
-
- import time
- t=time.time()
-
- now_east=DateTime(t,'US/Eastern')
- # Time t represented as US/Eastern
-
- now_west=DateTime(t,'US/Pacific')
- # Time t represented as US/Pacific
-
- # now_east == now_west
- # only their representations are different
-
-
- - If the function is invoked with three or more numeric
- arguments, then the first is taken to be an integer
- year, the second is taken to be an integer month, and
- the third is taken to be an integer day. If the
- combination of values is not valid, then a
- DateError is raised. Two-digit years are assumed
- to be in the twentieth century. The fourth, fifth, and
- sixth arguments specify a time in hours, minutes, and
- seconds; hours and minutes should be positive integers
- and seconds is a positive floating point value, all of
- these default to zero if not given. An optional string may
- be given as the final argument to indicate timezone (the
- effect of this is as if you had taken the value of time.time()
- at that time on a machine in the specified timezone).
-
- New in Zope 2.7:
- A new keyword parameter "datefmt" can be passed to the
- constructor. If set to "international", the constructor
- is forced to treat ambigious dates as "days before month
- before year". This useful if you need to parse non-US
- dates in a reliable way
-
- In any case that a floating point number of seconds is given
- or derived, it's rounded to the nearest millisecond.
-
- If a string argument passed to the DateTime constructor cannot be
- parsed, it will raise DateTime.SyntaxError. Invalid date components
- will raise a DateError, while invalid time or timezone components
- will raise a DateTimeError.
-
- The module function Timezones() will return a list of the (common)
- timezones recognized by the DateTime module. Recognition of
- timezone names is case-insensitive.
- """
-
- datefmt = kw.get('datefmt', getDefaultDateFormat())
- d = t = s = None
- ac = len(args)
- microsecs = None
-
- if ac == 10:
- # Internal format called only by DateTime
- yr, mo, dy, hr, mn, sc, tz, t, d, s = args
- elif ac == 11:
- # Internal format that includes milliseconds (from the epoch)
- yr, mo, dy, hr, mn, sc, tz, t, d, s, millisecs = args
- microsecs = millisecs * 1000
-
- elif ac == 12:
- # Internal format that includes microseconds (from the epoch) and a
- # flag indicating whether this was constructed in a timezone naive
- # manner
- yr, mo, dy, hr, mn, sc, tz, t, d, s, microsecs, tznaive = args
- if tznaive is not None: # preserve this information
- self._timezone_naive = tznaive
-
- elif not args or (ac and args[0] is None):
- # Current time, to be displayed in local timezone
- t = time()
- lt = safelocaltime(t)
- tz = self.localZone(lt)
- ms = (t - math.floor(t))
- s, d = _calcSD(t)
- yr, mo, dy, hr, mn, sc = lt[:6]
- sc = sc + ms
- self._timezone_naive = False
-
- elif ac == 1:
- arg = args[0]
-
- if arg == '':
- raise SyntaxError(arg)
-
- if isinstance(arg, DateTime):
- """Construct a new DateTime instance from a given
- DateTime instance.
- """
- t = arg.timeTime()
- s, d = _calcSD(t)
- yr, mo, dy, hr, mn, sc, tz = arg.parts()
-
- elif isinstance(arg, datetime):
- yr, mo, dy, hr, mn, sc, numerictz, tznaive = \
- self._parse_iso8601_preserving_tznaive(arg.isoformat())
- if arg.tzinfo is None:
- self._timezone_naive = True
- tz = None
- else:
- self._timezone_naive = False
- # if we have a pytz tzinfo, use the `zone` attribute
- # as a key
- tz = getattr(arg.tzinfo, 'zone', numerictz)
- ms = sc - math.floor(sc)
- x = _calcDependentSecond2(yr, mo, dy, hr, mn, sc)
-
- if tz:
- try:
- zone = _TZINFO[tz]
- except DateTimeError:
- try:
- zone = _TZINFO[numerictz]
- except DateTimeError:
- raise DateTimeError(
- 'Unknown time zone in date: %s' % arg)
- tz = zone.tzinfo.zone
- else:
- tz = self._calcTimezoneName(x, ms)
- s, d, t, microsecs = _calcIndependentSecondEtc(tz, x, ms)
-
- elif (isinstance(arg, basestring) and
- arg.lower() in _TZINFO._zidx):
- # Current time, to be displayed in specified timezone
- t, tz = time(), _TZINFO._zmap[arg.lower()]
- ms = (t - math.floor(t))
- # Use integer arithmetic as much as possible.
- s, d = _calcSD(t)
- x = _calcDependentSecond(tz, t)
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x, ms)
-
- elif isinstance(arg, basestring):
- # Date/time string
- iso8601 = iso8601Match(arg.strip())
- fields_iso8601 = iso8601 and iso8601.groupdict() or {}
- if fields_iso8601 and not fields_iso8601.get('garbage'):
- yr, mo, dy, hr, mn, sc, tz, tznaive = \
- self._parse_iso8601_preserving_tznaive(arg)
- self._timezone_naive = tznaive
- else:
- yr, mo, dy, hr, mn, sc, tz = self._parse(arg, datefmt)
-
- if not self._validDate(yr, mo, dy):
- raise DateError('Invalid date: %s' % arg)
- if not self._validTime(hr, mn, int(sc)):
- raise TimeError('Invalid time: %s' % arg)
- ms = sc - math.floor(sc)
- x = _calcDependentSecond2(yr, mo, dy, hr, mn, sc)
-
- if tz:
- try:
- tz = _TZINFO._zmap[tz.lower()]
- except KeyError:
- if numericTimeZoneMatch(tz) is None:
- raise DateTimeError(
- 'Unknown time zone in date: %s' % arg)
- else:
- tz = self._calcTimezoneName(x, ms)
- s, d, t, microsecs = _calcIndependentSecondEtc(tz, x, ms)
-
- else:
- # Seconds from epoch, gmt
- t = arg
- lt = safelocaltime(t)
- tz = self.localZone(lt)
- ms = (t - math.floor(t))
- s, d = _calcSD(t)
- yr, mo, dy, hr, mn, sc = lt[:6]
- sc = sc + ms
-
- elif ac == 2:
- if isinstance(args[1], basestring):
- # Seconds from epoch (gmt) and timezone
- t, tz = args
- ms = (t - math.floor(t))
- try:
- tz = _TZINFO._zmap[tz.lower()]
- except KeyError:
- if numericTimeZoneMatch(tz) is None:
- raise DateTimeError('Unknown time zone: %s' % tz)
- # Use integer arithmetic as much as possible.
- s, d = _calcSD(t)
- x = _calcDependentSecond(tz, t)
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x, ms)
- else:
- # Year, julian expressed in local zone
- t = time()
- lt = safelocaltime(t)
- tz = self.localZone(lt)
- yr, jul = args
- yr = _correctYear(yr)
- d = (_julianday(yr, 1, 0) - jd1901) + jul
- x_float = d * 86400.0
- x_floor = math.floor(x_float)
- ms = x_float - x_floor
- x = long(x_floor)
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x, ms)
- s, d, t, microsecs = _calcIndependentSecondEtc(tz, x, ms)
- else:
- # Explicit format
- yr, mo, dy = args[:3]
- hr, mn, sc, tz = 0, 0, 0, 0
- yr = _correctYear(yr)
- if not self._validDate(yr, mo, dy):
- raise DateError('Invalid date: %s' % (args, ))
- args = args[3:]
- if args:
- hr, args = args[0], args[1:]
- if args:
- mn, args = args[0], args[1:]
- if args:
- sc, args = args[0], args[1:]
- if args:
- tz, args = args[0], args[1:]
- if args:
- raise DateTimeError('Too many arguments')
- if not self._validTime(hr, mn, sc):
- raise TimeError('Invalid time: %s' % repr(args))
-
- x = _calcDependentSecond2(yr, mo, dy, hr, mn, sc)
- ms = sc - math.floor(sc)
- if tz:
- try:
- tz = _TZINFO._zmap[tz.lower()]
- except KeyError:
- if numericTimeZoneMatch(tz) is None:
- raise DateTimeError('Unknown time zone: %s' % tz)
- else:
- # Get local time zone name
- tz = self._calcTimezoneName(x, ms)
- s, d, t, microsecs = _calcIndependentSecondEtc(tz, x, ms)
-
- self._dayoffset = int((_julianday(yr, mo, dy) + 2) % 7)
- # Round to nearest microsecond in platform-independent way. You
- # cannot rely on C sprintf (Python '%') formatting to round
- # consistently; doing it ourselves ensures that all but truly
- # horrid C sprintf implementations will yield the same result
- # x-platform, provided the format asks for exactly 6 digits after
- # the decimal point.
- sc = round(sc, 6)
- if sc >= 60.0: # can happen if, e.g., orig sc was 59.9999999
- sc = 59.999999
- self._nearsec = math.floor(sc)
- self._year, self._month, self._day = yr, mo, dy
- self._hour, self._minute, self._second = hr, mn, sc
- self.time, self._d, self._tz = s, d, tz
- # self._micros is the time since the epoch
- # in long integer microseconds.
- if microsecs is None:
- microsecs = long(math.floor(t * 1000000.0))
- self._micros = microsecs
-
- def localZone(self, ltm=None):
- '''Returns the time zone on the given date. The time zone
- can change according to daylight savings.'''
- if not _multipleZones:
- return _localzone0
- if ltm is None:
- ltm = localtime(time())
- isDST = ltm[8]
- lz = isDST and _localzone1 or _localzone0
- return lz
-
- def _calcTimezoneName(self, x, ms):
- # Derive the name of the local time zone at the given
- # timezone-dependent second.
- if not _multipleZones:
- return _localzone0
- fsetAtEpoch = _tzoffset(_localzone0, 0.0)
- nearTime = x - fsetAtEpoch - long(EPOCH) + 86400 + ms
- # nearTime is within an hour of being correct.
- try:
- ltm = safelocaltime(nearTime)
- except:
- # We are beyond the range of Python's date support.
- # Hopefully we can assume that daylight savings schedules
- # repeat every 28 years. Calculate the name of the
- # time zone using a supported range of years.
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x, 0)
- yr = ((yr - 1970) % 28) + 1970
- x = _calcDependentSecond2(yr, mo, dy, hr, mn, sc)
- nearTime = x - fsetAtEpoch - long(EPOCH) + 86400 + ms
-
- # nearTime might still be negative if we are east of Greenwich.
- # But we can asume on 1969/12/31 were no timezone changes.
- nearTime = max(0, nearTime)
-
- ltm = safelocaltime(nearTime)
- tz = self.localZone(ltm)
- return tz
-
- def _parse(self, st, datefmt=getDefaultDateFormat()):
- # Parse date-time components from a string
- month = year = tz = tm = None
- ValidZones = _TZINFO._zidx
- TimeModifiers = ['am', 'pm']
-
- # Find timezone first, since it should always be the last
- # element, and may contain a slash, confusing the parser.
- st = st.strip()
- sp = st.split()
- tz = sp[-1]
- if tz and (tz.lower() in ValidZones):
- self._timezone_naive = False
- st = ' '.join(sp[:-1])
- else:
- self._timezone_naive = True
- tz = None # Decide later, since the default time zone
- # could depend on the date.
-
- ints = []
- i = 0
- l = len(st)
- while i < l:
- while i < l and st[i] in SPACE_CHARS:
- i += 1
- if i < l and st[i] in DELIMITERS:
- d = st[i]
- i += 1
- else:
- d = ''
- while i < l and st[i] in SPACE_CHARS:
- i += 1
-
- # The float pattern needs to look back 1 character, because it
- # actually looks for a preceding colon like ':33.33'. This is
- # needed to avoid accidentally matching the date part of a
- # dot-separated date string such as '1999.12.31'.
- if i > 0:
- b = i - 1
- else:
- b = i
-
- ts_results = FLT_PATTERN.match(st, b)
- if ts_results:
- s = ts_results.group(1)
- i = i + len(s)
- ints.append(float(s))
- continue
-
- #AJ
- ts_results = INT_PATTERN.match(st, i)
- if ts_results:
- s = ts_results.group(0)
-
- ls = len(s)
- i = i + ls
- if (ls == 4 and d and d in '+-' and
- (len(ints) + (not not month) >= 3)):
- tz = '%s%s' % (d, s)
- else:
- v = int(s)
- ints.append(v)
- continue
-
- ts_results = NAME_PATTERN.match(st, i)
- if ts_results:
- s = ts_results.group(0).lower()
- i = i + len(s)
- if i < l and st[i] == '.':
- i += 1
- # Check for month name:
- _v = _MONTHMAP.get(s)
- if _v is not None:
- if month is None:
- month = _v
- else:
- raise SyntaxError(st)
- continue
- # Check for time modifier:
- if s in TimeModifiers:
- if tm is None:
- tm = s
- else:
- raise SyntaxError(st)
- continue
- # Check for and skip day of week:
- if s in _DAYMAP:
- continue
-
- raise SyntaxError(st)
-
- day = None
- if ints[-1] > 60 and d not in ('.', ':', '/') and len(ints) > 2:
- year = ints[-1]
- del ints[-1]
- if month:
- day = ints[0]
- del ints[:1]
- else:
- if datefmt == "us":
- month = ints[0]
- day = ints[1]
- else:
- month = ints[1]
- day = ints[0]
- del ints[:2]
- elif month:
- if len(ints) > 1:
- if ints[0] > 31:
- year = ints[0]
- day = ints[1]
- else:
- year = ints[1]
- day = ints[0]
- del ints[:2]
- elif len(ints) > 2:
- if ints[0] > 31:
- year = ints[0]
- if ints[1] > 12:
- day = ints[1]
- month = ints[2]
- else:
- day = ints[2]
- month = ints[1]
- if ints[1] > 31:
- year = ints[1]
- if ints[0] > 12 and ints[2] <= 12:
- day = ints[0]
- month = ints[2]
- elif ints[2] > 12 and ints[0] <= 12:
- day = ints[2]
- month = ints[0]
- elif ints[2] > 31:
- year = ints[2]
- if ints[0] > 12:
- day = ints[0]
- month = ints[1]
- else:
- if datefmt == "us":
- day = ints[1]
- month = ints[0]
- else:
- day = ints[0]
- month = ints[1]
-
- elif ints[0] <= 12:
- month = ints[0]
- day = ints[1]
- year = ints[2]
- del ints[:3]
-
- if day is None:
- # Use today's date.
- year, month, day = localtime(time())[:3]
-
- year = _correctYear(year)
- if year < 1000:
- raise SyntaxError(st)
-
- leap = year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
- try:
- if not day or day > _MONTH_LEN[leap][month]:
- raise DateError(st)
- except IndexError:
- raise DateError(st)
-
- tod = 0
- if ints:
- i = ints[0]
- # Modify hour to reflect am/pm
- if tm and (tm == 'pm') and i < 12:
- i += 12
- if tm and (tm == 'am') and i == 12:
- i = 0
- if i > 24:
- raise TimeError(st)
- tod = tod + int(i) * 3600
- del ints[0]
- if ints:
- i = ints[0]
- if i > 60:
- raise TimeError(st)
- tod = tod + int(i) * 60
- del ints[0]
- if ints:
- i = ints[0]
- if i > 60:
- raise TimeError(st)
- tod = tod + i
- del ints[0]
- if ints:
- raise SyntaxError(st)
-
- tod_int = int(math.floor(tod))
- ms = tod - tod_int
- hr, mn, sc = _calcHMS(tod_int, ms)
- if not tz:
- # Figure out what time zone it is in the local area
- # on the given date.
- x = _calcDependentSecond2(year, month, day, hr, mn, sc)
- tz = self._calcTimezoneName(x, ms)
-
- return year, month, day, hr, mn, sc, tz
-
- # Internal methods
- def _validDate(self, y, m, d):
- if m < 1 or m > 12 or y < 0 or d < 1 or d > 31:
- return 0
- return d <= _MONTH_LEN[
- (y % 4 == 0 and (y % 100 != 0 or y % 400 == 0))][m]
-
- def _validTime(self, h, m, s):
- return h >= 0 and h <= 23 and m >= 0 and m <= 59 and s >= 0 and s < 60
-
- def __getattr__(self, name):
- if '%' in name:
- return strftimeFormatter(self, name)
- raise AttributeError(name)
-
- # Conversion and comparison methods
-
- def timeTime(self):
- """Return the date/time as a floating-point number in UTC,
- in the format used by the python time module.
-
- Note that it is possible to create date/time values with
- DateTime that have no meaningful value to the time module.
- """
- return self._micros / 1000000.0
-
- def toZone(self, z):
- """Return a DateTime with the value as the current
- object, represented in the indicated timezone.
- """
- t, tz = self._t, _TZINFO._zmap[z.lower()]
- micros = self.micros()
- tznaive = False # you're performing a timzone change, can't be naive
-
- try:
- # Try to use time module for speed.
- yr, mo, dy, hr, mn, sc = safegmtime(t + _tzoffset(tz, t))[:6]
- sc = self._second
- return self.__class__(yr, mo, dy, hr, mn, sc, tz, t,
- self._d, self.time, micros, tznaive)
- except Exception:
- # gmtime can't perform the calculation in the given range.
- # Calculate the difference between the two time zones.
- tzdiff = _tzoffset(tz, t) - _tzoffset(self._tz, t)
- if tzdiff == 0:
- return self
- sc = self._second
- ms = sc - math.floor(sc)
- x = _calcDependentSecond2(self._year, self._month, self._day,
- self._hour, self._minute, sc)
- x_new = x + tzdiff
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x_new, ms)
- return self.__class__(yr, mo, dy, hr, mn, sc, tz, t,
- self._d, self.time, micros, tznaive)
-
- def isFuture(self):
- """Return true if this object represents a date/time
- later than the time of the call.
- """
- return (self._t > time())
-
- def isPast(self):
- """Return true if this object represents a date/time
- earlier than the time of the call.
- """
- return (self._t < time())
-
- def isCurrentYear(self):
- """Return true if this object represents a date/time
- that falls within the current year, in the context
- of this object\'s timezone representation.
- """
- t = time()
- return safegmtime(t + _tzoffset(self._tz, t))[0] == self._year
-
- def isCurrentMonth(self):
- """Return true if this object represents a date/time
- that falls within the current month, in the context
- of this object\'s timezone representation.
- """
- t = time()
- gmt = safegmtime(t + _tzoffset(self._tz, t))
- return gmt[0] == self._year and gmt[1] == self._month
-
- def isCurrentDay(self):
- """Return true if this object represents a date/time
- that falls within the current day, in the context
- of this object\'s timezone representation.
- """
- t = time()
- gmt = safegmtime(t + _tzoffset(self._tz, t))
- return (gmt[0] == self._year and gmt[1] == self._month and
- gmt[2] == self._day)
-
- def isCurrentHour(self):
- """Return true if this object represents a date/time
- that falls within the current hour, in the context
- of this object\'s timezone representation.
- """
- t = time()
- gmt = safegmtime(t + _tzoffset(self._tz, t))
- return (gmt[0] == self._year and gmt[1] == self._month and
- gmt[2] == self._day and gmt[3] == self._hour)
-
- def isCurrentMinute(self):
- """Return true if this object represents a date/time
- that falls within the current minute, in the context
- of this object\'s timezone representation.
- """
- t = time()
- gmt = safegmtime(t + _tzoffset(self._tz, t))
- return (gmt[0] == self._year and gmt[1] == self._month and
- gmt[2] == self._day and gmt[3] == self._hour and
- gmt[4] == self._minute)
-
- def earliestTime(self):
- """Return a new DateTime object that represents the earliest
- possible time (in whole seconds) that still falls within
- the current object\'s day, in the object\'s timezone context.
- """
- return self.__class__(
- self._year, self._month, self._day, 0, 0, 0, self._tz)
-
- def latestTime(self):
- """Return a new DateTime object that represents the latest
- possible time (in whole seconds) that still falls within
- the current object\'s day, in the object\'s timezone context.
- """
- return self.__class__(
- self._year, self._month, self._day, 23, 59, 59, self._tz)
-
- def greaterThan(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time greater
- than the specified DateTime or time module style time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- if t is None:
- t = 0
- if isinstance(t, float):
- return self._micros > long(t * 1000000)
- try:
- return self._micros > t._micros
- except AttributeError:
- return self._micros > t
-
- __gt__ = greaterThan
-
- def greaterThanEqualTo(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time greater
- than or equal to the specified DateTime or time module style
- time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- if t is None:
- t = 0
- if isinstance(t, float):
- return self._micros >= long(t * 1000000)
- try:
- return self._micros >= t._micros
- except AttributeError:
- return self._micros >= t
-
- __ge__ = greaterThanEqualTo
-
- def equalTo(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time equal to
- the specified DateTime or time module style time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- if t is None:
- t = 0
- if isinstance(t, float):
- return self._micros == long(t * 1000000)
- try:
- return self._micros == t._micros
- except AttributeError:
- return self._micros == t
-
- def notEqualTo(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time not equal
- to the specified DateTime or time module style time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- return not self.equalTo(t)
-
- def __eq__(self, t):
- """Compare this DateTime object to another DateTime object.
- Return True if their internal state is the same. Two objects
- representing the same time in different timezones are regared as
- unequal. Use the equalTo method if you are only interested in them
- refering to the same moment in time.
- """
- if not isinstance(t, DateTime):
- return False
- return (self._micros, self._tz) == (t._micros, t._tz)
-
- def __ne__(self, t):
- return not self.__eq__(t)
-
- def lessThan(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time less than
- the specified DateTime or time module style time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- if t is None:
- t = 0
- if isinstance(t, float):
- return self._micros < long(t * 1000000)
- try:
- return self._micros < t._micros
- except AttributeError:
- return self._micros < t
-
- __lt__ = lessThan
-
- def lessThanEqualTo(self, t):
- """Compare this DateTime object to another DateTime object
- OR a floating point number such as that which is returned
- by the python time module.
-
- Returns true if the object represents a date/time less than
- or equal to the specified DateTime or time module style time.
-
- Revised to give more correct results through comparison of
- long integer microseconds.
- """
- if t is None:
- t = 0
- if isinstance(t, float):
- return self._micros <= long(t * 1000000)
- try:
- return self._micros <= t._micros
- except AttributeError:
- return self._micros <= t
-
- __le__ = lessThanEqualTo
-
- def isLeapYear(self):
- """Return true if the current year (in the context of the
- object\'s timezone) is a leap year.
- """
- return (self._year % 4 == 0 and
- (self._year % 100 != 0 or self._year % 400 == 0))
-
- def dayOfYear(self):
- """Return the day of the year, in context of the timezone
- representation of the object.
- """
- d = int(self._d + (_tzoffset(self._tz, self._t) / 86400.0))
- return int((d + jd1901) - _julianday(self._year, 1, 0))
-
- # Component access
- def parts(self):
- """Return a tuple containing the calendar year, month,
- day, hour, minute second and timezone of the object.
- """
- return (self._year, self._month, self._day, self._hour,
- self._minute, self._second, self._tz)
-
- def timezone(self):
- """Return the timezone in which the object is represented."""
- return self._tz
-
- def tzoffset(self):
- """Return the timezone offset for the objects timezone."""
- return _tzoffset(self._tz, self._t)
-
- def year(self):
- """Return the calendar year of the object."""
- return self._year
-
- def month(self):
- """Return the month of the object as an integer."""
- return self._month
-
- @property
- def _fmon(self):
- return _MONTHS[self._month]
-
- def Month(self):
- """Return the full month name."""
- return self._fmon
-
- @property
- def _amon(self):
- return _MONTHS_A[self._month]
-
- def aMonth(self):
- """Return the abreviated month name."""
- return self._amon
-
- def Mon(self):
- """Compatibility: see aMonth."""
- return self._amon
-
- @property
- def _pmon(self):
- return _MONTHS_P[self._month]
-
- def pMonth(self):
- """Return the abreviated (with period) month name."""
- return self._pmon
-
- def Mon_(self):
- """Compatibility: see pMonth."""
- return self._pmon
-
- def day(self):
- """Return the integer day."""
- return self._day
-
- @property
- def _fday(self):
- return _DAYS[self._dayoffset]
-
- def Day(self):
- """Return the full name of the day of the week."""
- return self._fday
-
- def DayOfWeek(self):
- """Compatibility: see Day."""
- return self._fday
-
- @property
- def _aday(self):
- return _DAYS_A[self._dayoffset]
-
- def aDay(self):
- """Return the abreviated name of the day of the week."""
- return self._aday
-
- @property
- def _pday(self):
- return _DAYS_P[self._dayoffset]
-
- def pDay(self):
- """Return the abreviated (with period) name of the day of the week."""
- return self._pday
-
- def Day_(self):
- """Compatibility: see pDay."""
- return self._pday
-
- def dow(self):
- """Return the integer day of the week, where sunday is 0."""
- return self._dayoffset
-
- def dow_1(self):
- """Return the integer day of the week, where sunday is 1."""
- return self._dayoffset + 1
-
- @property
- def _pmhour(self):
- hr = self._hour
- if hr > 12:
- return hr - 12
- return hr or 12
-
- def h_12(self):
- """Return the 12-hour clock representation of the hour."""
- return self._pmhour
-
- def h_24(self):
- """Return the 24-hour clock representation of the hour."""
- return self._hour
-
- @property
- def _pm(self):
- hr = self._hour
- if hr >= 12:
- return 'pm'
- return 'am'
-
- def ampm(self):
- """Return the appropriate time modifier (am or pm)."""
- return self._pm
-
- def hour(self):
- """Return the 24-hour clock representation of the hour."""
- return self._hour
-
- def minute(self):
- """Return the minute."""
- return self._minute
-
- def second(self):
- """Return the second."""
- return self._second
-
- def millis(self):
- """Return the millisecond since the epoch in GMT."""
- return self._micros // 1000
-
- def micros(self):
- """Return the microsecond since the epoch in GMT."""
- return self._micros
-
- def timezoneNaive(self):
- """The python datetime module introduces the idea of distinguishing
- between timezone aware and timezone naive datetime values. For lossless
- conversion to and from datetime.datetime record if we record this
- information using True / False. DateTime makes no distinction, when we
- don't have any information we return None here.
- """
- try:
- return self._timezone_naive
- except AttributeError:
- return None
-
- def strftime(self, format):
- """Format the date/time using the *current timezone representation*."""
- x = _calcDependentSecond2(self._year, self._month, self._day,
- self._hour, self._minute, self._second)
- ltz = self._calcTimezoneName(x, 0)
- tzdiff = _tzoffset(ltz, self._t) - _tzoffset(self._tz, self._t)
- zself = self + tzdiff / 86400.0
- microseconds = int((zself._second - zself._nearsec) * 1000000)
- unicode_format = False
- if isinstance(format, explicit_unicode_type):
- format = format.encode('utf-8')
- unicode_format = True
- ds = datetime(zself._year, zself._month, zself._day, zself._hour,
- zself._minute, int(zself._nearsec),
- microseconds).strftime(format)
- if unicode_format:
- return ds.decode('utf-8')
- return ds
-
- # General formats from previous DateTime
- def Date(self):
- """Return the date string for the object."""
- return "%s/%2.2d/%2.2d" % (self._year, self._month, self._day)
-
- def Time(self):
- """Return the time string for an object to the nearest second."""
- return '%2.2d:%2.2d:%2.2d' % (self._hour, self._minute, self._nearsec)
-
- def TimeMinutes(self):
- """Return the time string for an object not showing seconds."""
- return '%2.2d:%2.2d' % (self._hour, self._minute)
-
- def AMPM(self):
- """Return the time string for an object to the nearest second."""
- return '%2.2d:%2.2d:%2.2d %s' % (
- self._pmhour, self._minute, self._nearsec, self._pm)
-
- def AMPMMinutes(self):
- """Return the time string for an object not showing seconds."""
- return '%2.2d:%2.2d %s' % (self._pmhour, self._minute, self._pm)
-
- def PreciseTime(self):
- """Return the time string for the object."""
- return '%2.2d:%2.2d:%06.3f' % (self._hour, self._minute, self._second)
-
- def PreciseAMPM(self):
- """Return the time string for the object."""
- return '%2.2d:%2.2d:%06.3f %s' % (
- self._pmhour, self._minute, self._second, self._pm)
-
- def yy(self):
- """Return calendar year as a 2 digit string."""
- return str(self._year)[-2:]
-
- def mm(self):
- """Return month as a 2 digit string."""
- return '%02d' % self._month
-
- def dd(self):
- """Return day as a 2 digit string."""
- return '%02d' % self._day
-
- def rfc822(self):
- """Return the date in RFC 822 format."""
- tzoffset = _tzoffset2rfc822zone(_tzoffset(self._tz, self._t))
- return '%s, %2.2d %s %d %2.2d:%2.2d:%2.2d %s' % (
- self._aday, self._day, self._amon, self._year,
- self._hour, self._minute, self._nearsec, tzoffset)
-
- # New formats
- def fCommon(self):
- """Return a string representing the object\'s value
- in the format: March 1, 1997 1:45 pm.
- """
- return '%s %s, %4.4d %s:%2.2d %s' % (
- self._fmon, self._day, self._year, self._pmhour,
- self._minute, self._pm)
-
- def fCommonZ(self):
- """Return a string representing the object\'s value
- in the format: March 1, 1997 1:45 pm US/Eastern.
- """
- return '%s %s, %4.4d %d:%2.2d %s %s' % (
- self._fmon, self._day, self._year, self._pmhour,
- self._minute, self._pm, self._tz)
-
- def aCommon(self):
- """Return a string representing the object\'s value
- in the format: Mar 1, 1997 1:45 pm.
- """
- return '%s %s, %4.4d %s:%2.2d %s' % (
- self._amon, self._day, self._year, self._pmhour,
- self._minute, self._pm)
-
- def aCommonZ(self):
- """Return a string representing the object\'s value
- in the format: Mar 1, 1997 1:45 pm US/Eastern.
- """
- return '%s %s, %4.4d %d:%2.2d %s %s' % (
- self._amon, self._day, self._year, self._pmhour,
- self._minute, self._pm, self._tz)
-
- def pCommon(self):
- """Return a string representing the object\'s value
- in the format: Mar. 1, 1997 1:45 pm.
- """
- return '%s %s, %4.4d %s:%2.2d %s' % (
- self._pmon, self._day, self._year, self._pmhour,
- self._minute, self._pm)
-
- def pCommonZ(self):
- """Return a string representing the object\'s value
- in the format: Mar. 1, 1997 1:45 pm US/Eastern.
- """
- return '%s %s, %4.4d %d:%2.2d %s %s' % (
- self._pmon, self._day, self._year, self._pmhour,
- self._minute, self._pm, self._tz)
-
- def ISO(self):
- """Return the object in ISO standard format.
-
- Note: this is *not* ISO 8601-format! See the ISO8601 and
- HTML4 methods below for ISO 8601-compliant output.
-
- Dates are output as: YYYY-MM-DD HH:MM:SS
- """
- return "%.4d-%.2d-%.2d %.2d:%.2d:%.2d" % (
- self._year, self._month, self._day,
- self._hour, self._minute, self._second)
-
- def ISO8601(self):
- """Return the object in ISO 8601-compatible format containing the
- date, time with seconds-precision and the time zone identifier.
-
- See: http://www.w3.org/TR/NOTE-datetime
-
- Dates are output as: YYYY-MM-DDTHH:MM:SSTZD
- T is a literal character.
- TZD is Time Zone Designator, format +HH:MM or -HH:MM
-
- If the instance is timezone naive (it was not specified with a timezone
- when it was constructed) then the timezone is ommitted.
-
- The HTML4 method below offers the same formatting, but converts
- to UTC before returning the value and sets the TZD "Z".
- """
- if self.timezoneNaive():
- return "%0.4d-%0.2d-%0.2dT%0.2d:%0.2d:%0.2d" % (
- self._year, self._month, self._day,
- self._hour, self._minute, self._second)
- tzoffset = _tzoffset2iso8601zone(_tzoffset(self._tz, self._t))
- return "%0.4d-%0.2d-%0.2dT%0.2d:%0.2d:%0.2d%s" % (
- self._year, self._month, self._day,
- self._hour, self._minute, self._second, tzoffset)
-
- def HTML4(self):
- """Return the object in the format used in the HTML4.0 specification,
- one of the standard forms in ISO8601.
-
- See: http://www.w3.org/TR/NOTE-datetime
-
- Dates are output as: YYYY-MM-DDTHH:MM:SSZ
- T, Z are literal characters.
- The time is in UTC.
- """
- newdate = self.toZone('UTC')
- return "%0.4d-%0.2d-%0.2dT%0.2d:%0.2d:%0.2dZ" % (
- newdate._year, newdate._month, newdate._day,
- newdate._hour, newdate._minute, newdate._second)
-
- def asdatetime(self):
- """Return a standard libary datetime.datetime
- """
- tznaive = self.timezoneNaive()
- if tznaive:
- tzinfo = None
- else:
- tzinfo = _TZINFO[self._tz].tzinfo
- second = int(self._second)
- microsec = self.micros() % 1000000
- dt = datetime(self._year, self._month, self._day, self._hour,
- self._minute, second, microsec, tzinfo)
- return dt
-
- def utcdatetime(self):
- """Convert the time to UTC then return a timezone naive datetime object
- """
- utc = self.toZone('UTC')
- second = int(utc._second)
- microsec = utc.micros() % 1000000
- dt = datetime(utc._year, utc._month, utc._day, utc._hour,
- utc._minute, second, microsec)
- return dt
-
- def __add__(self, other):
- """A DateTime may be added to a number and a number may be
- added to a DateTime; two DateTimes cannot be added.
- """
- if hasattr(other, '_t'):
- raise DateTimeError('Cannot add two DateTimes')
- o = float(other)
- tz = self._tz
- omicros = round(o * 86400000000)
- tmicros = self.micros() + omicros
- t = tmicros / 1000000.0
- d = (tmicros + long(EPOCH * 1000000)) / 86400000000.0
- s = d - math.floor(d)
- ms = t - math.floor(t)
- x = _calcDependentSecond(tz, t)
- yr, mo, dy, hr, mn, sc = _calcYMDHMS(x, ms)
- return self.__class__(yr, mo, dy, hr, mn, sc, self._tz,
- t, d, s, None, self.timezoneNaive())
-
- __radd__ = __add__
-
- def __sub__(self, other):
- """Either a DateTime or a number may be subtracted from a
- DateTime, however, a DateTime may not be subtracted from
- a number.
- """
- if hasattr(other, '_d'):
- return (self.micros() - other.micros()) / 86400000000.0
- else:
- return self.__add__(-(other))
-
- def __repr__(self):
- """Convert a DateTime to a string that looks like a Python
- expression.
- """
- return '%s(\'%s\')' % (self.__class__.__name__, str(self))
-
- def __str__(self):
- """Convert a DateTime to a string."""
- y, m, d = self._year, self._month, self._day
- h, mn, s, t = self._hour, self._minute, self._second, self._tz
- if s == int(s):
- # A whole number of seconds -- suppress milliseconds.
- return '%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d %s' % (
- y, m, d, h, mn, s, t)
- else:
- # s is already rounded to the nearest microsecond, and
- # it's not a whole number of seconds. Be sure to print
- # 2 digits before the decimal point.
- return '%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%06.6f %s' % (
- y, m, d, h, mn, s, t)
-
- def __hash__(self):
- """Compute a hash value for a DateTime."""
- return int(((self._year % 100 * 12 + self._month) * 31 +
- self._day + self.time) * 100)
-
- def __int__(self):
- """Convert to an integer number of seconds since the epoch (gmt)."""
- return int(self.micros() // 1000000)
-
- def __long__(self):
- """Convert to a long-int number of seconds since the epoch (gmt)."""
- return long(self.micros() // 1000000)
-
- def __float__(self):
- """Convert to floating-point number of seconds since the epoch (gmt).
- """
- return self.micros() / 1000000.0
-
- @property
- def _t(self):
- return self._micros / 1000000.0
-
- def _parse_iso8601(self, s):
- # preserve the previously implied contract
- # who know where this could be used...
- return self._parse_iso8601_preserving_tznaive(s)[:7]
-
- def _parse_iso8601_preserving_tznaive(self, s):
- try:
- return self.__parse_iso8601(s)
- except IndexError:
- raise SyntaxError(
- 'Not an ISO 8601 compliant date string: "%s"' % s)
-
- def __parse_iso8601(self, s):
- """Parse an ISO 8601 compliant date.
-
- See: http://en.wikipedia.org/wiki/ISO_8601
- """
- month = day = week_day = 1
- year = hour = minute = seconds = hour_off = min_off = 0
- tznaive = True
-
- iso8601 = iso8601Match(s.strip())
- fields = iso8601 and iso8601.groupdict() or {}
- if not iso8601 or fields.get('garbage'):
- raise IndexError
-
- if fields['year']:
- year = int(fields['year'])
- if fields['month']:
- month = int(fields['month'])
- if fields['day']:
- day = int(fields['day'])
-
- if fields['year_day']:
- d = DateTime('%s-01-01' % year) + int(fields['year_day']) - 1
- month = d.month()
- day = d.day()
-
- if fields['week']:
- week = int(fields['week'])
- if fields['week_day']:
- week_day = int(fields['week_day'])
- d = DateTime('%s-01-04' % year)
- d = d - (d.dow() + 6) % 7 + week * 7 + week_day - 8
- month = d.month()
- day = d.day()
-
- if fields['hour']:
- hour = int(fields['hour'])
-
- if fields['minute']:
- minute = int(fields['minute'])
- elif fields['fraction']:
- minute = 60.0 * float('0.%s' % fields['fraction'])
- seconds, minute = math.modf(minute)
- minute = int(minute)
- seconds = 60.0 * seconds
- # Avoid reprocess when handling seconds, bellow
- fields['fraction'] = None
-
- if fields['second']:
- seconds = int(fields['second'])
- if fields['fraction']:
- seconds = seconds + float('0.%s' % fields['fraction'])
- elif fields['fraction']:
- seconds = 60.0 * float('0.%s' % fields['fraction'])
-
- if fields['hour_off']:
- hour_off = int(fields['hour_off'])
- if fields['signal'] == '-':
- hour_off *= -1
-
- if fields['min_off']:
- min_off = int(fields['min_off'])
-
- if fields['signal'] or fields['Z']:
- tznaive = False
- else:
- tznaive = True
-
- # Differ from the specification here. To preserve backwards
- # compatibility assume a default timezone == UTC.
- tz = 'GMT%+03d%02d' % (hour_off, min_off)
-
- return year, month, day, hour, minute, seconds, tz, tznaive
-
- def JulianDay(self):
- """Return the Julian day.
-
- See: http://www.tondering.dk/claus/cal/node3.html#sec-calcjd
- """
- a = (14 - self._month) // 12
- y = self._year + 4800 - a
- m = self._month + (12 * a) - 3
- return (self._day + (153 * m + 2) // 5 + 365 * y +
- y // 4 - y // 100 + y // 400 - 32045)
-
- def week(self):
- """Return the week number according to ISO.
-
- See: http://www.tondering.dk/claus/cal/node6.html
- """
- J = self.JulianDay()
- d4 = (J + 31741 - (J % 7)) % 146097 % 36524 % 1461
- L = d4 // 1460
- d1 = ((d4 - L) % 365) + L
- return d1 // 7 + 1
-
- def encode(self, out):
- """Encode value for XML-RPC."""
- out.write('')
- out.write(self.ISO8601())
- out.write('\n')
-
-
-# Provide the _dt_reconstructor function here, in case something
-# accidentally creates a reference to this function
-
-orig_reconstructor = copy_reg._reconstructor
-
-
-def _dt_reconstructor(cls, base, state):
- if cls is DateTime:
- return cls(state)
- return orig_reconstructor(cls, base, state)
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/DateTime.txt b/server/venv/lib/python3.7/site-packages/DateTime/DateTime.txt
deleted file mode 100644
index 5467047..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/DateTime.txt
+++ /dev/null
@@ -1,785 +0,0 @@
-The DateTime package
-====================
-
-Encapsulation of date/time values.
-
-
-Function Timezones()
---------------------
-
-Returns the list of recognized timezone names:
-
- >>> from DateTime import Timezones
- >>> zones = set(Timezones())
-
-Almost all of the standard pytz timezones are included, with the exception
-of some commonly-used but ambiguous abbreviations, where historical Zope
-usage conflicts with the name used by pytz:
-
- >>> import pytz
- >>> [x for x in pytz.all_timezones if x not in zones]
- ['CET', 'EET', 'EST', 'MET', 'MST', 'WET']
-
-Class DateTime
---------------
-
-DateTime objects represent instants in time and provide interfaces for
-controlling its representation without affecting the absolute value of
-the object.
-
-DateTime objects may be created from a wide variety of string or
-numeric data, or may be computed from other DateTime objects.
-DateTimes support the ability to convert their representations to many
-major timezones, as well as the ablility to create a DateTime object
-in the context of a given timezone.
-
-DateTime objects provide partial numerical behavior:
-
-* Two date-time objects can be subtracted to obtain a time, in days
- between the two.
-
-* A date-time object and a positive or negative number may be added to
- obtain a new date-time object that is the given number of days later
- than the input date-time object.
-
-* A positive or negative number and a date-time object may be added to
- obtain a new date-time object that is the given number of days later
- than the input date-time object.
-
-* A positive or negative number may be subtracted from a date-time
- object to obtain a new date-time object that is the given number of
- days earlier than the input date-time object.
-
-DateTime objects may be converted to integer, long, or float numbers
-of days since January 1, 1901, using the standard int, long, and float
-functions (Compatibility Note: int, long and float return the number
-of days since 1901 in GMT rather than local machine timezone).
-DateTime objects also provide access to their value in a float format
-usable with the python time module, provided that the value of the
-object falls in the range of the epoch-based time module.
-
-A DateTime object should be considered immutable; all conversion and numeric
-operations return a new DateTime object rather than modify the current object.
-
-A DateTime object always maintains its value as an absolute UTC time,
-and is represented in the context of some timezone based on the
-arguments used to create the object. A DateTime object's methods
-return values based on the timezone context.
-
-Note that in all cases the local machine timezone is used for
-representation if no timezone is specified.
-
-Constructor for DateTime
-------------------------
-
-DateTime() returns a new date-time object. DateTimes may be created
-with from zero to seven arguments:
-
-* If the function is called with no arguments, then the current date/
- time is returned, represented in the timezone of the local machine.
-
-* If the function is invoked with a single string argument which is a
- recognized timezone name, an object representing the current time is
- returned, represented in the specified timezone.
-
-* If the function is invoked with a single string argument
- representing a valid date/time, an object representing that date/
- time will be returned.
-
- As a general rule, any date-time representation that is recognized
- and unambigous to a resident of North America is acceptable. (The
- reason for this qualification is that in North America, a date like:
- 2/1/1994 is interpreted as February 1, 1994, while in some parts of
- the world, it is interpreted as January 2, 1994.) A date/ time
- string consists of two components, a date component and an optional
- time component, separated by one or more spaces. If the time
- component is omited, 12:00am is assumed.
-
- Any recognized timezone name specified as the final element of the
- date/time string will be used for computing the date/time value.
- (If you create a DateTime with the string,
- "Mar 9, 1997 1:45pm US/Pacific", the value will essentially be the
- same as if you had captured time.time() at the specified date and
- time on a machine in that timezone). If no timezone is passed, then
- the timezone configured on the local machine will be used, **except**
- that if the date format matches ISO 8601 ('YYYY-MM-DD'), the instance
- will use UTC / CMT+0 as the timezone.
-
- o Returns current date/time, represented in US/Eastern:
-
- >>> from DateTime import DateTime
- >>> e = DateTime('US/Eastern')
- >>> e.timezone()
- 'US/Eastern'
-
- o Returns specified time, represented in local machine zone:
-
- >>> x = DateTime('1997/3/9 1:45pm')
- >>> x.parts() # doctest: +ELLIPSIS
- (1997, 3, 9, 13, 45, ...)
-
- o Specified time in local machine zone, verbose format:
-
- >>> y = DateTime('Mar 9, 1997 13:45:00')
- >>> y.parts() # doctest: +ELLIPSIS
- (1997, 3, 9, 13, 45, ...)
- >>> y == x
- True
-
- o Specified time in UTC via ISO 8601 rule:
-
- >>> z = DateTime('2014-03-24')
- >>> z.parts() # doctest: +ELLIPSIS
- (2014, 3, 24, 0, 0, ...)
- >>> z.timezone()
- 'GMT+0'
-
- The date component consists of year, month, and day values. The
- year value must be a one-, two-, or four-digit integer. If a one-
- or two-digit year is used, the year is assumed to be in the
- twentieth century. The month may an integer, from 1 to 12, a month
- name, or a month abreviation, where a period may optionally follow
- the abreviation. The day must be an integer from 1 to the number of
- days in the month. The year, month, and day values may be separated
- by periods, hyphens, forward, shashes, or spaces. Extra spaces are
- permitted around the delimiters. Year, month, and day values may be
- given in any order as long as it is possible to distinguish the
- components. If all three components are numbers that are less than
- 13, then a a month-day-year ordering is assumed.
-
- The time component consists of hour, minute, and second values
- separated by colons. The hour value must be an integer between 0
- and 23 inclusively. The minute value must be an integer between 0
- and 59 inclusively. The second value may be an integer value
- between 0 and 59.999 inclusively. The second value or both the
- minute and second values may be ommitted. The time may be followed
- by am or pm in upper or lower case, in which case a 12-hour clock is
- assumed.
-
-* If the DateTime function is invoked with a single Numeric argument,
- the number is assumed to be either a floating point value such as
- that returned by time.time() , or a number of days after January 1,
- 1901 00:00:00 UTC.
-
- A DateTime object is returned that represents either the gmt value
- of the time.time() float represented in the local machine's
- timezone, or that number of days after January 1, 1901. Note that
- the number of days after 1901 need to be expressed from the
- viewpoint of the local machine's timezone. A negative argument will
- yield a date-time value before 1901.
-
-* If the function is invoked with two numeric arguments, then the
- first is taken to be an integer year and the second argument is
- taken to be an offset in days from the beginning of the year, in the
- context of the local machine timezone. The date-time value returned
- is the given offset number of days from the beginning of the given
- year, represented in the timezone of the local machine. The offset
- may be positive or negative. Two-digit years are assumed to be in
- the twentieth century.
-
-* If the function is invoked with two arguments, the first a float
- representing a number of seconds past the epoch in gmt (such as
- those returned by time.time()) and the second a string naming a
- recognized timezone, a DateTime with a value of that gmt time will
- be returned, represented in the given timezone.
-
- >>> import time
- >>> t = time.time()
-
- Time t represented as US/Eastern:
-
- >>> now_east = DateTime(t, 'US/Eastern')
-
- Time t represented as US/Pacific:
-
- >>> now_west = DateTime(t, 'US/Pacific')
-
- Only their representations are different:
-
- >>> now_east.equalTo(now_west)
- True
-
-* If the function is invoked with three or more numeric arguments,
- then the first is taken to be an integer year, the second is taken
- to be an integer month, and the third is taken to be an integer day.
- If the combination of values is not valid, then a DateTimeError is
- raised. One- or two-digit years up to 69 are assumed to be in the
- 21st century, whereas values 70-99 are assumed to be 20th century.
- The fourth, fifth, and sixth arguments are floating point, positive
- or negative offsets in units of hours, minutes, and days, and
- default to zero if not given. An optional string may be given as
- the final argument to indicate timezone (the effect of this is as if
- you had taken the value of time.time() at that time on a machine in
- the specified timezone).
-
-If a string argument passed to the DateTime constructor cannot be
-parsed, it will raise SyntaxError. Invalid date, time, or
-timezone components will raise a DateTimeError.
-
-The module function Timezones() will return a list of the timezones
-recognized by the DateTime module. Recognition of timezone names is
-case-insensitive.
-
-Instance Methods for DateTime (IDateTime interface)
----------------------------------------------------
-
-Conversion and comparison methods
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* ``timeTime()`` returns the date/time as a floating-point number in
- UTC, in the format used by the python time module. Note that it is
- possible to create date /time values with DateTime that have no
- meaningful value to the time module, and in such cases a
- DateTimeError is raised. A DateTime object's value must generally
- be between Jan 1, 1970 (or your local machine epoch) and Jan 2038 to
- produce a valid time.time() style value.
-
- >>> dt = DateTime('Mar 9, 1997 13:45:00 US/Eastern')
- >>> dt.timeTime()
- 857933100.0
-
- >>> DateTime('2040/01/01 UTC').timeTime()
- 2208988800.0
-
- >>> DateTime('1900/01/01 UTC').timeTime()
- -2208988800.0
-
-* ``toZone(z)`` returns a DateTime with the value as the current
- object, represented in the indicated timezone:
-
- >>> dt.toZone('UTC')
- DateTime('1997/03/09 18:45:00 UTC')
-
- >>> dt.toZone('UTC').equalTo(dt)
- True
-
-* ``isFuture()`` returns true if this object represents a date/time
- later than the time of the call:
-
- >>> dt.isFuture()
- False
- >>> DateTime('Jan 1 3000').isFuture() # not time-machine safe!
- True
-
-* ``isPast()`` returns true if this object represents a date/time
- earlier than the time of the call:
-
- >>> dt.isPast()
- True
- >>> DateTime('Jan 1 3000').isPast() # not time-machine safe!
- False
-
-* ``isCurrentYear()`` returns true if this object represents a
- date/time that falls within the current year, in the context of this
- object's timezone representation:
-
- >>> dt.isCurrentYear()
- False
- >>> DateTime().isCurrentYear()
- True
-
-* ``isCurrentMonth()`` returns true if this object represents a
- date/time that falls within the current month, in the context of
- this object's timezone representation:
-
- >>> dt.isCurrentMonth()
- False
- >>> DateTime().isCurrentMonth()
- True
-
-* ``isCurrentDay()`` returns true if this object represents a
- date/time that falls within the current day, in the context of this
- object's timezone representation:
-
- >>> dt.isCurrentDay()
- False
- >>> DateTime().isCurrentDay()
- True
-
-* ``isCurrentHour()`` returns true if this object represents a
- date/time that falls within the current hour, in the context of this
- object's timezone representation:
-
- >>> dt.isCurrentHour()
- False
-
- >>> DateTime().isCurrentHour()
- True
-
-* ``isCurrentMinute()`` returns true if this object represents a
- date/time that falls within the current minute, in the context of
- this object's timezone representation:
-
- >>> dt.isCurrentMinute()
- False
- >>> DateTime().isCurrentMinute()
- True
-
-* ``isLeapYear()`` returns true if the current year (in the context of
- the object's timezone) is a leap year:
-
- >>> dt.isLeapYear()
- False
- >>> DateTime('Mar 8 2004').isLeapYear()
- True
-
-* ``earliestTime()`` returns a new DateTime object that represents the
- earliest possible time (in whole seconds) that still falls within
- the current object's day, in the object's timezone context:
-
- >>> dt.earliestTime()
- DateTime('1997/03/09 00:00:00 US/Eastern')
-
-* ``latestTime()`` return a new DateTime object that represents the
- latest possible time (in whole seconds) that still falls within the
- current object's day, in the object's timezone context
-
- >>> dt.latestTime()
- DateTime('1997/03/09 23:59:59 US/Eastern')
-
-Component access
-~~~~~~~~~~~~~~~~
-
-* ``parts()`` returns a tuple containing the calendar year, month,
- day, hour, minute second and timezone of the object
-
- >>> dt.parts() # doctest: +ELLIPSIS
- (1997, 3, 9, 13, 45, ... 'US/Eastern')
-
-* ``timezone()`` returns the timezone in which the object is represented:
-
- >>> dt.timezone() in Timezones()
- True
-
-* ``tzoffset()`` returns the timezone offset for the objects timezone:
-
- >>> dt.tzoffset()
- -18000
-
-* ``year()`` returns the calendar year of the object:
-
- >>> dt.year()
- 1997
-
-* ``month()`` retursn the month of the object as an integer:
-
- >>> dt.month()
- 3
-
-* ``Month()`` returns the full month name:
-
- >>> dt.Month()
- 'March'
-
-* ``aMonth()`` returns the abreviated month name:
-
- >>> dt.aMonth()
- 'Mar'
-
-* ``pMonth()`` returns the abreviated (with period) month name:
-
- >>> dt.pMonth()
- 'Mar.'
-
-* ``day()`` returns the integer day:
-
- >>> dt.day()
- 9
-
-* ``Day()`` returns the full name of the day of the week:
-
- >>> dt.Day()
- 'Sunday'
-
-* ``dayOfYear()`` returns the day of the year, in context of the
- timezone representation of the object:
-
- >>> dt.dayOfYear()
- 68
-
-* ``aDay()`` returns the abreviated name of the day of the week:
-
- >>> dt.aDay()
- 'Sun'
-
-* ``pDay()`` returns the abreviated (with period) name of the day of
- the week:
-
- >>> dt.pDay()
- 'Sun.'
-
-* ``dow()`` returns the integer day of the week, where Sunday is 0:
-
- >>> dt.dow()
- 0
-
-* ``dow_1()`` returns the integer day of the week, where sunday is 1:
-
- >>> dt.dow_1()
- 1
-
-* ``h_12()`` returns the 12-hour clock representation of the hour:
-
- >>> dt.h_12()
- 1
-
-* ``h_24()`` returns the 24-hour clock representation of the hour:
-
- >>> dt.h_24()
- 13
-
-* ``ampm()`` returns the appropriate time modifier (am or pm):
-
- >>> dt.ampm()
- 'pm'
-
-* ``hour()`` returns the 24-hour clock representation of the hour:
-
- >>> dt.hour()
- 13
-
-* ``minute()`` returns the minute:
-
- >>> dt.minute()
- 45
-
-* ``second()`` returns the second:
-
- >>> dt.second() == 0
- True
-
-* ``millis()`` returns the milliseconds since the epoch in GMT.
-
- >>> dt.millis() == 857933100000
- True
-
-strftime()
-~~~~~~~~~~
-
-See ``tests/test_datetime.py``.
-
-General formats from previous DateTime
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* ``Date()`` return the date string for the object:
-
- >>> dt.Date()
- '1997/03/09'
-
-* ``Time()`` returns the time string for an object to the nearest
- second:
-
- >>> dt.Time()
- '13:45:00'
-
-* ``TimeMinutes()`` returns the time string for an object not showing
- seconds:
-
- >>> dt.TimeMinutes()
- '13:45'
-
-* ``AMPM()`` returns the time string for an object to the nearest second:
-
- >>> dt.AMPM()
- '01:45:00 pm'
-
-* ``AMPMMinutes()`` returns the time string for an object not showing
- seconds:
-
- >>> dt.AMPMMinutes()
- '01:45 pm'
-
-* ``PreciseTime()`` returns the time string for the object:
-
- >>> dt.PreciseTime()
- '13:45:00.000'
-
-* ``PreciseAMPM()`` returns the time string for the object:
-
- >>> dt.PreciseAMPM()
- '01:45:00.000 pm'
-
-* ``yy()`` returns the calendar year as a 2 digit string
-
- >>> dt.yy()
- '97'
-
-* ``mm()`` returns the month as a 2 digit string
-
- >>> dt.mm()
- '03'
-
-* ``dd()`` returns the day as a 2 digit string:
-
- >>> dt.dd()
- '09'
-
-* ``rfc822()`` returns the date in RFC 822 format:
-
- >>> dt.rfc822()
- 'Sun, 09 Mar 1997 13:45:00 -0500'
-
-New formats
-~~~~~~~~~~~
-
-* ``fCommon()`` returns a string representing the object's value in
- the format: March 9, 1997 1:45 pm:
-
- >>> dt.fCommon()
- 'March 9, 1997 1:45 pm'
-
-* ``fCommonZ()`` returns a string representing the object's value in
- the format: March 9, 1997 1:45 pm US/Eastern:
-
- >>> dt.fCommonZ()
- 'March 9, 1997 1:45 pm US/Eastern'
-
-* ``aCommon()`` returns a string representing the object's value in
- the format: Mar 9, 1997 1:45 pm:
-
- >>> dt.aCommon()
- 'Mar 9, 1997 1:45 pm'
-
-* ``aCommonZ()`` return a string representing the object's value in
- the format: Mar 9, 1997 1:45 pm US/Eastern:
-
- >>> dt.aCommonZ()
- 'Mar 9, 1997 1:45 pm US/Eastern'
-
-* ``pCommon()`` returns a string representing the object's value in
- the format Mar. 9, 1997 1:45 pm:
-
- >>> dt.pCommon()
- 'Mar. 9, 1997 1:45 pm'
-
-* ``pCommonZ()`` returns a string representing the object's value in
- the format: Mar. 9, 1997 1:45 pm US/Eastern:
-
- >>> dt.pCommonZ()
- 'Mar. 9, 1997 1:45 pm US/Eastern'
-
-* ``ISO()`` returns a string with the date/time in ISO format. Note:
- this is not ISO 8601-format! See the ISO8601 and HTML4 methods below
- for ISO 8601-compliant output. Dates are output as: YYYY-MM-DD HH:MM:SS
-
- >>> dt.ISO()
- '1997-03-09 13:45:00'
-
-* ``ISO8601()`` returns the object in ISO 8601-compatible format
- containing the date, time with seconds-precision and the time zone
- identifier - see http://www.w3.org/TR/NOTE-datetime. Dates are
- output as: YYYY-MM-DDTHH:MM:SSTZD (T is a literal character, TZD is
- Time Zone Designator, format +HH:MM or -HH:MM).
-
- The ``HTML4()`` method below offers the same formatting, but
- converts to UTC before returning the value and sets the TZD"Z"
-
- >>> dt.ISO8601()
- '1997-03-09T13:45:00-05:00'
-
-
-* ``HTML4()`` returns the object in the format used in the HTML4.0
- specification, one of the standard forms in ISO8601. See
- http://www.w3.org/TR/NOTE-datetime. Dates are output as:
- YYYY-MM-DDTHH:MM:SSZ (T, Z are literal characters, the time is in
- UTC.):
-
- >>> dt.HTML4()
- '1997-03-09T18:45:00Z'
-
-* ``JulianDay()`` returns the Julian day according to
- http://www.tondering.dk/claus/cal/node3.html#sec-calcjd
-
- >>> dt.JulianDay()
- 2450517
-
-* ``week()`` returns the week number according to ISO
- see http://www.tondering.dk/claus/cal/node6.html#SECTION00670000000000000000
-
- >>> dt.week()
- 10
-
-Deprecated API
-~~~~~~~~~~~~~~
-
-* DayOfWeek(): see Day()
-
-* Day_(): see pDay()
-
-* Mon(): see aMonth()
-
-* Mon_(): see pMonth
-
-General Services Provided by DateTime
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-DateTimes can be repr()'ed; the result will be a string indicating how
-to make a DateTime object like this:
-
- >>> repr(dt)
- "DateTime('1997/03/09 13:45:00 US/Eastern')"
-
-When we convert them into a string, we get a nicer string that could
-actually be shown to a user:
-
- >>> str(dt)
- '1997/03/09 13:45:00 US/Eastern'
-
-The hash value of a DateTime is based on the date and time and is
-equal for different representations of the DateTime:
-
- >>> hash(dt)
- 3618678
- >>> hash(dt.toZone('UTC'))
- 3618678
-
-DateTime objects can be compared to other DateTime objects OR floating
-point numbers such as the ones which are returned by the python time
-module by using the equalTo method. Using this API, True is returned if the
-object represents a date/time equal to the specified DateTime or time module
-style time:
-
- >>> dt.equalTo(dt)
- True
- >>> dt.equalTo(dt.toZone('UTC'))
- True
- >>> dt.equalTo(dt.timeTime())
- True
- >>> dt.equalTo(DateTime())
- False
-
-Same goes for inequalities:
-
- >>> dt.notEqualTo(dt)
- False
- >>> dt.notEqualTo(dt.toZone('UTC'))
- False
- >>> dt.notEqualTo(dt.timeTime())
- False
- >>> dt.notEqualTo(DateTime())
- True
-
-Normal equality operations only work with datetime objects and take the
-timezone setting into account:
-
- >>> dt == dt
- True
- >>> dt == dt.toZone('UTC')
- False
- >>> dt == DateTime()
- False
-
- >>> dt != dt
- False
- >>> dt != dt.toZone('UTC')
- True
- >>> dt != DateTime()
- True
-
-But the other comparison operations compare the referenced moment in time and
-not the representation itself:
-
- >>> dt > dt
- False
- >>> DateTime() > dt
- True
- >>> dt > DateTime().timeTime()
- False
- >>> DateTime().timeTime() > dt
- True
-
- >>> dt.greaterThan(dt)
- False
- >>> DateTime().greaterThan(dt)
- True
- >>> dt.greaterThan(DateTime().timeTime())
- False
-
- >>> dt >= dt
- True
- >>> DateTime() >= dt
- True
- >>> dt >= DateTime().timeTime()
- False
- >>> DateTime().timeTime() >= dt
- True
-
- >>> dt.greaterThanEqualTo(dt)
- True
- >>> DateTime().greaterThanEqualTo(dt)
- True
- >>> dt.greaterThanEqualTo(DateTime().timeTime())
- False
-
- >>> dt < dt
- False
- >>> DateTime() < dt
- False
- >>> dt < DateTime().timeTime()
- True
- >>> DateTime().timeTime() < dt
- False
-
- >>> dt.lessThan(dt)
- False
- >>> DateTime().lessThan(dt)
- False
- >>> dt.lessThan(DateTime().timeTime())
- True
-
- >>> dt <= dt
- True
- >>> DateTime() <= dt
- False
- >>> dt <= DateTime().timeTime()
- True
- >>> DateTime().timeTime() <= dt
- False
-
- >>> dt.lessThanEqualTo(dt)
- True
- >>> DateTime().lessThanEqualTo(dt)
- False
- >>> dt.lessThanEqualTo(DateTime().timeTime())
- True
-
-Numeric Services Provided by DateTime
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A DateTime may be added to a number and a number may be added to a
-DateTime:
-
- >>> dt + 5
- DateTime('1997/03/14 13:45:00 US/Eastern')
- >>> 5 + dt
- DateTime('1997/03/14 13:45:00 US/Eastern')
-
-Two DateTimes cannot be added:
-
- >>> from DateTime.interfaces import DateTimeError
- >>> try:
- ... dt + dt
- ... print('fail')
- ... except DateTimeError:
- ... print('ok')
- ok
-
-Either a DateTime or a number may be subtracted from a DateTime,
-however, a DateTime may not be subtracted from a number:
-
- >>> DateTime('1997/03/10 13:45 US/Eastern') - dt
- 1.0
- >>> dt - 1
- DateTime('1997/03/08 13:45:00 US/Eastern')
- >>> 1 - dt
- Traceback (most recent call last):
- ...
- TypeError: unsupported operand type(s) for -: 'int' and 'DateTime'
-
-DateTimes can also be converted to integers (number of seconds since
-the epoch) and floats:
-
- >>> int(dt)
- 857933100
- >>> float(dt)
- 857933100.0
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/__init__.py b/server/venv/lib/python3.7/site-packages/DateTime/__init__.py
deleted file mode 100644
index b4181ad..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2002 Zope Foundation and Contributors.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
-#
-##############################################################################
-
-from .DateTime import DateTime
-from .DateTime import Timezones
-
-__all__ = ('DateTime', 'Timezones')
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/DateTime.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/DateTime.cpython-37.pyc
deleted file mode 100644
index b60b4f4..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/DateTime.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index cb8cbfd..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/interfaces.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/interfaces.cpython-37.pyc
deleted file mode 100644
index 819d0fe..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/interfaces.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/pytz_support.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/pytz_support.cpython-37.pyc
deleted file mode 100644
index 60d0eb4..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/__pycache__/pytz_support.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/interfaces.py b/server/venv/lib/python3.7/site-packages/DateTime/interfaces.py
deleted file mode 100644
index 5f29cff..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/interfaces.py
+++ /dev/null
@@ -1,375 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2005 Zope Foundation and Contributors.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
-#
-##############################################################################
-from zope.interface import Interface
-
-
-class DateTimeError(Exception):
- pass
-
-
-class SyntaxError(DateTimeError):
- pass
-
-
-class DateError(DateTimeError):
- pass
-
-
-class TimeError(DateTimeError):
- pass
-
-
-class IDateTime(Interface):
- # Conversion and comparison methods
-
- #TODO determine whether this method really is part of the public API
- def localZone(ltm=None):
- '''Returns the time zone on the given date. The time zone
- can change according to daylight savings.'''
-
- def timeTime():
- """Return the date/time as a floating-point number in UTC, in
- the format used by the python time module. Note that it is
- possible to create date/time values with DateTime that have no
- meaningful value to the time module."""
-
- def toZone(z):
- """Return a DateTime with the value as the current object,
- represented in the indicated timezone."""
-
- def isFuture():
- """Return true if this object represents a date/time later
- than the time of the call"""
-
- def isPast():
- """Return true if this object represents a date/time earlier
- than the time of the call"""
-
- def isCurrentYear():
- """Return true if this object represents a date/time that
- falls within the current year, in the context of this
- object's timezone representation"""
-
- def isCurrentMonth():
- """Return true if this object represents a date/time that
- falls within the current month, in the context of this
- object's timezone representation"""
-
- def isCurrentDay():
- """Return true if this object represents a date/time that
- falls within the current day, in the context of this object's
- timezone representation"""
-
- def isCurrentHour():
- """Return true if this object represents a date/time that
- falls within the current hour, in the context of this object's
- timezone representation"""
-
- def isCurrentMinute():
- """Return true if this object represents a date/time that
- falls within the current minute, in the context of this
- object's timezone representation"""
-
- def isLeapYear():
- """Return true if the current year (in the context of the
- object's timezone) is a leap year"""
-
- def earliestTime():
- """Return a new DateTime object that represents the earliest
- possible time (in whole seconds) that still falls within the
- current object's day, in the object's timezone context"""
-
- def latestTime():
- """Return a new DateTime object that represents the latest
- possible time (in whole seconds) that still falls within the
- current object's day, in the object's timezone context"""
-
- def greaterThan(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time greater than the specified DateTime or time module
- style time. Revised to give more correct results through
- comparison of long integer milliseconds."""
-
- __gt__ = greaterThan
-
- def greaterThanEqualTo(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time greater than or equal to the specified DateTime or
- time module style time. Revised to give more correct results
- through comparison of long integer milliseconds."""
-
- __ge__ = greaterThanEqualTo
-
- def equalTo(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time equal to the specified DateTime or time module style
- time. Revised to give more correct results through comparison
- of long integer milliseconds."""
-
- __eq__ = equalTo
-
- def notEqualTo(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time not equal to the specified DateTime or time module
- style time. Revised to give more correct results through
- comparison of long integer milliseconds."""
-
- __ne__ = notEqualTo
-
- def lessThan(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time less than the specified DateTime or time module
- style time. Revised to give more correct results through
- comparison of long integer milliseconds."""
-
- __lt__ = lessThan
-
- def lessThanEqualTo(t):
- """Compare this DateTime object to another DateTime object OR
- a floating point number such as that which is returned by the
- python time module. Returns true if the object represents a
- date/time less than or equal to the specified DateTime or time
- module style time. Revised to give more correct results
- through comparison of long integer milliseconds."""
-
- __le__ = lessThanEqualTo
-
- # Component access
-
- def parts():
- """Return a tuple containing the calendar year, month, day,
- hour, minute second and timezone of the object"""
-
- def timezone():
- """Return the timezone in which the object is represented."""
-
- def tzoffset():
- """Return the timezone offset for the objects timezone."""
-
- def year():
- """Return the calendar year of the object"""
-
- def month():
- """Return the month of the object as an integer"""
-
- def Month():
- """Return the full month name"""
-
- def aMonth():
- """Return the abreviated month name."""
-
- def Mon():
- """Compatibility: see aMonth"""
-
- def pMonth():
- """Return the abreviated (with period) month name."""
-
- def Mon_():
- """Compatibility: see pMonth"""
-
- def day():
- """Return the integer day"""
-
- def Day():
- """Return the full name of the day of the week"""
-
- def DayOfWeek():
- """Compatibility: see Day"""
-
- def dayOfYear():
- """Return the day of the year, in context of the timezone
- representation of the object"""
-
- def aDay():
- """Return the abreviated name of the day of the week"""
-
- def pDay():
- """Return the abreviated (with period) name of the day of the
- week"""
-
- def Day_():
- """Compatibility: see pDay"""
-
- def dow():
- """Return the integer day of the week, where sunday is 0"""
-
- def dow_1():
- """Return the integer day of the week, where sunday is 1"""
-
- def h_12():
- """Return the 12-hour clock representation of the hour"""
-
- def h_24():
- """Return the 24-hour clock representation of the hour"""
-
- def ampm():
- """Return the appropriate time modifier (am or pm)"""
-
- def hour():
- """Return the 24-hour clock representation of the hour"""
-
- def minute():
- """Return the minute"""
-
- def second():
- """Return the second"""
-
- def millis():
- """Return the millisecond since the epoch in GMT."""
-
- def strftime(format):
- """Format the date/time using the *current timezone representation*."""
-
- # General formats from previous DateTime
-
- def Date():
- """Return the date string for the object."""
-
- def Time():
- """Return the time string for an object to the nearest second."""
-
- def TimeMinutes():
- """Return the time string for an object not showing seconds."""
-
- def AMPM():
- """Return the time string for an object to the nearest second."""
-
- def AMPMMinutes():
- """Return the time string for an object not showing seconds."""
-
- def PreciseTime():
- """Return the time string for the object."""
-
- def PreciseAMPM():
- """Return the time string for the object."""
-
- def yy():
- """Return calendar year as a 2 digit string"""
-
- def mm():
- """Return month as a 2 digit string"""
-
- def dd():
- """Return day as a 2 digit string"""
-
- def rfc822():
- """Return the date in RFC 822 format"""
-
- # New formats
-
- def fCommon():
- """Return a string representing the object's value in the
- format: March 1, 1997 1:45 pm"""
-
- def fCommonZ():
- """Return a string representing the object's value in the
- format: March 1, 1997 1:45 pm US/Eastern"""
-
- def aCommon():
- """Return a string representing the object's value in the
- format: Mar 1, 1997 1:45 pm"""
-
- def aCommonZ():
- """Return a string representing the object's value in the
- format: Mar 1, 1997 1:45 pm US/Eastern"""
-
- def pCommon():
- """Return a string representing the object's value in the
- format: Mar. 1, 1997 1:45 pm"""
-
- def pCommonZ():
- """Return a string representing the object's value
- in the format: Mar. 1, 1997 1:45 pm US/Eastern"""
-
- def ISO():
- """Return the object in ISO standard format. Note: this is
- *not* ISO 8601-format! See the ISO8601 and HTML4 methods below
- for ISO 8601-compliant output
-
- Dates are output as: YYYY-MM-DD HH:MM:SS
- """
-
- def ISO8601():
- """Return the object in ISO 8601-compatible format containing
- the date, time with seconds-precision and the time zone
- identifier - see http://www.w3.org/TR/NOTE-datetime
-
- Dates are output as: YYYY-MM-DDTHH:MM:SSTZD
- T is a literal character.
- TZD is Time Zone Designator, format +HH:MM or -HH:MM
-
- The HTML4 method below offers the same formatting, but
- converts to UTC before returning the value and sets the TZD"Z"
- """
-
- def HTML4():
- """Return the object in the format used in the HTML4.0
- specification, one of the standard forms in ISO8601. See
- http://www.w3.org/TR/NOTE-datetime
-
- Dates are output as: YYYY-MM-DDTHH:MM:SSZ
- T, Z are literal characters.
- The time is in UTC.
- """
-
- def JulianDay():
- """Return the Julian day according to
- http://www.tondering.dk/claus/cal/node3.html#sec-calcjd
- """
-
- def week():
- """Return the week number according to ISO
- see http://www.tondering.dk/claus/cal/node6.html#SECTION00670000000000000000
- """
-
- # Python operator and conversion API
-
- def __add__(other):
- """A DateTime may be added to a number and a number may be
- added to a DateTime; two DateTimes cannot be added."""
-
- __radd__ = __add__
-
- def __sub__(other):
- """Either a DateTime or a number may be subtracted from a
- DateTime, however, a DateTime may not be subtracted from a
- number."""
-
- def __repr__():
- """Convert a DateTime to a string that looks like a Python
- expression."""
-
- def __str__():
- """Convert a DateTime to a string."""
-
- def __hash__():
- """Compute a hash value for a DateTime"""
-
- def __int__():
- """Convert to an integer number of seconds since the epoch (gmt)"""
-
- def __long__():
- """Convert to a long-int number of seconds since the epoch (gmt)"""
-
- def __float__():
- """Convert to floating-point number of seconds since the epoch (gmt)"""
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/pytz.txt b/server/venv/lib/python3.7/site-packages/DateTime/pytz.txt
deleted file mode 100644
index 33de811..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/pytz.txt
+++ /dev/null
@@ -1,192 +0,0 @@
-Pytz Support
-============
-
-Allows the pytz package to be used for time zone information. The
-advantage of using pytz is that it has a more complete and up to date
-time zone and daylight savings time database.
-
-Usage
------
-You don't have to do anything special to make it work.
-
- >>> from DateTime import DateTime, Timezones
- >>> d = DateTime('March 11, 2007 US/Eastern')
-
-Daylight Savings
-----------------
-In 2007 daylight savings time in the US was changed. The Energy Policy
-Act of 2005 mandates that DST will start on the second Sunday in March
-and end on the first Sunday in November.
-
-In 2007, the start and stop dates are March 11 and November 4,
-respectively. These dates are different from previous DST start and
-stop dates. In 2006, the dates were the first Sunday in April (April
-2, 2006) and the last Sunday in October (October 29, 2006).
-
-Let's make sure that DateTime can deal with this, since the primary
-motivation to use pytz for time zone information is the fact that it
-is kept up to date with daylight savings changes.
-
- >>> DateTime('March 11, 2007 US/Eastern').tzoffset()
- -18000
- >>> DateTime('March 12, 2007 US/Eastern').tzoffset()
- -14400
- >>> DateTime('November 4, 2007 US/Eastern').tzoffset()
- -14400
- >>> DateTime('November 5, 2007 US/Eastern').tzoffset()
- -18000
-
-Let's compare this to 2006.
-
- >>> DateTime('April 2, 2006 US/Eastern').tzoffset()
- -18000
- >>> DateTime('April 3, 2006 US/Eastern').tzoffset()
- -14400
- >>> DateTime('October 29, 2006 US/Eastern').tzoffset()
- -14400
- >>> DateTime('October 30, 2006 US/Eastern').tzoffset()
- -18000
-
-Time Zones
----------
-DateTime can use pytz's large database of time zones. Here are some
-examples:
-
- >>> d = DateTime('Pacific/Kwajalein')
- >>> d = DateTime('America/Shiprock')
- >>> d = DateTime('Africa/Ouagadougou')
-
-Of course pytz doesn't know about everything.
-
- >>> from DateTime.interfaces import SyntaxError
- >>> try:
- ... d = DateTime('July 21, 1969 Moon/Eastern')
- ... print('fail')
- ... except SyntaxError:
- ... print('ok')
- ok
-
-You can still use zone names that DateTime defines that aren't part of
-the pytz database.
-
- >>> d = DateTime('eet')
- >>> d = DateTime('iceland')
-
-These time zones use DateTimes database. So it's preferable to use the
-official time zone name.
-
-One trickiness is that DateTime supports some zone name
-abbreviations. Some of these map to pytz names, so these abbreviations
-will give you time zone date from pytz. Notable among abbreviations
-that work this way are 'est', 'cst', 'mst', and 'pst'.
-
-Let's verify that 'est' picks up the 2007 daylight savings time changes.
-
- >>> DateTime('March 11, 2007 est').tzoffset()
- -18000
- >>> DateTime('March 12, 2007 est').tzoffset()
- -14400
- >>> DateTime('November 4, 2007 est').tzoffset()
- -14400
- >>> DateTime('November 5, 2007 est').tzoffset()
- -18000
-
-You can get a list of time zones supported by calling the Timezones() function.
-
- >>> Timezones() #doctest: +ELLIPSIS
- ['Africa/Abidjan', 'Africa/Accra', 'Africa/Addis_Ababa', ...]
-
-Note that you can mess with this list without hurting things.
-
- >>> t = Timezones()
- >>> t.remove('US/Eastern')
- >>> d = DateTime('US/Eastern')
-
-
-Internal Components
--------------------
-
-The following are tests of internal components.
-
-Cache
-~~~~~
-
-The DateTime class uses a new time zone cache.
-
- >>> from DateTime.DateTime import _TZINFO
- >>> _TZINFO #doctest: +ELLIPSIS
-
-
-The cache maps time zone names to time zone instances.
-
- >>> cache = _TZINFO
- >>> tz = cache['GMT+730']
- >>> tz = cache['US/Mountain']
-
-The cache also must provide a few attributes for use by the DateTime
-class.
-
-The _zlst attribute is a list of supported time zone names.
-
- >>> cache._zlst #doctest: +ELLIPSIS
- ['Africa/Abidjan'... 'Africa/Accra'... 'IDLE'... 'NZST'... 'NZT'...]
-
-The _zidx attribute is a list of lower-case and possibly abbreviated
-time zone names that can be mapped to offical zone names.
-
- >>> 'australia/yancowinna' in cache._zidx
- True
- >>> 'europe/isle_of_man' in cache._zidx
- True
- >>> 'gmt+0500' in cache._zidx
- True
-
-Note that there are more items in _zidx than in _zlst since there are
-multiple names for some time zones.
-
- >>> len(cache._zidx) > len(cache._zlst)
- True
-
-Each entry in _zlst should also be present in _zidx in lower case form.
-
- >>> for name in cache._zlst:
- ... if not name.lower() in cache._zidx:
- ... print("Error %s not in _zidx" % name.lower())
-
-The _zmap attribute maps the names in _zidx to official names in _zlst.
-
- >>> cache._zmap['africa/abidjan']
- 'Africa/Abidjan'
- >>> cache._zmap['gmt+1']
- 'GMT+1'
- >>> cache._zmap['gmt+0100']
- 'GMT+1'
- >>> cache._zmap['utc']
- 'UTC'
-
-Let's make sure that _zmap and _zidx agree.
-
- >>> idx = set(cache._zidx)
- >>> keys = set(cache._zmap.keys())
- >>> idx == keys
- True
-
-Timezone objects
-~~~~~~~~~~~~~~~~
-The timezone instances have only one public method info(). It returns
-a tuple of (offset, is_dst, name). The method takes a timestamp, which
-is used to determine dst information.
-
- >>> t1 = DateTime('November 4, 00:00 2007 US/Mountain').timeTime()
- >>> t2 = DateTime('November 4, 02:00 2007 US/Mountain').timeTime()
- >>> tz.info(t1)
- (-21600, 1, 'MDT')
- >>> tz.info(t2)
- (-25200, 0, 'MST')
-
-If you don't pass any arguments to info it provides daylight savings
-time information as of today.
-
- >>> tz.info() in ((-21600, 1, 'MDT'), (-25200, 0, 'MST'))
- True
-
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/pytz_support.py b/server/venv/lib/python3.7/site-packages/DateTime/pytz_support.py
deleted file mode 100644
index 8cfbfc5..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/pytz_support.py
+++ /dev/null
@@ -1,259 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 Zope Foundation and Contributors.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE
-#
-##############################################################################
-
-from datetime import datetime, timedelta
-
-import pytz
-import pytz.reference
-from pytz.tzinfo import StaticTzInfo, memorized_timedelta
-
-from .interfaces import DateTimeError
-
-EPOCH = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
-
-_numeric_timezone_data = {
- 'GMT': ('GMT', 0, 1, [], '', [(0, 0, 0)], 'GMT\000'),
- 'GMT+0': ('GMT+0', 0, 1, [], '', [(0, 0, 0)], 'GMT+0000\000'),
- 'GMT+1': ('GMT+1', 0, 1, [], '', [(3600, 0, 0)], 'GMT+0100\000'),
- 'GMT+2': ('GMT+2', 0, 1, [], '', [(7200, 0, 0)], 'GMT+0200\000'),
- 'GMT+3': ('GMT+3', 0, 1, [], '', [(10800, 0, 0)], 'GMT+0300\000'),
- 'GMT+4': ('GMT+4', 0, 1, [], '', [(14400, 0, 0)], 'GMT+0400\000'),
- 'GMT+5': ('GMT+5', 0, 1, [], '', [(18000, 0, 0)], 'GMT+0500\000'),
- 'GMT+6': ('GMT+6', 0, 1, [], '', [(21600, 0, 0)], 'GMT+0600\000'),
- 'GMT+7': ('GMT+7', 0, 1, [], '', [(25200, 0, 0)], 'GMT+0700\000'),
- 'GMT+8': ('GMT+8', 0, 1, [], '', [(28800, 0, 0)], 'GMT+0800\000'),
- 'GMT+9': ('GMT+9', 0, 1, [], '', [(32400, 0, 0)], 'GMT+0900\000'),
- 'GMT+10': ('GMT+10', 0, 1, [], '', [(36000, 0, 0)], 'GMT+1000\000'),
- 'GMT+11': ('GMT+11', 0, 1, [], '', [(39600, 0, 0)], 'GMT+1100\000'),
- 'GMT+12': ('GMT+12', 0, 1, [], '', [(43200, 0, 0)], 'GMT+1200\000'),
- 'GMT+13': ('GMT+13', 0, 1, [], '', [(46800, 0, 0)], 'GMT+1300\000'),
-
- 'GMT-1': ('GMT-1', 0, 1, [], '', [(-3600, 0, 0)], 'GMT-0100\000'),
- 'GMT-2': ('GMT-2', 0, 1, [], '', [(-7200, 0, 0)], 'GMT-0200\000'),
- 'GMT-3': ('GMT-3', 0, 1, [], '', [(-10800, 0, 0)], 'GMT-0300\000'),
- 'GMT-4': ('GMT-4', 0, 1, [], '', [(-14400, 0, 0)], 'GMT-0400\000'),
- 'GMT-5': ('GMT-5', 0, 1, [], '', [(-18000, 0, 0)], 'GMT-0500\000'),
- 'GMT-6': ('GMT-6', 0, 1, [], '', [(-21600, 0, 0)], 'GMT-0600\000'),
- 'GMT-7': ('GMT-7', 0, 1, [], '', [(-25200, 0, 0)], 'GMT-0700\000'),
- 'GMT-8': ('GMT-8', 0, 1, [], '', [(-28800, 0, 0)], 'GMT-0800\000'),
- 'GMT-9': ('GMT-9', 0, 1, [], '', [(-32400, 0, 0)], 'GMT-0900\000'),
- 'GMT-10': ('GMT-10', 0, 1, [], '', [(-36000, 0, 0)], 'GMT-1000\000'),
- 'GMT-11': ('GMT-11', 0, 1, [], '', [(-39600, 0, 0)], 'GMT-1100\000'),
- 'GMT-12': ('GMT-12', 0, 1, [], '', [(-43200, 0, 0)], 'GMT-1200\000'),
-
- 'GMT+0130': ('GMT+0130', 0, 1, [], '', [(5400, 0, 0)], 'GMT+0130\000'),
- 'GMT+0230': ('GMT+0230', 0, 1, [], '', [(9000, 0, 0)], 'GMT+0230\000'),
- 'GMT+0330': ('GMT+0330', 0, 1, [], '', [(12600, 0, 0)], 'GMT+0330\000'),
- 'GMT+0430': ('GMT+0430', 0, 1, [], '', [(16200, 0, 0)], 'GMT+0430\000'),
- 'GMT+0530': ('GMT+0530', 0, 1, [], '', [(19800, 0, 0)], 'GMT+0530\000'),
- 'GMT+0630': ('GMT+0630', 0, 1, [], '', [(23400, 0, 0)], 'GMT+0630\000'),
- 'GMT+0730': ('GMT+0730', 0, 1, [], '', [(27000, 0, 0)], 'GMT+0730\000'),
- 'GMT+0830': ('GMT+0830', 0, 1, [], '', [(30600, 0, 0)], 'GMT+0830\000'),
- 'GMT+0930': ('GMT+0930', 0, 1, [], '', [(34200, 0, 0)], 'GMT+0930\000'),
- 'GMT+1030': ('GMT+1030', 0, 1, [], '', [(37800, 0, 0)], 'GMT+1030\000'),
- 'GMT+1130': ('GMT+1130', 0, 1, [], '', [(41400, 0, 0)], 'GMT+1130\000'),
- 'GMT+1230': ('GMT+1230', 0, 1, [], '', [(45000, 0, 0)], 'GMT+1230\000'),
-
- 'GMT-0130': ('GMT-0130', 0, 1, [], '', [(-5400, 0, 0)], 'GMT-0130\000'),
- 'GMT-0230': ('GMT-0230', 0, 1, [], '', [(-9000, 0, 0)], 'GMT-0230\000'),
- 'GMT-0330': ('GMT-0330', 0, 1, [], '', [(-12600, 0, 0)], 'GMT-0330\000'),
- 'GMT-0430': ('GMT-0430', 0, 1, [], '', [(-16200, 0, 0)], 'GMT-0430\000'),
- 'GMT-0530': ('GMT-0530', 0, 1, [], '', [(-19800, 0, 0)], 'GMT-0530\000'),
- 'GMT-0630': ('GMT-0630', 0, 1, [], '', [(-23400, 0, 0)], 'GMT-0630\000'),
- 'GMT-0730': ('GMT-0730', 0, 1, [], '', [(-27000, 0, 0)], 'GMT-0730\000'),
- 'GMT-0830': ('GMT-0830', 0, 1, [], '', [(-30600, 0, 0)], 'GMT-0830\000'),
- 'GMT-0930': ('GMT-0930', 0, 1, [], '', [(-34200, 0, 0)], 'GMT-0930\000'),
- 'GMT-1030': ('GMT-1030', 0, 1, [], '', [(-37800, 0, 0)], 'GMT-1030\000'),
- 'GMT-1130': ('GMT-1130', 0, 1, [], '', [(-41400, 0, 0)], 'GMT-1130\000'),
- 'GMT-1230': ('GMT-1230', 0, 1, [], '', [(-45000, 0, 0)], 'GMT-1230\000'),
-}
-
-# These are the timezones not in pytz.common_timezones
-_old_zlst = [
- 'AST', 'AT', 'BST', 'BT', 'CCT',
- 'CET', 'CST', 'Cuba', 'EADT', 'EAST',
- 'EEST', 'EET', 'EST', 'Egypt', 'FST',
- 'FWT', 'GB-Eire', 'GMT+0100', 'GMT+0130', 'GMT+0200',
- 'GMT+0230', 'GMT+0300', 'GMT+0330', 'GMT+0400', 'GMT+0430',
- 'GMT+0500', 'GMT+0530', 'GMT+0600', 'GMT+0630', 'GMT+0700',
- 'GMT+0730', 'GMT+0800', 'GMT+0830', 'GMT+0900', 'GMT+0930',
- 'GMT+1', 'GMT+1000', 'GMT+1030', 'GMT+1100', 'GMT+1130',
- 'GMT+1200', 'GMT+1230', 'GMT+1300', 'GMT-0100', 'GMT-0130',
- 'GMT-0200', 'GMT-0300', 'GMT-0400', 'GMT-0500', 'GMT-0600',
- 'GMT-0630', 'GMT-0700', 'GMT-0730', 'GMT-0800', 'GMT-0830',
- 'GMT-0900', 'GMT-0930', 'GMT-1000', 'GMT-1030', 'GMT-1100',
- 'GMT-1130', 'GMT-1200', 'GMT-1230', 'GST', 'Greenwich',
- 'Hongkong', 'IDLE', 'IDLW', 'Iceland', 'Iran',
- 'Israel', 'JST', 'Jamaica', 'Japan', 'MEST',
- 'MET', 'MEWT', 'MST', 'NT', 'NZDT',
- 'NZST', 'NZT', 'PST', 'Poland', 'SST',
- 'SWT', 'Singapore', 'Turkey', 'UCT', 'UT',
- 'Universal', 'WADT', 'WAST', 'WAT', 'WET',
- 'ZP4', 'ZP5', 'ZP6',
-]
-
-_old_zmap = {
- 'aest': 'GMT+10', 'aedt': 'GMT+11',
- 'aus eastern standard time': 'GMT+10',
- 'sydney standard time': 'GMT+10',
- 'tasmania standard time': 'GMT+10',
- 'e. australia standard time': 'GMT+10',
- 'aus central standard time': 'GMT+0930',
- 'cen. australia standard time': 'GMT+0930',
- 'w. australia standard time': 'GMT+8',
-
- 'central europe standard time': 'GMT+1',
- 'eastern standard time': 'US/Eastern',
- 'us eastern standard time': 'US/Eastern',
- 'central standard time': 'US/Central',
- 'mountain standard time': 'US/Mountain',
- 'pacific standard time': 'US/Pacific',
- 'mst': 'US/Mountain', 'pst': 'US/Pacific',
- 'cst': 'US/Central', 'est': 'US/Eastern',
-
- 'gmt+0000': 'GMT+0', 'gmt+0': 'GMT+0',
-
- 'gmt+0100': 'GMT+1', 'gmt+0200': 'GMT+2', 'gmt+0300': 'GMT+3',
- 'gmt+0400': 'GMT+4', 'gmt+0500': 'GMT+5', 'gmt+0600': 'GMT+6',
- 'gmt+0700': 'GMT+7', 'gmt+0800': 'GMT+8', 'gmt+0900': 'GMT+9',
- 'gmt+1000': 'GMT+10', 'gmt+1100': 'GMT+11', 'gmt+1200': 'GMT+12',
- 'gmt+1300': 'GMT+13',
- 'gmt-0100': 'GMT-1', 'gmt-0200': 'GMT-2', 'gmt-0300': 'GMT-3',
- 'gmt-0400': 'GMT-4', 'gmt-0500': 'GMT-5', 'gmt-0600': 'GMT-6',
- 'gmt-0700': 'GMT-7', 'gmt-0800': 'GMT-8', 'gmt-0900': 'GMT-9',
- 'gmt-1000': 'GMT-10', 'gmt-1100': 'GMT-11', 'gmt-1200': 'GMT-12',
-
- 'gmt+1': 'GMT+1', 'gmt+2': 'GMT+2', 'gmt+3': 'GMT+3',
- 'gmt+4': 'GMT+4', 'gmt+5': 'GMT+5', 'gmt+6': 'GMT+6',
- 'gmt+7': 'GMT+7', 'gmt+8': 'GMT+8', 'gmt+9': 'GMT+9',
- 'gmt+10': 'GMT+10', 'gmt+11': 'GMT+11', 'gmt+12': 'GMT+12',
- 'gmt+13': 'GMT+13',
- 'gmt-1': 'GMT-1', 'gmt-2': 'GMT-2', 'gmt-3': 'GMT-3',
- 'gmt-4': 'GMT-4', 'gmt-5': 'GMT-5', 'gmt-6': 'GMT-6',
- 'gmt-7': 'GMT-7', 'gmt-8': 'GMT-8', 'gmt-9': 'GMT-9',
- 'gmt-10': 'GMT-10', 'gmt-11': 'GMT-11', 'gmt-12': 'GMT-12',
-
- 'gmt+130': 'GMT+0130', 'gmt+0130': 'GMT+0130',
- 'gmt+230': 'GMT+0230', 'gmt+0230': 'GMT+0230',
- 'gmt+330': 'GMT+0330', 'gmt+0330': 'GMT+0330',
- 'gmt+430': 'GMT+0430', 'gmt+0430': 'GMT+0430',
- 'gmt+530': 'GMT+0530', 'gmt+0530': 'GMT+0530',
- 'gmt+630': 'GMT+0630', 'gmt+0630': 'GMT+0630',
- 'gmt+730': 'GMT+0730', 'gmt+0730': 'GMT+0730',
- 'gmt+830': 'GMT+0830', 'gmt+0830': 'GMT+0830',
- 'gmt+930': 'GMT+0930', 'gmt+0930': 'GMT+0930',
- 'gmt+1030': 'GMT+1030',
- 'gmt+1130': 'GMT+1130',
- 'gmt+1230': 'GMT+1230',
-
- 'gmt-130': 'GMT-0130', 'gmt-0130': 'GMT-0130',
- 'gmt-230': 'GMT-0230', 'gmt-0230': 'GMT-0230',
- 'gmt-330': 'GMT-0330', 'gmt-0330': 'GMT-0330',
- 'gmt-430': 'GMT-0430', 'gmt-0430': 'GMT-0430',
- 'gmt-530': 'GMT-0530', 'gmt-0530': 'GMT-0530',
- 'gmt-630': 'GMT-0630', 'gmt-0630': 'GMT-0630',
- 'gmt-730': 'GMT-0730', 'gmt-0730': 'GMT-0730',
- 'gmt-830': 'GMT-0830', 'gmt-0830': 'GMT-0830',
- 'gmt-930': 'GMT-0930', 'gmt-0930': 'GMT-0930',
- 'gmt-1030': 'GMT-1030',
- 'gmt-1130': 'GMT-1130',
- 'gmt-1230': 'GMT-1230',
-
- 'ut': 'Universal',
- 'bst': 'GMT+1', 'mest': 'GMT+2', 'sst': 'GMT+2',
- 'fst': 'GMT+2', 'wadt': 'GMT+8', 'eadt': 'GMT+11', 'nzdt': 'GMT+13',
- 'wet': 'GMT', 'wat': 'GMT-1', 'at': 'GMT-2', 'ast': 'GMT-4',
- 'nt': 'GMT-11', 'idlw': 'GMT-12', 'cet': 'GMT+1', 'cest': 'GMT+2',
- 'met': 'GMT+1',
- 'mewt': 'GMT+1', 'swt': 'GMT+1', 'fwt': 'GMT+1', 'eet': 'GMT+2',
- 'eest': 'GMT+3',
- 'bt': 'GMT+3', 'zp4': 'GMT+4', 'zp5': 'GMT+5', 'zp6': 'GMT+6',
- 'wast': 'GMT+7', 'cct': 'GMT+8', 'jst': 'GMT+9', 'east': 'GMT+10',
- 'gst': 'GMT+10', 'nzt': 'GMT+12', 'nzst': 'GMT+12', 'idle': 'GMT+12',
- 'ret': 'GMT+4', 'ist': 'GMT+0530', 'edt': 'GMT-4',
-
-}
-
-
-# some timezone definitions of the "-0400" are not working
-# when upgrading
-for hour in range(0, 13):
- hour = hour
- fhour = str(hour)
- if len(fhour) == 1:
- fhour = '0' + fhour
- _old_zmap['-%s00' % fhour] = 'GMT-%i' % hour
- _old_zmap['+%s00' % fhour] = 'GMT+%i' % hour
-
-
-def _static_timezone_factory(data):
- zone = data[0]
- cls = type(zone, (StaticTzInfo,), dict(
- zone=zone,
- _utcoffset=memorized_timedelta(data[5][0][0]),
- _tzname=data[6][:-1])) # strip the trailing null
- return cls()
-
-_numeric_timezones = dict((key, _static_timezone_factory(data))
- for key, data in _numeric_timezone_data.items())
-
-
-class Timezone:
- """
- Timezone information returned by PytzCache.__getitem__
- Adapts datetime.tzinfo object to DateTime._timezone interface
- """
- def __init__(self, tzinfo):
- self.tzinfo = tzinfo
-
- def info(self, t=None):
- if t is None:
- dt = datetime.utcnow().replace(tzinfo=pytz.utc)
- else:
- # can't use utcfromtimestamp past 2038
- dt = EPOCH + timedelta(0, t)
-
- # need to normalize tzinfo for the datetime to deal with
- # daylight savings time.
- normalized_dt = self.tzinfo.normalize(dt.astimezone(self.tzinfo))
- normalized_tzinfo = normalized_dt.tzinfo
-
- offset = normalized_tzinfo.utcoffset(normalized_dt)
- secs = offset.days * 24 * 60 * 60 + offset.seconds
- dst = normalized_tzinfo.dst(normalized_dt)
- if dst == timedelta(0):
- is_dst = 0
- else:
- is_dst = 1
- return secs, is_dst, normalized_tzinfo.tzname(normalized_dt)
-
-
-class PytzCache:
- """
- Reimplementation of the DateTime._cache class that uses for timezone info
- """
-
- _zlst = pytz.common_timezones + _old_zlst # used by DateTime.TimeZones
- _zmap = dict((name.lower(), name) for name in pytz.all_timezones)
- _zmap.update(_old_zmap) # These must take priority
- _zidx = _zmap.keys()
-
- def __getitem__(self, key):
- name = self._zmap.get(key.lower(), key) # fallback to key
- try:
- return Timezone(pytz.timezone(name))
- except pytz.UnknownTimeZoneError:
- try:
- return Timezone(_numeric_timezones[name])
- except KeyError:
- raise DateTimeError('Unrecognized timezone: %s' % key)
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/tests/__init__.py b/server/venv/lib/python3.7/site-packages/DateTime/tests/__init__.py
deleted file mode 100644
index e67bcb6..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/tests/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-
-# This file is needed to make this a package.
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 1be1ea2..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/test_datetime.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/test_datetime.cpython-37.pyc
deleted file mode 100644
index 9a60bc1..0000000
Binary files a/server/venv/lib/python3.7/site-packages/DateTime/tests/__pycache__/test_datetime.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/tests/julian_testdata.txt b/server/venv/lib/python3.7/site-packages/DateTime/tests/julian_testdata.txt
deleted file mode 100644
index 386c3da..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/tests/julian_testdata.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-1970-01-01 (1970, 1, 4)
-1970-01-02 (1970, 1, 5)
-1970-01-30 (1970, 5, 5)
-1970-01-31 (1970, 5, 6)
-1970-02-01 (1970, 5, 7)
-1970-02-02 (1970, 6, 1)
-1970-02-28 (1970, 9, 6)
-1970-03-01 (1970, 9, 7)
-1970-03-30 (1970, 14, 1)
-1970-03-31 (1970, 14, 2)
-1970-04-01 (1970, 14, 3)
-1970-09-30 (1970, 40, 3)
-1970-10-01 (1970, 40, 4)
-1970-10-02 (1970, 40, 5)
-1970-10-03 (1970, 40, 6)
-1970-10-04 (1970, 40, 7)
-1970-10-05 (1970, 41, 1)
-1971-01-02 (1970, 53, 6)
-1971-01-03 (1970, 53, 7)
-1971-01-04 (1971, 1, 1)
-1971-01-05 (1971, 1, 2)
-1971-12-31 (1971, 52, 5)
-1972-01-01 (1971, 52, 6)
-1972-01-02 (1971, 52, 7)
-1972-01-03 (1972, 1, 1)
-1972-01-04 (1972, 1, 2)
-1972-12-30 (1972, 52, 6)
-1972-12-31 (1972, 52, 7)
-1973-01-01 (1973, 1, 1)
-1973-01-02 (1973, 1, 2)
-1973-12-29 (1973, 52, 6)
-1973-12-30 (1973, 52, 7)
-1973-12-31 (1974, 1, 1)
-1974-01-01 (1974, 1, 2)
-1998-12-30 (1998, 53, 3)
-1998-12-31 (1998, 53, 4)
-1999-01-01 (1998, 53, 5)
-1999-01-02 (1998, 53, 6)
-1999-01-03 (1998, 53, 7)
-1999-01-04 (1999, 1, 1)
-1999-01-05 (1999, 1, 2)
-1999-12-30 (1999, 52, 4)
-1999-12-31 (1999, 52, 5)
-2000-01-01 (1999, 52, 6)
-2000-01-02 (1999, 52, 7)
-2000-01-03 (2000, 1, 1)
-2000-01-04 (2000, 1, 2)
-2000-01-05 (2000, 1, 3)
-2000-01-06 (2000, 1, 4)
-2000-01-07 (2000, 1, 5)
-2000-01-08 (2000, 1, 6)
-2000-01-09 (2000, 1, 7)
-2000-01-10 (2000, 2, 1)
-2019-12-28 (2019, 52, 6)
-2019-12-29 (2019, 52, 7)
-2019-12-30 (2020, 1, 1)
-2019-12-31 (2020, 1, 2)
diff --git a/server/venv/lib/python3.7/site-packages/DateTime/tests/test_datetime.py b/server/venv/lib/python3.7/site-packages/DateTime/tests/test_datetime.py
deleted file mode 100644
index 7172adb..0000000
--- a/server/venv/lib/python3.7/site-packages/DateTime/tests/test_datetime.py
+++ /dev/null
@@ -1,686 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2003 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-
-from datetime import date, datetime, tzinfo, timedelta
-import math
-import platform
-import os
-import sys
-import time
-import unittest
-
-import pytz
-
-from DateTime.DateTime import _findLocalTimeZoneName
-from DateTime import DateTime
-
-if sys.version_info > (3, ):
- import pickle
- unicode = str
- PY3K = True
-else:
- import cPickle as pickle
- PY3K = False
-
-try:
- __file__
-except NameError:
- f = sys.argv[0]
-else:
- f = __file__
-
-IS_PYPY = getattr(platform, 'python_implementation', lambda: None)() == 'PyPy'
-
-DATADIR = os.path.dirname(os.path.abspath(f))
-del f
-
-ZERO = timedelta(0)
-
-
-class FixedOffset(tzinfo):
- """Fixed offset in minutes east from UTC."""
-
- def __init__(self, offset, name):
- self.__offset = timedelta(minutes=offset)
- self.__name = name
-
- def utcoffset(self, dt):
- return self.__offset
-
- def tzname(self, dt):
- return self.__name
-
- def dst(self, dt):
- return ZERO
-
-
-class DateTimeTests(unittest.TestCase):
-
- def _compare(self, dt1, dt2):
- '''Compares the internal representation of dt1 with
- the representation in dt2. Allows sub-millisecond variations.
- Primarily for testing.'''
- self.assertEqual(round(dt1._t, 3), round(dt2._t, 3))
- self.assertEqual(round(dt1._d, 9), round(dt2._d, 9))
- self.assertEqual(round(dt1.time, 9), round(dt2.time, 9))
- self.assertEqual(dt1.millis(), dt2.millis())
- self.assertEqual(dt1._micros, dt2._micros)
-
- def testBug1203(self):
- # 01:59:60 occurred in old DateTime
- dt = DateTime(7200, 'GMT')
- self.assertTrue(str(dt).find('60') < 0, dt)
-
- def testDSTInEffect(self):
- # Checks GMT offset for a DST date in the US/Eastern time zone
- dt = DateTime(2000, 5, 9, 15, 0, 0, 'US/Eastern')
- self.assertEqual(dt.toZone('GMT').hour(), 19,
- (dt, dt.toZone('GMT')))
-
- def testDSTNotInEffect(self):
- # Checks GMT offset for a non-DST date in the US/Eastern time zone
- dt = DateTime(2000, 11, 9, 15, 0, 0, 'US/Eastern')
- self.assertEqual(dt.toZone('GMT').hour(), 20,
- (dt, dt.toZone('GMT')))
-
- def testAddPrecision(self):
- # Precision of serial additions
- dt = DateTime()
- self.assertEqual(str(dt + 0.10 + 3.14 + 6.76 - 10), str(dt),
- dt)
-
- def testConstructor3(self):
- # Constructor from date/time string
- dt = DateTime()
- dt1s = '%d/%d/%d %d:%d:%f %s' % (
- dt.year(),
- dt.month(),
- dt.day(),
- dt.hour(),
- dt.minute(),
- dt.second(),
- dt.timezone())
- dt1 = DateTime(dt1s)
- # Compare representations as it's the
- # only way to compare the dates to the same accuracy
- self.assertEqual(repr(dt), repr(dt1))
-
- def testConstructor4(self):
- # Constructor from time float
- dt = DateTime()
- dt1 = DateTime(float(dt))
- self._compare(dt, dt1)
-
- def testConstructor5(self):
- # Constructor from time float and timezone
- dt = DateTime()
- dt1 = DateTime(float(dt), dt.timezone())
- self.assertEqual(str(dt), str(dt1), (dt, dt1))
- dt1 = DateTime(float(dt), unicode(dt.timezone()))
- self.assertEqual(str(dt), str(dt1), (dt, dt1))
-
- def testConstructor6(self):
- # Constructor from year and julian date
- # This test must normalize the time zone, or it *will* break when
- # DST changes!
- dt1 = DateTime(2000, 5.500000578705)
- dt = DateTime('2000/1/5 12:00:00.050 pm %s' % dt1.localZone())
- self._compare(dt, dt1)
-
- def testConstructor7(self):
- # Constructor from parts
- dt = DateTime()
- dt1 = DateTime(
- dt.year(),
- dt.month(),
- dt.day(),
- dt.hour(),
- dt.minute(),
- dt.second(),
- dt.timezone())
- # Compare representations as it's the
- # only way to compare the dates to the same accuracy
- self.assertEqual(repr(dt), repr(dt1))
-
- def testDayOfWeek(self):
- # Compare to the datetime.date value to make it locale independent
- expected = date(2000, 6, 16).strftime('%A')
- # strftime() used to always be passed a day of week of 0
- dt = DateTime('2000/6/16')
- s = dt.strftime('%A')
- self.assertEqual(s, expected, (dt, s))
-
- def testOldDate(self):
- # Fails when an 1800 date is displayed with negative signs
- dt = DateTime('1830/5/6 12:31:46.213 pm')
- dt1 = dt.toZone('GMT+6')
- self.assertTrue(str(dt1).find('-') < 0, (dt, dt1))
-
- def testSubtraction(self):
- # Reconstruction of a DateTime from its parts, with subtraction
- # this also tests the accuracy of addition and reconstruction
- dt = DateTime()
- dt1 = dt - 3.141592653
- dt2 = DateTime(
- dt.year(),
- dt.month(),
- dt.day(),
- dt.hour(),
- dt.minute(),
- dt.second())
- dt3 = dt2 - 3.141592653
- self.assertEqual(dt1, dt3, (dt, dt1, dt2, dt3))
-
- def testTZ1add(self):
- # Time zone manipulation: add to a date
- dt = DateTime('1997/3/8 1:45am GMT-4')
- dt1 = DateTime('1997/3/9 1:45pm GMT+8')
- self.assertTrue((dt + 1.0).equalTo(dt1))
-
- def testTZ1sub(self):
- # Time zone manipulation: subtract from a date
- dt = DateTime('1997/3/8 1:45am GMT-4')
- dt1 = DateTime('1997/3/9 1:45pm GMT+8')
- self.assertTrue((dt1 - 1.0).equalTo(dt))
-
- def testTZ1diff(self):
- # Time zone manipulation: diff two dates
- dt = DateTime('1997/3/8 1:45am GMT-4')
- dt1 = DateTime('1997/3/9 1:45pm GMT+8')
- self.assertEqual(dt1 - dt, 1.0, (dt, dt1))
-
- def test_compare_methods(self):
- # Compare two dates using several methods
- dt = DateTime('1997/1/1')
- dt1 = DateTime('1997/2/2')
- self.assertTrue(dt1.greaterThan(dt))
- self.assertTrue(dt1.greaterThanEqualTo(dt))
- self.assertTrue(dt.lessThan(dt1))
- self.assertTrue(dt.lessThanEqualTo(dt1))
- self.assertTrue(dt.notEqualTo(dt1))
- self.assertFalse(dt.equalTo(dt1))
-
- def test_compare_methods_none(self):
- # Compare a date to None
- dt = DateTime('1997/1/1')
- self.assertTrue(dt.greaterThan(None))
- self.assertTrue(dt.greaterThanEqualTo(None))
- self.assertFalse(dt.lessThan(None))
- self.assertFalse(dt.lessThanEqualTo(None))
- self.assertTrue(dt.notEqualTo(None))
- self.assertFalse(dt.equalTo(None))
-
- def test_pickle(self):
- dt = DateTime()
- data = pickle.dumps(dt, 1)
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def test_pickle_with_tz(self):
- dt = DateTime('2002/5/2 8:00am GMT+8')
- data = pickle.dumps(dt, 1)
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def test_pickle_with_numerical_tz(self):
- for dt_str in ('2007/01/02 12:34:56.789 +0300',
- '2007/01/02 12:34:56.789 +0430',
- '2007/01/02 12:34:56.789 -1234'):
- dt = DateTime(dt_str)
- data = pickle.dumps(dt, 1)
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def test_pickle_with_micros(self):
- dt = DateTime('2002/5/2 8:00:14.123 GMT+8')
- data = pickle.dumps(dt, 1)
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def test_pickle_old(self):
- dt = DateTime('2002/5/2 8:00am GMT+0')
- data = ('(cDateTime.DateTime\nDateTime\nq\x01Noq\x02}q\x03(U\x05'
- '_amonq\x04U\x03Mayq\x05U\x05_adayq\x06U\x03Thuq\x07U\x05_pmonq'
- '\x08h\x05U\x05_hourq\tK\x08U\x05_fmonq\nh\x05U\x05_pdayq\x0bU'
- '\x04Thu.q\x0cU\x05_fdayq\rU\x08Thursdayq\x0eU\x03_pmq\x0fU\x02amq'
- '\x10U\x02_tq\x11GA\xcehy\x00\x00\x00\x00U\x07_minuteq\x12K\x00U'
- '\x07_microsq\x13L1020326400000000L\nU\x02_dq\x14G@\xe2\x12j\xaa'
- '\xaa\xaa\xabU\x07_secondq\x15G\x00\x00\x00\x00\x00\x00\x00\x00U'
- '\x03_tzq\x16U\x05GMT+0q\x17U\x06_monthq\x18K\x05U'
- '\x0f_timezone_naiveq\x19I00\nU\x04_dayq\x1aK\x02U\x05_yearq'
- '\x1bM\xd2\x07U\x08_nearsecq\x1cG\x00\x00\x00\x00\x00\x00\x00'
- '\x00U\x07_pmhourq\x1dK\x08U\n_dayoffsetq\x1eK\x04U\x04timeq'
- '\x1fG?\xd5UUUV\x00\x00ub.')
- if PY3K:
- data = data.encode('latin-1')
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def test_pickle_old_without_micros(self):
- dt = DateTime('2002/5/2 8:00am GMT+0')
- data = ('(cDateTime.DateTime\nDateTime\nq\x01Noq\x02}q\x03(U\x05'
- '_amonq\x04U\x03Mayq\x05U\x05_adayq\x06U\x03Thuq\x07U\x05_pmonq'
- '\x08h\x05U\x05_hourq\tK\x08U\x05_fmonq\nh\x05U\x05_pdayq\x0bU'
- '\x04Thu.q\x0cU\x05_fdayq\rU\x08Thursdayq\x0eU\x03_pmq\x0fU'
- '\x02amq\x10U\x02_tq\x11GA\xcehy\x00\x00\x00\x00U\x07_minuteq'
- '\x12K\x00U\x02_dq\x13G@\xe2\x12j\xaa\xaa\xaa\xabU\x07_secondq'
- '\x14G\x00\x00\x00\x00\x00\x00\x00\x00U\x03_tzq\x15U\x05GMT+0q'
- '\x16U\x06_monthq\x17K\x05U\x0f_timezone_naiveq\x18I00\nU'
- '\x04_dayq\x19K\x02U\x05_yearq\x1aM\xd2\x07U\x08_nearsecq'
- '\x1bG\x00\x00\x00\x00\x00\x00\x00\x00U\x07_pmhourq\x1cK\x08U'
- '\n_dayoffsetq\x1dK\x04U\x04timeq\x1eG?\xd5UUUV\x00\x00ub.')
- if PY3K:
- data = data.encode('latin-1')
- new = pickle.loads(data)
- for key in DateTime.__slots__:
- self.assertEqual(getattr(dt, key), getattr(new, key))
-
- def testTZ2(self):
- # Time zone manipulation test 2
- dt = DateTime()
- dt1 = dt.toZone('GMT')
- s = dt.second()
- s1 = dt1.second()
- self.assertEqual(s, s1, (dt, dt1, s, s1))
-
- def testTZDiffDaylight(self):
- # Diff dates across daylight savings dates
- dt = DateTime('2000/6/8 1:45am US/Eastern')
- dt1 = DateTime('2000/12/8 12:45am US/Eastern')
- self.assertEqual(dt1 - dt, 183, (dt, dt1, dt1 - dt))
-
- def testY10KDate(self):
- # Comparison of a Y10K date and a Y2K date
- dt = DateTime('10213/09/21')
- dt1 = DateTime(2000, 1, 1)
-
- dsec = (dt.millis() - dt1.millis()) / 1000.0
- ddays = math.floor((dsec / 86400.0) + 0.5)
-
- self.assertEqual(ddays, 3000000, ddays)
-
- def test_tzoffset(self):
- # Test time-zone given as an offset
-
- # GMT
- dt = DateTime('Tue, 10 Sep 2001 09:41:03 GMT')
- self.assertEqual(dt.tzoffset(), 0)
-
- # Timezone by name, a timezone that hasn't got daylightsaving.
- dt = DateTime('Tue, 2 Mar 2001 09:41:03 GMT+3')
- self.assertEqual(dt.tzoffset(), 10800)
-
- # Timezone by name, has daylightsaving but is not in effect.
- dt = DateTime('Tue, 21 Jan 2001 09:41:03 PST')
- self.assertEqual(dt.tzoffset(), -28800)
-
- # Timezone by name, with daylightsaving in effect
- dt = DateTime('Tue, 24 Aug 2001 09:41:03 PST')
- self.assertEqual(dt.tzoffset(), -25200)
-
- # A negative numerical timezone
- dt = DateTime('Tue, 24 Jul 2001 09:41:03 -0400')
- self.assertEqual(dt.tzoffset(), -14400)
-
- # A positive numerical timzone
- dt = DateTime('Tue, 6 Dec 1966 01:41:03 +0200')
- self.assertEqual(dt.tzoffset(), 7200)
-
- # A negative numerical timezone with minutes.
- dt = DateTime('Tue, 24 Jul 2001 09:41:03 -0637')
- self.assertEqual(dt.tzoffset(), -23820)
-
- # A positive numerical timezone with minutes.
- dt = DateTime('Tue, 24 Jul 2001 09:41:03 +0425')
- self.assertEqual(dt.tzoffset(), 15900)
-
- def testISO8601(self):
- # ISO8601 reference dates
- ref0 = DateTime('2002/5/2 8:00am GMT')
- ref1 = DateTime('2002/5/2 8:00am US/Eastern')
- ref2 = DateTime('2006/11/6 10:30 GMT')
- ref3 = DateTime('2004/06/14 14:30:15 GMT-3')
- ref4 = DateTime('2006/01/01 GMT')
-
- # Basic tests
- # Though this is timezone naive and according to specification should
- # be interpreted in the local timezone, to preserve backwards
- # compatibility with previously expected behaviour.
- isoDt = DateTime('2002-05-02T08:00:00')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-05-02T08:00:00Z')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-05-02T08:00:00+00:00')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-05-02T08:00:00-04:00')
- self.assertTrue(ref1.equalTo(isoDt))
- isoDt = DateTime('2002-05-02 08:00:00-04:00')
- self.assertTrue(ref1.equalTo(isoDt))
-
- # Bug 1386: the colon in the timezone offset is optional
- isoDt = DateTime('2002-05-02T08:00:00-0400')
- self.assertTrue(ref1.equalTo(isoDt))
-
- # Bug 2191: date reduced formats
- isoDt = DateTime('2006-01-01')
- self.assertTrue(ref4.equalTo(isoDt))
- isoDt = DateTime('200601-01')
- self.assertTrue(ref4.equalTo(isoDt))
- isoDt = DateTime('20060101')
- self.assertTrue(ref4.equalTo(isoDt))
- isoDt = DateTime('2006-01')
- self.assertTrue(ref4.equalTo(isoDt))
- isoDt = DateTime('200601')
- self.assertTrue(ref4.equalTo(isoDt))
- isoDt = DateTime('2006')
- self.assertTrue(ref4.equalTo(isoDt))
-
- # Bug 2191: date/time separators are also optional
- isoDt = DateTime('20020502T08:00:00')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-05-02T080000')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('20020502T080000')
- self.assertTrue(ref0.equalTo(isoDt))
-
- # Bug 2191: timezones with only one digit for hour
- isoDt = DateTime('20020502T080000+0')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('20020502 080000-4')
- self.assertTrue(ref1.equalTo(isoDt))
- isoDt = DateTime('20020502T080000-400')
- self.assertTrue(ref1.equalTo(isoDt))
- isoDt = DateTime('20020502T080000-4:00')
- self.assertTrue(ref1.equalTo(isoDt))
-
- # Bug 2191: optional seconds/minutes
- isoDt = DateTime('2002-05-02T0800')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-05-02T08')
- self.assertTrue(ref0.equalTo(isoDt))
-
- # Bug 2191: week format
- isoDt = DateTime('2002-W18-4T0800')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002-W184T0800')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002W18-4T0800')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002W184T08')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2004-W25-1T14:30:15-03:00')
- self.assertTrue(ref3.equalTo(isoDt))
- isoDt = DateTime('2004-W25T14:30:15-03:00')
- self.assertTrue(ref3.equalTo(isoDt))
-
- # Bug 2191: day of year format
- isoDt = DateTime('2002-122T0800')
- self.assertTrue(ref0.equalTo(isoDt))
- isoDt = DateTime('2002122T0800')
- self.assertTrue(ref0.equalTo(isoDt))
-
- # Bug 2191: hours/minutes fractions
- isoDt = DateTime('2006-11-06T10.5')
- self.assertTrue(ref2.equalTo(isoDt))
- isoDt = DateTime('2006-11-06T10,5')
- self.assertTrue(ref2.equalTo(isoDt))
- isoDt = DateTime('20040614T1430.25-3')
- self.assertTrue(ref3.equalTo(isoDt))
- isoDt = DateTime('2004-06-14T1430,25-3')
- self.assertTrue(ref3.equalTo(isoDt))
- isoDt = DateTime('2004-06-14T14:30.25-3')
- self.assertTrue(ref3.equalTo(isoDt))
- isoDt = DateTime('20040614T14:30,25-3')
- self.assertTrue(ref3.equalTo(isoDt))
-
- # ISO8601 standard format
- iso8601_string = '2002-05-02T08:00:00-04:00'
- iso8601DT = DateTime(iso8601_string)
- self.assertEqual(iso8601_string, iso8601DT.ISO8601())
-
- # ISO format with no timezone
- isoDt = DateTime('2006-01-01 00:00:00')
- self.assertTrue(ref4.equalTo(isoDt))
-
- def testJulianWeek(self):
- # Check JulianDayWeek function
- fn = os.path.join(DATADIR, 'julian_testdata.txt')
- with open(fn, 'r') as fd:
- lines = fd.readlines()
- for line in lines:
- d = DateTime(line[:10])
- result_from_mx = tuple(map(int, line[12:-2].split(',')))
- self.assertEqual(result_from_mx[1], d.week())
-
- def testCopyConstructor(self):
- d = DateTime('2004/04/04')
- self.assertEqual(DateTime(d), d)
- self.assertEqual(str(DateTime(d)), str(d))
- d2 = DateTime('1999/04/12 01:00:00')
- self.assertEqual(DateTime(d2), d2)
- self.assertEqual(str(DateTime(d2)), str(d2))
-
- def testCopyConstructorPreservesTimezone(self):
- # test for https://bugs.launchpad.net/zope2/+bug/200007
- # This always worked in the local timezone, so we need at least
- # two tests with different zones to be sure at least one of them
- # is not local.
- d = DateTime('2004/04/04')
- self.assertEqual(DateTime(d).timezone(), d.timezone())
- d2 = DateTime('2008/04/25 12:00:00 EST')
- self.assertEqual(DateTime(d2).timezone(), d2.timezone())
- self.assertEqual(str(DateTime(d2)), str(d2))
- d3 = DateTime('2008/04/25 12:00:00 PST')
- self.assertEqual(DateTime(d3).timezone(), d3.timezone())
- self.assertEqual(str(DateTime(d3)), str(d3))
-
- def testRFC822(self):
- # rfc822 conversion
- dt = DateTime('2002-05-02T08:00:00+00:00')
- self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0000')
-
- dt = DateTime('2002-05-02T08:00:00+02:00')
- self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0200')
-
- dt = DateTime('2002-05-02T08:00:00-02:00')
- self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 -0200')
-
- # Checking that conversion from local time is working.
- dt = DateTime()
- dts = dt.rfc822().split(' ')
- times = dts[4].split(':')
- _isDST = time.localtime(time.time())[8]
- if _isDST:
- offset = time.altzone
- else:
- offset = time.timezone
- self.assertEqual(dts[0], dt.aDay() + ',')
- self.assertEqual(int(dts[1]), dt.day())
- self.assertEqual(dts[2], dt.aMonth())
- self.assertEqual(int(dts[3]), dt.year())
- self.assertEqual(int(times[0]), dt.h_24())
- self.assertEqual(int(times[1]), dt.minute())
- self.assertEqual(int(times[2]), int(dt.second()))
- self.assertEqual(dts[5], "%+03d%02d" % divmod((-offset / 60), 60))
-
- def testInternationalDateformat(self):
- for year in (1990, 2001, 2020):
- for month in (1, 12):
- for day in (1, 12, 28, 31):
- try:
- d_us = DateTime("%d/%d/%d" % (year, month, day))
- except Exception:
- continue
-
- d_int = DateTime("%d.%d.%d" % (day, month, year),
- datefmt="international")
- self.assertEqual(d_us, d_int)
-
- d_int = DateTime("%d/%d/%d" % (day, month, year),
- datefmt="international")
- self.assertEqual(d_us, d_int)
-
- def test_intl_format_hyphen(self):
- d_jan = DateTime('2011-01-11 GMT')
- d_nov = DateTime('2011-11-01 GMT')
- d_us = DateTime('11-01-2011 GMT')
- d_int = DateTime('11-01-2011 GMT', datefmt="international")
- self.assertNotEqual(d_us, d_int)
- self.assertEqual(d_us, d_nov)
- self.assertEqual(d_int, d_jan)
-
- def test_calcTimezoneName(self):
- from DateTime.interfaces import TimeError
- timezone_dependent_epoch = 2177452800
- try:
- DateTime()._calcTimezoneName(timezone_dependent_epoch, 0)
- except TimeError:
- self.fail('Zope Collector issue #484 (negative time bug): '
- 'TimeError raised')
-
- def testStrftimeTZhandling(self):
- # strftime timezone testing
- # This is a test for collector issue #1127
- format = '%Y-%m-%d %H:%M %Z'
- dt = DateTime('Wed, 19 Nov 2003 18:32:07 -0215')
- dt_string = dt.strftime(format)
- dt_local = dt.toZone(_findLocalTimeZoneName(0))
- dt_localstring = dt_local.strftime(format)
- self.assertEqual(dt_string, dt_localstring)
-
- def testStrftimeFarDates(self):
- # Checks strftime in dates <= 1900 or >= 2038
- dt = DateTime('1900/01/30')
- self.assertEqual(dt.strftime('%d/%m/%Y'), '30/01/1900')
- dt = DateTime('2040/01/30')
- self.assertEqual(dt.strftime('%d/%m/%Y'), '30/01/2040')
-
- def testZoneInFarDates(self):
- # Checks time zone in dates <= 1900 or >= 2038
- dt1 = DateTime('2040/01/30 14:33 GMT+1')
- dt2 = DateTime('2040/01/30 11:33 GMT-2')
- self.assertEqual(dt1.strftime('%d/%m/%Y %H:%M'),
- dt2.strftime('%d/%m/%Y %H:%M'))
-
- def testStrftimeUnicode(self):
- if IS_PYPY:
- # Using Non-Ascii characters for strftime doesn't work in PyPy
- # https://bitbucket.org/pypy/pypy/issues/2161/pypy3-strftime-does-not-accept-unicode
- return
- dt = DateTime('2002-05-02T08:00:00+00:00')
- uchar = b'\xc3\xa0'.decode('utf-8')
- ok = dt.strftime('Le %d/%m/%Y a %Hh%M').replace('a', uchar)
- ustr = b'Le %d/%m/%Y \xc3\xa0 %Hh%M'.decode('utf-8')
- self.assertEqual(dt.strftime(ustr), ok)
-
- def testTimezoneNaiveHandling(self):
- # checks that we assign timezone naivity correctly
- dt = DateTime('2007-10-04T08:00:00+00:00')
- self.assertFalse(dt.timezoneNaive(),
- 'error with naivity handling in __parse_iso8601')
- dt = DateTime('2007-10-04T08:00:00Z')
- self.assertFalse(dt.timezoneNaive(),
- 'error with naivity handling in __parse_iso8601')
- dt = DateTime('2007-10-04T08:00:00')
- self.assertTrue(dt.timezoneNaive(),
- 'error with naivity handling in __parse_iso8601')
- dt = DateTime('2007/10/04 15:12:33.487618 GMT+1')
- self.assertFalse(dt.timezoneNaive(),
- 'error with naivity handling in _parse')
- dt = DateTime('2007/10/04 15:12:33.487618')
- self.assertTrue(dt.timezoneNaive(),
- 'error with naivity handling in _parse')
- dt = DateTime()
- self.assertFalse(dt.timezoneNaive(),
- 'error with naivity for current time')
- s = '2007-10-04T08:00:00'
- dt = DateTime(s)
- self.assertEqual(s, dt.ISO8601())
- s = '2007-10-04T08:00:00+00:00'
- dt = DateTime(s)
- self.assertEqual(s, dt.ISO8601())
-
- def testConversions(self):
- sdt0 = datetime.now() # this is a timezone naive datetime
- dt0 = DateTime(sdt0)
- self.assertTrue(dt0.timezoneNaive(), (sdt0, dt0))
- sdt1 = datetime(2007, 10, 4, 18, 14, 42, 580, pytz.utc)
- dt1 = DateTime(sdt1)
- self.assertFalse(dt1.timezoneNaive(), (sdt1, dt1))
-
- # convert back
- sdt2 = dt0.asdatetime()
- self.assertEqual(sdt0, sdt2)
- sdt3 = dt1.utcdatetime() # this returns a timezone naive datetime
- self.assertEqual(sdt1.hour, sdt3.hour)
-
- dt4 = DateTime('2007-10-04T10:00:00+05:00')
- sdt4 = datetime(2007, 10, 4, 5, 0)
- self.assertEqual(dt4.utcdatetime(), sdt4)
- self.assertEqual(dt4.asdatetime(), sdt4.replace(tzinfo=pytz.utc))
-
- dt5 = DateTime('2007-10-23 10:00:00 US/Eastern')
- tz = pytz.timezone('US/Eastern')
- sdt5 = datetime(2007, 10, 23, 10, 0, tzinfo=tz)
- dt6 = DateTime(sdt5)
- self.assertEqual(dt5.asdatetime(), sdt5)
- self.assertEqual(dt6.asdatetime(), sdt5)
- self.assertEqual(dt5, dt6)
- self.assertEqual(dt5.asdatetime().tzinfo, tz)
- self.assertEqual(dt6.asdatetime().tzinfo, tz)
-
- def testBasicTZ(self):
- # psycopg2 supplies it's own tzinfo instances, with no `zone` attribute
- tz = FixedOffset(60, 'GMT+1')
- dt1 = datetime(2008, 8, 5, 12, 0, tzinfo=tz)
- DT = DateTime(dt1)
- dt2 = DT.asdatetime()
- offset1 = dt1.tzinfo.utcoffset(dt1)
- offset2 = dt2.tzinfo.utcoffset(dt2)
- self.assertEqual(offset1, offset2)
-
- def testEDTTimezone(self):
- # should be able to parse EDT timezones: see lp:599856.
- dt = DateTime("Mon, 28 Jun 2010 10:12:25 EDT")
- self.assertEqual(dt.Day(), 'Monday')
- self.assertEqual(dt.day(), 28)
- self.assertEqual(dt.Month(), 'June')
- self.assertEqual(dt.timezone(), 'GMT-4')
-
- def testParseISO8601(self):
- parsed = DateTime()._parse_iso8601('2010-10-10')
- self.assertEqual(parsed, (2010, 10, 10, 0, 0, 0, 'GMT+0000'))
-
- def test_interface(self):
- from DateTime.interfaces import IDateTime
- self.assertTrue(IDateTime.providedBy(DateTime()))
-
- def test_security(self):
- dt = DateTime()
- self.assertEqual(dt.__roles__, None)
- self.assertEqual(dt.__allow_access_to_unprotected_subobjects__, 1)
-
-
-def test_suite():
- import doctest
- return unittest.TestSuite([
- unittest.makeSuite(DateTimeTests),
- doctest.DocFileSuite('DateTime.txt', package='DateTime'),
- doctest.DocFileSuite('pytz.txt', package='DateTime'),
- ])
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/INSTALLER b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/LICENSE.rst b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/LICENSE.rst
deleted file mode 100644
index 9d227a0..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2010 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/METADATA b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/METADATA
deleted file mode 100644
index 08fcc91..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/METADATA
+++ /dev/null
@@ -1,134 +0,0 @@
-Metadata-Version: 2.1
-Name: Flask
-Version: 1.1.1
-Summary: A simple framework for building complex web applications.
-Home-page: https://palletsprojects.com/p/flask/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Documentation, https://flask.palletsprojects.com/
-Project-URL: Code, https://github.com/pallets/flask
-Project-URL: Issue tracker, https://github.com/pallets/flask/issues
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Framework :: Flask
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
-Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
-Requires-Dist: Werkzeug (>=0.15)
-Requires-Dist: Jinja2 (>=2.10.1)
-Requires-Dist: itsdangerous (>=0.24)
-Requires-Dist: click (>=5.1)
-Provides-Extra: dev
-Requires-Dist: pytest ; extra == 'dev'
-Requires-Dist: coverage ; extra == 'dev'
-Requires-Dist: tox ; extra == 'dev'
-Requires-Dist: sphinx ; extra == 'dev'
-Requires-Dist: pallets-sphinx-themes ; extra == 'dev'
-Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'dev'
-Requires-Dist: sphinx-issues ; extra == 'dev'
-Provides-Extra: docs
-Requires-Dist: sphinx ; extra == 'docs'
-Requires-Dist: pallets-sphinx-themes ; extra == 'docs'
-Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'docs'
-Requires-Dist: sphinx-issues ; extra == 'docs'
-Provides-Extra: dotenv
-Requires-Dist: python-dotenv ; extra == 'dotenv'
-
-Flask
-=====
-
-Flask is a lightweight `WSGI`_ web application framework. It is designed
-to make getting started quick and easy, with the ability to scale up to
-complex applications. It began as a simple wrapper around `Werkzeug`_
-and `Jinja`_ and has become one of the most popular Python web
-application frameworks.
-
-Flask offers suggestions, but doesn't enforce any dependencies or
-project layout. It is up to the developer to choose the tools and
-libraries they want to use. There are many extensions provided by the
-community that make adding new functionality easy.
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- pip install -U Flask
-
-
-A Simple Example
-----------------
-
-.. code-block:: python
-
- from flask import Flask
-
- app = Flask(__name__)
-
- @app.route("/")
- def hello():
- return "Hello, World!"
-
-.. code-block:: text
-
- $ env FLASK_APP=hello.py flask run
- * Serving Flask app "hello"
- * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
-
-
-Contributing
-------------
-
-For guidance on setting up a development environment and how to make a
-contribution to Flask, see the `contributing guidelines`_.
-
-.. _contributing guidelines: https://github.com/pallets/flask/blob/master/CONTRIBUTING.rst
-
-
-Donate
-------
-
-The Pallets organization develops and supports Flask and the libraries
-it uses. In order to grow the community of contributors and users, and
-allow the maintainers to devote more time to the projects, `please
-donate today`_.
-
-.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20
-
-
-Links
------
-
-* Website: https://palletsprojects.com/p/flask/
-* Documentation: https://flask.palletsprojects.com/
-* Releases: https://pypi.org/project/Flask/
-* Code: https://github.com/pallets/flask
-* Issue tracker: https://github.com/pallets/flask/issues
-* Test status: https://dev.azure.com/pallets/flask/_build
-* Official chat: https://discord.gg/t6rrQZH
-
-.. _WSGI: https://wsgi.readthedocs.io
-.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
-.. _Jinja: https://www.palletsprojects.com/p/jinja/
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/RECORD b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/RECORD
deleted file mode 100644
index dfdc730..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/RECORD
+++ /dev/null
@@ -1,48 +0,0 @@
-../../../bin/flask,sha256=kSMgJ_jfOVGV1uX2njMuCOW6IurSDnDi1Ae0tYuEVtA,302
-Flask-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-Flask-1.1.1.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
-Flask-1.1.1.dist-info/METADATA,sha256=Ht4R6TpTKOaXOmmQHhEF3A0Obpzde2Ai0kzNdu6-VWQ,4400
-Flask-1.1.1.dist-info/RECORD,,
-Flask-1.1.1.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110
-Flask-1.1.1.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42
-Flask-1.1.1.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
-flask/__init__.py,sha256=qaBW4gy9Xxmdc3ygYO0_H214H1VpF7fq8xRR4XbqRjE,1894
-flask/__main__.py,sha256=fjVtt3QTANXlpJCOv3Ha7d5H-76MwzSIOab7SFD9TEk,254
-flask/__pycache__/__init__.cpython-37.pyc,,
-flask/__pycache__/__main__.cpython-37.pyc,,
-flask/__pycache__/_compat.cpython-37.pyc,,
-flask/__pycache__/app.cpython-37.pyc,,
-flask/__pycache__/blueprints.cpython-37.pyc,,
-flask/__pycache__/cli.cpython-37.pyc,,
-flask/__pycache__/config.cpython-37.pyc,,
-flask/__pycache__/ctx.cpython-37.pyc,,
-flask/__pycache__/debughelpers.cpython-37.pyc,,
-flask/__pycache__/globals.cpython-37.pyc,,
-flask/__pycache__/helpers.cpython-37.pyc,,
-flask/__pycache__/logging.cpython-37.pyc,,
-flask/__pycache__/sessions.cpython-37.pyc,,
-flask/__pycache__/signals.cpython-37.pyc,,
-flask/__pycache__/templating.cpython-37.pyc,,
-flask/__pycache__/testing.cpython-37.pyc,,
-flask/__pycache__/views.cpython-37.pyc,,
-flask/__pycache__/wrappers.cpython-37.pyc,,
-flask/_compat.py,sha256=8KPT54Iig96TuLipdogLRHNYToIcg-xPhnSV5VRERnw,4099
-flask/app.py,sha256=gLZInxueeQ9dkBo1wrntZ-bZqiDT4rYxy_AQ1xraFDc,98066
-flask/blueprints.py,sha256=vkdm8NusGsfZUeIfPdCluj733QFmiQcT4Sk1tuZLUjw,21400
-flask/cli.py,sha256=_WhPG1bggNdrP0QO95Vex6VJpDqTsVK0z54Y5poljKU,30933
-flask/config.py,sha256=3dejvQRYfNHw_V7dCLMxU8UNFpL34xIKemN7gHZIZ8Y,10052
-flask/ctx.py,sha256=cks-omGedkxawHFo6bKIrdOHsJCAgg1i_NWw_htxb5U,16724
-flask/debughelpers.py,sha256=-whvPKuAoU8AZ9c1z_INuOeBgfYDqE1J2xNBsoriugU,6475
-flask/globals.py,sha256=OgcHb6_NCyX6-TldciOdKcyj4PNfyQwClxdMhvov6aA,1637
-flask/helpers.py,sha256=x2Pa85R5dV6uA5f5423JTb6x4u6ZaMGf8sfosUZ76dQ,43004
-flask/json/__init__.py,sha256=6nITbZYiYOPB8Qfi1-dvsblwn01KRz8VOsMBIZyaYek,11988
-flask/json/__pycache__/__init__.cpython-37.pyc,,
-flask/json/__pycache__/tag.cpython-37.pyc,,
-flask/json/tag.py,sha256=vq9GOllg_0kTWKuVFrwmkeOQzR-jdBD23x-89JyCCQI,8306
-flask/logging.py,sha256=WcY5UkqTysGfmosyygSlXyZYGwOp3y-VsE6ehoJ48dk,3250
-flask/sessions.py,sha256=G0KsEkr_i1LG_wOINwFSOW3ts7Xbv4bNgEZKc7TRloc,14360
-flask/signals.py,sha256=yYLOed2x8WnQ7pirGalQYfpYpCILJ0LJhmNSrnWvjqw,2212
-flask/templating.py,sha256=F8E_IZXn9BGsjMzUJ5N_ACMyZdiFBp_SSEaUunvfZ7g,4939
-flask/testing.py,sha256=b0QaEejx0UcXqfSFP43k5W57bTVeDyrNK3uPD8JUpCk,10146
-flask/views.py,sha256=eeWnadLAj0QdQPLtjKipDetRZyG62CT2y7fNOFDJz0g,5802
-flask/wrappers.py,sha256=kgsvtZuMM6RQaDqhRbc5Pcj9vqTnaERl2pmXcdGL7LU,4736
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/WHEEL b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/WHEEL
deleted file mode 100644
index 78e6f69..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.33.4)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/entry_points.txt b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/entry_points.txt
deleted file mode 100644
index 1eb0252..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/entry_points.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-[console_scripts]
-flask = flask.cli:main
-
diff --git a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/top_level.txt b/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/top_level.txt
deleted file mode 100644
index 7e10602..0000000
--- a/server/venv/lib/python3.7/site-packages/Flask-1.1.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-flask
diff --git a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/INSTALLER b/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/LICENSE.rst b/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/LICENSE.rst
deleted file mode 100644
index c37cae4..0000000
--- a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/LICENSE.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-Copyright 2007 Pallets
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
-PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/METADATA b/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/METADATA
deleted file mode 100644
index 11c545a..0000000
--- a/server/venv/lib/python3.7/site-packages/Jinja2-2.10.3.dist-info/METADATA
+++ /dev/null
@@ -1,103 +0,0 @@
-Metadata-Version: 2.1
-Name: Jinja2
-Version: 2.10.3
-Summary: A very fast and expressive template engine.
-Home-page: https://palletsprojects.com/p/jinja/
-Author: Armin Ronacher
-Author-email: armin.ronacher@active-4.com
-Maintainer: Pallets
-Maintainer-email: contact@palletsprojects.com
-License: BSD-3-Clause
-Project-URL: Documentation, https://jinja.palletsprojects.com/
-Project-URL: Code, https://github.com/pallets/jinja
-Project-URL: Issue tracker, https://github.com/pallets/jinja/issues
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Text Processing :: Markup :: HTML
-Requires-Dist: MarkupSafe (>=0.23)
-Provides-Extra: i18n
-Requires-Dist: Babel (>=0.8) ; extra == 'i18n'
-
-Jinja
-=====
-
-Jinja is a fast, expressive, extensible templating engine. Special
-placeholders in the template allow writing code similar to Python
-syntax. Then the template is passed data to render the final document.
-
-It includes:
-
-- Template inheritance and inclusion.
-- Define and import macros within templates.
-- HTML templates can use autoescaping to prevent XSS from untrusted
- user input.
-- A sandboxed environment can safely render untrusted templates.
-- AsyncIO support for generating templates and calling async
- functions.
-- I18N support with Babel.
-- Templates are compiled to optimized Python code just-in-time and
- cached, or can be compiled ahead-of-time.
-- Exceptions point to the correct line in templates to make debugging
- easier.
-- Extensible filters, tests, functions, and even syntax.
-
-Jinja's philosophy is that while application logic belongs in Python if
-possible, it shouldn't make the template designer's job difficult by
-restricting functionality too much.
-
-
-Installing
-----------
-
-Install and update using `pip`_:
-
-.. code-block:: text
-
- $ pip install -U Jinja2
-
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
-
-
-In A Nutshell
--------------
-
-.. code-block:: jinja
-
- {% extends "base.html" %}
- {% block title %}Members{% endblock %}
- {% block content %}
-
"
- sorted_keys = sorted(self.keys, key=repr)
- for key in sorted_keys:
- output += "
{key!r}
".format(key=key)
- for d in iter(self):
- output += "
"
- for k in sorted_keys:
- output += "
{val!r}
".format(val=d[k])
- output += "
"
- output += "
"
- return output
-
- def by_key(self):
- """Values by key
-
- This returns the transposed values of the cycler. Iterating
- over a `Cycler` yields dicts with a single value for each key,
- this method returns a `dict` of `list` which are the values
- for the given key.
-
- The returned value can be used to create an equivalent `Cycler`
- using only `+`.
-
- Returns
- -------
- transpose : dict
- dict of lists of the values for each key.
- """
-
- # TODO : sort out if this is a bottle neck, if there is a better way
- # and if we care.
-
- keys = self.keys
- # change this to dict comprehension when drop 2.6
- out = dict((k, list()) for k in keys)
-
- for d in self:
- for k in keys:
- out[k].append(d[k])
- return out
-
- # for back compatibility
- _transpose = by_key
-
- def simplify(self):
- """Simplify the Cycler
-
- Returned as a composition using only sums (no multiplications)
-
- Returns
- -------
- simple : Cycler
- An equivalent cycler using only summation"""
- # TODO: sort out if it is worth the effort to make sure this is
- # balanced. Currently it is is
- # (((a + b) + c) + d) vs
- # ((a + b) + (c + d))
- # I would believe that there is some performance implications
-
- trans = self.by_key()
- return reduce(add, (_cycler(k, v) for k, v in six.iteritems(trans)))
-
- def concat(self, other):
- """Concatenate this cycler and an other.
-
- The keys must match exactly.
-
- This returns a single Cycler which is equivalent to
- `itertools.chain(self, other)`
-
- Examples
- --------
-
- >>> num = cycler('a', range(3))
- >>> let = cycler('a', 'abc')
- >>> num.concat(let)
- cycler('a', [0, 1, 2, 'a', 'b', 'c'])
-
- Parameters
- ----------
- other : `Cycler`
- The `Cycler` to concatenate to this one.
-
- Returns
- -------
- ret : `Cycler`
- The concatenated `Cycler`
- """
- return concat(self, other)
-
-
-def concat(left, right):
- """Concatenate two cyclers.
-
- The keys must match exactly.
-
- This returns a single Cycler which is equivalent to
- `itertools.chain(left, right)`
-
- Examples
- --------
-
- >>> num = cycler('a', range(3))
- >>> let = cycler('a', 'abc')
- >>> num.concat(let)
- cycler('a', [0, 1, 2, 'a', 'b', 'c'])
-
- Parameters
- ----------
- left, right : `Cycler`
- The two `Cycler` instances to concatenate
-
- Returns
- -------
- ret : `Cycler`
- The concatenated `Cycler`
- """
- if left.keys != right.keys:
- msg = '\n\t'.join(["Keys do not match:",
- "Intersection: {both!r}",
- "Disjoint: {just_one!r}"]).format(
- both=left.keys & right.keys,
- just_one=left.keys ^ right.keys)
-
- raise ValueError(msg)
-
- _l = left.by_key()
- _r = right.by_key()
- return reduce(add, (_cycler(k, _l[k] + _r[k]) for k in left.keys))
-
-
-def cycler(*args, **kwargs):
- """
- Create a new `Cycler` object from a single positional argument,
- a pair of positional arguments, or the combination of keyword arguments.
-
- cycler(arg)
- cycler(label1=itr1[, label2=iter2[, ...]])
- cycler(label, itr)
-
- Form 1 simply copies a given `Cycler` object.
-
- Form 2 composes a `Cycler` as an inner product of the
- pairs of keyword arguments. In other words, all of the
- iterables are cycled simultaneously, as if through zip().
-
- Form 3 creates a `Cycler` from a label and an iterable.
- This is useful for when the label cannot be a keyword argument
- (e.g., an integer or a name that has a space in it).
-
- Parameters
- ----------
- arg : Cycler
- Copy constructor for Cycler (does a shallow copy of iterables).
-
- label : name
- The property key. In the 2-arg form of the function,
- the label can be any hashable object. In the keyword argument
- form of the function, it must be a valid python identifier.
-
- itr : iterable
- Finite length iterable of the property values.
- Can be a single-property `Cycler` that would
- be like a key change, but as a shallow copy.
-
- Returns
- -------
- cycler : Cycler
- New `Cycler` for the given property
-
- """
- if args and kwargs:
- raise TypeError("cyl() can only accept positional OR keyword "
- "arguments -- not both.")
-
- if len(args) == 1:
- if not isinstance(args[0], Cycler):
- raise TypeError("If only one positional argument given, it must "
- " be a Cycler instance.")
- return Cycler(args[0])
- elif len(args) == 2:
- return _cycler(*args)
- elif len(args) > 2:
- raise TypeError("Only a single Cycler can be accepted as the lone "
- "positional argument. Use keyword arguments instead.")
-
- if kwargs:
- return reduce(add, (_cycler(k, v) for k, v in six.iteritems(kwargs)))
-
- raise TypeError("Must have at least a positional OR keyword arguments")
-
-
-def _cycler(label, itr):
- """
- Create a new `Cycler` object from a property name and
- iterable of values.
-
- Parameters
- ----------
- label : hashable
- The property key.
-
- itr : iterable
- Finite length iterable of the property values.
-
- Returns
- -------
- cycler : Cycler
- New `Cycler` for the given property
- """
- if isinstance(itr, Cycler):
- keys = itr.keys
- if len(keys) != 1:
- msg = "Can not create Cycler from a multi-property Cycler"
- raise ValueError(msg)
-
- lab = keys.pop()
- # Doesn't need to be a new list because
- # _from_iter() will be creating that new list anyway.
- itr = (v[lab] for v in itr)
-
- return Cycler._from_iter(label, itr)
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__init__.py b/server/venv/lib/python3.7/site-packages/dateutil/__init__.py
deleted file mode 100644
index 0defb82..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- coding: utf-8 -*-
-try:
- from ._version import version as __version__
-except ImportError:
- __version__ = 'unknown'
-
-__all__ = ['easter', 'parser', 'relativedelta', 'rrule', 'tz',
- 'utils', 'zoneinfo']
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index e99a8a0..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_common.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_common.cpython-37.pyc
deleted file mode 100644
index 04a44db..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_common.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_version.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_version.cpython-37.pyc
deleted file mode 100644
index dc56e7e..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/_version.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/easter.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/easter.cpython-37.pyc
deleted file mode 100644
index 312614a..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/easter.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/relativedelta.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/relativedelta.cpython-37.pyc
deleted file mode 100644
index a3482b4..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/relativedelta.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/rrule.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/rrule.cpython-37.pyc
deleted file mode 100644
index 48bc4a0..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/rrule.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/tzwin.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/tzwin.cpython-37.pyc
deleted file mode 100644
index 194f9a3..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/tzwin.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/utils.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/utils.cpython-37.pyc
deleted file mode 100644
index 431f13c..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/__pycache__/utils.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/_common.py b/server/venv/lib/python3.7/site-packages/dateutil/_common.py
deleted file mode 100644
index 4eb2659..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/_common.py
+++ /dev/null
@@ -1,43 +0,0 @@
-"""
-Common code used in multiple modules.
-"""
-
-
-class weekday(object):
- __slots__ = ["weekday", "n"]
-
- def __init__(self, weekday, n=None):
- self.weekday = weekday
- self.n = n
-
- def __call__(self, n):
- if n == self.n:
- return self
- else:
- return self.__class__(self.weekday, n)
-
- def __eq__(self, other):
- try:
- if self.weekday != other.weekday or self.n != other.n:
- return False
- except AttributeError:
- return False
- return True
-
- def __hash__(self):
- return hash((
- self.weekday,
- self.n,
- ))
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday]
- if not self.n:
- return s
- else:
- return "%s(%+d)" % (s, self.n)
-
-# vim:ts=4:sw=4:et
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/_version.py b/server/venv/lib/python3.7/site-packages/dateutil/_version.py
deleted file mode 100644
index 670d7ab..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/_version.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# coding: utf-8
-# file generated by setuptools_scm
-# don't change, don't track in version control
-version = '2.8.0'
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/easter.py b/server/venv/lib/python3.7/site-packages/dateutil/easter.py
deleted file mode 100644
index 53b7c78..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/easter.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers a generic easter computing method for any given year, using
-Western, Orthodox or Julian algorithms.
-"""
-
-import datetime
-
-__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]
-
-EASTER_JULIAN = 1
-EASTER_ORTHODOX = 2
-EASTER_WESTERN = 3
-
-
-def easter(year, method=EASTER_WESTERN):
- """
- This method was ported from the work done by GM Arts,
- on top of the algorithm by Claus Tondering, which was
- based in part on the algorithm of Ouding (1940), as
- quoted in "Explanatory Supplement to the Astronomical
- Almanac", P. Kenneth Seidelmann, editor.
-
- This algorithm implements three different easter
- calculation methods:
-
- 1 - Original calculation in Julian calendar, valid in
- dates after 326 AD
- 2 - Original method, with date converted to Gregorian
- calendar, valid in years 1583 to 4099
- 3 - Revised method, in Gregorian calendar, valid in
- years 1583 to 4099 as well
-
- These methods are represented by the constants:
-
- * ``EASTER_JULIAN = 1``
- * ``EASTER_ORTHODOX = 2``
- * ``EASTER_WESTERN = 3``
-
- The default method is method 3.
-
- More about the algorithm may be found at:
-
- `GM Arts: Easter Algorithms `_
-
- and
-
- `The Calendar FAQ: Easter `_
-
- """
-
- if not (1 <= method <= 3):
- raise ValueError("invalid method")
-
- # g - Golden year - 1
- # c - Century
- # h - (23 - Epact) mod 30
- # i - Number of days from March 21 to Paschal Full Moon
- # j - Weekday for PFM (0=Sunday, etc)
- # p - Number of days from March 21 to Sunday on or before PFM
- # (-6 to 28 methods 1 & 3, to 56 for method 2)
- # e - Extra days to add for method 2 (converting Julian
- # date to Gregorian date)
-
- y = year
- g = y % 19
- e = 0
- if method < 3:
- # Old method
- i = (19*g + 15) % 30
- j = (y + y//4 + i) % 7
- if method == 2:
- # Extra dates to convert Julian to Gregorian date
- e = 10
- if y > 1600:
- e = e + y//100 - 16 - (y//100 - 16)//4
- else:
- # New method
- c = y//100
- h = (c - c//4 - (8*c + 13)//25 + 19*g + 15) % 30
- i = h - (h//28)*(1 - (h//28)*(29//(h + 1))*((21 - g)//11))
- j = (y + y//4 + i + 2 - c + c//4) % 7
-
- # p can be from -6 to 56 corresponding to dates 22 March to 23 May
- # (later dates apply to method 2, although 23 May never actually occurs)
- p = i - j + e
- d = 1 + (p + 27 + (p + 6)//40) % 31
- m = 3 + (p + 26)//30
- return datetime.date(int(y), int(m), int(d))
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/__init__.py b/server/venv/lib/python3.7/site-packages/dateutil/parser/__init__.py
deleted file mode 100644
index 216762c..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/parser/__init__.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-from ._parser import parse, parser, parserinfo
-from ._parser import DEFAULTPARSER, DEFAULTTZPARSER
-from ._parser import UnknownTimezoneWarning
-
-from ._parser import __doc__
-
-from .isoparser import isoparser, isoparse
-
-__all__ = ['parse', 'parser', 'parserinfo',
- 'isoparse', 'isoparser',
- 'UnknownTimezoneWarning']
-
-
-###
-# Deprecate portions of the private interface so that downstream code that
-# is improperly relying on it is given *some* notice.
-
-
-def __deprecated_private_func(f):
- from functools import wraps
- import warnings
-
- msg = ('{name} is a private function and may break without warning, '
- 'it will be moved and or renamed in future versions.')
- msg = msg.format(name=f.__name__)
-
- @wraps(f)
- def deprecated_func(*args, **kwargs):
- warnings.warn(msg, DeprecationWarning)
- return f(*args, **kwargs)
-
- return deprecated_func
-
-def __deprecate_private_class(c):
- import warnings
-
- msg = ('{name} is a private class and may break without warning, '
- 'it will be moved and or renamed in future versions.')
- msg = msg.format(name=c.__name__)
-
- class private_class(c):
- __doc__ = c.__doc__
-
- def __init__(self, *args, **kwargs):
- warnings.warn(msg, DeprecationWarning)
- super(private_class, self).__init__(*args, **kwargs)
-
- private_class.__name__ = c.__name__
-
- return private_class
-
-
-from ._parser import _timelex, _resultbase
-from ._parser import _tzparser, _parsetz
-
-_timelex = __deprecate_private_class(_timelex)
-_tzparser = __deprecate_private_class(_tzparser)
-_resultbase = __deprecate_private_class(_resultbase)
-_parsetz = __deprecated_private_func(_parsetz)
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index fec9024..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/_parser.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/_parser.cpython-37.pyc
deleted file mode 100644
index 93a9bd3..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/_parser.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/isoparser.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/isoparser.cpython-37.pyc
deleted file mode 100644
index f71823f..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/parser/__pycache__/isoparser.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/_parser.py b/server/venv/lib/python3.7/site-packages/dateutil/parser/_parser.py
deleted file mode 100644
index 0da0f3e..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/parser/_parser.py
+++ /dev/null
@@ -1,1580 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers a generic date/time string parser which is able to parse
-most known formats to represent a date and/or time.
-
-This module attempts to be forgiving with regards to unlikely input formats,
-returning a datetime object even for dates which are ambiguous. If an element
-of a date/time stamp is omitted, the following rules are applied:
-
-- If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour
- on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is
- specified.
-- If a time zone is omitted, a timezone-naive datetime is returned.
-
-If any other elements are missing, they are taken from the
-:class:`datetime.datetime` object passed to the parameter ``default``. If this
-results in a day number exceeding the valid number of days per month, the
-value falls back to the end of the month.
-
-Additional resources about date/time string formats can be found below:
-
-- `A summary of the international standard date and time notation
- `_
-- `W3C Date and Time Formats `_
-- `Time Formats (Planetary Rings Node) `_
-- `CPAN ParseDate module
- `_
-- `Java SimpleDateFormat Class
- `_
-"""
-from __future__ import unicode_literals
-
-import datetime
-import re
-import string
-import time
-import warnings
-
-from calendar import monthrange
-from io import StringIO
-
-import six
-from six import integer_types, text_type
-
-from decimal import Decimal
-
-from warnings import warn
-
-from .. import relativedelta
-from .. import tz
-
-__all__ = ["parse", "parserinfo"]
-
-
-# TODO: pandas.core.tools.datetimes imports this explicitly. Might be worth
-# making public and/or figuring out if there is something we can
-# take off their plate.
-class _timelex(object):
- # Fractional seconds are sometimes split by a comma
- _split_decimal = re.compile("([.,])")
-
- def __init__(self, instream):
- if six.PY2:
- # In Python 2, we can't duck type properly because unicode has
- # a 'decode' function, and we'd be double-decoding
- if isinstance(instream, (bytes, bytearray)):
- instream = instream.decode()
- else:
- if getattr(instream, 'decode', None) is not None:
- instream = instream.decode()
-
- if isinstance(instream, text_type):
- instream = StringIO(instream)
- elif getattr(instream, 'read', None) is None:
- raise TypeError('Parser must be a string or character stream, not '
- '{itype}'.format(itype=instream.__class__.__name__))
-
- self.instream = instream
- self.charstack = []
- self.tokenstack = []
- self.eof = False
-
- def get_token(self):
- """
- This function breaks the time string into lexical units (tokens), which
- can be parsed by the parser. Lexical units are demarcated by changes in
- the character set, so any continuous string of letters is considered
- one unit, any continuous string of numbers is considered one unit.
-
- The main complication arises from the fact that dots ('.') can be used
- both as separators (e.g. "Sep.20.2009") or decimal points (e.g.
- "4:30:21.447"). As such, it is necessary to read the full context of
- any dot-separated strings before breaking it into tokens; as such, this
- function maintains a "token stack", for when the ambiguous context
- demands that multiple tokens be parsed at once.
- """
- if self.tokenstack:
- return self.tokenstack.pop(0)
-
- seenletters = False
- token = None
- state = None
-
- while not self.eof:
- # We only realize that we've reached the end of a token when we
- # find a character that's not part of the current token - since
- # that character may be part of the next token, it's stored in the
- # charstack.
- if self.charstack:
- nextchar = self.charstack.pop(0)
- else:
- nextchar = self.instream.read(1)
- while nextchar == '\x00':
- nextchar = self.instream.read(1)
-
- if not nextchar:
- self.eof = True
- break
- elif not state:
- # First character of the token - determines if we're starting
- # to parse a word, a number or something else.
- token = nextchar
- if self.isword(nextchar):
- state = 'a'
- elif self.isnum(nextchar):
- state = '0'
- elif self.isspace(nextchar):
- token = ' '
- break # emit token
- else:
- break # emit token
- elif state == 'a':
- # If we've already started reading a word, we keep reading
- # letters until we find something that's not part of a word.
- seenletters = True
- if self.isword(nextchar):
- token += nextchar
- elif nextchar == '.':
- token += nextchar
- state = 'a.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == '0':
- # If we've already started reading a number, we keep reading
- # numbers until we find something that doesn't fit.
- if self.isnum(nextchar):
- token += nextchar
- elif nextchar == '.' or (nextchar == ',' and len(token) >= 2):
- token += nextchar
- state = '0.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == 'a.':
- # If we've seen some letters and a dot separator, continue
- # parsing, and the tokens will be broken up later.
- seenletters = True
- if nextchar == '.' or self.isword(nextchar):
- token += nextchar
- elif self.isnum(nextchar) and token[-1] == '.':
- token += nextchar
- state = '0.'
- else:
- self.charstack.append(nextchar)
- break # emit token
- elif state == '0.':
- # If we've seen at least one dot separator, keep going, we'll
- # break up the tokens later.
- if nextchar == '.' or self.isnum(nextchar):
- token += nextchar
- elif self.isword(nextchar) and token[-1] == '.':
- token += nextchar
- state = 'a.'
- else:
- self.charstack.append(nextchar)
- break # emit token
-
- if (state in ('a.', '0.') and (seenletters or token.count('.') > 1 or
- token[-1] in '.,')):
- l = self._split_decimal.split(token)
- token = l[0]
- for tok in l[1:]:
- if tok:
- self.tokenstack.append(tok)
-
- if state == '0.' and token.count('.') == 0:
- token = token.replace(',', '.')
-
- return token
-
- def __iter__(self):
- return self
-
- def __next__(self):
- token = self.get_token()
- if token is None:
- raise StopIteration
-
- return token
-
- def next(self):
- return self.__next__() # Python 2.x support
-
- @classmethod
- def split(cls, s):
- return list(cls(s))
-
- @classmethod
- def isword(cls, nextchar):
- """ Whether or not the next character is part of a word """
- return nextchar.isalpha()
-
- @classmethod
- def isnum(cls, nextchar):
- """ Whether the next character is part of a number """
- return nextchar.isdigit()
-
- @classmethod
- def isspace(cls, nextchar):
- """ Whether the next character is whitespace """
- return nextchar.isspace()
-
-
-class _resultbase(object):
-
- def __init__(self):
- for attr in self.__slots__:
- setattr(self, attr, None)
-
- def _repr(self, classname):
- l = []
- for attr in self.__slots__:
- value = getattr(self, attr)
- if value is not None:
- l.append("%s=%s" % (attr, repr(value)))
- return "%s(%s)" % (classname, ", ".join(l))
-
- def __len__(self):
- return (sum(getattr(self, attr) is not None
- for attr in self.__slots__))
-
- def __repr__(self):
- return self._repr(self.__class__.__name__)
-
-
-class parserinfo(object):
- """
- Class which handles what inputs are accepted. Subclass this to customize
- the language and acceptable values for each parameter.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM
- and YMD. Default is ``False``.
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken
- to be the year, otherwise the last number is taken to be the year.
- Default is ``False``.
- """
-
- # m from a.m/p.m, t from ISO T separator
- JUMP = [" ", ".", ",", ";", "-", "/", "'",
- "at", "on", "and", "ad", "m", "t", "of",
- "st", "nd", "rd", "th"]
-
- WEEKDAYS = [("Mon", "Monday"),
- ("Tue", "Tuesday"), # TODO: "Tues"
- ("Wed", "Wednesday"),
- ("Thu", "Thursday"), # TODO: "Thurs"
- ("Fri", "Friday"),
- ("Sat", "Saturday"),
- ("Sun", "Sunday")]
- MONTHS = [("Jan", "January"),
- ("Feb", "February"), # TODO: "Febr"
- ("Mar", "March"),
- ("Apr", "April"),
- ("May", "May"),
- ("Jun", "June"),
- ("Jul", "July"),
- ("Aug", "August"),
- ("Sep", "Sept", "September"),
- ("Oct", "October"),
- ("Nov", "November"),
- ("Dec", "December")]
- HMS = [("h", "hour", "hours"),
- ("m", "minute", "minutes"),
- ("s", "second", "seconds")]
- AMPM = [("am", "a"),
- ("pm", "p")]
- UTCZONE = ["UTC", "GMT", "Z", "z"]
- PERTAIN = ["of"]
- TZOFFSET = {}
- # TODO: ERA = ["AD", "BC", "CE", "BCE", "Stardate",
- # "Anno Domini", "Year of Our Lord"]
-
- def __init__(self, dayfirst=False, yearfirst=False):
- self._jump = self._convert(self.JUMP)
- self._weekdays = self._convert(self.WEEKDAYS)
- self._months = self._convert(self.MONTHS)
- self._hms = self._convert(self.HMS)
- self._ampm = self._convert(self.AMPM)
- self._utczone = self._convert(self.UTCZONE)
- self._pertain = self._convert(self.PERTAIN)
-
- self.dayfirst = dayfirst
- self.yearfirst = yearfirst
-
- self._year = time.localtime().tm_year
- self._century = self._year // 100 * 100
-
- def _convert(self, lst):
- dct = {}
- for i, v in enumerate(lst):
- if isinstance(v, tuple):
- for v in v:
- dct[v.lower()] = i
- else:
- dct[v.lower()] = i
- return dct
-
- def jump(self, name):
- return name.lower() in self._jump
-
- def weekday(self, name):
- try:
- return self._weekdays[name.lower()]
- except KeyError:
- pass
- return None
-
- def month(self, name):
- try:
- return self._months[name.lower()] + 1
- except KeyError:
- pass
- return None
-
- def hms(self, name):
- try:
- return self._hms[name.lower()]
- except KeyError:
- return None
-
- def ampm(self, name):
- try:
- return self._ampm[name.lower()]
- except KeyError:
- return None
-
- def pertain(self, name):
- return name.lower() in self._pertain
-
- def utczone(self, name):
- return name.lower() in self._utczone
-
- def tzoffset(self, name):
- if name in self._utczone:
- return 0
-
- return self.TZOFFSET.get(name)
-
- def convertyear(self, year, century_specified=False):
- """
- Converts two-digit years to year within [-50, 49]
- range of self._year (current local time)
- """
-
- # Function contract is that the year is always positive
- assert year >= 0
-
- if year < 100 and not century_specified:
- # assume current century to start
- year += self._century
-
- if year >= self._year + 50: # if too far in future
- year -= 100
- elif year < self._year - 50: # if too far in past
- year += 100
-
- return year
-
- def validate(self, res):
- # move to info
- if res.year is not None:
- res.year = self.convertyear(res.year, res.century_specified)
-
- if ((res.tzoffset == 0 and not res.tzname) or
- (res.tzname == 'Z' or res.tzname == 'z')):
- res.tzname = "UTC"
- res.tzoffset = 0
- elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname):
- res.tzoffset = 0
- return True
-
-
-class _ymd(list):
- def __init__(self, *args, **kwargs):
- super(self.__class__, self).__init__(*args, **kwargs)
- self.century_specified = False
- self.dstridx = None
- self.mstridx = None
- self.ystridx = None
-
- @property
- def has_year(self):
- return self.ystridx is not None
-
- @property
- def has_month(self):
- return self.mstridx is not None
-
- @property
- def has_day(self):
- return self.dstridx is not None
-
- def could_be_day(self, value):
- if self.has_day:
- return False
- elif not self.has_month:
- return 1 <= value <= 31
- elif not self.has_year:
- # Be permissive, assume leapyear
- month = self[self.mstridx]
- return 1 <= value <= monthrange(2000, month)[1]
- else:
- month = self[self.mstridx]
- year = self[self.ystridx]
- return 1 <= value <= monthrange(year, month)[1]
-
- def append(self, val, label=None):
- if hasattr(val, '__len__'):
- if val.isdigit() and len(val) > 2:
- self.century_specified = True
- if label not in [None, 'Y']: # pragma: no cover
- raise ValueError(label)
- label = 'Y'
- elif val > 100:
- self.century_specified = True
- if label not in [None, 'Y']: # pragma: no cover
- raise ValueError(label)
- label = 'Y'
-
- super(self.__class__, self).append(int(val))
-
- if label == 'M':
- if self.has_month:
- raise ValueError('Month is already set')
- self.mstridx = len(self) - 1
- elif label == 'D':
- if self.has_day:
- raise ValueError('Day is already set')
- self.dstridx = len(self) - 1
- elif label == 'Y':
- if self.has_year:
- raise ValueError('Year is already set')
- self.ystridx = len(self) - 1
-
- def _resolve_from_stridxs(self, strids):
- """
- Try to resolve the identities of year/month/day elements using
- ystridx, mstridx, and dstridx, if enough of these are specified.
- """
- if len(self) == 3 and len(strids) == 2:
- # we can back out the remaining stridx value
- missing = [x for x in range(3) if x not in strids.values()]
- key = [x for x in ['y', 'm', 'd'] if x not in strids]
- assert len(missing) == len(key) == 1
- key = key[0]
- val = missing[0]
- strids[key] = val
-
- assert len(self) == len(strids) # otherwise this should not be called
- out = {key: self[strids[key]] for key in strids}
- return (out.get('y'), out.get('m'), out.get('d'))
-
- def resolve_ymd(self, yearfirst, dayfirst):
- len_ymd = len(self)
- year, month, day = (None, None, None)
-
- strids = (('y', self.ystridx),
- ('m', self.mstridx),
- ('d', self.dstridx))
-
- strids = {key: val for key, val in strids if val is not None}
- if (len(self) == len(strids) > 0 or
- (len(self) == 3 and len(strids) == 2)):
- return self._resolve_from_stridxs(strids)
-
- mstridx = self.mstridx
-
- if len_ymd > 3:
- raise ValueError("More than three YMD values")
- elif len_ymd == 1 or (mstridx is not None and len_ymd == 2):
- # One member, or two members with a month string
- if mstridx is not None:
- month = self[mstridx]
- # since mstridx is 0 or 1, self[mstridx-1] always
- # looks up the other element
- other = self[mstridx - 1]
- else:
- other = self[0]
-
- if len_ymd > 1 or mstridx is None:
- if other > 31:
- year = other
- else:
- day = other
-
- elif len_ymd == 2:
- # Two members with numbers
- if self[0] > 31:
- # 99-01
- year, month = self
- elif self[1] > 31:
- # 01-99
- month, year = self
- elif dayfirst and self[1] <= 12:
- # 13-01
- day, month = self
- else:
- # 01-13
- month, day = self
-
- elif len_ymd == 3:
- # Three members
- if mstridx == 0:
- if self[1] > 31:
- # Apr-2003-25
- month, year, day = self
- else:
- month, day, year = self
- elif mstridx == 1:
- if self[0] > 31 or (yearfirst and self[2] <= 31):
- # 99-Jan-01
- year, month, day = self
- else:
- # 01-Jan-01
- # Give precendence to day-first, since
- # two-digit years is usually hand-written.
- day, month, year = self
-
- elif mstridx == 2:
- # WTF!?
- if self[1] > 31:
- # 01-99-Jan
- day, year, month = self
- else:
- # 99-01-Jan
- year, day, month = self
-
- else:
- if (self[0] > 31 or
- self.ystridx == 0 or
- (yearfirst and self[1] <= 12 and self[2] <= 31)):
- # 99-01-01
- if dayfirst and self[2] <= 12:
- year, day, month = self
- else:
- year, month, day = self
- elif self[0] > 12 or (dayfirst and self[1] <= 12):
- # 13-01-01
- day, month, year = self
- else:
- # 01-13-01
- month, day, year = self
-
- return year, month, day
-
-
-class parser(object):
- def __init__(self, info=None):
- self.info = info or parserinfo()
-
- def parse(self, timestr, default=None,
- ignoretz=False, tzinfos=None, **kwargs):
- """
- Parse the date/time string into a :class:`datetime.datetime` object.
-
- :param timestr:
- Any date/time string using the supported formats.
-
- :param default:
- The default datetime object, if this is a datetime object and not
- ``None``, elements specified in ``timestr`` replace elements in the
- default object.
-
- :param ignoretz:
- If set ``True``, time zones in parsed strings are ignored and a
- naive :class:`datetime.datetime` object is returned.
-
- :param tzinfos:
- Additional time zone names / aliases which may be present in the
- string. This argument maps time zone names (and optionally offsets
- from those time zones) to time zones. This parameter can be a
- dictionary with timezone aliases mapping time zone names to time
- zones or a function taking two parameters (``tzname`` and
- ``tzoffset``) and returning a time zone.
-
- The timezones to which the names are mapped can be an integer
- offset from UTC in seconds or a :class:`tzinfo` object.
-
- .. doctest::
- :options: +NORMALIZE_WHITESPACE
-
- >>> from dateutil.parser import parse
- >>> from dateutil.tz import gettz
- >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
- >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
- >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21,
- tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
-
- This parameter is ignored if ``ignoretz`` is set.
-
- :param \\*\\*kwargs:
- Keyword arguments as passed to ``_parse()``.
-
- :return:
- Returns a :class:`datetime.datetime` object or, if the
- ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
- first element being a :class:`datetime.datetime` object, the second
- a tuple containing the fuzzy tokens.
-
- :raises ValueError:
- Raised for invalid or unknown string format, if the provided
- :class:`tzinfo` is not in a valid format, or if an invalid date
- would be created.
-
- :raises TypeError:
- Raised for non-string or character stream input.
-
- :raises OverflowError:
- Raised if the parsed date exceeds the largest valid C integer on
- your system.
- """
-
- if default is None:
- default = datetime.datetime.now().replace(hour=0, minute=0,
- second=0, microsecond=0)
-
- res, skipped_tokens = self._parse(timestr, **kwargs)
-
- if res is None:
- raise ValueError("Unknown string format:", timestr)
-
- if len(res) == 0:
- raise ValueError("String does not contain a date:", timestr)
-
- ret = self._build_naive(res, default)
-
- if not ignoretz:
- ret = self._build_tzaware(ret, res, tzinfos)
-
- if kwargs.get('fuzzy_with_tokens', False):
- return ret, skipped_tokens
- else:
- return ret
-
- class _result(_resultbase):
- __slots__ = ["year", "month", "day", "weekday",
- "hour", "minute", "second", "microsecond",
- "tzname", "tzoffset", "ampm","any_unused_tokens"]
-
- def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
- fuzzy_with_tokens=False):
- """
- Private method which performs the heavy lifting of parsing, called from
- ``parse()``, which passes on its ``kwargs`` to this function.
-
- :param timestr:
- The string to parse.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM
- and YMD. If set to ``None``, this value is retrieved from the
- current :class:`parserinfo` object (which itself defaults to
- ``False``).
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken
- to be the year, otherwise the last number is taken to be the year.
- If this is set to ``None``, the value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param fuzzy:
- Whether to allow fuzzy parsing, allowing for string like "Today is
- January 1, 2047 at 8:21:00AM".
-
- :param fuzzy_with_tokens:
- If ``True``, ``fuzzy`` is automatically set to True, and the parser
- will return a tuple where the first element is the parsed
- :class:`datetime.datetime` datetimestamp and the second element is
- a tuple containing the portions of the string which were ignored:
-
- .. doctest::
-
- >>> from dateutil.parser import parse
- >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
- (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
-
- """
- if fuzzy_with_tokens:
- fuzzy = True
-
- info = self.info
-
- if dayfirst is None:
- dayfirst = info.dayfirst
-
- if yearfirst is None:
- yearfirst = info.yearfirst
-
- res = self._result()
- l = _timelex.split(timestr) # Splits the timestr into tokens
-
- skipped_idxs = []
-
- # year/month/day list
- ymd = _ymd()
-
- len_l = len(l)
- i = 0
- try:
- while i < len_l:
-
- # Check if it's a number
- value_repr = l[i]
- try:
- value = float(value_repr)
- except ValueError:
- value = None
-
- if value is not None:
- # Numeric token
- i = self._parse_numeric_token(l, i, info, ymd, res, fuzzy)
-
- # Check weekday
- elif info.weekday(l[i]) is not None:
- value = info.weekday(l[i])
- res.weekday = value
-
- # Check month name
- elif info.month(l[i]) is not None:
- value = info.month(l[i])
- ymd.append(value, 'M')
-
- if i + 1 < len_l:
- if l[i + 1] in ('-', '/'):
- # Jan-01[-99]
- sep = l[i + 1]
- ymd.append(l[i + 2])
-
- if i + 3 < len_l and l[i + 3] == sep:
- # Jan-01-99
- ymd.append(l[i + 4])
- i += 2
-
- i += 2
-
- elif (i + 4 < len_l and l[i + 1] == l[i + 3] == ' ' and
- info.pertain(l[i + 2])):
- # Jan of 01
- # In this case, 01 is clearly year
- if l[i + 4].isdigit():
- # Convert it here to become unambiguous
- value = int(l[i + 4])
- year = str(info.convertyear(value))
- ymd.append(year, 'Y')
- else:
- # Wrong guess
- pass
- # TODO: not hit in tests
- i += 4
-
- # Check am/pm
- elif info.ampm(l[i]) is not None:
- value = info.ampm(l[i])
- val_is_ampm = self._ampm_valid(res.hour, res.ampm, fuzzy)
-
- if val_is_ampm:
- res.hour = self._adjust_ampm(res.hour, value)
- res.ampm = value
-
- elif fuzzy:
- skipped_idxs.append(i)
-
- # Check for a timezone name
- elif self._could_be_tzname(res.hour, res.tzname, res.tzoffset, l[i]):
- res.tzname = l[i]
- res.tzoffset = info.tzoffset(res.tzname)
-
- # Check for something like GMT+3, or BRST+3. Notice
- # that it doesn't mean "I am 3 hours after GMT", but
- # "my time +3 is GMT". If found, we reverse the
- # logic so that timezone parsing code will get it
- # right.
- if i + 1 < len_l and l[i + 1] in ('+', '-'):
- l[i + 1] = ('+', '-')[l[i + 1] == '+']
- res.tzoffset = None
- if info.utczone(res.tzname):
- # With something like GMT+3, the timezone
- # is *not* GMT.
- res.tzname = None
-
- # Check for a numbered timezone
- elif res.hour is not None and l[i] in ('+', '-'):
- signal = (-1, 1)[l[i] == '+']
- len_li = len(l[i + 1])
-
- # TODO: check that l[i + 1] is integer?
- if len_li == 4:
- # -0300
- hour_offset = int(l[i + 1][:2])
- min_offset = int(l[i + 1][2:])
- elif i + 2 < len_l and l[i + 2] == ':':
- # -03:00
- hour_offset = int(l[i + 1])
- min_offset = int(l[i + 3]) # TODO: Check that l[i+3] is minute-like?
- i += 2
- elif len_li <= 2:
- # -[0]3
- hour_offset = int(l[i + 1][:2])
- min_offset = 0
- else:
- raise ValueError(timestr)
-
- res.tzoffset = signal * (hour_offset * 3600 + min_offset * 60)
-
- # Look for a timezone name between parenthesis
- if (i + 5 < len_l and
- info.jump(l[i + 2]) and l[i + 3] == '(' and
- l[i + 5] == ')' and
- 3 <= len(l[i + 4]) and
- self._could_be_tzname(res.hour, res.tzname,
- None, l[i + 4])):
- # -0300 (BRST)
- res.tzname = l[i + 4]
- i += 4
-
- i += 1
-
- # Check jumps
- elif not (info.jump(l[i]) or fuzzy):
- raise ValueError(timestr)
-
- else:
- skipped_idxs.append(i)
- i += 1
-
- # Process year/month/day
- year, month, day = ymd.resolve_ymd(yearfirst, dayfirst)
-
- res.century_specified = ymd.century_specified
- res.year = year
- res.month = month
- res.day = day
-
- except (IndexError, ValueError):
- return None, None
-
- if not info.validate(res):
- return None, None
-
- if fuzzy_with_tokens:
- skipped_tokens = self._recombine_skipped(l, skipped_idxs)
- return res, tuple(skipped_tokens)
- else:
- return res, None
-
- def _parse_numeric_token(self, tokens, idx, info, ymd, res, fuzzy):
- # Token is a number
- value_repr = tokens[idx]
- try:
- value = self._to_decimal(value_repr)
- except Exception as e:
- six.raise_from(ValueError('Unknown numeric token'), e)
-
- len_li = len(value_repr)
-
- len_l = len(tokens)
-
- if (len(ymd) == 3 and len_li in (2, 4) and
- res.hour is None and
- (idx + 1 >= len_l or
- (tokens[idx + 1] != ':' and
- info.hms(tokens[idx + 1]) is None))):
- # 19990101T23[59]
- s = tokens[idx]
- res.hour = int(s[:2])
-
- if len_li == 4:
- res.minute = int(s[2:])
-
- elif len_li == 6 or (len_li > 6 and tokens[idx].find('.') == 6):
- # YYMMDD or HHMMSS[.ss]
- s = tokens[idx]
-
- if not ymd and '.' not in tokens[idx]:
- ymd.append(s[:2])
- ymd.append(s[2:4])
- ymd.append(s[4:])
- else:
- # 19990101T235959[.59]
-
- # TODO: Check if res attributes already set.
- res.hour = int(s[:2])
- res.minute = int(s[2:4])
- res.second, res.microsecond = self._parsems(s[4:])
-
- elif len_li in (8, 12, 14):
- # YYYYMMDD
- s = tokens[idx]
- ymd.append(s[:4], 'Y')
- ymd.append(s[4:6])
- ymd.append(s[6:8])
-
- if len_li > 8:
- res.hour = int(s[8:10])
- res.minute = int(s[10:12])
-
- if len_li > 12:
- res.second = int(s[12:])
-
- elif self._find_hms_idx(idx, tokens, info, allow_jump=True) is not None:
- # HH[ ]h or MM[ ]m or SS[.ss][ ]s
- hms_idx = self._find_hms_idx(idx, tokens, info, allow_jump=True)
- (idx, hms) = self._parse_hms(idx, tokens, info, hms_idx)
- if hms is not None:
- # TODO: checking that hour/minute/second are not
- # already set?
- self._assign_hms(res, value_repr, hms)
-
- elif idx + 2 < len_l and tokens[idx + 1] == ':':
- # HH:MM[:SS[.ss]]
- res.hour = int(value)
- value = self._to_decimal(tokens[idx + 2]) # TODO: try/except for this?
- (res.minute, res.second) = self._parse_min_sec(value)
-
- if idx + 4 < len_l and tokens[idx + 3] == ':':
- res.second, res.microsecond = self._parsems(tokens[idx + 4])
-
- idx += 2
-
- idx += 2
-
- elif idx + 1 < len_l and tokens[idx + 1] in ('-', '/', '.'):
- sep = tokens[idx + 1]
- ymd.append(value_repr)
-
- if idx + 2 < len_l and not info.jump(tokens[idx + 2]):
- if tokens[idx + 2].isdigit():
- # 01-01[-01]
- ymd.append(tokens[idx + 2])
- else:
- # 01-Jan[-01]
- value = info.month(tokens[idx + 2])
-
- if value is not None:
- ymd.append(value, 'M')
- else:
- raise ValueError()
-
- if idx + 3 < len_l and tokens[idx + 3] == sep:
- # We have three members
- value = info.month(tokens[idx + 4])
-
- if value is not None:
- ymd.append(value, 'M')
- else:
- ymd.append(tokens[idx + 4])
- idx += 2
-
- idx += 1
- idx += 1
-
- elif idx + 1 >= len_l or info.jump(tokens[idx + 1]):
- if idx + 2 < len_l and info.ampm(tokens[idx + 2]) is not None:
- # 12 am
- hour = int(value)
- res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 2]))
- idx += 1
- else:
- # Year, month or day
- ymd.append(value)
- idx += 1
-
- elif info.ampm(tokens[idx + 1]) is not None and (0 <= value < 24):
- # 12am
- hour = int(value)
- res.hour = self._adjust_ampm(hour, info.ampm(tokens[idx + 1]))
- idx += 1
-
- elif ymd.could_be_day(value):
- ymd.append(value)
-
- elif not fuzzy:
- raise ValueError()
-
- return idx
-
- def _find_hms_idx(self, idx, tokens, info, allow_jump):
- len_l = len(tokens)
-
- if idx+1 < len_l and info.hms(tokens[idx+1]) is not None:
- # There is an "h", "m", or "s" label following this token. We take
- # assign the upcoming label to the current token.
- # e.g. the "12" in 12h"
- hms_idx = idx + 1
-
- elif (allow_jump and idx+2 < len_l and tokens[idx+1] == ' ' and
- info.hms(tokens[idx+2]) is not None):
- # There is a space and then an "h", "m", or "s" label.
- # e.g. the "12" in "12 h"
- hms_idx = idx + 2
-
- elif idx > 0 and info.hms(tokens[idx-1]) is not None:
- # There is a "h", "m", or "s" preceeding this token. Since neither
- # of the previous cases was hit, there is no label following this
- # token, so we use the previous label.
- # e.g. the "04" in "12h04"
- hms_idx = idx-1
-
- elif (1 < idx == len_l-1 and tokens[idx-1] == ' ' and
- info.hms(tokens[idx-2]) is not None):
- # If we are looking at the final token, we allow for a
- # backward-looking check to skip over a space.
- # TODO: Are we sure this is the right condition here?
- hms_idx = idx - 2
-
- else:
- hms_idx = None
-
- return hms_idx
-
- def _assign_hms(self, res, value_repr, hms):
- # See GH issue #427, fixing float rounding
- value = self._to_decimal(value_repr)
-
- if hms == 0:
- # Hour
- res.hour = int(value)
- if value % 1:
- res.minute = int(60*(value % 1))
-
- elif hms == 1:
- (res.minute, res.second) = self._parse_min_sec(value)
-
- elif hms == 2:
- (res.second, res.microsecond) = self._parsems(value_repr)
-
- def _could_be_tzname(self, hour, tzname, tzoffset, token):
- return (hour is not None and
- tzname is None and
- tzoffset is None and
- len(token) <= 5 and
- (all(x in string.ascii_uppercase for x in token)
- or token in self.info.UTCZONE))
-
- def _ampm_valid(self, hour, ampm, fuzzy):
- """
- For fuzzy parsing, 'a' or 'am' (both valid English words)
- may erroneously trigger the AM/PM flag. Deal with that
- here.
- """
- val_is_ampm = True
-
- # If there's already an AM/PM flag, this one isn't one.
- if fuzzy and ampm is not None:
- val_is_ampm = False
-
- # If AM/PM is found and hour is not, raise a ValueError
- if hour is None:
- if fuzzy:
- val_is_ampm = False
- else:
- raise ValueError('No hour specified with AM or PM flag.')
- elif not 0 <= hour <= 12:
- # If AM/PM is found, it's a 12 hour clock, so raise
- # an error for invalid range
- if fuzzy:
- val_is_ampm = False
- else:
- raise ValueError('Invalid hour specified for 12-hour clock.')
-
- return val_is_ampm
-
- def _adjust_ampm(self, hour, ampm):
- if hour < 12 and ampm == 1:
- hour += 12
- elif hour == 12 and ampm == 0:
- hour = 0
- return hour
-
- def _parse_min_sec(self, value):
- # TODO: Every usage of this function sets res.second to the return
- # value. Are there any cases where second will be returned as None and
- # we *dont* want to set res.second = None?
- minute = int(value)
- second = None
-
- sec_remainder = value % 1
- if sec_remainder:
- second = int(60 * sec_remainder)
- return (minute, second)
-
- def _parsems(self, value):
- """Parse a I[.F] seconds value into (seconds, microseconds)."""
- if "." not in value:
- return int(value), 0
- else:
- i, f = value.split(".")
- return int(i), int(f.ljust(6, "0")[:6])
-
- def _parse_hms(self, idx, tokens, info, hms_idx):
- # TODO: Is this going to admit a lot of false-positives for when we
- # just happen to have digits and "h", "m" or "s" characters in non-date
- # text? I guess hex hashes won't have that problem, but there's plenty
- # of random junk out there.
- if hms_idx is None:
- hms = None
- new_idx = idx
- elif hms_idx > idx:
- hms = info.hms(tokens[hms_idx])
- new_idx = hms_idx
- else:
- # Looking backwards, increment one.
- hms = info.hms(tokens[hms_idx]) + 1
- new_idx = idx
-
- return (new_idx, hms)
-
- def _recombine_skipped(self, tokens, skipped_idxs):
- """
- >>> tokens = ["foo", " ", "bar", " ", "19June2000", "baz"]
- >>> skipped_idxs = [0, 1, 2, 5]
- >>> _recombine_skipped(tokens, skipped_idxs)
- ["foo bar", "baz"]
- """
- skipped_tokens = []
- for i, idx in enumerate(sorted(skipped_idxs)):
- if i > 0 and idx - 1 == skipped_idxs[i - 1]:
- skipped_tokens[-1] = skipped_tokens[-1] + tokens[idx]
- else:
- skipped_tokens.append(tokens[idx])
-
- return skipped_tokens
-
- def _build_tzinfo(self, tzinfos, tzname, tzoffset):
- if callable(tzinfos):
- tzdata = tzinfos(tzname, tzoffset)
- else:
- tzdata = tzinfos.get(tzname)
- # handle case where tzinfo is paased an options that returns None
- # eg tzinfos = {'BRST' : None}
- if isinstance(tzdata, datetime.tzinfo) or tzdata is None:
- tzinfo = tzdata
- elif isinstance(tzdata, text_type):
- tzinfo = tz.tzstr(tzdata)
- elif isinstance(tzdata, integer_types):
- tzinfo = tz.tzoffset(tzname, tzdata)
- return tzinfo
-
- def _build_tzaware(self, naive, res, tzinfos):
- if (callable(tzinfos) or (tzinfos and res.tzname in tzinfos)):
- tzinfo = self._build_tzinfo(tzinfos, res.tzname, res.tzoffset)
- aware = naive.replace(tzinfo=tzinfo)
- aware = self._assign_tzname(aware, res.tzname)
-
- elif res.tzname and res.tzname in time.tzname:
- aware = naive.replace(tzinfo=tz.tzlocal())
-
- # Handle ambiguous local datetime
- aware = self._assign_tzname(aware, res.tzname)
-
- # This is mostly relevant for winter GMT zones parsed in the UK
- if (aware.tzname() != res.tzname and
- res.tzname in self.info.UTCZONE):
- aware = aware.replace(tzinfo=tz.tzutc())
-
- elif res.tzoffset == 0:
- aware = naive.replace(tzinfo=tz.tzutc())
-
- elif res.tzoffset:
- aware = naive.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
-
- elif not res.tzname and not res.tzoffset:
- # i.e. no timezone information was found.
- aware = naive
-
- elif res.tzname:
- # tz-like string was parsed but we don't know what to do
- # with it
- warnings.warn("tzname {tzname} identified but not understood. "
- "Pass `tzinfos` argument in order to correctly "
- "return a timezone-aware datetime. In a future "
- "version, this will raise an "
- "exception.".format(tzname=res.tzname),
- category=UnknownTimezoneWarning)
- aware = naive
-
- return aware
-
- def _build_naive(self, res, default):
- repl = {}
- for attr in ("year", "month", "day", "hour",
- "minute", "second", "microsecond"):
- value = getattr(res, attr)
- if value is not None:
- repl[attr] = value
-
- if 'day' not in repl:
- # If the default day exceeds the last day of the month, fall back
- # to the end of the month.
- cyear = default.year if res.year is None else res.year
- cmonth = default.month if res.month is None else res.month
- cday = default.day if res.day is None else res.day
-
- if cday > monthrange(cyear, cmonth)[1]:
- repl['day'] = monthrange(cyear, cmonth)[1]
-
- naive = default.replace(**repl)
-
- if res.weekday is not None and not res.day:
- naive = naive + relativedelta.relativedelta(weekday=res.weekday)
-
- return naive
-
- def _assign_tzname(self, dt, tzname):
- if dt.tzname() != tzname:
- new_dt = tz.enfold(dt, fold=1)
- if new_dt.tzname() == tzname:
- return new_dt
-
- return dt
-
- def _to_decimal(self, val):
- try:
- decimal_value = Decimal(val)
- # See GH 662, edge case, infinite value should not be converted via `_to_decimal`
- if not decimal_value.is_finite():
- raise ValueError("Converted decimal value is infinite or NaN")
- except Exception as e:
- msg = "Could not convert %s to decimal" % val
- six.raise_from(ValueError(msg), e)
- else:
- return decimal_value
-
-
-DEFAULTPARSER = parser()
-
-
-def parse(timestr, parserinfo=None, **kwargs):
- """
-
- Parse a string in one of the supported formats, using the
- ``parserinfo`` parameters.
-
- :param timestr:
- A string containing a date/time stamp.
-
- :param parserinfo:
- A :class:`parserinfo` object containing parameters for the parser.
- If ``None``, the default arguments to the :class:`parserinfo`
- constructor are used.
-
- The ``**kwargs`` parameter takes the following keyword arguments:
-
- :param default:
- The default datetime object, if this is a datetime object and not
- ``None``, elements specified in ``timestr`` replace elements in the
- default object.
-
- :param ignoretz:
- If set ``True``, time zones in parsed strings are ignored and a naive
- :class:`datetime` object is returned.
-
- :param tzinfos:
- Additional time zone names / aliases which may be present in the
- string. This argument maps time zone names (and optionally offsets
- from those time zones) to time zones. This parameter can be a
- dictionary with timezone aliases mapping time zone names to time
- zones or a function taking two parameters (``tzname`` and
- ``tzoffset``) and returning a time zone.
-
- The timezones to which the names are mapped can be an integer
- offset from UTC in seconds or a :class:`tzinfo` object.
-
- .. doctest::
- :options: +NORMALIZE_WHITESPACE
-
- >>> from dateutil.parser import parse
- >>> from dateutil.tz import gettz
- >>> tzinfos = {"BRST": -7200, "CST": gettz("America/Chicago")}
- >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -7200))
- >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
- datetime.datetime(2012, 1, 19, 17, 21,
- tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
-
- This parameter is ignored if ``ignoretz`` is set.
-
- :param dayfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the day (``True``) or month (``False``). If
- ``yearfirst`` is set to ``True``, this distinguishes between YDM and
- YMD. If set to ``None``, this value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param yearfirst:
- Whether to interpret the first value in an ambiguous 3-integer date
- (e.g. 01/05/09) as the year. If ``True``, the first number is taken to
- be the year, otherwise the last number is taken to be the year. If
- this is set to ``None``, the value is retrieved from the current
- :class:`parserinfo` object (which itself defaults to ``False``).
-
- :param fuzzy:
- Whether to allow fuzzy parsing, allowing for string like "Today is
- January 1, 2047 at 8:21:00AM".
-
- :param fuzzy_with_tokens:
- If ``True``, ``fuzzy`` is automatically set to True, and the parser
- will return a tuple where the first element is the parsed
- :class:`datetime.datetime` datetimestamp and the second element is
- a tuple containing the portions of the string which were ignored:
-
- .. doctest::
-
- >>> from dateutil.parser import parse
- >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
- (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
-
- :return:
- Returns a :class:`datetime.datetime` object or, if the
- ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
- first element being a :class:`datetime.datetime` object, the second
- a tuple containing the fuzzy tokens.
-
- :raises ValueError:
- Raised for invalid or unknown string format, if the provided
- :class:`tzinfo` is not in a valid format, or if an invalid date
- would be created.
-
- :raises OverflowError:
- Raised if the parsed date exceeds the largest valid C integer on
- your system.
- """
- if parserinfo:
- return parser(parserinfo).parse(timestr, **kwargs)
- else:
- return DEFAULTPARSER.parse(timestr, **kwargs)
-
-
-class _tzparser(object):
-
- class _result(_resultbase):
-
- __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset",
- "start", "end"]
-
- class _attr(_resultbase):
- __slots__ = ["month", "week", "weekday",
- "yday", "jyday", "day", "time"]
-
- def __repr__(self):
- return self._repr("")
-
- def __init__(self):
- _resultbase.__init__(self)
- self.start = self._attr()
- self.end = self._attr()
-
- def parse(self, tzstr):
- res = self._result()
- l = [x for x in re.split(r'([,:.]|[a-zA-Z]+|[0-9]+)',tzstr) if x]
- used_idxs = list()
- try:
-
- len_l = len(l)
-
- i = 0
- while i < len_l:
- # BRST+3[BRDT[+2]]
- j = i
- while j < len_l and not [x for x in l[j]
- if x in "0123456789:,-+"]:
- j += 1
- if j != i:
- if not res.stdabbr:
- offattr = "stdoffset"
- res.stdabbr = "".join(l[i:j])
- else:
- offattr = "dstoffset"
- res.dstabbr = "".join(l[i:j])
-
- for ii in range(j):
- used_idxs.append(ii)
- i = j
- if (i < len_l and (l[i] in ('+', '-') or l[i][0] in
- "0123456789")):
- if l[i] in ('+', '-'):
- # Yes, that's right. See the TZ variable
- # documentation.
- signal = (1, -1)[l[i] == '+']
- used_idxs.append(i)
- i += 1
- else:
- signal = -1
- len_li = len(l[i])
- if len_li == 4:
- # -0300
- setattr(res, offattr, (int(l[i][:2]) * 3600 +
- int(l[i][2:]) * 60) * signal)
- elif i + 1 < len_l and l[i + 1] == ':':
- # -03:00
- setattr(res, offattr,
- (int(l[i]) * 3600 +
- int(l[i + 2]) * 60) * signal)
- used_idxs.append(i)
- i += 2
- elif len_li <= 2:
- # -[0]3
- setattr(res, offattr,
- int(l[i][:2]) * 3600 * signal)
- else:
- return None
- used_idxs.append(i)
- i += 1
- if res.dstabbr:
- break
- else:
- break
-
-
- if i < len_l:
- for j in range(i, len_l):
- if l[j] == ';':
- l[j] = ','
-
- assert l[i] == ','
-
- i += 1
-
- if i >= len_l:
- pass
- elif (8 <= l.count(',') <= 9 and
- not [y for x in l[i:] if x != ','
- for y in x if y not in "0123456789+-"]):
- # GMT0BST,3,0,30,3600,10,0,26,7200[,3600]
- for x in (res.start, res.end):
- x.month = int(l[i])
- used_idxs.append(i)
- i += 2
- if l[i] == '-':
- value = int(l[i + 1]) * -1
- used_idxs.append(i)
- i += 1
- else:
- value = int(l[i])
- used_idxs.append(i)
- i += 2
- if value:
- x.week = value
- x.weekday = (int(l[i]) - 1) % 7
- else:
- x.day = int(l[i])
- used_idxs.append(i)
- i += 2
- x.time = int(l[i])
- used_idxs.append(i)
- i += 2
- if i < len_l:
- if l[i] in ('-', '+'):
- signal = (-1, 1)[l[i] == "+"]
- used_idxs.append(i)
- i += 1
- else:
- signal = 1
- used_idxs.append(i)
- res.dstoffset = (res.stdoffset + int(l[i]) * signal)
-
- # This was a made-up format that is not in normal use
- warn(('Parsed time zone "%s"' % tzstr) +
- 'is in a non-standard dateutil-specific format, which ' +
- 'is now deprecated; support for parsing this format ' +
- 'will be removed in future versions. It is recommended ' +
- 'that you switch to a standard format like the GNU ' +
- 'TZ variable format.', tz.DeprecatedTzFormatWarning)
- elif (l.count(',') == 2 and l[i:].count('/') <= 2 and
- not [y for x in l[i:] if x not in (',', '/', 'J', 'M',
- '.', '-', ':')
- for y in x if y not in "0123456789"]):
- for x in (res.start, res.end):
- if l[i] == 'J':
- # non-leap year day (1 based)
- used_idxs.append(i)
- i += 1
- x.jyday = int(l[i])
- elif l[i] == 'M':
- # month[-.]week[-.]weekday
- used_idxs.append(i)
- i += 1
- x.month = int(l[i])
- used_idxs.append(i)
- i += 1
- assert l[i] in ('-', '.')
- used_idxs.append(i)
- i += 1
- x.week = int(l[i])
- if x.week == 5:
- x.week = -1
- used_idxs.append(i)
- i += 1
- assert l[i] in ('-', '.')
- used_idxs.append(i)
- i += 1
- x.weekday = (int(l[i]) - 1) % 7
- else:
- # year day (zero based)
- x.yday = int(l[i]) + 1
-
- used_idxs.append(i)
- i += 1
-
- if i < len_l and l[i] == '/':
- used_idxs.append(i)
- i += 1
- # start time
- len_li = len(l[i])
- if len_li == 4:
- # -0300
- x.time = (int(l[i][:2]) * 3600 +
- int(l[i][2:]) * 60)
- elif i + 1 < len_l and l[i + 1] == ':':
- # -03:00
- x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60
- used_idxs.append(i)
- i += 2
- if i + 1 < len_l and l[i + 1] == ':':
- used_idxs.append(i)
- i += 2
- x.time += int(l[i])
- elif len_li <= 2:
- # -[0]3
- x.time = (int(l[i][:2]) * 3600)
- else:
- return None
- used_idxs.append(i)
- i += 1
-
- assert i == len_l or l[i] == ','
-
- i += 1
-
- assert i >= len_l
-
- except (IndexError, ValueError, AssertionError):
- return None
-
- unused_idxs = set(range(len_l)).difference(used_idxs)
- res.any_unused_tokens = not {l[n] for n in unused_idxs}.issubset({",",":"})
- return res
-
-
-DEFAULTTZPARSER = _tzparser()
-
-
-def _parsetz(tzstr):
- return DEFAULTTZPARSER.parse(tzstr)
-
-class UnknownTimezoneWarning(RuntimeWarning):
- """Raised when the parser finds a timezone it cannot parse into a tzinfo"""
-# vim:ts=4:sw=4:et
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/parser/isoparser.py b/server/venv/lib/python3.7/site-packages/dateutil/parser/isoparser.py
deleted file mode 100644
index e3cf6d8..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/parser/isoparser.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers a parser for ISO-8601 strings
-
-It is intended to support all valid date, time and datetime formats per the
-ISO-8601 specification.
-
-..versionadded:: 2.7.0
-"""
-from datetime import datetime, timedelta, time, date
-import calendar
-from dateutil import tz
-
-from functools import wraps
-
-import re
-import six
-
-__all__ = ["isoparse", "isoparser"]
-
-
-def _takes_ascii(f):
- @wraps(f)
- def func(self, str_in, *args, **kwargs):
- # If it's a stream, read the whole thing
- str_in = getattr(str_in, 'read', lambda: str_in)()
-
- # If it's unicode, turn it into bytes, since ISO-8601 only covers ASCII
- if isinstance(str_in, six.text_type):
- # ASCII is the same in UTF-8
- try:
- str_in = str_in.encode('ascii')
- except UnicodeEncodeError as e:
- msg = 'ISO-8601 strings should contain only ASCII characters'
- six.raise_from(ValueError(msg), e)
-
- return f(self, str_in, *args, **kwargs)
-
- return func
-
-
-class isoparser(object):
- def __init__(self, sep=None):
- """
- :param sep:
- A single character that separates date and time portions. If
- ``None``, the parser will accept any single character.
- For strict ISO-8601 adherence, pass ``'T'``.
- """
- if sep is not None:
- if (len(sep) != 1 or ord(sep) >= 128 or sep in '0123456789'):
- raise ValueError('Separator must be a single, non-numeric ' +
- 'ASCII character')
-
- sep = sep.encode('ascii')
-
- self._sep = sep
-
- @_takes_ascii
- def isoparse(self, dt_str):
- """
- Parse an ISO-8601 datetime string into a :class:`datetime.datetime`.
-
- An ISO-8601 datetime string consists of a date portion, followed
- optionally by a time portion - the date and time portions are separated
- by a single character separator, which is ``T`` in the official
- standard. Incomplete date formats (such as ``YYYY-MM``) may *not* be
- combined with a time portion.
-
- Supported date formats are:
-
- Common:
-
- - ``YYYY``
- - ``YYYY-MM`` or ``YYYYMM``
- - ``YYYY-MM-DD`` or ``YYYYMMDD``
-
- Uncommon:
-
- - ``YYYY-Www`` or ``YYYYWww`` - ISO week (day defaults to 0)
- - ``YYYY-Www-D`` or ``YYYYWwwD`` - ISO week and day
-
- The ISO week and day numbering follows the same logic as
- :func:`datetime.date.isocalendar`.
-
- Supported time formats are:
-
- - ``hh``
- - ``hh:mm`` or ``hhmm``
- - ``hh:mm:ss`` or ``hhmmss``
- - ``hh:mm:ss.ssssss`` (Up to 6 sub-second digits)
-
- Midnight is a special case for `hh`, as the standard supports both
- 00:00 and 24:00 as a representation. The decimal separator can be
- either a dot or a comma.
-
-
- .. caution::
-
- Support for fractional components other than seconds is part of the
- ISO-8601 standard, but is not currently implemented in this parser.
-
- Supported time zone offset formats are:
-
- - `Z` (UTC)
- - `±HH:MM`
- - `±HHMM`
- - `±HH`
-
- Offsets will be represented as :class:`dateutil.tz.tzoffset` objects,
- with the exception of UTC, which will be represented as
- :class:`dateutil.tz.tzutc`. Time zone offsets equivalent to UTC (such
- as `+00:00`) will also be represented as :class:`dateutil.tz.tzutc`.
-
- :param dt_str:
- A string or stream containing only an ISO-8601 datetime string
-
- :return:
- Returns a :class:`datetime.datetime` representing the string.
- Unspecified components default to their lowest value.
-
- .. warning::
-
- As of version 2.7.0, the strictness of the parser should not be
- considered a stable part of the contract. Any valid ISO-8601 string
- that parses correctly with the default settings will continue to
- parse correctly in future versions, but invalid strings that
- currently fail (e.g. ``2017-01-01T00:00+00:00:00``) are not
- guaranteed to continue failing in future versions if they encode
- a valid date.
-
- .. versionadded:: 2.7.0
- """
- components, pos = self._parse_isodate(dt_str)
-
- if len(dt_str) > pos:
- if self._sep is None or dt_str[pos:pos + 1] == self._sep:
- components += self._parse_isotime(dt_str[pos + 1:])
- else:
- raise ValueError('String contains unknown ISO components')
-
- if len(components) > 3 and components[3] == 24:
- components[3] = 0
- return datetime(*components) + timedelta(days=1)
-
- return datetime(*components)
-
- @_takes_ascii
- def parse_isodate(self, datestr):
- """
- Parse the date portion of an ISO string.
-
- :param datestr:
- The string portion of an ISO string, without a separator
-
- :return:
- Returns a :class:`datetime.date` object
- """
- components, pos = self._parse_isodate(datestr)
- if pos < len(datestr):
- raise ValueError('String contains unknown ISO ' +
- 'components: {}'.format(datestr))
- return date(*components)
-
- @_takes_ascii
- def parse_isotime(self, timestr):
- """
- Parse the time portion of an ISO string.
-
- :param timestr:
- The time portion of an ISO string, without a separator
-
- :return:
- Returns a :class:`datetime.time` object
- """
- components = self._parse_isotime(timestr)
- if components[0] == 24:
- components[0] = 0
- return time(*components)
-
- @_takes_ascii
- def parse_tzstr(self, tzstr, zero_as_utc=True):
- """
- Parse a valid ISO time zone string.
-
- See :func:`isoparser.isoparse` for details on supported formats.
-
- :param tzstr:
- A string representing an ISO time zone offset
-
- :param zero_as_utc:
- Whether to return :class:`dateutil.tz.tzutc` for zero-offset zones
-
- :return:
- Returns :class:`dateutil.tz.tzoffset` for offsets and
- :class:`dateutil.tz.tzutc` for ``Z`` and (if ``zero_as_utc`` is
- specified) offsets equivalent to UTC.
- """
- return self._parse_tzstr(tzstr, zero_as_utc=zero_as_utc)
-
- # Constants
- _DATE_SEP = b'-'
- _TIME_SEP = b':'
- _FRACTION_REGEX = re.compile(b'[\\.,]([0-9]+)')
-
- def _parse_isodate(self, dt_str):
- try:
- return self._parse_isodate_common(dt_str)
- except ValueError:
- return self._parse_isodate_uncommon(dt_str)
-
- def _parse_isodate_common(self, dt_str):
- len_str = len(dt_str)
- components = [1, 1, 1]
-
- if len_str < 4:
- raise ValueError('ISO string too short')
-
- # Year
- components[0] = int(dt_str[0:4])
- pos = 4
- if pos >= len_str:
- return components, pos
-
- has_sep = dt_str[pos:pos + 1] == self._DATE_SEP
- if has_sep:
- pos += 1
-
- # Month
- if len_str - pos < 2:
- raise ValueError('Invalid common month')
-
- components[1] = int(dt_str[pos:pos + 2])
- pos += 2
-
- if pos >= len_str:
- if has_sep:
- return components, pos
- else:
- raise ValueError('Invalid ISO format')
-
- if has_sep:
- if dt_str[pos:pos + 1] != self._DATE_SEP:
- raise ValueError('Invalid separator in ISO string')
- pos += 1
-
- # Day
- if len_str - pos < 2:
- raise ValueError('Invalid common day')
- components[2] = int(dt_str[pos:pos + 2])
- return components, pos + 2
-
- def _parse_isodate_uncommon(self, dt_str):
- if len(dt_str) < 4:
- raise ValueError('ISO string too short')
-
- # All ISO formats start with the year
- year = int(dt_str[0:4])
-
- has_sep = dt_str[4:5] == self._DATE_SEP
-
- pos = 4 + has_sep # Skip '-' if it's there
- if dt_str[pos:pos + 1] == b'W':
- # YYYY-?Www-?D?
- pos += 1
- weekno = int(dt_str[pos:pos + 2])
- pos += 2
-
- dayno = 1
- if len(dt_str) > pos:
- if (dt_str[pos:pos + 1] == self._DATE_SEP) != has_sep:
- raise ValueError('Inconsistent use of dash separator')
-
- pos += has_sep
-
- dayno = int(dt_str[pos:pos + 1])
- pos += 1
-
- base_date = self._calculate_weekdate(year, weekno, dayno)
- else:
- # YYYYDDD or YYYY-DDD
- if len(dt_str) - pos < 3:
- raise ValueError('Invalid ordinal day')
-
- ordinal_day = int(dt_str[pos:pos + 3])
- pos += 3
-
- if ordinal_day < 1 or ordinal_day > (365 + calendar.isleap(year)):
- raise ValueError('Invalid ordinal day' +
- ' {} for year {}'.format(ordinal_day, year))
-
- base_date = date(year, 1, 1) + timedelta(days=ordinal_day - 1)
-
- components = [base_date.year, base_date.month, base_date.day]
- return components, pos
-
- def _calculate_weekdate(self, year, week, day):
- """
- Calculate the day of corresponding to the ISO year-week-day calendar.
-
- This function is effectively the inverse of
- :func:`datetime.date.isocalendar`.
-
- :param year:
- The year in the ISO calendar
-
- :param week:
- The week in the ISO calendar - range is [1, 53]
-
- :param day:
- The day in the ISO calendar - range is [1 (MON), 7 (SUN)]
-
- :return:
- Returns a :class:`datetime.date`
- """
- if not 0 < week < 54:
- raise ValueError('Invalid week: {}'.format(week))
-
- if not 0 < day < 8: # Range is 1-7
- raise ValueError('Invalid weekday: {}'.format(day))
-
- # Get week 1 for the specific year:
- jan_4 = date(year, 1, 4) # Week 1 always has January 4th in it
- week_1 = jan_4 - timedelta(days=jan_4.isocalendar()[2] - 1)
-
- # Now add the specific number of weeks and days to get what we want
- week_offset = (week - 1) * 7 + (day - 1)
- return week_1 + timedelta(days=week_offset)
-
- def _parse_isotime(self, timestr):
- len_str = len(timestr)
- components = [0, 0, 0, 0, None]
- pos = 0
- comp = -1
-
- if len(timestr) < 2:
- raise ValueError('ISO time too short')
-
- has_sep = len_str >= 3 and timestr[2:3] == self._TIME_SEP
-
- while pos < len_str and comp < 5:
- comp += 1
-
- if timestr[pos:pos + 1] in b'-+Zz':
- # Detect time zone boundary
- components[-1] = self._parse_tzstr(timestr[pos:])
- pos = len_str
- break
-
- if comp < 3:
- # Hour, minute, second
- components[comp] = int(timestr[pos:pos + 2])
- pos += 2
- if (has_sep and pos < len_str and
- timestr[pos:pos + 1] == self._TIME_SEP):
- pos += 1
-
- if comp == 3:
- # Fraction of a second
- frac = self._FRACTION_REGEX.match(timestr[pos:])
- if not frac:
- continue
-
- us_str = frac.group(1)[:6] # Truncate to microseconds
- components[comp] = int(us_str) * 10**(6 - len(us_str))
- pos += len(frac.group())
-
- if pos < len_str:
- raise ValueError('Unused components in ISO string')
-
- if components[0] == 24:
- # Standard supports 00:00 and 24:00 as representations of midnight
- if any(component != 0 for component in components[1:4]):
- raise ValueError('Hour may only be 24 at 24:00:00.000')
-
- return components
-
- def _parse_tzstr(self, tzstr, zero_as_utc=True):
- if tzstr == b'Z' or tzstr == b'z':
- return tz.tzutc()
-
- if len(tzstr) not in {3, 5, 6}:
- raise ValueError('Time zone offset must be 1, 3, 5 or 6 characters')
-
- if tzstr[0:1] == b'-':
- mult = -1
- elif tzstr[0:1] == b'+':
- mult = 1
- else:
- raise ValueError('Time zone offset requires sign')
-
- hours = int(tzstr[1:3])
- if len(tzstr) == 3:
- minutes = 0
- else:
- minutes = int(tzstr[(4 if tzstr[3:4] == self._TIME_SEP else 3):])
-
- if zero_as_utc and hours == 0 and minutes == 0:
- return tz.tzutc()
- else:
- if minutes > 59:
- raise ValueError('Invalid minutes in time zone offset')
-
- if hours > 23:
- raise ValueError('Invalid hours in time zone offset')
-
- return tz.tzoffset(None, mult * (hours * 60 + minutes) * 60)
-
-
-DEFAULT_ISOPARSER = isoparser()
-isoparse = DEFAULT_ISOPARSER.isoparse
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/relativedelta.py b/server/venv/lib/python3.7/site-packages/dateutil/relativedelta.py
deleted file mode 100644
index c65c66e..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/relativedelta.py
+++ /dev/null
@@ -1,599 +0,0 @@
-# -*- coding: utf-8 -*-
-import datetime
-import calendar
-
-import operator
-from math import copysign
-
-from six import integer_types
-from warnings import warn
-
-from ._common import weekday
-
-MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7))
-
-__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
-
-
-class relativedelta(object):
- """
- The relativedelta type is designed to be applied to an existing datetime and
- can replace specific components of that datetime, or represents an interval
- of time.
-
- It is based on the specification of the excellent work done by M.-A. Lemburg
- in his
- `mx.DateTime `_ extension.
- However, notice that this type does *NOT* implement the same algorithm as
- his work. Do *NOT* expect it to behave like mx.DateTime's counterpart.
-
- There are two different ways to build a relativedelta instance. The
- first one is passing it two date/datetime classes::
-
- relativedelta(datetime1, datetime2)
-
- The second one is passing it any number of the following keyword arguments::
-
- relativedelta(arg1=x,arg2=y,arg3=z...)
-
- year, month, day, hour, minute, second, microsecond:
- Absolute information (argument is singular); adding or subtracting a
- relativedelta with absolute information does not perform an arithmetic
- operation, but rather REPLACES the corresponding value in the
- original datetime with the value(s) in relativedelta.
-
- years, months, weeks, days, hours, minutes, seconds, microseconds:
- Relative information, may be negative (argument is plural); adding
- or subtracting a relativedelta with relative information performs
- the corresponding aritmetic operation on the original datetime value
- with the information in the relativedelta.
-
- weekday:
- One of the weekday instances (MO, TU, etc) available in the
- relativedelta module. These instances may receive a parameter N,
- specifying the Nth weekday, which could be positive or negative
- (like MO(+1) or MO(-2)). Not specifying it is the same as specifying
- +1. You can also use an integer, where 0=MO. This argument is always
- relative e.g. if the calculated date is already Monday, using MO(1)
- or MO(-1) won't change the day. To effectively make it absolute, use
- it in combination with the day argument (e.g. day=1, MO(1) for first
- Monday of the month).
-
- leapdays:
- Will add given days to the date found, if year is a leap
- year, and the date found is post 28 of february.
-
- yearday, nlyearday:
- Set the yearday or the non-leap year day (jump leap days).
- These are converted to day/month/leapdays information.
-
- There are relative and absolute forms of the keyword
- arguments. The plural is relative, and the singular is
- absolute. For each argument in the order below, the absolute form
- is applied first (by setting each attribute to that value) and
- then the relative form (by adding the value to the attribute).
-
- The order of attributes considered when this relativedelta is
- added to a datetime is:
-
- 1. Year
- 2. Month
- 3. Day
- 4. Hours
- 5. Minutes
- 6. Seconds
- 7. Microseconds
-
- Finally, weekday is applied, using the rule described above.
-
- For example
-
- >>> from datetime import datetime
- >>> from dateutil.relativedelta import relativedelta, MO
- >>> dt = datetime(2018, 4, 9, 13, 37, 0)
- >>> delta = relativedelta(hours=25, day=1, weekday=MO(1))
- >>> dt + delta
- datetime.datetime(2018, 4, 2, 14, 37)
-
- First, the day is set to 1 (the first of the month), then 25 hours
- are added, to get to the 2nd day and 14th hour, finally the
- weekday is applied, but since the 2nd is already a Monday there is
- no effect.
-
- """
-
- def __init__(self, dt1=None, dt2=None,
- years=0, months=0, days=0, leapdays=0, weeks=0,
- hours=0, minutes=0, seconds=0, microseconds=0,
- year=None, month=None, day=None, weekday=None,
- yearday=None, nlyearday=None,
- hour=None, minute=None, second=None, microsecond=None):
-
- if dt1 and dt2:
- # datetime is a subclass of date. So both must be date
- if not (isinstance(dt1, datetime.date) and
- isinstance(dt2, datetime.date)):
- raise TypeError("relativedelta only diffs datetime/date")
-
- # We allow two dates, or two datetimes, so we coerce them to be
- # of the same type
- if (isinstance(dt1, datetime.datetime) !=
- isinstance(dt2, datetime.datetime)):
- if not isinstance(dt1, datetime.datetime):
- dt1 = datetime.datetime.fromordinal(dt1.toordinal())
- elif not isinstance(dt2, datetime.datetime):
- dt2 = datetime.datetime.fromordinal(dt2.toordinal())
-
- self.years = 0
- self.months = 0
- self.days = 0
- self.leapdays = 0
- self.hours = 0
- self.minutes = 0
- self.seconds = 0
- self.microseconds = 0
- self.year = None
- self.month = None
- self.day = None
- self.weekday = None
- self.hour = None
- self.minute = None
- self.second = None
- self.microsecond = None
- self._has_time = 0
-
- # Get year / month delta between the two
- months = (dt1.year - dt2.year) * 12 + (dt1.month - dt2.month)
- self._set_months(months)
-
- # Remove the year/month delta so the timedelta is just well-defined
- # time units (seconds, days and microseconds)
- dtm = self.__radd__(dt2)
-
- # If we've overshot our target, make an adjustment
- if dt1 < dt2:
- compare = operator.gt
- increment = 1
- else:
- compare = operator.lt
- increment = -1
-
- while compare(dt1, dtm):
- months += increment
- self._set_months(months)
- dtm = self.__radd__(dt2)
-
- # Get the timedelta between the "months-adjusted" date and dt1
- delta = dt1 - dtm
- self.seconds = delta.seconds + delta.days * 86400
- self.microseconds = delta.microseconds
- else:
- # Check for non-integer values in integer-only quantities
- if any(x is not None and x != int(x) for x in (years, months)):
- raise ValueError("Non-integer years and months are "
- "ambiguous and not currently supported.")
-
- # Relative information
- self.years = int(years)
- self.months = int(months)
- self.days = days + weeks * 7
- self.leapdays = leapdays
- self.hours = hours
- self.minutes = minutes
- self.seconds = seconds
- self.microseconds = microseconds
-
- # Absolute information
- self.year = year
- self.month = month
- self.day = day
- self.hour = hour
- self.minute = minute
- self.second = second
- self.microsecond = microsecond
-
- if any(x is not None and int(x) != x
- for x in (year, month, day, hour,
- minute, second, microsecond)):
- # For now we'll deprecate floats - later it'll be an error.
- warn("Non-integer value passed as absolute information. " +
- "This is not a well-defined condition and will raise " +
- "errors in future versions.", DeprecationWarning)
-
- if isinstance(weekday, integer_types):
- self.weekday = weekdays[weekday]
- else:
- self.weekday = weekday
-
- yday = 0
- if nlyearday:
- yday = nlyearday
- elif yearday:
- yday = yearday
- if yearday > 59:
- self.leapdays = -1
- if yday:
- ydayidx = [31, 59, 90, 120, 151, 181, 212,
- 243, 273, 304, 334, 366]
- for idx, ydays in enumerate(ydayidx):
- if yday <= ydays:
- self.month = idx+1
- if idx == 0:
- self.day = yday
- else:
- self.day = yday-ydayidx[idx-1]
- break
- else:
- raise ValueError("invalid year day (%d)" % yday)
-
- self._fix()
-
- def _fix(self):
- if abs(self.microseconds) > 999999:
- s = _sign(self.microseconds)
- div, mod = divmod(self.microseconds * s, 1000000)
- self.microseconds = mod * s
- self.seconds += div * s
- if abs(self.seconds) > 59:
- s = _sign(self.seconds)
- div, mod = divmod(self.seconds * s, 60)
- self.seconds = mod * s
- self.minutes += div * s
- if abs(self.minutes) > 59:
- s = _sign(self.minutes)
- div, mod = divmod(self.minutes * s, 60)
- self.minutes = mod * s
- self.hours += div * s
- if abs(self.hours) > 23:
- s = _sign(self.hours)
- div, mod = divmod(self.hours * s, 24)
- self.hours = mod * s
- self.days += div * s
- if abs(self.months) > 11:
- s = _sign(self.months)
- div, mod = divmod(self.months * s, 12)
- self.months = mod * s
- self.years += div * s
- if (self.hours or self.minutes or self.seconds or self.microseconds
- or self.hour is not None or self.minute is not None or
- self.second is not None or self.microsecond is not None):
- self._has_time = 1
- else:
- self._has_time = 0
-
- @property
- def weeks(self):
- return int(self.days / 7.0)
-
- @weeks.setter
- def weeks(self, value):
- self.days = self.days - (self.weeks * 7) + value * 7
-
- def _set_months(self, months):
- self.months = months
- if abs(self.months) > 11:
- s = _sign(self.months)
- div, mod = divmod(self.months * s, 12)
- self.months = mod * s
- self.years = div * s
- else:
- self.years = 0
-
- def normalized(self):
- """
- Return a version of this object represented entirely using integer
- values for the relative attributes.
-
- >>> relativedelta(days=1.5, hours=2).normalized()
- relativedelta(days=+1, hours=+14)
-
- :return:
- Returns a :class:`dateutil.relativedelta.relativedelta` object.
- """
- # Cascade remainders down (rounding each to roughly nearest microsecond)
- days = int(self.days)
-
- hours_f = round(self.hours + 24 * (self.days - days), 11)
- hours = int(hours_f)
-
- minutes_f = round(self.minutes + 60 * (hours_f - hours), 10)
- minutes = int(minutes_f)
-
- seconds_f = round(self.seconds + 60 * (minutes_f - minutes), 8)
- seconds = int(seconds_f)
-
- microseconds = round(self.microseconds + 1e6 * (seconds_f - seconds))
-
- # Constructor carries overflow back up with call to _fix()
- return self.__class__(years=self.years, months=self.months,
- days=days, hours=hours, minutes=minutes,
- seconds=seconds, microseconds=microseconds,
- leapdays=self.leapdays, year=self.year,
- month=self.month, day=self.day,
- weekday=self.weekday, hour=self.hour,
- minute=self.minute, second=self.second,
- microsecond=self.microsecond)
-
- def __add__(self, other):
- if isinstance(other, relativedelta):
- return self.__class__(years=other.years + self.years,
- months=other.months + self.months,
- days=other.days + self.days,
- hours=other.hours + self.hours,
- minutes=other.minutes + self.minutes,
- seconds=other.seconds + self.seconds,
- microseconds=(other.microseconds +
- self.microseconds),
- leapdays=other.leapdays or self.leapdays,
- year=(other.year if other.year is not None
- else self.year),
- month=(other.month if other.month is not None
- else self.month),
- day=(other.day if other.day is not None
- else self.day),
- weekday=(other.weekday if other.weekday is not None
- else self.weekday),
- hour=(other.hour if other.hour is not None
- else self.hour),
- minute=(other.minute if other.minute is not None
- else self.minute),
- second=(other.second if other.second is not None
- else self.second),
- microsecond=(other.microsecond if other.microsecond
- is not None else
- self.microsecond))
- if isinstance(other, datetime.timedelta):
- return self.__class__(years=self.years,
- months=self.months,
- days=self.days + other.days,
- hours=self.hours,
- minutes=self.minutes,
- seconds=self.seconds + other.seconds,
- microseconds=self.microseconds + other.microseconds,
- leapdays=self.leapdays,
- year=self.year,
- month=self.month,
- day=self.day,
- weekday=self.weekday,
- hour=self.hour,
- minute=self.minute,
- second=self.second,
- microsecond=self.microsecond)
- if not isinstance(other, datetime.date):
- return NotImplemented
- elif self._has_time and not isinstance(other, datetime.datetime):
- other = datetime.datetime.fromordinal(other.toordinal())
- year = (self.year or other.year)+self.years
- month = self.month or other.month
- if self.months:
- assert 1 <= abs(self.months) <= 12
- month += self.months
- if month > 12:
- year += 1
- month -= 12
- elif month < 1:
- year -= 1
- month += 12
- day = min(calendar.monthrange(year, month)[1],
- self.day or other.day)
- repl = {"year": year, "month": month, "day": day}
- for attr in ["hour", "minute", "second", "microsecond"]:
- value = getattr(self, attr)
- if value is not None:
- repl[attr] = value
- days = self.days
- if self.leapdays and month > 2 and calendar.isleap(year):
- days += self.leapdays
- ret = (other.replace(**repl)
- + datetime.timedelta(days=days,
- hours=self.hours,
- minutes=self.minutes,
- seconds=self.seconds,
- microseconds=self.microseconds))
- if self.weekday:
- weekday, nth = self.weekday.weekday, self.weekday.n or 1
- jumpdays = (abs(nth) - 1) * 7
- if nth > 0:
- jumpdays += (7 - ret.weekday() + weekday) % 7
- else:
- jumpdays += (ret.weekday() - weekday) % 7
- jumpdays *= -1
- ret += datetime.timedelta(days=jumpdays)
- return ret
-
- def __radd__(self, other):
- return self.__add__(other)
-
- def __rsub__(self, other):
- return self.__neg__().__radd__(other)
-
- def __sub__(self, other):
- if not isinstance(other, relativedelta):
- return NotImplemented # In case the other object defines __rsub__
- return self.__class__(years=self.years - other.years,
- months=self.months - other.months,
- days=self.days - other.days,
- hours=self.hours - other.hours,
- minutes=self.minutes - other.minutes,
- seconds=self.seconds - other.seconds,
- microseconds=self.microseconds - other.microseconds,
- leapdays=self.leapdays or other.leapdays,
- year=(self.year if self.year is not None
- else other.year),
- month=(self.month if self.month is not None else
- other.month),
- day=(self.day if self.day is not None else
- other.day),
- weekday=(self.weekday if self.weekday is not None else
- other.weekday),
- hour=(self.hour if self.hour is not None else
- other.hour),
- minute=(self.minute if self.minute is not None else
- other.minute),
- second=(self.second if self.second is not None else
- other.second),
- microsecond=(self.microsecond if self.microsecond
- is not None else
- other.microsecond))
-
- def __abs__(self):
- return self.__class__(years=abs(self.years),
- months=abs(self.months),
- days=abs(self.days),
- hours=abs(self.hours),
- minutes=abs(self.minutes),
- seconds=abs(self.seconds),
- microseconds=abs(self.microseconds),
- leapdays=self.leapdays,
- year=self.year,
- month=self.month,
- day=self.day,
- weekday=self.weekday,
- hour=self.hour,
- minute=self.minute,
- second=self.second,
- microsecond=self.microsecond)
-
- def __neg__(self):
- return self.__class__(years=-self.years,
- months=-self.months,
- days=-self.days,
- hours=-self.hours,
- minutes=-self.minutes,
- seconds=-self.seconds,
- microseconds=-self.microseconds,
- leapdays=self.leapdays,
- year=self.year,
- month=self.month,
- day=self.day,
- weekday=self.weekday,
- hour=self.hour,
- minute=self.minute,
- second=self.second,
- microsecond=self.microsecond)
-
- def __bool__(self):
- return not (not self.years and
- not self.months and
- not self.days and
- not self.hours and
- not self.minutes and
- not self.seconds and
- not self.microseconds and
- not self.leapdays and
- self.year is None and
- self.month is None and
- self.day is None and
- self.weekday is None and
- self.hour is None and
- self.minute is None and
- self.second is None and
- self.microsecond is None)
- # Compatibility with Python 2.x
- __nonzero__ = __bool__
-
- def __mul__(self, other):
- try:
- f = float(other)
- except TypeError:
- return NotImplemented
-
- return self.__class__(years=int(self.years * f),
- months=int(self.months * f),
- days=int(self.days * f),
- hours=int(self.hours * f),
- minutes=int(self.minutes * f),
- seconds=int(self.seconds * f),
- microseconds=int(self.microseconds * f),
- leapdays=self.leapdays,
- year=self.year,
- month=self.month,
- day=self.day,
- weekday=self.weekday,
- hour=self.hour,
- minute=self.minute,
- second=self.second,
- microsecond=self.microsecond)
-
- __rmul__ = __mul__
-
- def __eq__(self, other):
- if not isinstance(other, relativedelta):
- return NotImplemented
- if self.weekday or other.weekday:
- if not self.weekday or not other.weekday:
- return False
- if self.weekday.weekday != other.weekday.weekday:
- return False
- n1, n2 = self.weekday.n, other.weekday.n
- if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)):
- return False
- return (self.years == other.years and
- self.months == other.months and
- self.days == other.days and
- self.hours == other.hours and
- self.minutes == other.minutes and
- self.seconds == other.seconds and
- self.microseconds == other.microseconds and
- self.leapdays == other.leapdays and
- self.year == other.year and
- self.month == other.month and
- self.day == other.day and
- self.hour == other.hour and
- self.minute == other.minute and
- self.second == other.second and
- self.microsecond == other.microsecond)
-
- def __hash__(self):
- return hash((
- self.weekday,
- self.years,
- self.months,
- self.days,
- self.hours,
- self.minutes,
- self.seconds,
- self.microseconds,
- self.leapdays,
- self.year,
- self.month,
- self.day,
- self.hour,
- self.minute,
- self.second,
- self.microsecond,
- ))
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def __div__(self, other):
- try:
- reciprocal = 1 / float(other)
- except TypeError:
- return NotImplemented
-
- return self.__mul__(reciprocal)
-
- __truediv__ = __div__
-
- def __repr__(self):
- l = []
- for attr in ["years", "months", "days", "leapdays",
- "hours", "minutes", "seconds", "microseconds"]:
- value = getattr(self, attr)
- if value:
- l.append("{attr}={value:+g}".format(attr=attr, value=value))
- for attr in ["year", "month", "day", "weekday",
- "hour", "minute", "second", "microsecond"]:
- value = getattr(self, attr)
- if value is not None:
- l.append("{attr}={value}".format(attr=attr, value=repr(value)))
- return "{classname}({attrs})".format(classname=self.__class__.__name__,
- attrs=", ".join(l))
-
-
-def _sign(x):
- return int(copysign(1, x))
-
-# vim:ts=4:sw=4:et
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/rrule.py b/server/venv/lib/python3.7/site-packages/dateutil/rrule.py
deleted file mode 100644
index 20a0c4a..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/rrule.py
+++ /dev/null
@@ -1,1736 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-The rrule module offers a small, complete, and very fast, implementation of
-the recurrence rules documented in the
-`iCalendar RFC `_,
-including support for caching of results.
-"""
-import itertools
-import datetime
-import calendar
-import re
-import sys
-
-try:
- from math import gcd
-except ImportError:
- from fractions import gcd
-
-from six import advance_iterator, integer_types
-from six.moves import _thread, range
-import heapq
-
-from ._common import weekday as weekdaybase
-from .tz import tzutc, tzlocal
-
-# For warning about deprecation of until and count
-from warnings import warn
-
-__all__ = ["rrule", "rruleset", "rrulestr",
- "YEARLY", "MONTHLY", "WEEKLY", "DAILY",
- "HOURLY", "MINUTELY", "SECONDLY",
- "MO", "TU", "WE", "TH", "FR", "SA", "SU"]
-
-# Every mask is 7 days longer to handle cross-year weekly periods.
-M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30 +
- [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7)
-M365MASK = list(M366MASK)
-M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32))
-MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
-MDAY365MASK = list(MDAY366MASK)
-M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0))
-NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7])
-NMDAY365MASK = list(NMDAY366MASK)
-M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366)
-M365RANGE = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
-WDAYMASK = [0, 1, 2, 3, 4, 5, 6]*55
-del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31]
-MDAY365MASK = tuple(MDAY365MASK)
-M365MASK = tuple(M365MASK)
-
-FREQNAMES = ['YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY', 'HOURLY', 'MINUTELY', 'SECONDLY']
-
-(YEARLY,
- MONTHLY,
- WEEKLY,
- DAILY,
- HOURLY,
- MINUTELY,
- SECONDLY) = list(range(7))
-
-# Imported on demand.
-easter = None
-parser = None
-
-
-class weekday(weekdaybase):
- """
- This version of weekday does not allow n = 0.
- """
- def __init__(self, wkday, n=None):
- if n == 0:
- raise ValueError("Can't create weekday with n==0")
-
- super(weekday, self).__init__(wkday, n)
-
-
-MO, TU, WE, TH, FR, SA, SU = weekdays = tuple(weekday(x) for x in range(7))
-
-
-def _invalidates_cache(f):
- """
- Decorator for rruleset methods which may invalidate the
- cached length.
- """
- def inner_func(self, *args, **kwargs):
- rv = f(self, *args, **kwargs)
- self._invalidate_cache()
- return rv
-
- return inner_func
-
-
-class rrulebase(object):
- def __init__(self, cache=False):
- if cache:
- self._cache = []
- self._cache_lock = _thread.allocate_lock()
- self._invalidate_cache()
- else:
- self._cache = None
- self._cache_complete = False
- self._len = None
-
- def __iter__(self):
- if self._cache_complete:
- return iter(self._cache)
- elif self._cache is None:
- return self._iter()
- else:
- return self._iter_cached()
-
- def _invalidate_cache(self):
- if self._cache is not None:
- self._cache = []
- self._cache_complete = False
- self._cache_gen = self._iter()
-
- if self._cache_lock.locked():
- self._cache_lock.release()
-
- self._len = None
-
- def _iter_cached(self):
- i = 0
- gen = self._cache_gen
- cache = self._cache
- acquire = self._cache_lock.acquire
- release = self._cache_lock.release
- while gen:
- if i == len(cache):
- acquire()
- if self._cache_complete:
- break
- try:
- for j in range(10):
- cache.append(advance_iterator(gen))
- except StopIteration:
- self._cache_gen = gen = None
- self._cache_complete = True
- break
- release()
- yield cache[i]
- i += 1
- while i < self._len:
- yield cache[i]
- i += 1
-
- def __getitem__(self, item):
- if self._cache_complete:
- return self._cache[item]
- elif isinstance(item, slice):
- if item.step and item.step < 0:
- return list(iter(self))[item]
- else:
- return list(itertools.islice(self,
- item.start or 0,
- item.stop or sys.maxsize,
- item.step or 1))
- elif item >= 0:
- gen = iter(self)
- try:
- for i in range(item+1):
- res = advance_iterator(gen)
- except StopIteration:
- raise IndexError
- return res
- else:
- return list(iter(self))[item]
-
- def __contains__(self, item):
- if self._cache_complete:
- return item in self._cache
- else:
- for i in self:
- if i == item:
- return True
- elif i > item:
- return False
- return False
-
- # __len__() introduces a large performance penality.
- def count(self):
- """ Returns the number of recurrences in this set. It will have go
- trough the whole recurrence, if this hasn't been done before. """
- if self._len is None:
- for x in self:
- pass
- return self._len
-
- def before(self, dt, inc=False):
- """ Returns the last recurrence before the given datetime instance. The
- inc keyword defines what happens if dt is an occurrence. With
- inc=True, if dt itself is an occurrence, it will be returned. """
- if self._cache_complete:
- gen = self._cache
- else:
- gen = self
- last = None
- if inc:
- for i in gen:
- if i > dt:
- break
- last = i
- else:
- for i in gen:
- if i >= dt:
- break
- last = i
- return last
-
- def after(self, dt, inc=False):
- """ Returns the first recurrence after the given datetime instance. The
- inc keyword defines what happens if dt is an occurrence. With
- inc=True, if dt itself is an occurrence, it will be returned. """
- if self._cache_complete:
- gen = self._cache
- else:
- gen = self
- if inc:
- for i in gen:
- if i >= dt:
- return i
- else:
- for i in gen:
- if i > dt:
- return i
- return None
-
- def xafter(self, dt, count=None, inc=False):
- """
- Generator which yields up to `count` recurrences after the given
- datetime instance, equivalent to `after`.
-
- :param dt:
- The datetime at which to start generating recurrences.
-
- :param count:
- The maximum number of recurrences to generate. If `None` (default),
- dates are generated until the recurrence rule is exhausted.
-
- :param inc:
- If `dt` is an instance of the rule and `inc` is `True`, it is
- included in the output.
-
- :yields: Yields a sequence of `datetime` objects.
- """
-
- if self._cache_complete:
- gen = self._cache
- else:
- gen = self
-
- # Select the comparison function
- if inc:
- comp = lambda dc, dtc: dc >= dtc
- else:
- comp = lambda dc, dtc: dc > dtc
-
- # Generate dates
- n = 0
- for d in gen:
- if comp(d, dt):
- if count is not None:
- n += 1
- if n > count:
- break
-
- yield d
-
- def between(self, after, before, inc=False, count=1):
- """ Returns all the occurrences of the rrule between after and before.
- The inc keyword defines what happens if after and/or before are
- themselves occurrences. With inc=True, they will be included in the
- list, if they are found in the recurrence set. """
- if self._cache_complete:
- gen = self._cache
- else:
- gen = self
- started = False
- l = []
- if inc:
- for i in gen:
- if i > before:
- break
- elif not started:
- if i >= after:
- started = True
- l.append(i)
- else:
- l.append(i)
- else:
- for i in gen:
- if i >= before:
- break
- elif not started:
- if i > after:
- started = True
- l.append(i)
- else:
- l.append(i)
- return l
-
-
-class rrule(rrulebase):
- """
- That's the base of the rrule operation. It accepts all the keywords
- defined in the RFC as its constructor parameters (except byday,
- which was renamed to byweekday) and more. The constructor prototype is::
-
- rrule(freq)
-
- Where freq must be one of YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY,
- or SECONDLY.
-
- .. note::
- Per RFC section 3.3.10, recurrence instances falling on invalid dates
- and times are ignored rather than coerced:
-
- Recurrence rules may generate recurrence instances with an invalid
- date (e.g., February 30) or nonexistent local time (e.g., 1:30 AM
- on a day where the local time is moved forward by an hour at 1:00
- AM). Such recurrence instances MUST be ignored and MUST NOT be
- counted as part of the recurrence set.
-
- This can lead to possibly surprising behavior when, for example, the
- start date occurs at the end of the month:
-
- >>> from dateutil.rrule import rrule, MONTHLY
- >>> from datetime import datetime
- >>> start_date = datetime(2014, 12, 31)
- >>> list(rrule(freq=MONTHLY, count=4, dtstart=start_date))
- ... # doctest: +NORMALIZE_WHITESPACE
- [datetime.datetime(2014, 12, 31, 0, 0),
- datetime.datetime(2015, 1, 31, 0, 0),
- datetime.datetime(2015, 3, 31, 0, 0),
- datetime.datetime(2015, 5, 31, 0, 0)]
-
- Additionally, it supports the following keyword arguments:
-
- :param dtstart:
- The recurrence start. Besides being the base for the recurrence,
- missing parameters in the final recurrence instances will also be
- extracted from this date. If not given, datetime.now() will be used
- instead.
- :param interval:
- The interval between each freq iteration. For example, when using
- YEARLY, an interval of 2 means once every two years, but with HOURLY,
- it means once every two hours. The default interval is 1.
- :param wkst:
- The week start day. Must be one of the MO, TU, WE constants, or an
- integer, specifying the first day of the week. This will affect
- recurrences based on weekly periods. The default week start is got
- from calendar.firstweekday(), and may be modified by
- calendar.setfirstweekday().
- :param count:
- If given, this determines how many occurrences will be generated.
-
- .. note::
- As of version 2.5.0, the use of the keyword ``until`` in conjunction
- with ``count`` is deprecated, to make sure ``dateutil`` is fully
- compliant with `RFC-5545 Sec. 3.3.10 `_. Therefore, ``until`` and ``count``
- **must not** occur in the same call to ``rrule``.
- :param until:
- If given, this must be a datetime instance specifying the upper-bound
- limit of the recurrence. The last recurrence in the rule is the greatest
- datetime that is less than or equal to the value specified in the
- ``until`` parameter.
-
- .. note::
- As of version 2.5.0, the use of the keyword ``until`` in conjunction
- with ``count`` is deprecated, to make sure ``dateutil`` is fully
- compliant with `RFC-5545 Sec. 3.3.10 `_. Therefore, ``until`` and ``count``
- **must not** occur in the same call to ``rrule``.
- :param bysetpos:
- If given, it must be either an integer, or a sequence of integers,
- positive or negative. Each given integer will specify an occurrence
- number, corresponding to the nth occurrence of the rule inside the
- frequency period. For example, a bysetpos of -1 if combined with a
- MONTHLY frequency, and a byweekday of (MO, TU, WE, TH, FR), will
- result in the last work day of every month.
- :param bymonth:
- If given, it must be either an integer, or a sequence of integers,
- meaning the months to apply the recurrence to.
- :param bymonthday:
- If given, it must be either an integer, or a sequence of integers,
- meaning the month days to apply the recurrence to.
- :param byyearday:
- If given, it must be either an integer, or a sequence of integers,
- meaning the year days to apply the recurrence to.
- :param byeaster:
- If given, it must be either an integer, or a sequence of integers,
- positive or negative. Each integer will define an offset from the
- Easter Sunday. Passing the offset 0 to byeaster will yield the Easter
- Sunday itself. This is an extension to the RFC specification.
- :param byweekno:
- If given, it must be either an integer, or a sequence of integers,
- meaning the week numbers to apply the recurrence to. Week numbers
- have the meaning described in ISO8601, that is, the first week of
- the year is that containing at least four days of the new year.
- :param byweekday:
- If given, it must be either an integer (0 == MO), a sequence of
- integers, one of the weekday constants (MO, TU, etc), or a sequence
- of these constants. When given, these variables will define the
- weekdays where the recurrence will be applied. It's also possible to
- use an argument n for the weekday instances, which will mean the nth
- occurrence of this weekday in the period. For example, with MONTHLY,
- or with YEARLY and BYMONTH, using FR(+1) in byweekday will specify the
- first friday of the month where the recurrence happens. Notice that in
- the RFC documentation, this is specified as BYDAY, but was renamed to
- avoid the ambiguity of that keyword.
- :param byhour:
- If given, it must be either an integer, or a sequence of integers,
- meaning the hours to apply the recurrence to.
- :param byminute:
- If given, it must be either an integer, or a sequence of integers,
- meaning the minutes to apply the recurrence to.
- :param bysecond:
- If given, it must be either an integer, or a sequence of integers,
- meaning the seconds to apply the recurrence to.
- :param cache:
- If given, it must be a boolean value specifying to enable or disable
- caching of results. If you will use the same rrule instance multiple
- times, enabling caching will improve the performance considerably.
- """
- def __init__(self, freq, dtstart=None,
- interval=1, wkst=None, count=None, until=None, bysetpos=None,
- bymonth=None, bymonthday=None, byyearday=None, byeaster=None,
- byweekno=None, byweekday=None,
- byhour=None, byminute=None, bysecond=None,
- cache=False):
- super(rrule, self).__init__(cache)
- global easter
- if not dtstart:
- if until and until.tzinfo:
- dtstart = datetime.datetime.now(tz=until.tzinfo).replace(microsecond=0)
- else:
- dtstart = datetime.datetime.now().replace(microsecond=0)
- elif not isinstance(dtstart, datetime.datetime):
- dtstart = datetime.datetime.fromordinal(dtstart.toordinal())
- else:
- dtstart = dtstart.replace(microsecond=0)
- self._dtstart = dtstart
- self._tzinfo = dtstart.tzinfo
- self._freq = freq
- self._interval = interval
- self._count = count
-
- # Cache the original byxxx rules, if they are provided, as the _byxxx
- # attributes do not necessarily map to the inputs, and this can be
- # a problem in generating the strings. Only store things if they've
- # been supplied (the string retrieval will just use .get())
- self._original_rule = {}
-
- if until and not isinstance(until, datetime.datetime):
- until = datetime.datetime.fromordinal(until.toordinal())
- self._until = until
-
- if self._dtstart and self._until:
- if (self._dtstart.tzinfo is not None) != (self._until.tzinfo is not None):
- # According to RFC5545 Section 3.3.10:
- # https://tools.ietf.org/html/rfc5545#section-3.3.10
- #
- # > If the "DTSTART" property is specified as a date with UTC
- # > time or a date with local time and time zone reference,
- # > then the UNTIL rule part MUST be specified as a date with
- # > UTC time.
- raise ValueError(
- 'RRULE UNTIL values must be specified in UTC when DTSTART '
- 'is timezone-aware'
- )
-
- if count is not None and until:
- warn("Using both 'count' and 'until' is inconsistent with RFC 5545"
- " and has been deprecated in dateutil. Future versions will "
- "raise an error.", DeprecationWarning)
-
- if wkst is None:
- self._wkst = calendar.firstweekday()
- elif isinstance(wkst, integer_types):
- self._wkst = wkst
- else:
- self._wkst = wkst.weekday
-
- if bysetpos is None:
- self._bysetpos = None
- elif isinstance(bysetpos, integer_types):
- if bysetpos == 0 or not (-366 <= bysetpos <= 366):
- raise ValueError("bysetpos must be between 1 and 366, "
- "or between -366 and -1")
- self._bysetpos = (bysetpos,)
- else:
- self._bysetpos = tuple(bysetpos)
- for pos in self._bysetpos:
- if pos == 0 or not (-366 <= pos <= 366):
- raise ValueError("bysetpos must be between 1 and 366, "
- "or between -366 and -1")
-
- if self._bysetpos:
- self._original_rule['bysetpos'] = self._bysetpos
-
- if (byweekno is None and byyearday is None and bymonthday is None and
- byweekday is None and byeaster is None):
- if freq == YEARLY:
- if bymonth is None:
- bymonth = dtstart.month
- self._original_rule['bymonth'] = None
- bymonthday = dtstart.day
- self._original_rule['bymonthday'] = None
- elif freq == MONTHLY:
- bymonthday = dtstart.day
- self._original_rule['bymonthday'] = None
- elif freq == WEEKLY:
- byweekday = dtstart.weekday()
- self._original_rule['byweekday'] = None
-
- # bymonth
- if bymonth is None:
- self._bymonth = None
- else:
- if isinstance(bymonth, integer_types):
- bymonth = (bymonth,)
-
- self._bymonth = tuple(sorted(set(bymonth)))
-
- if 'bymonth' not in self._original_rule:
- self._original_rule['bymonth'] = self._bymonth
-
- # byyearday
- if byyearday is None:
- self._byyearday = None
- else:
- if isinstance(byyearday, integer_types):
- byyearday = (byyearday,)
-
- self._byyearday = tuple(sorted(set(byyearday)))
- self._original_rule['byyearday'] = self._byyearday
-
- # byeaster
- if byeaster is not None:
- if not easter:
- from dateutil import easter
- if isinstance(byeaster, integer_types):
- self._byeaster = (byeaster,)
- else:
- self._byeaster = tuple(sorted(byeaster))
-
- self._original_rule['byeaster'] = self._byeaster
- else:
- self._byeaster = None
-
- # bymonthday
- if bymonthday is None:
- self._bymonthday = ()
- self._bynmonthday = ()
- else:
- if isinstance(bymonthday, integer_types):
- bymonthday = (bymonthday,)
-
- bymonthday = set(bymonthday) # Ensure it's unique
-
- self._bymonthday = tuple(sorted(x for x in bymonthday if x > 0))
- self._bynmonthday = tuple(sorted(x for x in bymonthday if x < 0))
-
- # Storing positive numbers first, then negative numbers
- if 'bymonthday' not in self._original_rule:
- self._original_rule['bymonthday'] = tuple(
- itertools.chain(self._bymonthday, self._bynmonthday))
-
- # byweekno
- if byweekno is None:
- self._byweekno = None
- else:
- if isinstance(byweekno, integer_types):
- byweekno = (byweekno,)
-
- self._byweekno = tuple(sorted(set(byweekno)))
-
- self._original_rule['byweekno'] = self._byweekno
-
- # byweekday / bynweekday
- if byweekday is None:
- self._byweekday = None
- self._bynweekday = None
- else:
- # If it's one of the valid non-sequence types, convert to a
- # single-element sequence before the iterator that builds the
- # byweekday set.
- if isinstance(byweekday, integer_types) or hasattr(byweekday, "n"):
- byweekday = (byweekday,)
-
- self._byweekday = set()
- self._bynweekday = set()
- for wday in byweekday:
- if isinstance(wday, integer_types):
- self._byweekday.add(wday)
- elif not wday.n or freq > MONTHLY:
- self._byweekday.add(wday.weekday)
- else:
- self._bynweekday.add((wday.weekday, wday.n))
-
- if not self._byweekday:
- self._byweekday = None
- elif not self._bynweekday:
- self._bynweekday = None
-
- if self._byweekday is not None:
- self._byweekday = tuple(sorted(self._byweekday))
- orig_byweekday = [weekday(x) for x in self._byweekday]
- else:
- orig_byweekday = ()
-
- if self._bynweekday is not None:
- self._bynweekday = tuple(sorted(self._bynweekday))
- orig_bynweekday = [weekday(*x) for x in self._bynweekday]
- else:
- orig_bynweekday = ()
-
- if 'byweekday' not in self._original_rule:
- self._original_rule['byweekday'] = tuple(itertools.chain(
- orig_byweekday, orig_bynweekday))
-
- # byhour
- if byhour is None:
- if freq < HOURLY:
- self._byhour = {dtstart.hour}
- else:
- self._byhour = None
- else:
- if isinstance(byhour, integer_types):
- byhour = (byhour,)
-
- if freq == HOURLY:
- self._byhour = self.__construct_byset(start=dtstart.hour,
- byxxx=byhour,
- base=24)
- else:
- self._byhour = set(byhour)
-
- self._byhour = tuple(sorted(self._byhour))
- self._original_rule['byhour'] = self._byhour
-
- # byminute
- if byminute is None:
- if freq < MINUTELY:
- self._byminute = {dtstart.minute}
- else:
- self._byminute = None
- else:
- if isinstance(byminute, integer_types):
- byminute = (byminute,)
-
- if freq == MINUTELY:
- self._byminute = self.__construct_byset(start=dtstart.minute,
- byxxx=byminute,
- base=60)
- else:
- self._byminute = set(byminute)
-
- self._byminute = tuple(sorted(self._byminute))
- self._original_rule['byminute'] = self._byminute
-
- # bysecond
- if bysecond is None:
- if freq < SECONDLY:
- self._bysecond = ((dtstart.second,))
- else:
- self._bysecond = None
- else:
- if isinstance(bysecond, integer_types):
- bysecond = (bysecond,)
-
- self._bysecond = set(bysecond)
-
- if freq == SECONDLY:
- self._bysecond = self.__construct_byset(start=dtstart.second,
- byxxx=bysecond,
- base=60)
- else:
- self._bysecond = set(bysecond)
-
- self._bysecond = tuple(sorted(self._bysecond))
- self._original_rule['bysecond'] = self._bysecond
-
- if self._freq >= HOURLY:
- self._timeset = None
- else:
- self._timeset = []
- for hour in self._byhour:
- for minute in self._byminute:
- for second in self._bysecond:
- self._timeset.append(
- datetime.time(hour, minute, second,
- tzinfo=self._tzinfo))
- self._timeset.sort()
- self._timeset = tuple(self._timeset)
-
- def __str__(self):
- """
- Output a string that would generate this RRULE if passed to rrulestr.
- This is mostly compatible with RFC5545, except for the
- dateutil-specific extension BYEASTER.
- """
-
- output = []
- h, m, s = [None] * 3
- if self._dtstart:
- output.append(self._dtstart.strftime('DTSTART:%Y%m%dT%H%M%S'))
- h, m, s = self._dtstart.timetuple()[3:6]
-
- parts = ['FREQ=' + FREQNAMES[self._freq]]
- if self._interval != 1:
- parts.append('INTERVAL=' + str(self._interval))
-
- if self._wkst:
- parts.append('WKST=' + repr(weekday(self._wkst))[0:2])
-
- if self._count is not None:
- parts.append('COUNT=' + str(self._count))
-
- if self._until:
- parts.append(self._until.strftime('UNTIL=%Y%m%dT%H%M%S'))
-
- if self._original_rule.get('byweekday') is not None:
- # The str() method on weekday objects doesn't generate
- # RFC5545-compliant strings, so we should modify that.
- original_rule = dict(self._original_rule)
- wday_strings = []
- for wday in original_rule['byweekday']:
- if wday.n:
- wday_strings.append('{n:+d}{wday}'.format(
- n=wday.n,
- wday=repr(wday)[0:2]))
- else:
- wday_strings.append(repr(wday))
-
- original_rule['byweekday'] = wday_strings
- else:
- original_rule = self._original_rule
-
- partfmt = '{name}={vals}'
- for name, key in [('BYSETPOS', 'bysetpos'),
- ('BYMONTH', 'bymonth'),
- ('BYMONTHDAY', 'bymonthday'),
- ('BYYEARDAY', 'byyearday'),
- ('BYWEEKNO', 'byweekno'),
- ('BYDAY', 'byweekday'),
- ('BYHOUR', 'byhour'),
- ('BYMINUTE', 'byminute'),
- ('BYSECOND', 'bysecond'),
- ('BYEASTER', 'byeaster')]:
- value = original_rule.get(key)
- if value:
- parts.append(partfmt.format(name=name, vals=(','.join(str(v)
- for v in value))))
-
- output.append('RRULE:' + ';'.join(parts))
- return '\n'.join(output)
-
- def replace(self, **kwargs):
- """Return new rrule with same attributes except for those attributes given new
- values by whichever keyword arguments are specified."""
- new_kwargs = {"interval": self._interval,
- "count": self._count,
- "dtstart": self._dtstart,
- "freq": self._freq,
- "until": self._until,
- "wkst": self._wkst,
- "cache": False if self._cache is None else True }
- new_kwargs.update(self._original_rule)
- new_kwargs.update(kwargs)
- return rrule(**new_kwargs)
-
- def _iter(self):
- year, month, day, hour, minute, second, weekday, yearday, _ = \
- self._dtstart.timetuple()
-
- # Some local variables to speed things up a bit
- freq = self._freq
- interval = self._interval
- wkst = self._wkst
- until = self._until
- bymonth = self._bymonth
- byweekno = self._byweekno
- byyearday = self._byyearday
- byweekday = self._byweekday
- byeaster = self._byeaster
- bymonthday = self._bymonthday
- bynmonthday = self._bynmonthday
- bysetpos = self._bysetpos
- byhour = self._byhour
- byminute = self._byminute
- bysecond = self._bysecond
-
- ii = _iterinfo(self)
- ii.rebuild(year, month)
-
- getdayset = {YEARLY: ii.ydayset,
- MONTHLY: ii.mdayset,
- WEEKLY: ii.wdayset,
- DAILY: ii.ddayset,
- HOURLY: ii.ddayset,
- MINUTELY: ii.ddayset,
- SECONDLY: ii.ddayset}[freq]
-
- if freq < HOURLY:
- timeset = self._timeset
- else:
- gettimeset = {HOURLY: ii.htimeset,
- MINUTELY: ii.mtimeset,
- SECONDLY: ii.stimeset}[freq]
- if ((freq >= HOURLY and
- self._byhour and hour not in self._byhour) or
- (freq >= MINUTELY and
- self._byminute and minute not in self._byminute) or
- (freq >= SECONDLY and
- self._bysecond and second not in self._bysecond)):
- timeset = ()
- else:
- timeset = gettimeset(hour, minute, second)
-
- total = 0
- count = self._count
- while True:
- # Get dayset with the right frequency
- dayset, start, end = getdayset(year, month, day)
-
- # Do the "hard" work ;-)
- filtered = False
- for i in dayset[start:end]:
- if ((bymonth and ii.mmask[i] not in bymonth) or
- (byweekno and not ii.wnomask[i]) or
- (byweekday and ii.wdaymask[i] not in byweekday) or
- (ii.nwdaymask and not ii.nwdaymask[i]) or
- (byeaster and not ii.eastermask[i]) or
- ((bymonthday or bynmonthday) and
- ii.mdaymask[i] not in bymonthday and
- ii.nmdaymask[i] not in bynmonthday) or
- (byyearday and
- ((i < ii.yearlen and i+1 not in byyearday and
- -ii.yearlen+i not in byyearday) or
- (i >= ii.yearlen and i+1-ii.yearlen not in byyearday and
- -ii.nextyearlen+i-ii.yearlen not in byyearday)))):
- dayset[i] = None
- filtered = True
-
- # Output results
- if bysetpos and timeset:
- poslist = []
- for pos in bysetpos:
- if pos < 0:
- daypos, timepos = divmod(pos, len(timeset))
- else:
- daypos, timepos = divmod(pos-1, len(timeset))
- try:
- i = [x for x in dayset[start:end]
- if x is not None][daypos]
- time = timeset[timepos]
- except IndexError:
- pass
- else:
- date = datetime.date.fromordinal(ii.yearordinal+i)
- res = datetime.datetime.combine(date, time)
- if res not in poslist:
- poslist.append(res)
- poslist.sort()
- for res in poslist:
- if until and res > until:
- self._len = total
- return
- elif res >= self._dtstart:
- if count is not None:
- count -= 1
- if count < 0:
- self._len = total
- return
- total += 1
- yield res
- else:
- for i in dayset[start:end]:
- if i is not None:
- date = datetime.date.fromordinal(ii.yearordinal + i)
- for time in timeset:
- res = datetime.datetime.combine(date, time)
- if until and res > until:
- self._len = total
- return
- elif res >= self._dtstart:
- if count is not None:
- count -= 1
- if count < 0:
- self._len = total
- return
-
- total += 1
- yield res
-
- # Handle frequency and interval
- fixday = False
- if freq == YEARLY:
- year += interval
- if year > datetime.MAXYEAR:
- self._len = total
- return
- ii.rebuild(year, month)
- elif freq == MONTHLY:
- month += interval
- if month > 12:
- div, mod = divmod(month, 12)
- month = mod
- year += div
- if month == 0:
- month = 12
- year -= 1
- if year > datetime.MAXYEAR:
- self._len = total
- return
- ii.rebuild(year, month)
- elif freq == WEEKLY:
- if wkst > weekday:
- day += -(weekday+1+(6-wkst))+self._interval*7
- else:
- day += -(weekday-wkst)+self._interval*7
- weekday = wkst
- fixday = True
- elif freq == DAILY:
- day += interval
- fixday = True
- elif freq == HOURLY:
- if filtered:
- # Jump to one iteration before next day
- hour += ((23-hour)//interval)*interval
-
- if byhour:
- ndays, hour = self.__mod_distance(value=hour,
- byxxx=self._byhour,
- base=24)
- else:
- ndays, hour = divmod(hour+interval, 24)
-
- if ndays:
- day += ndays
- fixday = True
-
- timeset = gettimeset(hour, minute, second)
- elif freq == MINUTELY:
- if filtered:
- # Jump to one iteration before next day
- minute += ((1439-(hour*60+minute))//interval)*interval
-
- valid = False
- rep_rate = (24*60)
- for j in range(rep_rate // gcd(interval, rep_rate)):
- if byminute:
- nhours, minute = \
- self.__mod_distance(value=minute,
- byxxx=self._byminute,
- base=60)
- else:
- nhours, minute = divmod(minute+interval, 60)
-
- div, hour = divmod(hour+nhours, 24)
- if div:
- day += div
- fixday = True
- filtered = False
-
- if not byhour or hour in byhour:
- valid = True
- break
-
- if not valid:
- raise ValueError('Invalid combination of interval and ' +
- 'byhour resulting in empty rule.')
-
- timeset = gettimeset(hour, minute, second)
- elif freq == SECONDLY:
- if filtered:
- # Jump to one iteration before next day
- second += (((86399 - (hour * 3600 + minute * 60 + second))
- // interval) * interval)
-
- rep_rate = (24 * 3600)
- valid = False
- for j in range(0, rep_rate // gcd(interval, rep_rate)):
- if bysecond:
- nminutes, second = \
- self.__mod_distance(value=second,
- byxxx=self._bysecond,
- base=60)
- else:
- nminutes, second = divmod(second+interval, 60)
-
- div, minute = divmod(minute+nminutes, 60)
- if div:
- hour += div
- div, hour = divmod(hour, 24)
- if div:
- day += div
- fixday = True
-
- if ((not byhour or hour in byhour) and
- (not byminute or minute in byminute) and
- (not bysecond or second in bysecond)):
- valid = True
- break
-
- if not valid:
- raise ValueError('Invalid combination of interval, ' +
- 'byhour and byminute resulting in empty' +
- ' rule.')
-
- timeset = gettimeset(hour, minute, second)
-
- if fixday and day > 28:
- daysinmonth = calendar.monthrange(year, month)[1]
- if day > daysinmonth:
- while day > daysinmonth:
- day -= daysinmonth
- month += 1
- if month == 13:
- month = 1
- year += 1
- if year > datetime.MAXYEAR:
- self._len = total
- return
- daysinmonth = calendar.monthrange(year, month)[1]
- ii.rebuild(year, month)
-
- def __construct_byset(self, start, byxxx, base):
- """
- If a `BYXXX` sequence is passed to the constructor at the same level as
- `FREQ` (e.g. `FREQ=HOURLY,BYHOUR={2,4,7},INTERVAL=3`), there are some
- specifications which cannot be reached given some starting conditions.
-
- This occurs whenever the interval is not coprime with the base of a
- given unit and the difference between the starting position and the
- ending position is not coprime with the greatest common denominator
- between the interval and the base. For example, with a FREQ of hourly
- starting at 17:00 and an interval of 4, the only valid values for
- BYHOUR would be {21, 1, 5, 9, 13, 17}, because 4 and 24 are not
- coprime.
-
- :param start:
- Specifies the starting position.
- :param byxxx:
- An iterable containing the list of allowed values.
- :param base:
- The largest allowable value for the specified frequency (e.g.
- 24 hours, 60 minutes).
-
- This does not preserve the type of the iterable, returning a set, since
- the values should be unique and the order is irrelevant, this will
- speed up later lookups.
-
- In the event of an empty set, raises a :exception:`ValueError`, as this
- results in an empty rrule.
- """
-
- cset = set()
-
- # Support a single byxxx value.
- if isinstance(byxxx, integer_types):
- byxxx = (byxxx, )
-
- for num in byxxx:
- i_gcd = gcd(self._interval, base)
- # Use divmod rather than % because we need to wrap negative nums.
- if i_gcd == 1 or divmod(num - start, i_gcd)[1] == 0:
- cset.add(num)
-
- if len(cset) == 0:
- raise ValueError("Invalid rrule byxxx generates an empty set.")
-
- return cset
-
- def __mod_distance(self, value, byxxx, base):
- """
- Calculates the next value in a sequence where the `FREQ` parameter is
- specified along with a `BYXXX` parameter at the same "level"
- (e.g. `HOURLY` specified with `BYHOUR`).
-
- :param value:
- The old value of the component.
- :param byxxx:
- The `BYXXX` set, which should have been generated by
- `rrule._construct_byset`, or something else which checks that a
- valid rule is present.
- :param base:
- The largest allowable value for the specified frequency (e.g.
- 24 hours, 60 minutes).
-
- If a valid value is not found after `base` iterations (the maximum
- number before the sequence would start to repeat), this raises a
- :exception:`ValueError`, as no valid values were found.
-
- This returns a tuple of `divmod(n*interval, base)`, where `n` is the
- smallest number of `interval` repetitions until the next specified
- value in `byxxx` is found.
- """
- accumulator = 0
- for ii in range(1, base + 1):
- # Using divmod() over % to account for negative intervals
- div, value = divmod(value + self._interval, base)
- accumulator += div
- if value in byxxx:
- return (accumulator, value)
-
-
-class _iterinfo(object):
- __slots__ = ["rrule", "lastyear", "lastmonth",
- "yearlen", "nextyearlen", "yearordinal", "yearweekday",
- "mmask", "mrange", "mdaymask", "nmdaymask",
- "wdaymask", "wnomask", "nwdaymask", "eastermask"]
-
- def __init__(self, rrule):
- for attr in self.__slots__:
- setattr(self, attr, None)
- self.rrule = rrule
-
- def rebuild(self, year, month):
- # Every mask is 7 days longer to handle cross-year weekly periods.
- rr = self.rrule
- if year != self.lastyear:
- self.yearlen = 365 + calendar.isleap(year)
- self.nextyearlen = 365 + calendar.isleap(year + 1)
- firstyday = datetime.date(year, 1, 1)
- self.yearordinal = firstyday.toordinal()
- self.yearweekday = firstyday.weekday()
-
- wday = datetime.date(year, 1, 1).weekday()
- if self.yearlen == 365:
- self.mmask = M365MASK
- self.mdaymask = MDAY365MASK
- self.nmdaymask = NMDAY365MASK
- self.wdaymask = WDAYMASK[wday:]
- self.mrange = M365RANGE
- else:
- self.mmask = M366MASK
- self.mdaymask = MDAY366MASK
- self.nmdaymask = NMDAY366MASK
- self.wdaymask = WDAYMASK[wday:]
- self.mrange = M366RANGE
-
- if not rr._byweekno:
- self.wnomask = None
- else:
- self.wnomask = [0]*(self.yearlen+7)
- # no1wkst = firstwkst = self.wdaymask.index(rr._wkst)
- no1wkst = firstwkst = (7-self.yearweekday+rr._wkst) % 7
- if no1wkst >= 4:
- no1wkst = 0
- # Number of days in the year, plus the days we got
- # from last year.
- wyearlen = self.yearlen+(self.yearweekday-rr._wkst) % 7
- else:
- # Number of days in the year, minus the days we
- # left in last year.
- wyearlen = self.yearlen-no1wkst
- div, mod = divmod(wyearlen, 7)
- numweeks = div+mod//4
- for n in rr._byweekno:
- if n < 0:
- n += numweeks+1
- if not (0 < n <= numweeks):
- continue
- if n > 1:
- i = no1wkst+(n-1)*7
- if no1wkst != firstwkst:
- i -= 7-firstwkst
- else:
- i = no1wkst
- for j in range(7):
- self.wnomask[i] = 1
- i += 1
- if self.wdaymask[i] == rr._wkst:
- break
- if 1 in rr._byweekno:
- # Check week number 1 of next year as well
- # TODO: Check -numweeks for next year.
- i = no1wkst+numweeks*7
- if no1wkst != firstwkst:
- i -= 7-firstwkst
- if i < self.yearlen:
- # If week starts in next year, we
- # don't care about it.
- for j in range(7):
- self.wnomask[i] = 1
- i += 1
- if self.wdaymask[i] == rr._wkst:
- break
- if no1wkst:
- # Check last week number of last year as
- # well. If no1wkst is 0, either the year
- # started on week start, or week number 1
- # got days from last year, so there are no
- # days from last year's last week number in
- # this year.
- if -1 not in rr._byweekno:
- lyearweekday = datetime.date(year-1, 1, 1).weekday()
- lno1wkst = (7-lyearweekday+rr._wkst) % 7
- lyearlen = 365+calendar.isleap(year-1)
- if lno1wkst >= 4:
- lno1wkst = 0
- lnumweeks = 52+(lyearlen +
- (lyearweekday-rr._wkst) % 7) % 7//4
- else:
- lnumweeks = 52+(self.yearlen-no1wkst) % 7//4
- else:
- lnumweeks = -1
- if lnumweeks in rr._byweekno:
- for i in range(no1wkst):
- self.wnomask[i] = 1
-
- if (rr._bynweekday and (month != self.lastmonth or
- year != self.lastyear)):
- ranges = []
- if rr._freq == YEARLY:
- if rr._bymonth:
- for month in rr._bymonth:
- ranges.append(self.mrange[month-1:month+1])
- else:
- ranges = [(0, self.yearlen)]
- elif rr._freq == MONTHLY:
- ranges = [self.mrange[month-1:month+1]]
- if ranges:
- # Weekly frequency won't get here, so we may not
- # care about cross-year weekly periods.
- self.nwdaymask = [0]*self.yearlen
- for first, last in ranges:
- last -= 1
- for wday, n in rr._bynweekday:
- if n < 0:
- i = last+(n+1)*7
- i -= (self.wdaymask[i]-wday) % 7
- else:
- i = first+(n-1)*7
- i += (7-self.wdaymask[i]+wday) % 7
- if first <= i <= last:
- self.nwdaymask[i] = 1
-
- if rr._byeaster:
- self.eastermask = [0]*(self.yearlen+7)
- eyday = easter.easter(year).toordinal()-self.yearordinal
- for offset in rr._byeaster:
- self.eastermask[eyday+offset] = 1
-
- self.lastyear = year
- self.lastmonth = month
-
- def ydayset(self, year, month, day):
- return list(range(self.yearlen)), 0, self.yearlen
-
- def mdayset(self, year, month, day):
- dset = [None]*self.yearlen
- start, end = self.mrange[month-1:month+1]
- for i in range(start, end):
- dset[i] = i
- return dset, start, end
-
- def wdayset(self, year, month, day):
- # We need to handle cross-year weeks here.
- dset = [None]*(self.yearlen+7)
- i = datetime.date(year, month, day).toordinal()-self.yearordinal
- start = i
- for j in range(7):
- dset[i] = i
- i += 1
- # if (not (0 <= i < self.yearlen) or
- # self.wdaymask[i] == self.rrule._wkst):
- # This will cross the year boundary, if necessary.
- if self.wdaymask[i] == self.rrule._wkst:
- break
- return dset, start, i
-
- def ddayset(self, year, month, day):
- dset = [None] * self.yearlen
- i = datetime.date(year, month, day).toordinal() - self.yearordinal
- dset[i] = i
- return dset, i, i + 1
-
- def htimeset(self, hour, minute, second):
- tset = []
- rr = self.rrule
- for minute in rr._byminute:
- for second in rr._bysecond:
- tset.append(datetime.time(hour, minute, second,
- tzinfo=rr._tzinfo))
- tset.sort()
- return tset
-
- def mtimeset(self, hour, minute, second):
- tset = []
- rr = self.rrule
- for second in rr._bysecond:
- tset.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo))
- tset.sort()
- return tset
-
- def stimeset(self, hour, minute, second):
- return (datetime.time(hour, minute, second,
- tzinfo=self.rrule._tzinfo),)
-
-
-class rruleset(rrulebase):
- """ The rruleset type allows more complex recurrence setups, mixing
- multiple rules, dates, exclusion rules, and exclusion dates. The type
- constructor takes the following keyword arguments:
-
- :param cache: If True, caching of results will be enabled, improving
- performance of multiple queries considerably. """
-
- class _genitem(object):
- def __init__(self, genlist, gen):
- try:
- self.dt = advance_iterator(gen)
- genlist.append(self)
- except StopIteration:
- pass
- self.genlist = genlist
- self.gen = gen
-
- def __next__(self):
- try:
- self.dt = advance_iterator(self.gen)
- except StopIteration:
- if self.genlist[0] is self:
- heapq.heappop(self.genlist)
- else:
- self.genlist.remove(self)
- heapq.heapify(self.genlist)
-
- next = __next__
-
- def __lt__(self, other):
- return self.dt < other.dt
-
- def __gt__(self, other):
- return self.dt > other.dt
-
- def __eq__(self, other):
- return self.dt == other.dt
-
- def __ne__(self, other):
- return self.dt != other.dt
-
- def __init__(self, cache=False):
- super(rruleset, self).__init__(cache)
- self._rrule = []
- self._rdate = []
- self._exrule = []
- self._exdate = []
-
- @_invalidates_cache
- def rrule(self, rrule):
- """ Include the given :py:class:`rrule` instance in the recurrence set
- generation. """
- self._rrule.append(rrule)
-
- @_invalidates_cache
- def rdate(self, rdate):
- """ Include the given :py:class:`datetime` instance in the recurrence
- set generation. """
- self._rdate.append(rdate)
-
- @_invalidates_cache
- def exrule(self, exrule):
- """ Include the given rrule instance in the recurrence set exclusion
- list. Dates which are part of the given recurrence rules will not
- be generated, even if some inclusive rrule or rdate matches them.
- """
- self._exrule.append(exrule)
-
- @_invalidates_cache
- def exdate(self, exdate):
- """ Include the given datetime instance in the recurrence set
- exclusion list. Dates included that way will not be generated,
- even if some inclusive rrule or rdate matches them. """
- self._exdate.append(exdate)
-
- def _iter(self):
- rlist = []
- self._rdate.sort()
- self._genitem(rlist, iter(self._rdate))
- for gen in [iter(x) for x in self._rrule]:
- self._genitem(rlist, gen)
- exlist = []
- self._exdate.sort()
- self._genitem(exlist, iter(self._exdate))
- for gen in [iter(x) for x in self._exrule]:
- self._genitem(exlist, gen)
- lastdt = None
- total = 0
- heapq.heapify(rlist)
- heapq.heapify(exlist)
- while rlist:
- ritem = rlist[0]
- if not lastdt or lastdt != ritem.dt:
- while exlist and exlist[0] < ritem:
- exitem = exlist[0]
- advance_iterator(exitem)
- if exlist and exlist[0] is exitem:
- heapq.heapreplace(exlist, exitem)
- if not exlist or ritem != exlist[0]:
- total += 1
- yield ritem.dt
- lastdt = ritem.dt
- advance_iterator(ritem)
- if rlist and rlist[0] is ritem:
- heapq.heapreplace(rlist, ritem)
- self._len = total
-
-
-
-
-class _rrulestr(object):
- """ Parses a string representation of a recurrence rule or set of
- recurrence rules.
-
- :param s:
- Required, a string defining one or more recurrence rules.
-
- :param dtstart:
- If given, used as the default recurrence start if not specified in the
- rule string.
-
- :param cache:
- If set ``True`` caching of results will be enabled, improving
- performance of multiple queries considerably.
-
- :param unfold:
- If set ``True`` indicates that a rule string is split over more
- than one line and should be joined before processing.
-
- :param forceset:
- If set ``True`` forces a :class:`dateutil.rrule.rruleset` to
- be returned.
-
- :param compatible:
- If set ``True`` forces ``unfold`` and ``forceset`` to be ``True``.
-
- :param ignoretz:
- If set ``True``, time zones in parsed strings are ignored and a naive
- :class:`datetime.datetime` object is returned.
-
- :param tzids:
- If given, a callable or mapping used to retrieve a
- :class:`datetime.tzinfo` from a string representation.
- Defaults to :func:`dateutil.tz.gettz`.
-
- :param tzinfos:
- Additional time zone names / aliases which may be present in a string
- representation. See :func:`dateutil.parser.parse` for more
- information.
-
- :return:
- Returns a :class:`dateutil.rrule.rruleset` or
- :class:`dateutil.rrule.rrule`
- """
-
- _freq_map = {"YEARLY": YEARLY,
- "MONTHLY": MONTHLY,
- "WEEKLY": WEEKLY,
- "DAILY": DAILY,
- "HOURLY": HOURLY,
- "MINUTELY": MINUTELY,
- "SECONDLY": SECONDLY}
-
- _weekday_map = {"MO": 0, "TU": 1, "WE": 2, "TH": 3,
- "FR": 4, "SA": 5, "SU": 6}
-
- def _handle_int(self, rrkwargs, name, value, **kwargs):
- rrkwargs[name.lower()] = int(value)
-
- def _handle_int_list(self, rrkwargs, name, value, **kwargs):
- rrkwargs[name.lower()] = [int(x) for x in value.split(',')]
-
- _handle_INTERVAL = _handle_int
- _handle_COUNT = _handle_int
- _handle_BYSETPOS = _handle_int_list
- _handle_BYMONTH = _handle_int_list
- _handle_BYMONTHDAY = _handle_int_list
- _handle_BYYEARDAY = _handle_int_list
- _handle_BYEASTER = _handle_int_list
- _handle_BYWEEKNO = _handle_int_list
- _handle_BYHOUR = _handle_int_list
- _handle_BYMINUTE = _handle_int_list
- _handle_BYSECOND = _handle_int_list
-
- def _handle_FREQ(self, rrkwargs, name, value, **kwargs):
- rrkwargs["freq"] = self._freq_map[value]
-
- def _handle_UNTIL(self, rrkwargs, name, value, **kwargs):
- global parser
- if not parser:
- from dateutil import parser
- try:
- rrkwargs["until"] = parser.parse(value,
- ignoretz=kwargs.get("ignoretz"),
- tzinfos=kwargs.get("tzinfos"))
- except ValueError:
- raise ValueError("invalid until date")
-
- def _handle_WKST(self, rrkwargs, name, value, **kwargs):
- rrkwargs["wkst"] = self._weekday_map[value]
-
- def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwargs):
- """
- Two ways to specify this: +1MO or MO(+1)
- """
- l = []
- for wday in value.split(','):
- if '(' in wday:
- # If it's of the form TH(+1), etc.
- splt = wday.split('(')
- w = splt[0]
- n = int(splt[1][:-1])
- elif len(wday):
- # If it's of the form +1MO
- for i in range(len(wday)):
- if wday[i] not in '+-0123456789':
- break
- n = wday[:i] or None
- w = wday[i:]
- if n:
- n = int(n)
- else:
- raise ValueError("Invalid (empty) BYDAY specification.")
-
- l.append(weekdays[self._weekday_map[w]](n))
- rrkwargs["byweekday"] = l
-
- _handle_BYDAY = _handle_BYWEEKDAY
-
- def _parse_rfc_rrule(self, line,
- dtstart=None,
- cache=False,
- ignoretz=False,
- tzinfos=None):
- if line.find(':') != -1:
- name, value = line.split(':')
- if name != "RRULE":
- raise ValueError("unknown parameter name")
- else:
- value = line
- rrkwargs = {}
- for pair in value.split(';'):
- name, value = pair.split('=')
- name = name.upper()
- value = value.upper()
- try:
- getattr(self, "_handle_"+name)(rrkwargs, name, value,
- ignoretz=ignoretz,
- tzinfos=tzinfos)
- except AttributeError:
- raise ValueError("unknown parameter '%s'" % name)
- except (KeyError, ValueError):
- raise ValueError("invalid '%s': %s" % (name, value))
- return rrule(dtstart=dtstart, cache=cache, **rrkwargs)
-
- def _parse_date_value(self, date_value, parms, rule_tzids,
- ignoretz, tzids, tzinfos):
- global parser
- if not parser:
- from dateutil import parser
-
- datevals = []
- value_found = False
- TZID = None
-
- for parm in parms:
- if parm.startswith("TZID="):
- try:
- tzkey = rule_tzids[parm.split('TZID=')[-1]]
- except KeyError:
- continue
- if tzids is None:
- from . import tz
- tzlookup = tz.gettz
- elif callable(tzids):
- tzlookup = tzids
- else:
- tzlookup = getattr(tzids, 'get', None)
- if tzlookup is None:
- msg = ('tzids must be a callable, mapping, or None, '
- 'not %s' % tzids)
- raise ValueError(msg)
-
- TZID = tzlookup(tzkey)
- continue
-
- # RFC 5445 3.8.2.4: The VALUE parameter is optional, but may be found
- # only once.
- if parm not in {"VALUE=DATE-TIME", "VALUE=DATE"}:
- raise ValueError("unsupported parm: " + parm)
- else:
- if value_found:
- msg = ("Duplicate value parameter found in: " + parm)
- raise ValueError(msg)
- value_found = True
-
- for datestr in date_value.split(','):
- date = parser.parse(datestr, ignoretz=ignoretz, tzinfos=tzinfos)
- if TZID is not None:
- if date.tzinfo is None:
- date = date.replace(tzinfo=TZID)
- else:
- raise ValueError('DTSTART/EXDATE specifies multiple timezone')
- datevals.append(date)
-
- return datevals
-
- def _parse_rfc(self, s,
- dtstart=None,
- cache=False,
- unfold=False,
- forceset=False,
- compatible=False,
- ignoretz=False,
- tzids=None,
- tzinfos=None):
- global parser
- if compatible:
- forceset = True
- unfold = True
-
- TZID_NAMES = dict(map(
- lambda x: (x.upper(), x),
- re.findall('TZID=(?P[^:]+):', s)
- ))
- s = s.upper()
- if not s.strip():
- raise ValueError("empty string")
- if unfold:
- lines = s.splitlines()
- i = 0
- while i < len(lines):
- line = lines[i].rstrip()
- if not line:
- del lines[i]
- elif i > 0 and line[0] == " ":
- lines[i-1] += line[1:]
- del lines[i]
- else:
- i += 1
- else:
- lines = s.split()
- if (not forceset and len(lines) == 1 and (s.find(':') == -1 or
- s.startswith('RRULE:'))):
- return self._parse_rfc_rrule(lines[0], cache=cache,
- dtstart=dtstart, ignoretz=ignoretz,
- tzinfos=tzinfos)
- else:
- rrulevals = []
- rdatevals = []
- exrulevals = []
- exdatevals = []
- for line in lines:
- if not line:
- continue
- if line.find(':') == -1:
- name = "RRULE"
- value = line
- else:
- name, value = line.split(':', 1)
- parms = name.split(';')
- if not parms:
- raise ValueError("empty property name")
- name = parms[0]
- parms = parms[1:]
- if name == "RRULE":
- for parm in parms:
- raise ValueError("unsupported RRULE parm: "+parm)
- rrulevals.append(value)
- elif name == "RDATE":
- for parm in parms:
- if parm != "VALUE=DATE-TIME":
- raise ValueError("unsupported RDATE parm: "+parm)
- rdatevals.append(value)
- elif name == "EXRULE":
- for parm in parms:
- raise ValueError("unsupported EXRULE parm: "+parm)
- exrulevals.append(value)
- elif name == "EXDATE":
- exdatevals.extend(
- self._parse_date_value(value, parms,
- TZID_NAMES, ignoretz,
- tzids, tzinfos)
- )
- elif name == "DTSTART":
- dtvals = self._parse_date_value(value, parms, TZID_NAMES,
- ignoretz, tzids, tzinfos)
- if len(dtvals) != 1:
- raise ValueError("Multiple DTSTART values specified:" +
- value)
- dtstart = dtvals[0]
- else:
- raise ValueError("unsupported property: "+name)
- if (forceset or len(rrulevals) > 1 or rdatevals
- or exrulevals or exdatevals):
- if not parser and (rdatevals or exdatevals):
- from dateutil import parser
- rset = rruleset(cache=cache)
- for value in rrulevals:
- rset.rrule(self._parse_rfc_rrule(value, dtstart=dtstart,
- ignoretz=ignoretz,
- tzinfos=tzinfos))
- for value in rdatevals:
- for datestr in value.split(','):
- rset.rdate(parser.parse(datestr,
- ignoretz=ignoretz,
- tzinfos=tzinfos))
- for value in exrulevals:
- rset.exrule(self._parse_rfc_rrule(value, dtstart=dtstart,
- ignoretz=ignoretz,
- tzinfos=tzinfos))
- for value in exdatevals:
- rset.exdate(value)
- if compatible and dtstart:
- rset.rdate(dtstart)
- return rset
- else:
- return self._parse_rfc_rrule(rrulevals[0],
- dtstart=dtstart,
- cache=cache,
- ignoretz=ignoretz,
- tzinfos=tzinfos)
-
- def __call__(self, s, **kwargs):
- return self._parse_rfc(s, **kwargs)
-
-
-rrulestr = _rrulestr()
-
-# vim:ts=4:sw=4:et
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__init__.py b/server/venv/lib/python3.7/site-packages/dateutil/tz/__init__.py
deleted file mode 100644
index 5a2d9cd..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tz/__init__.py
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- coding: utf-8 -*-
-from .tz import *
-from .tz import __doc__
-
-#: Convenience constant providing a :class:`tzutc()` instance
-#:
-#: .. versionadded:: 2.7.0
-UTC = tzutc()
-
-__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange",
- "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz",
- "enfold", "datetime_ambiguous", "datetime_exists",
- "resolve_imaginary", "UTC", "DeprecatedTzFormatWarning"]
-
-
-class DeprecatedTzFormatWarning(Warning):
- """Warning raised when time zones are parsed from deprecated formats."""
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 72c4376..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_common.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_common.cpython-37.pyc
deleted file mode 100644
index 4152884..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_common.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_factories.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_factories.cpython-37.pyc
deleted file mode 100644
index 7643538..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/_factories.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/tz.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/tz.cpython-37.pyc
deleted file mode 100644
index fa240d6..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/tz.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/win.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/win.cpython-37.pyc
deleted file mode 100644
index bfff0c8..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/tz/__pycache__/win.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/_common.py b/server/venv/lib/python3.7/site-packages/dateutil/tz/_common.py
deleted file mode 100644
index 594e082..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tz/_common.py
+++ /dev/null
@@ -1,419 +0,0 @@
-from six import PY2
-
-from functools import wraps
-
-from datetime import datetime, timedelta, tzinfo
-
-
-ZERO = timedelta(0)
-
-__all__ = ['tzname_in_python2', 'enfold']
-
-
-def tzname_in_python2(namefunc):
- """Change unicode output into bytestrings in Python 2
-
- tzname() API changed in Python 3. It used to return bytes, but was changed
- to unicode strings
- """
- if PY2:
- @wraps(namefunc)
- def adjust_encoding(*args, **kwargs):
- name = namefunc(*args, **kwargs)
- if name is not None:
- name = name.encode()
-
- return name
-
- return adjust_encoding
- else:
- return namefunc
-
-
-# The following is adapted from Alexander Belopolsky's tz library
-# https://github.com/abalkin/tz
-if hasattr(datetime, 'fold'):
- # This is the pre-python 3.6 fold situation
- def enfold(dt, fold=1):
- """
- Provides a unified interface for assigning the ``fold`` attribute to
- datetimes both before and after the implementation of PEP-495.
-
- :param fold:
- The value for the ``fold`` attribute in the returned datetime. This
- should be either 0 or 1.
-
- :return:
- Returns an object for which ``getattr(dt, 'fold', 0)`` returns
- ``fold`` for all versions of Python. In versions prior to
- Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
- subclass of :py:class:`datetime.datetime` with the ``fold``
- attribute added, if ``fold`` is 1.
-
- .. versionadded:: 2.6.0
- """
- return dt.replace(fold=fold)
-
-else:
- class _DatetimeWithFold(datetime):
- """
- This is a class designed to provide a PEP 495-compliant interface for
- Python versions before 3.6. It is used only for dates in a fold, so
- the ``fold`` attribute is fixed at ``1``.
-
- .. versionadded:: 2.6.0
- """
- __slots__ = ()
-
- def replace(self, *args, **kwargs):
- """
- Return a datetime with the same attributes, except for those
- attributes given new values by whichever keyword arguments are
- specified. Note that tzinfo=None can be specified to create a naive
- datetime from an aware datetime with no conversion of date and time
- data.
-
- This is reimplemented in ``_DatetimeWithFold`` because pypy3 will
- return a ``datetime.datetime`` even if ``fold`` is unchanged.
- """
- argnames = (
- 'year', 'month', 'day', 'hour', 'minute', 'second',
- 'microsecond', 'tzinfo'
- )
-
- for arg, argname in zip(args, argnames):
- if argname in kwargs:
- raise TypeError('Duplicate argument: {}'.format(argname))
-
- kwargs[argname] = arg
-
- for argname in argnames:
- if argname not in kwargs:
- kwargs[argname] = getattr(self, argname)
-
- dt_class = self.__class__ if kwargs.get('fold', 1) else datetime
-
- return dt_class(**kwargs)
-
- @property
- def fold(self):
- return 1
-
- def enfold(dt, fold=1):
- """
- Provides a unified interface for assigning the ``fold`` attribute to
- datetimes both before and after the implementation of PEP-495.
-
- :param fold:
- The value for the ``fold`` attribute in the returned datetime. This
- should be either 0 or 1.
-
- :return:
- Returns an object for which ``getattr(dt, 'fold', 0)`` returns
- ``fold`` for all versions of Python. In versions prior to
- Python 3.6, this is a ``_DatetimeWithFold`` object, which is a
- subclass of :py:class:`datetime.datetime` with the ``fold``
- attribute added, if ``fold`` is 1.
-
- .. versionadded:: 2.6.0
- """
- if getattr(dt, 'fold', 0) == fold:
- return dt
-
- args = dt.timetuple()[:6]
- args += (dt.microsecond, dt.tzinfo)
-
- if fold:
- return _DatetimeWithFold(*args)
- else:
- return datetime(*args)
-
-
-def _validate_fromutc_inputs(f):
- """
- The CPython version of ``fromutc`` checks that the input is a ``datetime``
- object and that ``self`` is attached as its ``tzinfo``.
- """
- @wraps(f)
- def fromutc(self, dt):
- if not isinstance(dt, datetime):
- raise TypeError("fromutc() requires a datetime argument")
- if dt.tzinfo is not self:
- raise ValueError("dt.tzinfo is not self")
-
- return f(self, dt)
-
- return fromutc
-
-
-class _tzinfo(tzinfo):
- """
- Base class for all ``dateutil`` ``tzinfo`` objects.
- """
-
- def is_ambiguous(self, dt):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
-
- dt = dt.replace(tzinfo=self)
-
- wall_0 = enfold(dt, fold=0)
- wall_1 = enfold(dt, fold=1)
-
- same_offset = wall_0.utcoffset() == wall_1.utcoffset()
- same_dt = wall_0.replace(tzinfo=None) == wall_1.replace(tzinfo=None)
-
- return same_dt and not same_offset
-
- def _fold_status(self, dt_utc, dt_wall):
- """
- Determine the fold status of a "wall" datetime, given a representation
- of the same datetime as a (naive) UTC datetime. This is calculated based
- on the assumption that ``dt.utcoffset() - dt.dst()`` is constant for all
- datetimes, and that this offset is the actual number of hours separating
- ``dt_utc`` and ``dt_wall``.
-
- :param dt_utc:
- Representation of the datetime as UTC
-
- :param dt_wall:
- Representation of the datetime as "wall time". This parameter must
- either have a `fold` attribute or have a fold-naive
- :class:`datetime.tzinfo` attached, otherwise the calculation may
- fail.
- """
- if self.is_ambiguous(dt_wall):
- delta_wall = dt_wall - dt_utc
- _fold = int(delta_wall == (dt_utc.utcoffset() - dt_utc.dst()))
- else:
- _fold = 0
-
- return _fold
-
- def _fold(self, dt):
- return getattr(dt, 'fold', 0)
-
- def _fromutc(self, dt):
- """
- Given a timezone-aware datetime in a given timezone, calculates a
- timezone-aware datetime in a new timezone.
-
- Since this is the one time that we *know* we have an unambiguous
- datetime object, we take this opportunity to determine whether the
- datetime is ambiguous and in a "fold" state (e.g. if it's the first
- occurence, chronologically, of the ambiguous datetime).
-
- :param dt:
- A timezone-aware :class:`datetime.datetime` object.
- """
-
- # Re-implement the algorithm from Python's datetime.py
- dtoff = dt.utcoffset()
- if dtoff is None:
- raise ValueError("fromutc() requires a non-None utcoffset() "
- "result")
-
- # The original datetime.py code assumes that `dst()` defaults to
- # zero during ambiguous times. PEP 495 inverts this presumption, so
- # for pre-PEP 495 versions of python, we need to tweak the algorithm.
- dtdst = dt.dst()
- if dtdst is None:
- raise ValueError("fromutc() requires a non-None dst() result")
- delta = dtoff - dtdst
-
- dt += delta
- # Set fold=1 so we can default to being in the fold for
- # ambiguous dates.
- dtdst = enfold(dt, fold=1).dst()
- if dtdst is None:
- raise ValueError("fromutc(): dt.dst gave inconsistent "
- "results; cannot convert")
- return dt + dtdst
-
- @_validate_fromutc_inputs
- def fromutc(self, dt):
- """
- Given a timezone-aware datetime in a given timezone, calculates a
- timezone-aware datetime in a new timezone.
-
- Since this is the one time that we *know* we have an unambiguous
- datetime object, we take this opportunity to determine whether the
- datetime is ambiguous and in a "fold" state (e.g. if it's the first
- occurance, chronologically, of the ambiguous datetime).
-
- :param dt:
- A timezone-aware :class:`datetime.datetime` object.
- """
- dt_wall = self._fromutc(dt)
-
- # Calculate the fold status given the two datetimes.
- _fold = self._fold_status(dt, dt_wall)
-
- # Set the default fold value for ambiguous dates
- return enfold(dt_wall, fold=_fold)
-
-
-class tzrangebase(_tzinfo):
- """
- This is an abstract base class for time zones represented by an annual
- transition into and out of DST. Child classes should implement the following
- methods:
-
- * ``__init__(self, *args, **kwargs)``
- * ``transitions(self, year)`` - this is expected to return a tuple of
- datetimes representing the DST on and off transitions in standard
- time.
-
- A fully initialized ``tzrangebase`` subclass should also provide the
- following attributes:
- * ``hasdst``: Boolean whether or not the zone uses DST.
- * ``_dst_offset`` / ``_std_offset``: :class:`datetime.timedelta` objects
- representing the respective UTC offsets.
- * ``_dst_abbr`` / ``_std_abbr``: Strings representing the timezone short
- abbreviations in DST and STD, respectively.
- * ``_hasdst``: Whether or not the zone has DST.
-
- .. versionadded:: 2.6.0
- """
- def __init__(self):
- raise NotImplementedError('tzrangebase is an abstract base class')
-
- def utcoffset(self, dt):
- isdst = self._isdst(dt)
-
- if isdst is None:
- return None
- elif isdst:
- return self._dst_offset
- else:
- return self._std_offset
-
- def dst(self, dt):
- isdst = self._isdst(dt)
-
- if isdst is None:
- return None
- elif isdst:
- return self._dst_base_offset
- else:
- return ZERO
-
- @tzname_in_python2
- def tzname(self, dt):
- if self._isdst(dt):
- return self._dst_abbr
- else:
- return self._std_abbr
-
- def fromutc(self, dt):
- """ Given a datetime in UTC, return local time """
- if not isinstance(dt, datetime):
- raise TypeError("fromutc() requires a datetime argument")
-
- if dt.tzinfo is not self:
- raise ValueError("dt.tzinfo is not self")
-
- # Get transitions - if there are none, fixed offset
- transitions = self.transitions(dt.year)
- if transitions is None:
- return dt + self.utcoffset(dt)
-
- # Get the transition times in UTC
- dston, dstoff = transitions
-
- dston -= self._std_offset
- dstoff -= self._std_offset
-
- utc_transitions = (dston, dstoff)
- dt_utc = dt.replace(tzinfo=None)
-
- isdst = self._naive_isdst(dt_utc, utc_transitions)
-
- if isdst:
- dt_wall = dt + self._dst_offset
- else:
- dt_wall = dt + self._std_offset
-
- _fold = int(not isdst and self.is_ambiguous(dt_wall))
-
- return enfold(dt_wall, fold=_fold)
-
- def is_ambiguous(self, dt):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
- if not self.hasdst:
- return False
-
- start, end = self.transitions(dt.year)
-
- dt = dt.replace(tzinfo=None)
- return (end <= dt < end + self._dst_base_offset)
-
- def _isdst(self, dt):
- if not self.hasdst:
- return False
- elif dt is None:
- return None
-
- transitions = self.transitions(dt.year)
-
- if transitions is None:
- return False
-
- dt = dt.replace(tzinfo=None)
-
- isdst = self._naive_isdst(dt, transitions)
-
- # Handle ambiguous dates
- if not isdst and self.is_ambiguous(dt):
- return not self._fold(dt)
- else:
- return isdst
-
- def _naive_isdst(self, dt, transitions):
- dston, dstoff = transitions
-
- dt = dt.replace(tzinfo=None)
-
- if dston < dstoff:
- isdst = dston <= dt < dstoff
- else:
- isdst = not dstoff <= dt < dston
-
- return isdst
-
- @property
- def _dst_base_offset(self):
- return self._dst_offset - self._std_offset
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return "%s(...)" % self.__class__.__name__
-
- __reduce__ = object.__reduce__
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/_factories.py b/server/venv/lib/python3.7/site-packages/dateutil/tz/_factories.py
deleted file mode 100644
index d2560eb..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tz/_factories.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from datetime import timedelta
-import weakref
-from collections import OrderedDict
-
-
-class _TzSingleton(type):
- def __init__(cls, *args, **kwargs):
- cls.__instance = None
- super(_TzSingleton, cls).__init__(*args, **kwargs)
-
- def __call__(cls):
- if cls.__instance is None:
- cls.__instance = super(_TzSingleton, cls).__call__()
- return cls.__instance
-
-
-class _TzFactory(type):
- def instance(cls, *args, **kwargs):
- """Alternate constructor that returns a fresh instance"""
- return type.__call__(cls, *args, **kwargs)
-
-
-class _TzOffsetFactory(_TzFactory):
- def __init__(cls, *args, **kwargs):
- cls.__instances = weakref.WeakValueDictionary()
- cls.__strong_cache = OrderedDict()
- cls.__strong_cache_size = 8
-
- def __call__(cls, name, offset):
- if isinstance(offset, timedelta):
- key = (name, offset.total_seconds())
- else:
- key = (name, offset)
-
- instance = cls.__instances.get(key, None)
- if instance is None:
- instance = cls.__instances.setdefault(key,
- cls.instance(name, offset))
-
- cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
-
- # Remove an item if the strong cache is overpopulated
- # TODO: Maybe this should be under a lock?
- if len(cls.__strong_cache) > cls.__strong_cache_size:
- cls.__strong_cache.popitem(last=False)
-
- return instance
-
-
-class _TzStrFactory(_TzFactory):
- def __init__(cls, *args, **kwargs):
- cls.__instances = weakref.WeakValueDictionary()
- cls.__strong_cache = OrderedDict()
- cls.__strong_cache_size = 8
-
- def __call__(cls, s, posix_offset=False):
- key = (s, posix_offset)
- instance = cls.__instances.get(key, None)
-
- if instance is None:
- instance = cls.__instances.setdefault(key,
- cls.instance(s, posix_offset))
-
- cls.__strong_cache[key] = cls.__strong_cache.pop(key, instance)
-
-
- # Remove an item if the strong cache is overpopulated
- # TODO: Maybe this should be under a lock?
- if len(cls.__strong_cache) > cls.__strong_cache_size:
- cls.__strong_cache.popitem(last=False)
-
- return instance
-
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/tz.py b/server/venv/lib/python3.7/site-packages/dateutil/tz/tz.py
deleted file mode 100644
index d05414e..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tz/tz.py
+++ /dev/null
@@ -1,1836 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers timezone implementations subclassing the abstract
-:py:class:`datetime.tzinfo` type. There are classes to handle tzfile format
-files (usually are in :file:`/etc/localtime`, :file:`/usr/share/zoneinfo`,
-etc), TZ environment string (in all known formats), given ranges (with help
-from relative deltas), local machine timezone, fixed offset timezone, and UTC
-timezone.
-"""
-import datetime
-import struct
-import time
-import sys
-import os
-import bisect
-import weakref
-from collections import OrderedDict
-
-import six
-from six import string_types
-from six.moves import _thread
-from ._common import tzname_in_python2, _tzinfo
-from ._common import tzrangebase, enfold
-from ._common import _validate_fromutc_inputs
-
-from ._factories import _TzSingleton, _TzOffsetFactory
-from ._factories import _TzStrFactory
-try:
- from .win import tzwin, tzwinlocal
-except ImportError:
- tzwin = tzwinlocal = None
-
-# For warning about rounding tzinfo
-from warnings import warn
-
-ZERO = datetime.timedelta(0)
-EPOCH = datetime.datetime.utcfromtimestamp(0)
-EPOCHORDINAL = EPOCH.toordinal()
-
-
-@six.add_metaclass(_TzSingleton)
-class tzutc(datetime.tzinfo):
- """
- This is a tzinfo object that represents the UTC time zone.
-
- **Examples:**
-
- .. doctest::
-
- >>> from datetime import *
- >>> from dateutil.tz import *
-
- >>> datetime.now()
- datetime.datetime(2003, 9, 27, 9, 40, 1, 521290)
-
- >>> datetime.now(tzutc())
- datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc())
-
- >>> datetime.now(tzutc()).tzname()
- 'UTC'
-
- .. versionchanged:: 2.7.0
- ``tzutc()`` is now a singleton, so the result of ``tzutc()`` will
- always return the same object.
-
- .. doctest::
-
- >>> from dateutil.tz import tzutc, UTC
- >>> tzutc() is tzutc()
- True
- >>> tzutc() is UTC
- True
- """
- def utcoffset(self, dt):
- return ZERO
-
- def dst(self, dt):
- return ZERO
-
- @tzname_in_python2
- def tzname(self, dt):
- return "UTC"
-
- def is_ambiguous(self, dt):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
- return False
-
- @_validate_fromutc_inputs
- def fromutc(self, dt):
- """
- Fast track version of fromutc() returns the original ``dt`` object for
- any valid :py:class:`datetime.datetime` object.
- """
- return dt
-
- def __eq__(self, other):
- if not isinstance(other, (tzutc, tzoffset)):
- return NotImplemented
-
- return (isinstance(other, tzutc) or
- (isinstance(other, tzoffset) and other._offset == ZERO))
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return "%s()" % self.__class__.__name__
-
- __reduce__ = object.__reduce__
-
-
-@six.add_metaclass(_TzOffsetFactory)
-class tzoffset(datetime.tzinfo):
- """
- A simple class for representing a fixed offset from UTC.
-
- :param name:
- The timezone name, to be returned when ``tzname()`` is called.
- :param offset:
- The time zone offset in seconds, or (since version 2.6.0, represented
- as a :py:class:`datetime.timedelta` object).
- """
- def __init__(self, name, offset):
- self._name = name
-
- try:
- # Allow a timedelta
- offset = offset.total_seconds()
- except (TypeError, AttributeError):
- pass
-
- self._offset = datetime.timedelta(seconds=_get_supported_offset(offset))
-
- def utcoffset(self, dt):
- return self._offset
-
- def dst(self, dt):
- return ZERO
-
- @tzname_in_python2
- def tzname(self, dt):
- return self._name
-
- @_validate_fromutc_inputs
- def fromutc(self, dt):
- return dt + self._offset
-
- def is_ambiguous(self, dt):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
- return False
-
- def __eq__(self, other):
- if not isinstance(other, tzoffset):
- return NotImplemented
-
- return self._offset == other._offset
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return "%s(%s, %s)" % (self.__class__.__name__,
- repr(self._name),
- int(self._offset.total_seconds()))
-
- __reduce__ = object.__reduce__
-
-
-class tzlocal(_tzinfo):
- """
- A :class:`tzinfo` subclass built around the ``time`` timezone functions.
- """
- def __init__(self):
- super(tzlocal, self).__init__()
-
- self._std_offset = datetime.timedelta(seconds=-time.timezone)
- if time.daylight:
- self._dst_offset = datetime.timedelta(seconds=-time.altzone)
- else:
- self._dst_offset = self._std_offset
-
- self._dst_saved = self._dst_offset - self._std_offset
- self._hasdst = bool(self._dst_saved)
- self._tznames = tuple(time.tzname)
-
- def utcoffset(self, dt):
- if dt is None and self._hasdst:
- return None
-
- if self._isdst(dt):
- return self._dst_offset
- else:
- return self._std_offset
-
- def dst(self, dt):
- if dt is None and self._hasdst:
- return None
-
- if self._isdst(dt):
- return self._dst_offset - self._std_offset
- else:
- return ZERO
-
- @tzname_in_python2
- def tzname(self, dt):
- return self._tznames[self._isdst(dt)]
-
- def is_ambiguous(self, dt):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
- naive_dst = self._naive_is_dst(dt)
- return (not naive_dst and
- (naive_dst != self._naive_is_dst(dt - self._dst_saved)))
-
- def _naive_is_dst(self, dt):
- timestamp = _datetime_to_timestamp(dt)
- return time.localtime(timestamp + time.timezone).tm_isdst
-
- def _isdst(self, dt, fold_naive=True):
- # We can't use mktime here. It is unstable when deciding if
- # the hour near to a change is DST or not.
- #
- # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour,
- # dt.minute, dt.second, dt.weekday(), 0, -1))
- # return time.localtime(timestamp).tm_isdst
- #
- # The code above yields the following result:
- #
- # >>> import tz, datetime
- # >>> t = tz.tzlocal()
- # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
- # 'BRDT'
- # >>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname()
- # 'BRST'
- # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
- # 'BRST'
- # >>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname()
- # 'BRDT'
- # >>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname()
- # 'BRDT'
- #
- # Here is a more stable implementation:
- #
- if not self._hasdst:
- return False
-
- # Check for ambiguous times:
- dstval = self._naive_is_dst(dt)
- fold = getattr(dt, 'fold', None)
-
- if self.is_ambiguous(dt):
- if fold is not None:
- return not self._fold(dt)
- else:
- return True
-
- return dstval
-
- def __eq__(self, other):
- if isinstance(other, tzlocal):
- return (self._std_offset == other._std_offset and
- self._dst_offset == other._dst_offset)
- elif isinstance(other, tzutc):
- return (not self._hasdst and
- self._tznames[0] in {'UTC', 'GMT'} and
- self._std_offset == ZERO)
- elif isinstance(other, tzoffset):
- return (not self._hasdst and
- self._tznames[0] == other._name and
- self._std_offset == other._offset)
- else:
- return NotImplemented
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return "%s()" % self.__class__.__name__
-
- __reduce__ = object.__reduce__
-
-
-class _ttinfo(object):
- __slots__ = ["offset", "delta", "isdst", "abbr",
- "isstd", "isgmt", "dstoffset"]
-
- def __init__(self):
- for attr in self.__slots__:
- setattr(self, attr, None)
-
- def __repr__(self):
- l = []
- for attr in self.__slots__:
- value = getattr(self, attr)
- if value is not None:
- l.append("%s=%s" % (attr, repr(value)))
- return "%s(%s)" % (self.__class__.__name__, ", ".join(l))
-
- def __eq__(self, other):
- if not isinstance(other, _ttinfo):
- return NotImplemented
-
- return (self.offset == other.offset and
- self.delta == other.delta and
- self.isdst == other.isdst and
- self.abbr == other.abbr and
- self.isstd == other.isstd and
- self.isgmt == other.isgmt and
- self.dstoffset == other.dstoffset)
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __getstate__(self):
- state = {}
- for name in self.__slots__:
- state[name] = getattr(self, name, None)
- return state
-
- def __setstate__(self, state):
- for name in self.__slots__:
- if name in state:
- setattr(self, name, state[name])
-
-
-class _tzfile(object):
- """
- Lightweight class for holding the relevant transition and time zone
- information read from binary tzfiles.
- """
- attrs = ['trans_list', 'trans_list_utc', 'trans_idx', 'ttinfo_list',
- 'ttinfo_std', 'ttinfo_dst', 'ttinfo_before', 'ttinfo_first']
-
- def __init__(self, **kwargs):
- for attr in self.attrs:
- setattr(self, attr, kwargs.get(attr, None))
-
-
-class tzfile(_tzinfo):
- """
- This is a ``tzinfo`` subclass thant allows one to use the ``tzfile(5)``
- format timezone files to extract current and historical zone information.
-
- :param fileobj:
- This can be an opened file stream or a file name that the time zone
- information can be read from.
-
- :param filename:
- This is an optional parameter specifying the source of the time zone
- information in the event that ``fileobj`` is a file object. If omitted
- and ``fileobj`` is a file stream, this parameter will be set either to
- ``fileobj``'s ``name`` attribute or to ``repr(fileobj)``.
-
- See `Sources for Time Zone and Daylight Saving Time Data
- `_ for more information.
- Time zone files can be compiled from the `IANA Time Zone database files
- `_ with the `zic time zone compiler
- `_
-
- .. note::
-
- Only construct a ``tzfile`` directly if you have a specific timezone
- file on disk that you want to read into a Python ``tzinfo`` object.
- If you want to get a ``tzfile`` representing a specific IANA zone,
- (e.g. ``'America/New_York'``), you should call
- :func:`dateutil.tz.gettz` with the zone identifier.
-
-
- **Examples:**
-
- Using the US Eastern time zone as an example, we can see that a ``tzfile``
- provides time zone information for the standard Daylight Saving offsets:
-
- .. testsetup:: tzfile
-
- from dateutil.tz import gettz
- from datetime import datetime
-
- .. doctest:: tzfile
-
- >>> NYC = gettz('America/New_York')
- >>> NYC
- tzfile('/usr/share/zoneinfo/America/New_York')
-
- >>> print(datetime(2016, 1, 3, tzinfo=NYC)) # EST
- 2016-01-03 00:00:00-05:00
-
- >>> print(datetime(2016, 7, 7, tzinfo=NYC)) # EDT
- 2016-07-07 00:00:00-04:00
-
-
- The ``tzfile`` structure contains a fully history of the time zone,
- so historical dates will also have the right offsets. For example, before
- the adoption of the UTC standards, New York used local solar mean time:
-
- .. doctest:: tzfile
-
- >>> print(datetime(1901, 4, 12, tzinfo=NYC)) # LMT
- 1901-04-12 00:00:00-04:56
-
- And during World War II, New York was on "Eastern War Time", which was a
- state of permanent daylight saving time:
-
- .. doctest:: tzfile
-
- >>> print(datetime(1944, 2, 7, tzinfo=NYC)) # EWT
- 1944-02-07 00:00:00-04:00
-
- """
-
- def __init__(self, fileobj, filename=None):
- super(tzfile, self).__init__()
-
- file_opened_here = False
- if isinstance(fileobj, string_types):
- self._filename = fileobj
- fileobj = open(fileobj, 'rb')
- file_opened_here = True
- elif filename is not None:
- self._filename = filename
- elif hasattr(fileobj, "name"):
- self._filename = fileobj.name
- else:
- self._filename = repr(fileobj)
-
- if fileobj is not None:
- if not file_opened_here:
- fileobj = _nullcontext(fileobj)
-
- with fileobj as file_stream:
- tzobj = self._read_tzfile(file_stream)
-
- self._set_tzdata(tzobj)
-
- def _set_tzdata(self, tzobj):
- """ Set the time zone data of this object from a _tzfile object """
- # Copy the relevant attributes over as private attributes
- for attr in _tzfile.attrs:
- setattr(self, '_' + attr, getattr(tzobj, attr))
-
- def _read_tzfile(self, fileobj):
- out = _tzfile()
-
- # From tzfile(5):
- #
- # The time zone information files used by tzset(3)
- # begin with the magic characters "TZif" to identify
- # them as time zone information files, followed by
- # sixteen bytes reserved for future use, followed by
- # six four-byte values of type long, written in a
- # ``standard'' byte order (the high-order byte
- # of the value is written first).
- if fileobj.read(4).decode() != "TZif":
- raise ValueError("magic not found")
-
- fileobj.read(16)
-
- (
- # The number of UTC/local indicators stored in the file.
- ttisgmtcnt,
-
- # The number of standard/wall indicators stored in the file.
- ttisstdcnt,
-
- # The number of leap seconds for which data is
- # stored in the file.
- leapcnt,
-
- # The number of "transition times" for which data
- # is stored in the file.
- timecnt,
-
- # The number of "local time types" for which data
- # is stored in the file (must not be zero).
- typecnt,
-
- # The number of characters of "time zone
- # abbreviation strings" stored in the file.
- charcnt,
-
- ) = struct.unpack(">6l", fileobj.read(24))
-
- # The above header is followed by tzh_timecnt four-byte
- # values of type long, sorted in ascending order.
- # These values are written in ``standard'' byte order.
- # Each is used as a transition time (as returned by
- # time(2)) at which the rules for computing local time
- # change.
-
- if timecnt:
- out.trans_list_utc = list(struct.unpack(">%dl" % timecnt,
- fileobj.read(timecnt*4)))
- else:
- out.trans_list_utc = []
-
- # Next come tzh_timecnt one-byte values of type unsigned
- # char; each one tells which of the different types of
- # ``local time'' types described in the file is associated
- # with the same-indexed transition time. These values
- # serve as indices into an array of ttinfo structures that
- # appears next in the file.
-
- if timecnt:
- out.trans_idx = struct.unpack(">%dB" % timecnt,
- fileobj.read(timecnt))
- else:
- out.trans_idx = []
-
- # Each ttinfo structure is written as a four-byte value
- # for tt_gmtoff of type long, in a standard byte
- # order, followed by a one-byte value for tt_isdst
- # and a one-byte value for tt_abbrind. In each
- # structure, tt_gmtoff gives the number of
- # seconds to be added to UTC, tt_isdst tells whether
- # tm_isdst should be set by localtime(3), and
- # tt_abbrind serves as an index into the array of
- # time zone abbreviation characters that follow the
- # ttinfo structure(s) in the file.
-
- ttinfo = []
-
- for i in range(typecnt):
- ttinfo.append(struct.unpack(">lbb", fileobj.read(6)))
-
- abbr = fileobj.read(charcnt).decode()
-
- # Then there are tzh_leapcnt pairs of four-byte
- # values, written in standard byte order; the
- # first value of each pair gives the time (as
- # returned by time(2)) at which a leap second
- # occurs; the second gives the total number of
- # leap seconds to be applied after the given time.
- # The pairs of values are sorted in ascending order
- # by time.
-
- # Not used, for now (but seek for correct file position)
- if leapcnt:
- fileobj.seek(leapcnt * 8, os.SEEK_CUR)
-
- # Then there are tzh_ttisstdcnt standard/wall
- # indicators, each stored as a one-byte value;
- # they tell whether the transition times associated
- # with local time types were specified as standard
- # time or wall clock time, and are used when
- # a time zone file is used in handling POSIX-style
- # time zone environment variables.
-
- if ttisstdcnt:
- isstd = struct.unpack(">%db" % ttisstdcnt,
- fileobj.read(ttisstdcnt))
-
- # Finally, there are tzh_ttisgmtcnt UTC/local
- # indicators, each stored as a one-byte value;
- # they tell whether the transition times associated
- # with local time types were specified as UTC or
- # local time, and are used when a time zone file
- # is used in handling POSIX-style time zone envi-
- # ronment variables.
-
- if ttisgmtcnt:
- isgmt = struct.unpack(">%db" % ttisgmtcnt,
- fileobj.read(ttisgmtcnt))
-
- # Build ttinfo list
- out.ttinfo_list = []
- for i in range(typecnt):
- gmtoff, isdst, abbrind = ttinfo[i]
- gmtoff = _get_supported_offset(gmtoff)
- tti = _ttinfo()
- tti.offset = gmtoff
- tti.dstoffset = datetime.timedelta(0)
- tti.delta = datetime.timedelta(seconds=gmtoff)
- tti.isdst = isdst
- tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)]
- tti.isstd = (ttisstdcnt > i and isstd[i] != 0)
- tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0)
- out.ttinfo_list.append(tti)
-
- # Replace ttinfo indexes for ttinfo objects.
- out.trans_idx = [out.ttinfo_list[idx] for idx in out.trans_idx]
-
- # Set standard, dst, and before ttinfos. before will be
- # used when a given time is before any transitions,
- # and will be set to the first non-dst ttinfo, or to
- # the first dst, if all of them are dst.
- out.ttinfo_std = None
- out.ttinfo_dst = None
- out.ttinfo_before = None
- if out.ttinfo_list:
- if not out.trans_list_utc:
- out.ttinfo_std = out.ttinfo_first = out.ttinfo_list[0]
- else:
- for i in range(timecnt-1, -1, -1):
- tti = out.trans_idx[i]
- if not out.ttinfo_std and not tti.isdst:
- out.ttinfo_std = tti
- elif not out.ttinfo_dst and tti.isdst:
- out.ttinfo_dst = tti
-
- if out.ttinfo_std and out.ttinfo_dst:
- break
- else:
- if out.ttinfo_dst and not out.ttinfo_std:
- out.ttinfo_std = out.ttinfo_dst
-
- for tti in out.ttinfo_list:
- if not tti.isdst:
- out.ttinfo_before = tti
- break
- else:
- out.ttinfo_before = out.ttinfo_list[0]
-
- # Now fix transition times to become relative to wall time.
- #
- # I'm not sure about this. In my tests, the tz source file
- # is setup to wall time, and in the binary file isstd and
- # isgmt are off, so it should be in wall time. OTOH, it's
- # always in gmt time. Let me know if you have comments
- # about this.
- lastdst = None
- lastoffset = None
- lastdstoffset = None
- lastbaseoffset = None
- out.trans_list = []
-
- for i, tti in enumerate(out.trans_idx):
- offset = tti.offset
- dstoffset = 0
-
- if lastdst is not None:
- if tti.isdst:
- if not lastdst:
- dstoffset = offset - lastoffset
-
- if not dstoffset and lastdstoffset:
- dstoffset = lastdstoffset
-
- tti.dstoffset = datetime.timedelta(seconds=dstoffset)
- lastdstoffset = dstoffset
-
- # If a time zone changes its base offset during a DST transition,
- # then you need to adjust by the previous base offset to get the
- # transition time in local time. Otherwise you use the current
- # base offset. Ideally, I would have some mathematical proof of
- # why this is true, but I haven't really thought about it enough.
- baseoffset = offset - dstoffset
- adjustment = baseoffset
- if (lastbaseoffset is not None and baseoffset != lastbaseoffset
- and tti.isdst != lastdst):
- # The base DST has changed
- adjustment = lastbaseoffset
-
- lastdst = tti.isdst
- lastoffset = offset
- lastbaseoffset = baseoffset
-
- out.trans_list.append(out.trans_list_utc[i] + adjustment)
-
- out.trans_idx = tuple(out.trans_idx)
- out.trans_list = tuple(out.trans_list)
- out.trans_list_utc = tuple(out.trans_list_utc)
-
- return out
-
- def _find_last_transition(self, dt, in_utc=False):
- # If there's no list, there are no transitions to find
- if not self._trans_list:
- return None
-
- timestamp = _datetime_to_timestamp(dt)
-
- # Find where the timestamp fits in the transition list - if the
- # timestamp is a transition time, it's part of the "after" period.
- trans_list = self._trans_list_utc if in_utc else self._trans_list
- idx = bisect.bisect_right(trans_list, timestamp)
-
- # We want to know when the previous transition was, so subtract off 1
- return idx - 1
-
- def _get_ttinfo(self, idx):
- # For no list or after the last transition, default to _ttinfo_std
- if idx is None or (idx + 1) >= len(self._trans_list):
- return self._ttinfo_std
-
- # If there is a list and the time is before it, return _ttinfo_before
- if idx < 0:
- return self._ttinfo_before
-
- return self._trans_idx[idx]
-
- def _find_ttinfo(self, dt):
- idx = self._resolve_ambiguous_time(dt)
-
- return self._get_ttinfo(idx)
-
- def fromutc(self, dt):
- """
- The ``tzfile`` implementation of :py:func:`datetime.tzinfo.fromutc`.
-
- :param dt:
- A :py:class:`datetime.datetime` object.
-
- :raises TypeError:
- Raised if ``dt`` is not a :py:class:`datetime.datetime` object.
-
- :raises ValueError:
- Raised if this is called with a ``dt`` which does not have this
- ``tzinfo`` attached.
-
- :return:
- Returns a :py:class:`datetime.datetime` object representing the
- wall time in ``self``'s time zone.
- """
- # These isinstance checks are in datetime.tzinfo, so we'll preserve
- # them, even if we don't care about duck typing.
- if not isinstance(dt, datetime.datetime):
- raise TypeError("fromutc() requires a datetime argument")
-
- if dt.tzinfo is not self:
- raise ValueError("dt.tzinfo is not self")
-
- # First treat UTC as wall time and get the transition we're in.
- idx = self._find_last_transition(dt, in_utc=True)
- tti = self._get_ttinfo(idx)
-
- dt_out = dt + datetime.timedelta(seconds=tti.offset)
-
- fold = self.is_ambiguous(dt_out, idx=idx)
-
- return enfold(dt_out, fold=int(fold))
-
- def is_ambiguous(self, dt, idx=None):
- """
- Whether or not the "wall time" of a given datetime is ambiguous in this
- zone.
-
- :param dt:
- A :py:class:`datetime.datetime`, naive or time zone aware.
-
-
- :return:
- Returns ``True`` if ambiguous, ``False`` otherwise.
-
- .. versionadded:: 2.6.0
- """
- if idx is None:
- idx = self._find_last_transition(dt)
-
- # Calculate the difference in offsets from current to previous
- timestamp = _datetime_to_timestamp(dt)
- tti = self._get_ttinfo(idx)
-
- if idx is None or idx <= 0:
- return False
-
- od = self._get_ttinfo(idx - 1).offset - tti.offset
- tt = self._trans_list[idx] # Transition time
-
- return timestamp < tt + od
-
- def _resolve_ambiguous_time(self, dt):
- idx = self._find_last_transition(dt)
-
- # If we have no transitions, return the index
- _fold = self._fold(dt)
- if idx is None or idx == 0:
- return idx
-
- # If it's ambiguous and we're in a fold, shift to a different index.
- idx_offset = int(not _fold and self.is_ambiguous(dt, idx))
-
- return idx - idx_offset
-
- def utcoffset(self, dt):
- if dt is None:
- return None
-
- if not self._ttinfo_std:
- return ZERO
-
- return self._find_ttinfo(dt).delta
-
- def dst(self, dt):
- if dt is None:
- return None
-
- if not self._ttinfo_dst:
- return ZERO
-
- tti = self._find_ttinfo(dt)
-
- if not tti.isdst:
- return ZERO
-
- # The documentation says that utcoffset()-dst() must
- # be constant for every dt.
- return tti.dstoffset
-
- @tzname_in_python2
- def tzname(self, dt):
- if not self._ttinfo_std or dt is None:
- return None
- return self._find_ttinfo(dt).abbr
-
- def __eq__(self, other):
- if not isinstance(other, tzfile):
- return NotImplemented
- return (self._trans_list == other._trans_list and
- self._trans_idx == other._trans_idx and
- self._ttinfo_list == other._ttinfo_list)
-
- __hash__ = None
-
- def __ne__(self, other):
- return not (self == other)
-
- def __repr__(self):
- return "%s(%s)" % (self.__class__.__name__, repr(self._filename))
-
- def __reduce__(self):
- return self.__reduce_ex__(None)
-
- def __reduce_ex__(self, protocol):
- return (self.__class__, (None, self._filename), self.__dict__)
-
-
-class tzrange(tzrangebase):
- """
- The ``tzrange`` object is a time zone specified by a set of offsets and
- abbreviations, equivalent to the way the ``TZ`` variable can be specified
- in POSIX-like systems, but using Python delta objects to specify DST
- start, end and offsets.
-
- :param stdabbr:
- The abbreviation for standard time (e.g. ``'EST'``).
-
- :param stdoffset:
- An integer or :class:`datetime.timedelta` object or equivalent
- specifying the base offset from UTC.
-
- If unspecified, +00:00 is used.
-
- :param dstabbr:
- The abbreviation for DST / "Summer" time (e.g. ``'EDT'``).
-
- If specified, with no other DST information, DST is assumed to occur
- and the default behavior or ``dstoffset``, ``start`` and ``end`` is
- used. If unspecified and no other DST information is specified, it
- is assumed that this zone has no DST.
-
- If this is unspecified and other DST information is *is* specified,
- DST occurs in the zone but the time zone abbreviation is left
- unchanged.
-
- :param dstoffset:
- A an integer or :class:`datetime.timedelta` object or equivalent
- specifying the UTC offset during DST. If unspecified and any other DST
- information is specified, it is assumed to be the STD offset +1 hour.
-
- :param start:
- A :class:`relativedelta.relativedelta` object or equivalent specifying
- the time and time of year that daylight savings time starts. To
- specify, for example, that DST starts at 2AM on the 2nd Sunday in
- March, pass:
-
- ``relativedelta(hours=2, month=3, day=1, weekday=SU(+2))``
-
- If unspecified and any other DST information is specified, the default
- value is 2 AM on the first Sunday in April.
-
- :param end:
- A :class:`relativedelta.relativedelta` object or equivalent
- representing the time and time of year that daylight savings time
- ends, with the same specification method as in ``start``. One note is
- that this should point to the first time in the *standard* zone, so if
- a transition occurs at 2AM in the DST zone and the clocks are set back
- 1 hour to 1AM, set the ``hours`` parameter to +1.
-
-
- **Examples:**
-
- .. testsetup:: tzrange
-
- from dateutil.tz import tzrange, tzstr
-
- .. doctest:: tzrange
-
- >>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT")
- True
-
- >>> from dateutil.relativedelta import *
- >>> range1 = tzrange("EST", -18000, "EDT")
- >>> range2 = tzrange("EST", -18000, "EDT", -14400,
- ... relativedelta(hours=+2, month=4, day=1,
- ... weekday=SU(+1)),
- ... relativedelta(hours=+1, month=10, day=31,
- ... weekday=SU(-1)))
- >>> tzstr('EST5EDT') == range1 == range2
- True
-
- """
- def __init__(self, stdabbr, stdoffset=None,
- dstabbr=None, dstoffset=None,
- start=None, end=None):
-
- global relativedelta
- from dateutil import relativedelta
-
- self._std_abbr = stdabbr
- self._dst_abbr = dstabbr
-
- try:
- stdoffset = stdoffset.total_seconds()
- except (TypeError, AttributeError):
- pass
-
- try:
- dstoffset = dstoffset.total_seconds()
- except (TypeError, AttributeError):
- pass
-
- if stdoffset is not None:
- self._std_offset = datetime.timedelta(seconds=stdoffset)
- else:
- self._std_offset = ZERO
-
- if dstoffset is not None:
- self._dst_offset = datetime.timedelta(seconds=dstoffset)
- elif dstabbr and stdoffset is not None:
- self._dst_offset = self._std_offset + datetime.timedelta(hours=+1)
- else:
- self._dst_offset = ZERO
-
- if dstabbr and start is None:
- self._start_delta = relativedelta.relativedelta(
- hours=+2, month=4, day=1, weekday=relativedelta.SU(+1))
- else:
- self._start_delta = start
-
- if dstabbr and end is None:
- self._end_delta = relativedelta.relativedelta(
- hours=+1, month=10, day=31, weekday=relativedelta.SU(-1))
- else:
- self._end_delta = end
-
- self._dst_base_offset_ = self._dst_offset - self._std_offset
- self.hasdst = bool(self._start_delta)
-
- def transitions(self, year):
- """
- For a given year, get the DST on and off transition times, expressed
- always on the standard time side. For zones with no transitions, this
- function returns ``None``.
-
- :param year:
- The year whose transitions you would like to query.
-
- :return:
- Returns a :class:`tuple` of :class:`datetime.datetime` objects,
- ``(dston, dstoff)`` for zones with an annual DST transition, or
- ``None`` for fixed offset zones.
- """
- if not self.hasdst:
- return None
-
- base_year = datetime.datetime(year, 1, 1)
-
- start = base_year + self._start_delta
- end = base_year + self._end_delta
-
- return (start, end)
-
- def __eq__(self, other):
- if not isinstance(other, tzrange):
- return NotImplemented
-
- return (self._std_abbr == other._std_abbr and
- self._dst_abbr == other._dst_abbr and
- self._std_offset == other._std_offset and
- self._dst_offset == other._dst_offset and
- self._start_delta == other._start_delta and
- self._end_delta == other._end_delta)
-
- @property
- def _dst_base_offset(self):
- return self._dst_base_offset_
-
-
-@six.add_metaclass(_TzStrFactory)
-class tzstr(tzrange):
- """
- ``tzstr`` objects are time zone objects specified by a time-zone string as
- it would be passed to a ``TZ`` variable on POSIX-style systems (see
- the `GNU C Library: TZ Variable`_ for more details).
-
- There is one notable exception, which is that POSIX-style time zones use an
- inverted offset format, so normally ``GMT+3`` would be parsed as an offset
- 3 hours *behind* GMT. The ``tzstr`` time zone object will parse this as an
- offset 3 hours *ahead* of GMT. If you would like to maintain the POSIX
- behavior, pass a ``True`` value to ``posix_offset``.
-
- The :class:`tzrange` object provides the same functionality, but is
- specified using :class:`relativedelta.relativedelta` objects. rather than
- strings.
-
- :param s:
- A time zone string in ``TZ`` variable format. This can be a
- :class:`bytes` (2.x: :class:`str`), :class:`str` (2.x:
- :class:`unicode`) or a stream emitting unicode characters
- (e.g. :class:`StringIO`).
-
- :param posix_offset:
- Optional. If set to ``True``, interpret strings such as ``GMT+3`` or
- ``UTC+3`` as being 3 hours *behind* UTC rather than ahead, per the
- POSIX standard.
-
- .. caution::
-
- Prior to version 2.7.0, this function also supported time zones
- in the format:
-
- * ``EST5EDT,4,0,6,7200,10,0,26,7200,3600``
- * ``EST5EDT,4,1,0,7200,10,-1,0,7200,3600``
-
- This format is non-standard and has been deprecated; this function
- will raise a :class:`DeprecatedTZFormatWarning` until
- support is removed in a future version.
-
- .. _`GNU C Library: TZ Variable`:
- https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
- """
- def __init__(self, s, posix_offset=False):
- global parser
- from dateutil.parser import _parser as parser
-
- self._s = s
-
- res = parser._parsetz(s)
- if res is None or res.any_unused_tokens:
- raise ValueError("unknown string format")
-
- # Here we break the compatibility with the TZ variable handling.
- # GMT-3 actually *means* the timezone -3.
- if res.stdabbr in ("GMT", "UTC") and not posix_offset:
- res.stdoffset *= -1
-
- # We must initialize it first, since _delta() needs
- # _std_offset and _dst_offset set. Use False in start/end
- # to avoid building it two times.
- tzrange.__init__(self, res.stdabbr, res.stdoffset,
- res.dstabbr, res.dstoffset,
- start=False, end=False)
-
- if not res.dstabbr:
- self._start_delta = None
- self._end_delta = None
- else:
- self._start_delta = self._delta(res.start)
- if self._start_delta:
- self._end_delta = self._delta(res.end, isend=1)
-
- self.hasdst = bool(self._start_delta)
-
- def _delta(self, x, isend=0):
- from dateutil import relativedelta
- kwargs = {}
- if x.month is not None:
- kwargs["month"] = x.month
- if x.weekday is not None:
- kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week)
- if x.week > 0:
- kwargs["day"] = 1
- else:
- kwargs["day"] = 31
- elif x.day:
- kwargs["day"] = x.day
- elif x.yday is not None:
- kwargs["yearday"] = x.yday
- elif x.jyday is not None:
- kwargs["nlyearday"] = x.jyday
- if not kwargs:
- # Default is to start on first sunday of april, and end
- # on last sunday of october.
- if not isend:
- kwargs["month"] = 4
- kwargs["day"] = 1
- kwargs["weekday"] = relativedelta.SU(+1)
- else:
- kwargs["month"] = 10
- kwargs["day"] = 31
- kwargs["weekday"] = relativedelta.SU(-1)
- if x.time is not None:
- kwargs["seconds"] = x.time
- else:
- # Default is 2AM.
- kwargs["seconds"] = 7200
- if isend:
- # Convert to standard time, to follow the documented way
- # of working with the extra hour. See the documentation
- # of the tzinfo class.
- delta = self._dst_offset - self._std_offset
- kwargs["seconds"] -= delta.seconds + delta.days * 86400
- return relativedelta.relativedelta(**kwargs)
-
- def __repr__(self):
- return "%s(%s)" % (self.__class__.__name__, repr(self._s))
-
-
-class _tzicalvtzcomp(object):
- def __init__(self, tzoffsetfrom, tzoffsetto, isdst,
- tzname=None, rrule=None):
- self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom)
- self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto)
- self.tzoffsetdiff = self.tzoffsetto - self.tzoffsetfrom
- self.isdst = isdst
- self.tzname = tzname
- self.rrule = rrule
-
-
-class _tzicalvtz(_tzinfo):
- def __init__(self, tzid, comps=[]):
- super(_tzicalvtz, self).__init__()
-
- self._tzid = tzid
- self._comps = comps
- self._cachedate = []
- self._cachecomp = []
- self._cache_lock = _thread.allocate_lock()
-
- def _find_comp(self, dt):
- if len(self._comps) == 1:
- return self._comps[0]
-
- dt = dt.replace(tzinfo=None)
-
- try:
- with self._cache_lock:
- return self._cachecomp[self._cachedate.index(
- (dt, self._fold(dt)))]
- except ValueError:
- pass
-
- lastcompdt = None
- lastcomp = None
-
- for comp in self._comps:
- compdt = self._find_compdt(comp, dt)
-
- if compdt and (not lastcompdt or lastcompdt < compdt):
- lastcompdt = compdt
- lastcomp = comp
-
- if not lastcomp:
- # RFC says nothing about what to do when a given
- # time is before the first onset date. We'll look for the
- # first standard component, or the first component, if
- # none is found.
- for comp in self._comps:
- if not comp.isdst:
- lastcomp = comp
- break
- else:
- lastcomp = comp[0]
-
- with self._cache_lock:
- self._cachedate.insert(0, (dt, self._fold(dt)))
- self._cachecomp.insert(0, lastcomp)
-
- if len(self._cachedate) > 10:
- self._cachedate.pop()
- self._cachecomp.pop()
-
- return lastcomp
-
- def _find_compdt(self, comp, dt):
- if comp.tzoffsetdiff < ZERO and self._fold(dt):
- dt -= comp.tzoffsetdiff
-
- compdt = comp.rrule.before(dt, inc=True)
-
- return compdt
-
- def utcoffset(self, dt):
- if dt is None:
- return None
-
- return self._find_comp(dt).tzoffsetto
-
- def dst(self, dt):
- comp = self._find_comp(dt)
- if comp.isdst:
- return comp.tzoffsetdiff
- else:
- return ZERO
-
- @tzname_in_python2
- def tzname(self, dt):
- return self._find_comp(dt).tzname
-
- def __repr__(self):
- return "" % repr(self._tzid)
-
- __reduce__ = object.__reduce__
-
-
-class tzical(object):
- """
- This object is designed to parse an iCalendar-style ``VTIMEZONE`` structure
- as set out in `RFC 5545`_ Section 4.6.5 into one or more `tzinfo` objects.
-
- :param `fileobj`:
- A file or stream in iCalendar format, which should be UTF-8 encoded
- with CRLF endings.
-
- .. _`RFC 5545`: https://tools.ietf.org/html/rfc5545
- """
- def __init__(self, fileobj):
- global rrule
- from dateutil import rrule
-
- if isinstance(fileobj, string_types):
- self._s = fileobj
- # ical should be encoded in UTF-8 with CRLF
- fileobj = open(fileobj, 'r')
- else:
- self._s = getattr(fileobj, 'name', repr(fileobj))
- fileobj = _nullcontext(fileobj)
-
- self._vtz = {}
-
- with fileobj as fobj:
- self._parse_rfc(fobj.read())
-
- def keys(self):
- """
- Retrieves the available time zones as a list.
- """
- return list(self._vtz.keys())
-
- def get(self, tzid=None):
- """
- Retrieve a :py:class:`datetime.tzinfo` object by its ``tzid``.
-
- :param tzid:
- If there is exactly one time zone available, omitting ``tzid``
- or passing :py:const:`None` value returns it. Otherwise a valid
- key (which can be retrieved from :func:`keys`) is required.
-
- :raises ValueError:
- Raised if ``tzid`` is not specified but there are either more
- or fewer than 1 zone defined.
-
- :returns:
- Returns either a :py:class:`datetime.tzinfo` object representing
- the relevant time zone or :py:const:`None` if the ``tzid`` was
- not found.
- """
- if tzid is None:
- if len(self._vtz) == 0:
- raise ValueError("no timezones defined")
- elif len(self._vtz) > 1:
- raise ValueError("more than one timezone available")
- tzid = next(iter(self._vtz))
-
- return self._vtz.get(tzid)
-
- def _parse_offset(self, s):
- s = s.strip()
- if not s:
- raise ValueError("empty offset")
- if s[0] in ('+', '-'):
- signal = (-1, +1)[s[0] == '+']
- s = s[1:]
- else:
- signal = +1
- if len(s) == 4:
- return (int(s[:2]) * 3600 + int(s[2:]) * 60) * signal
- elif len(s) == 6:
- return (int(s[:2]) * 3600 + int(s[2:4]) * 60 + int(s[4:])) * signal
- else:
- raise ValueError("invalid offset: " + s)
-
- def _parse_rfc(self, s):
- lines = s.splitlines()
- if not lines:
- raise ValueError("empty string")
-
- # Unfold
- i = 0
- while i < len(lines):
- line = lines[i].rstrip()
- if not line:
- del lines[i]
- elif i > 0 and line[0] == " ":
- lines[i-1] += line[1:]
- del lines[i]
- else:
- i += 1
-
- tzid = None
- comps = []
- invtz = False
- comptype = None
- for line in lines:
- if not line:
- continue
- name, value = line.split(':', 1)
- parms = name.split(';')
- if not parms:
- raise ValueError("empty property name")
- name = parms[0].upper()
- parms = parms[1:]
- if invtz:
- if name == "BEGIN":
- if value in ("STANDARD", "DAYLIGHT"):
- # Process component
- pass
- else:
- raise ValueError("unknown component: "+value)
- comptype = value
- founddtstart = False
- tzoffsetfrom = None
- tzoffsetto = None
- rrulelines = []
- tzname = None
- elif name == "END":
- if value == "VTIMEZONE":
- if comptype:
- raise ValueError("component not closed: "+comptype)
- if not tzid:
- raise ValueError("mandatory TZID not found")
- if not comps:
- raise ValueError(
- "at least one component is needed")
- # Process vtimezone
- self._vtz[tzid] = _tzicalvtz(tzid, comps)
- invtz = False
- elif value == comptype:
- if not founddtstart:
- raise ValueError("mandatory DTSTART not found")
- if tzoffsetfrom is None:
- raise ValueError(
- "mandatory TZOFFSETFROM not found")
- if tzoffsetto is None:
- raise ValueError(
- "mandatory TZOFFSETFROM not found")
- # Process component
- rr = None
- if rrulelines:
- rr = rrule.rrulestr("\n".join(rrulelines),
- compatible=True,
- ignoretz=True,
- cache=True)
- comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto,
- (comptype == "DAYLIGHT"),
- tzname, rr)
- comps.append(comp)
- comptype = None
- else:
- raise ValueError("invalid component end: "+value)
- elif comptype:
- if name == "DTSTART":
- # DTSTART in VTIMEZONE takes a subset of valid RRULE
- # values under RFC 5545.
- for parm in parms:
- if parm != 'VALUE=DATE-TIME':
- msg = ('Unsupported DTSTART param in ' +
- 'VTIMEZONE: ' + parm)
- raise ValueError(msg)
- rrulelines.append(line)
- founddtstart = True
- elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"):
- rrulelines.append(line)
- elif name == "TZOFFSETFROM":
- if parms:
- raise ValueError(
- "unsupported %s parm: %s " % (name, parms[0]))
- tzoffsetfrom = self._parse_offset(value)
- elif name == "TZOFFSETTO":
- if parms:
- raise ValueError(
- "unsupported TZOFFSETTO parm: "+parms[0])
- tzoffsetto = self._parse_offset(value)
- elif name == "TZNAME":
- if parms:
- raise ValueError(
- "unsupported TZNAME parm: "+parms[0])
- tzname = value
- elif name == "COMMENT":
- pass
- else:
- raise ValueError("unsupported property: "+name)
- else:
- if name == "TZID":
- if parms:
- raise ValueError(
- "unsupported TZID parm: "+parms[0])
- tzid = value
- elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"):
- pass
- else:
- raise ValueError("unsupported property: "+name)
- elif name == "BEGIN" and value == "VTIMEZONE":
- tzid = None
- comps = []
- invtz = True
-
- def __repr__(self):
- return "%s(%s)" % (self.__class__.__name__, repr(self._s))
-
-
-if sys.platform != "win32":
- TZFILES = ["/etc/localtime", "localtime"]
- TZPATHS = ["/usr/share/zoneinfo",
- "/usr/lib/zoneinfo",
- "/usr/share/lib/zoneinfo",
- "/etc/zoneinfo"]
-else:
- TZFILES = []
- TZPATHS = []
-
-
-def __get_gettz():
- tzlocal_classes = (tzlocal,)
- if tzwinlocal is not None:
- tzlocal_classes += (tzwinlocal,)
-
- class GettzFunc(object):
- """
- Retrieve a time zone object from a string representation
-
- This function is intended to retrieve the :py:class:`tzinfo` subclass
- that best represents the time zone that would be used if a POSIX
- `TZ variable`_ were set to the same value.
-
- If no argument or an empty string is passed to ``gettz``, local time
- is returned:
-
- .. code-block:: python3
-
- >>> gettz()
- tzfile('/etc/localtime')
-
- This function is also the preferred way to map IANA tz database keys
- to :class:`tzfile` objects:
-
- .. code-block:: python3
-
- >>> gettz('Pacific/Kiritimati')
- tzfile('/usr/share/zoneinfo/Pacific/Kiritimati')
-
- On Windows, the standard is extended to include the Windows-specific
- zone names provided by the operating system:
-
- .. code-block:: python3
-
- >>> gettz('Egypt Standard Time')
- tzwin('Egypt Standard Time')
-
- Passing a GNU ``TZ`` style string time zone specification returns a
- :class:`tzstr` object:
-
- .. code-block:: python3
-
- >>> gettz('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
- tzstr('AEST-10AEDT-11,M10.1.0/2,M4.1.0/3')
-
- :param name:
- A time zone name (IANA, or, on Windows, Windows keys), location of
- a ``tzfile(5)`` zoneinfo file or ``TZ`` variable style time zone
- specifier. An empty string, no argument or ``None`` is interpreted
- as local time.
-
- :return:
- Returns an instance of one of ``dateutil``'s :py:class:`tzinfo`
- subclasses.
-
- .. versionchanged:: 2.7.0
-
- After version 2.7.0, any two calls to ``gettz`` using the same
- input strings will return the same object:
-
- .. code-block:: python3
-
- >>> tz.gettz('America/Chicago') is tz.gettz('America/Chicago')
- True
-
- In addition to improving performance, this ensures that
- `"same zone" semantics`_ are used for datetimes in the same zone.
-
-
- .. _`TZ variable`:
- https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
-
- .. _`"same zone" semantics`:
- https://blog.ganssle.io/articles/2018/02/aware-datetime-arithmetic.html
- """
- def __init__(self):
-
- self.__instances = weakref.WeakValueDictionary()
- self.__strong_cache_size = 8
- self.__strong_cache = OrderedDict()
- self._cache_lock = _thread.allocate_lock()
-
- def __call__(self, name=None):
- with self._cache_lock:
- rv = self.__instances.get(name, None)
-
- if rv is None:
- rv = self.nocache(name=name)
- if not (name is None
- or isinstance(rv, tzlocal_classes)
- or rv is None):
- # tzlocal is slightly more complicated than the other
- # time zone providers because it depends on environment
- # at construction time, so don't cache that.
- #
- # We also cannot store weak references to None, so we
- # will also not store that.
- self.__instances[name] = rv
- else:
- # No need for strong caching, return immediately
- return rv
-
- self.__strong_cache[name] = self.__strong_cache.pop(name, rv)
-
- if len(self.__strong_cache) > self.__strong_cache_size:
- self.__strong_cache.popitem(last=False)
-
- return rv
-
- def set_cache_size(self, size):
- with self._cache_lock:
- self.__strong_cache_size = size
- while len(self.__strong_cache) > size:
- self.__strong_cache.popitem(last=False)
-
- def cache_clear(self):
- with self._cache_lock:
- self.__instances = weakref.WeakValueDictionary()
- self.__strong_cache.clear()
-
- @staticmethod
- def nocache(name=None):
- """A non-cached version of gettz"""
- tz = None
- if not name:
- try:
- name = os.environ["TZ"]
- except KeyError:
- pass
- if name is None or name == ":":
- for filepath in TZFILES:
- if not os.path.isabs(filepath):
- filename = filepath
- for path in TZPATHS:
- filepath = os.path.join(path, filename)
- if os.path.isfile(filepath):
- break
- else:
- continue
- if os.path.isfile(filepath):
- try:
- tz = tzfile(filepath)
- break
- except (IOError, OSError, ValueError):
- pass
- else:
- tz = tzlocal()
- else:
- if name.startswith(":"):
- name = name[1:]
- if os.path.isabs(name):
- if os.path.isfile(name):
- tz = tzfile(name)
- else:
- tz = None
- else:
- for path in TZPATHS:
- filepath = os.path.join(path, name)
- if not os.path.isfile(filepath):
- filepath = filepath.replace(' ', '_')
- if not os.path.isfile(filepath):
- continue
- try:
- tz = tzfile(filepath)
- break
- except (IOError, OSError, ValueError):
- pass
- else:
- tz = None
- if tzwin is not None:
- try:
- tz = tzwin(name)
- except (WindowsError, UnicodeEncodeError):
- # UnicodeEncodeError is for Python 2.7 compat
- tz = None
-
- if not tz:
- from dateutil.zoneinfo import get_zonefile_instance
- tz = get_zonefile_instance().get(name)
-
- if not tz:
- for c in name:
- # name is not a tzstr unless it has at least
- # one offset. For short values of "name", an
- # explicit for loop seems to be the fastest way
- # To determine if a string contains a digit
- if c in "0123456789":
- try:
- tz = tzstr(name)
- except ValueError:
- pass
- break
- else:
- if name in ("GMT", "UTC"):
- tz = tzutc()
- elif name in time.tzname:
- tz = tzlocal()
- return tz
-
- return GettzFunc()
-
-
-gettz = __get_gettz()
-del __get_gettz
-
-
-def datetime_exists(dt, tz=None):
- """
- Given a datetime and a time zone, determine whether or not a given datetime
- would fall in a gap.
-
- :param dt:
- A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
- is provided.)
-
- :param tz:
- A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
- ``None`` or not provided, the datetime's own time zone will be used.
-
- :return:
- Returns a boolean value whether or not the "wall time" exists in
- ``tz``.
-
- .. versionadded:: 2.7.0
- """
- if tz is None:
- if dt.tzinfo is None:
- raise ValueError('Datetime is naive and no time zone provided.')
- tz = dt.tzinfo
-
- dt = dt.replace(tzinfo=None)
-
- # This is essentially a test of whether or not the datetime can survive
- # a round trip to UTC.
- dt_rt = dt.replace(tzinfo=tz).astimezone(tzutc()).astimezone(tz)
- dt_rt = dt_rt.replace(tzinfo=None)
-
- return dt == dt_rt
-
-
-def datetime_ambiguous(dt, tz=None):
- """
- Given a datetime and a time zone, determine whether or not a given datetime
- is ambiguous (i.e if there are two times differentiated only by their DST
- status).
-
- :param dt:
- A :class:`datetime.datetime` (whose time zone will be ignored if ``tz``
- is provided.)
-
- :param tz:
- A :class:`datetime.tzinfo` with support for the ``fold`` attribute. If
- ``None`` or not provided, the datetime's own time zone will be used.
-
- :return:
- Returns a boolean value whether or not the "wall time" is ambiguous in
- ``tz``.
-
- .. versionadded:: 2.6.0
- """
- if tz is None:
- if dt.tzinfo is None:
- raise ValueError('Datetime is naive and no time zone provided.')
-
- tz = dt.tzinfo
-
- # If a time zone defines its own "is_ambiguous" function, we'll use that.
- is_ambiguous_fn = getattr(tz, 'is_ambiguous', None)
- if is_ambiguous_fn is not None:
- try:
- return tz.is_ambiguous(dt)
- except Exception:
- pass
-
- # If it doesn't come out and tell us it's ambiguous, we'll just check if
- # the fold attribute has any effect on this particular date and time.
- dt = dt.replace(tzinfo=tz)
- wall_0 = enfold(dt, fold=0)
- wall_1 = enfold(dt, fold=1)
-
- same_offset = wall_0.utcoffset() == wall_1.utcoffset()
- same_dst = wall_0.dst() == wall_1.dst()
-
- return not (same_offset and same_dst)
-
-
-def resolve_imaginary(dt):
- """
- Given a datetime that may be imaginary, return an existing datetime.
-
- This function assumes that an imaginary datetime represents what the
- wall time would be in a zone had the offset transition not occurred, so
- it will always fall forward by the transition's change in offset.
-
- .. doctest::
-
- >>> from dateutil import tz
- >>> from datetime import datetime
- >>> NYC = tz.gettz('America/New_York')
- >>> print(tz.resolve_imaginary(datetime(2017, 3, 12, 2, 30, tzinfo=NYC)))
- 2017-03-12 03:30:00-04:00
-
- >>> KIR = tz.gettz('Pacific/Kiritimati')
- >>> print(tz.resolve_imaginary(datetime(1995, 1, 1, 12, 30, tzinfo=KIR)))
- 1995-01-02 12:30:00+14:00
-
- As a note, :func:`datetime.astimezone` is guaranteed to produce a valid,
- existing datetime, so a round-trip to and from UTC is sufficient to get
- an extant datetime, however, this generally "falls back" to an earlier time
- rather than falling forward to the STD side (though no guarantees are made
- about this behavior).
-
- :param dt:
- A :class:`datetime.datetime` which may or may not exist.
-
- :return:
- Returns an existing :class:`datetime.datetime`. If ``dt`` was not
- imaginary, the datetime returned is guaranteed to be the same object
- passed to the function.
-
- .. versionadded:: 2.7.0
- """
- if dt.tzinfo is not None and not datetime_exists(dt):
-
- curr_offset = (dt + datetime.timedelta(hours=24)).utcoffset()
- old_offset = (dt - datetime.timedelta(hours=24)).utcoffset()
-
- dt += curr_offset - old_offset
-
- return dt
-
-
-def _datetime_to_timestamp(dt):
- """
- Convert a :class:`datetime.datetime` object to an epoch timestamp in
- seconds since January 1, 1970, ignoring the time zone.
- """
- return (dt.replace(tzinfo=None) - EPOCH).total_seconds()
-
-
-if sys.version_info >= (3, 6):
- def _get_supported_offset(second_offset):
- return second_offset
-else:
- def _get_supported_offset(second_offset):
- # For python pre-3.6, round to full-minutes if that's not the case.
- # Python's datetime doesn't accept sub-minute timezones. Check
- # http://python.org/sf/1447945 or https://bugs.python.org/issue5288
- # for some information.
- old_offset = second_offset
- calculated_offset = 60 * ((second_offset + 30) // 60)
- return calculated_offset
-
-
-try:
- # Python 3.7 feature
- from contextmanager import nullcontext as _nullcontext
-except ImportError:
- class _nullcontext(object):
- """
- Class for wrapping contexts so that they are passed through in a
- with statement.
- """
- def __init__(self, context):
- self.context = context
-
- def __enter__(self):
- return self.context
-
- def __exit__(*args, **kwargs):
- pass
-
-# vim:ts=4:sw=4:et
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tz/win.py b/server/venv/lib/python3.7/site-packages/dateutil/tz/win.py
deleted file mode 100644
index cde07ba..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tz/win.py
+++ /dev/null
@@ -1,370 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module provides an interface to the native time zone data on Windows,
-including :py:class:`datetime.tzinfo` implementations.
-
-Attempting to import this module on a non-Windows platform will raise an
-:py:obj:`ImportError`.
-"""
-# This code was originally contributed by Jeffrey Harris.
-import datetime
-import struct
-
-from six.moves import winreg
-from six import text_type
-
-try:
- import ctypes
- from ctypes import wintypes
-except ValueError:
- # ValueError is raised on non-Windows systems for some horrible reason.
- raise ImportError("Running tzwin on non-Windows system")
-
-from ._common import tzrangebase
-
-__all__ = ["tzwin", "tzwinlocal", "tzres"]
-
-ONEWEEK = datetime.timedelta(7)
-
-TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones"
-TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones"
-TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation"
-
-
-def _settzkeyname():
- handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
- try:
- winreg.OpenKey(handle, TZKEYNAMENT).Close()
- TZKEYNAME = TZKEYNAMENT
- except WindowsError:
- TZKEYNAME = TZKEYNAME9X
- handle.Close()
- return TZKEYNAME
-
-
-TZKEYNAME = _settzkeyname()
-
-
-class tzres(object):
- """
- Class for accessing ``tzres.dll``, which contains timezone name related
- resources.
-
- .. versionadded:: 2.5.0
- """
- p_wchar = ctypes.POINTER(wintypes.WCHAR) # Pointer to a wide char
-
- def __init__(self, tzres_loc='tzres.dll'):
- # Load the user32 DLL so we can load strings from tzres
- user32 = ctypes.WinDLL('user32')
-
- # Specify the LoadStringW function
- user32.LoadStringW.argtypes = (wintypes.HINSTANCE,
- wintypes.UINT,
- wintypes.LPWSTR,
- ctypes.c_int)
-
- self.LoadStringW = user32.LoadStringW
- self._tzres = ctypes.WinDLL(tzres_loc)
- self.tzres_loc = tzres_loc
-
- def load_name(self, offset):
- """
- Load a timezone name from a DLL offset (integer).
-
- >>> from dateutil.tzwin import tzres
- >>> tzr = tzres()
- >>> print(tzr.load_name(112))
- 'Eastern Standard Time'
-
- :param offset:
- A positive integer value referring to a string from the tzres dll.
-
- .. note::
-
- Offsets found in the registry are generally of the form
- ``@tzres.dll,-114``. The offset in this case is 114, not -114.
-
- """
- resource = self.p_wchar()
- lpBuffer = ctypes.cast(ctypes.byref(resource), wintypes.LPWSTR)
- nchar = self.LoadStringW(self._tzres._handle, offset, lpBuffer, 0)
- return resource[:nchar]
-
- def name_from_string(self, tzname_str):
- """
- Parse strings as returned from the Windows registry into the time zone
- name as defined in the registry.
-
- >>> from dateutil.tzwin import tzres
- >>> tzr = tzres()
- >>> print(tzr.name_from_string('@tzres.dll,-251'))
- 'Dateline Daylight Time'
- >>> print(tzr.name_from_string('Eastern Standard Time'))
- 'Eastern Standard Time'
-
- :param tzname_str:
- A timezone name string as returned from a Windows registry key.
-
- :return:
- Returns the localized timezone string from tzres.dll if the string
- is of the form `@tzres.dll,-offset`, else returns the input string.
- """
- if not tzname_str.startswith('@'):
- return tzname_str
-
- name_splt = tzname_str.split(',-')
- try:
- offset = int(name_splt[1])
- except:
- raise ValueError("Malformed timezone string.")
-
- return self.load_name(offset)
-
-
-class tzwinbase(tzrangebase):
- """tzinfo class based on win32's timezones available in the registry."""
- def __init__(self):
- raise NotImplementedError('tzwinbase is an abstract base class')
-
- def __eq__(self, other):
- # Compare on all relevant dimensions, including name.
- if not isinstance(other, tzwinbase):
- return NotImplemented
-
- return (self._std_offset == other._std_offset and
- self._dst_offset == other._dst_offset and
- self._stddayofweek == other._stddayofweek and
- self._dstdayofweek == other._dstdayofweek and
- self._stdweeknumber == other._stdweeknumber and
- self._dstweeknumber == other._dstweeknumber and
- self._stdhour == other._stdhour and
- self._dsthour == other._dsthour and
- self._stdminute == other._stdminute and
- self._dstminute == other._dstminute and
- self._std_abbr == other._std_abbr and
- self._dst_abbr == other._dst_abbr)
-
- @staticmethod
- def list():
- """Return a list of all time zones known to the system."""
- with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
- with winreg.OpenKey(handle, TZKEYNAME) as tzkey:
- result = [winreg.EnumKey(tzkey, i)
- for i in range(winreg.QueryInfoKey(tzkey)[0])]
- return result
-
- def display(self):
- """
- Return the display name of the time zone.
- """
- return self._display
-
- def transitions(self, year):
- """
- For a given year, get the DST on and off transition times, expressed
- always on the standard time side. For zones with no transitions, this
- function returns ``None``.
-
- :param year:
- The year whose transitions you would like to query.
-
- :return:
- Returns a :class:`tuple` of :class:`datetime.datetime` objects,
- ``(dston, dstoff)`` for zones with an annual DST transition, or
- ``None`` for fixed offset zones.
- """
-
- if not self.hasdst:
- return None
-
- dston = picknthweekday(year, self._dstmonth, self._dstdayofweek,
- self._dsthour, self._dstminute,
- self._dstweeknumber)
-
- dstoff = picknthweekday(year, self._stdmonth, self._stddayofweek,
- self._stdhour, self._stdminute,
- self._stdweeknumber)
-
- # Ambiguous dates default to the STD side
- dstoff -= self._dst_base_offset
-
- return dston, dstoff
-
- def _get_hasdst(self):
- return self._dstmonth != 0
-
- @property
- def _dst_base_offset(self):
- return self._dst_base_offset_
-
-
-class tzwin(tzwinbase):
- """
- Time zone object created from the zone info in the Windows registry
-
- These are similar to :py:class:`dateutil.tz.tzrange` objects in that
- the time zone data is provided in the format of a single offset rule
- for either 0 or 2 time zone transitions per year.
-
- :param: name
- The name of a Windows time zone key, e.g. "Eastern Standard Time".
- The full list of keys can be retrieved with :func:`tzwin.list`.
- """
-
- def __init__(self, name):
- self._name = name
-
- with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
- tzkeyname = text_type("{kn}\\{name}").format(kn=TZKEYNAME, name=name)
- with winreg.OpenKey(handle, tzkeyname) as tzkey:
- keydict = valuestodict(tzkey)
-
- self._std_abbr = keydict["Std"]
- self._dst_abbr = keydict["Dlt"]
-
- self._display = keydict["Display"]
-
- # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm
- tup = struct.unpack("=3l16h", keydict["TZI"])
- stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1
- dstoffset = stdoffset-tup[2] # + DaylightBias * -1
- self._std_offset = datetime.timedelta(minutes=stdoffset)
- self._dst_offset = datetime.timedelta(minutes=dstoffset)
-
- # for the meaning see the win32 TIME_ZONE_INFORMATION structure docs
- # http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
- (self._stdmonth,
- self._stddayofweek, # Sunday = 0
- self._stdweeknumber, # Last = 5
- self._stdhour,
- self._stdminute) = tup[4:9]
-
- (self._dstmonth,
- self._dstdayofweek, # Sunday = 0
- self._dstweeknumber, # Last = 5
- self._dsthour,
- self._dstminute) = tup[12:17]
-
- self._dst_base_offset_ = self._dst_offset - self._std_offset
- self.hasdst = self._get_hasdst()
-
- def __repr__(self):
- return "tzwin(%s)" % repr(self._name)
-
- def __reduce__(self):
- return (self.__class__, (self._name,))
-
-
-class tzwinlocal(tzwinbase):
- """
- Class representing the local time zone information in the Windows registry
-
- While :class:`dateutil.tz.tzlocal` makes system calls (via the :mod:`time`
- module) to retrieve time zone information, ``tzwinlocal`` retrieves the
- rules directly from the Windows registry and creates an object like
- :class:`dateutil.tz.tzwin`.
-
- Because Windows does not have an equivalent of :func:`time.tzset`, on
- Windows, :class:`dateutil.tz.tzlocal` instances will always reflect the
- time zone settings *at the time that the process was started*, meaning
- changes to the machine's time zone settings during the run of a program
- on Windows will **not** be reflected by :class:`dateutil.tz.tzlocal`.
- Because ``tzwinlocal`` reads the registry directly, it is unaffected by
- this issue.
- """
- def __init__(self):
- with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:
- with winreg.OpenKey(handle, TZLOCALKEYNAME) as tzlocalkey:
- keydict = valuestodict(tzlocalkey)
-
- self._std_abbr = keydict["StandardName"]
- self._dst_abbr = keydict["DaylightName"]
-
- try:
- tzkeyname = text_type('{kn}\\{sn}').format(kn=TZKEYNAME,
- sn=self._std_abbr)
- with winreg.OpenKey(handle, tzkeyname) as tzkey:
- _keydict = valuestodict(tzkey)
- self._display = _keydict["Display"]
- except OSError:
- self._display = None
-
- stdoffset = -keydict["Bias"]-keydict["StandardBias"]
- dstoffset = stdoffset-keydict["DaylightBias"]
-
- self._std_offset = datetime.timedelta(minutes=stdoffset)
- self._dst_offset = datetime.timedelta(minutes=dstoffset)
-
- # For reasons unclear, in this particular key, the day of week has been
- # moved to the END of the SYSTEMTIME structure.
- tup = struct.unpack("=8h", keydict["StandardStart"])
-
- (self._stdmonth,
- self._stdweeknumber, # Last = 5
- self._stdhour,
- self._stdminute) = tup[1:5]
-
- self._stddayofweek = tup[7]
-
- tup = struct.unpack("=8h", keydict["DaylightStart"])
-
- (self._dstmonth,
- self._dstweeknumber, # Last = 5
- self._dsthour,
- self._dstminute) = tup[1:5]
-
- self._dstdayofweek = tup[7]
-
- self._dst_base_offset_ = self._dst_offset - self._std_offset
- self.hasdst = self._get_hasdst()
-
- def __repr__(self):
- return "tzwinlocal()"
-
- def __str__(self):
- # str will return the standard name, not the daylight name.
- return "tzwinlocal(%s)" % repr(self._std_abbr)
-
- def __reduce__(self):
- return (self.__class__, ())
-
-
-def picknthweekday(year, month, dayofweek, hour, minute, whichweek):
- """ dayofweek == 0 means Sunday, whichweek 5 means last instance """
- first = datetime.datetime(year, month, 1, hour, minute)
-
- # This will work if dayofweek is ISO weekday (1-7) or Microsoft-style (0-6),
- # Because 7 % 7 = 0
- weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % 7) + 1)
- wd = weekdayone + ((whichweek - 1) * ONEWEEK)
- if (wd.month != month):
- wd -= ONEWEEK
-
- return wd
-
-
-def valuestodict(key):
- """Convert a registry key's values to a dictionary."""
- dout = {}
- size = winreg.QueryInfoKey(key)[1]
- tz_res = None
-
- for i in range(size):
- key_name, value, dtype = winreg.EnumValue(key, i)
- if dtype == winreg.REG_DWORD or dtype == winreg.REG_DWORD_LITTLE_ENDIAN:
- # If it's a DWORD (32-bit integer), it's stored as unsigned - convert
- # that to a proper signed integer
- if value & (1 << 31):
- value = value - (1 << 32)
- elif dtype == winreg.REG_SZ:
- # If it's a reference to the tzres DLL, load the actual string
- if value.startswith('@tzres'):
- tz_res = tz_res or tzres()
- value = tz_res.name_from_string(value)
-
- value = value.rstrip('\x00') # Remove trailing nulls
-
- dout[key_name] = value
-
- return dout
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/tzwin.py b/server/venv/lib/python3.7/site-packages/dateutil/tzwin.py
deleted file mode 100644
index cebc673..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/tzwin.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# tzwin has moved to dateutil.tz.win
-from .tz.win import *
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/utils.py b/server/venv/lib/python3.7/site-packages/dateutil/utils.py
deleted file mode 100644
index ebcce6a..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/utils.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-This module offers general convenience and utility functions for dealing with
-datetimes.
-
-.. versionadded:: 2.7.0
-"""
-from __future__ import unicode_literals
-
-from datetime import datetime, time
-
-
-def today(tzinfo=None):
- """
- Returns a :py:class:`datetime` representing the current day at midnight
-
- :param tzinfo:
- The time zone to attach (also used to determine the current day).
-
- :return:
- A :py:class:`datetime.datetime` object representing the current day
- at midnight.
- """
-
- dt = datetime.now(tzinfo)
- return datetime.combine(dt.date(), time(0, tzinfo=tzinfo))
-
-
-def default_tzinfo(dt, tzinfo):
- """
- Sets the the ``tzinfo`` parameter on naive datetimes only
-
- This is useful for example when you are provided a datetime that may have
- either an implicit or explicit time zone, such as when parsing a time zone
- string.
-
- .. doctest::
-
- >>> from dateutil.tz import tzoffset
- >>> from dateutil.parser import parse
- >>> from dateutil.utils import default_tzinfo
- >>> dflt_tz = tzoffset("EST", -18000)
- >>> print(default_tzinfo(parse('2014-01-01 12:30 UTC'), dflt_tz))
- 2014-01-01 12:30:00+00:00
- >>> print(default_tzinfo(parse('2014-01-01 12:30'), dflt_tz))
- 2014-01-01 12:30:00-05:00
-
- :param dt:
- The datetime on which to replace the time zone
-
- :param tzinfo:
- The :py:class:`datetime.tzinfo` subclass instance to assign to
- ``dt`` if (and only if) it is naive.
-
- :return:
- Returns an aware :py:class:`datetime.datetime`.
- """
- if dt.tzinfo is not None:
- return dt
- else:
- return dt.replace(tzinfo=tzinfo)
-
-
-def within_delta(dt1, dt2, delta):
- """
- Useful for comparing two datetimes that may a negilible difference
- to be considered equal.
- """
- delta = abs(delta)
- difference = dt1 - dt2
- return -delta <= difference <= delta
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__init__.py b/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__init__.py
deleted file mode 100644
index 34f11ad..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__init__.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-import warnings
-import json
-
-from tarfile import TarFile
-from pkgutil import get_data
-from io import BytesIO
-
-from dateutil.tz import tzfile as _tzfile
-
-__all__ = ["get_zonefile_instance", "gettz", "gettz_db_metadata"]
-
-ZONEFILENAME = "dateutil-zoneinfo.tar.gz"
-METADATA_FN = 'METADATA'
-
-
-class tzfile(_tzfile):
- def __reduce__(self):
- return (gettz, (self._filename,))
-
-
-def getzoneinfofile_stream():
- try:
- return BytesIO(get_data(__name__, ZONEFILENAME))
- except IOError as e: # TODO switch to FileNotFoundError?
- warnings.warn("I/O error({0}): {1}".format(e.errno, e.strerror))
- return None
-
-
-class ZoneInfoFile(object):
- def __init__(self, zonefile_stream=None):
- if zonefile_stream is not None:
- with TarFile.open(fileobj=zonefile_stream) as tf:
- self.zones = {zf.name: tzfile(tf.extractfile(zf), filename=zf.name)
- for zf in tf.getmembers()
- if zf.isfile() and zf.name != METADATA_FN}
- # deal with links: They'll point to their parent object. Less
- # waste of memory
- links = {zl.name: self.zones[zl.linkname]
- for zl in tf.getmembers() if
- zl.islnk() or zl.issym()}
- self.zones.update(links)
- try:
- metadata_json = tf.extractfile(tf.getmember(METADATA_FN))
- metadata_str = metadata_json.read().decode('UTF-8')
- self.metadata = json.loads(metadata_str)
- except KeyError:
- # no metadata in tar file
- self.metadata = None
- else:
- self.zones = {}
- self.metadata = None
-
- def get(self, name, default=None):
- """
- Wrapper for :func:`ZoneInfoFile.zones.get`. This is a convenience method
- for retrieving zones from the zone dictionary.
-
- :param name:
- The name of the zone to retrieve. (Generally IANA zone names)
-
- :param default:
- The value to return in the event of a missing key.
-
- .. versionadded:: 2.6.0
-
- """
- return self.zones.get(name, default)
-
-
-# The current API has gettz as a module function, although in fact it taps into
-# a stateful class. So as a workaround for now, without changing the API, we
-# will create a new "global" class instance the first time a user requests a
-# timezone. Ugly, but adheres to the api.
-#
-# TODO: Remove after deprecation period.
-_CLASS_ZONE_INSTANCE = []
-
-
-def get_zonefile_instance(new_instance=False):
- """
- This is a convenience function which provides a :class:`ZoneInfoFile`
- instance using the data provided by the ``dateutil`` package. By default, it
- caches a single instance of the ZoneInfoFile object and returns that.
-
- :param new_instance:
- If ``True``, a new instance of :class:`ZoneInfoFile` is instantiated and
- used as the cached instance for the next call. Otherwise, new instances
- are created only as necessary.
-
- :return:
- Returns a :class:`ZoneInfoFile` object.
-
- .. versionadded:: 2.6
- """
- if new_instance:
- zif = None
- else:
- zif = getattr(get_zonefile_instance, '_cached_instance', None)
-
- if zif is None:
- zif = ZoneInfoFile(getzoneinfofile_stream())
-
- get_zonefile_instance._cached_instance = zif
-
- return zif
-
-
-def gettz(name):
- """
- This retrieves a time zone from the local zoneinfo tarball that is packaged
- with dateutil.
-
- :param name:
- An IANA-style time zone name, as found in the zoneinfo file.
-
- :return:
- Returns a :class:`dateutil.tz.tzfile` time zone object.
-
- .. warning::
- It is generally inadvisable to use this function, and it is only
- provided for API compatibility with earlier versions. This is *not*
- equivalent to ``dateutil.tz.gettz()``, which selects an appropriate
- time zone based on the inputs, favoring system zoneinfo. This is ONLY
- for accessing the dateutil-specific zoneinfo (which may be out of
- date compared to the system zoneinfo).
-
- .. deprecated:: 2.6
- If you need to use a specific zoneinfofile over the system zoneinfo,
- instantiate a :class:`dateutil.zoneinfo.ZoneInfoFile` object and call
- :func:`dateutil.zoneinfo.ZoneInfoFile.get(name)` instead.
-
- Use :func:`get_zonefile_instance` to retrieve an instance of the
- dateutil-provided zoneinfo.
- """
- warnings.warn("zoneinfo.gettz() will be removed in future versions, "
- "to use the dateutil-provided zoneinfo files, instantiate a "
- "ZoneInfoFile object and use ZoneInfoFile.zones.get() "
- "instead. See the documentation for details.",
- DeprecationWarning)
-
- if len(_CLASS_ZONE_INSTANCE) == 0:
- _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
- return _CLASS_ZONE_INSTANCE[0].zones.get(name)
-
-
-def gettz_db_metadata():
- """ Get the zonefile metadata
-
- See `zonefile_metadata`_
-
- :returns:
- A dictionary with the database metadata
-
- .. deprecated:: 2.6
- See deprecation warning in :func:`zoneinfo.gettz`. To get metadata,
- query the attribute ``zoneinfo.ZoneInfoFile.metadata``.
- """
- warnings.warn("zoneinfo.gettz_db_metadata() will be removed in future "
- "versions, to use the dateutil-provided zoneinfo files, "
- "ZoneInfoFile object and query the 'metadata' attribute "
- "instead. See the documentation for details.",
- DeprecationWarning)
-
- if len(_CLASS_ZONE_INSTANCE) == 0:
- _CLASS_ZONE_INSTANCE.append(ZoneInfoFile(getzoneinfofile_stream()))
- return _CLASS_ZONE_INSTANCE[0].metadata
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index 8e9728a..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-37.pyc
deleted file mode 100644
index fbb17a4..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz b/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz
deleted file mode 100644
index 124f3e1..0000000
Binary files a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/dateutil-zoneinfo.tar.gz and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/rebuild.py b/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/rebuild.py
deleted file mode 100644
index 78f0d1a..0000000
--- a/server/venv/lib/python3.7/site-packages/dateutil/zoneinfo/rebuild.py
+++ /dev/null
@@ -1,53 +0,0 @@
-import logging
-import os
-import tempfile
-import shutil
-import json
-from subprocess import check_call
-from tarfile import TarFile
-
-from dateutil.zoneinfo import METADATA_FN, ZONEFILENAME
-
-
-def rebuild(filename, tag=None, format="gz", zonegroups=[], metadata=None):
- """Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*
-
- filename is the timezone tarball from ``ftp.iana.org/tz``.
-
- """
- tmpdir = tempfile.mkdtemp()
- zonedir = os.path.join(tmpdir, "zoneinfo")
- moduledir = os.path.dirname(__file__)
- try:
- with TarFile.open(filename) as tf:
- for name in zonegroups:
- tf.extract(name, tmpdir)
- filepaths = [os.path.join(tmpdir, n) for n in zonegroups]
- try:
- check_call(["zic", "-d", zonedir] + filepaths)
- except OSError as e:
- _print_on_nosuchfile(e)
- raise
- # write metadata file
- with open(os.path.join(zonedir, METADATA_FN), 'w') as f:
- json.dump(metadata, f, indent=4, sort_keys=True)
- target = os.path.join(moduledir, ZONEFILENAME)
- with TarFile.open(target, "w:%s" % format) as tf:
- for entry in os.listdir(zonedir):
- entrypath = os.path.join(zonedir, entry)
- tf.add(entrypath, entry)
- finally:
- shutil.rmtree(tmpdir)
-
-
-def _print_on_nosuchfile(e):
- """Print helpful troubleshooting message
-
- e is an exception raised by subprocess.check_call()
-
- """
- if e.errno == 2:
- logging.error(
- "Could not find zic. Perhaps you need to install "
- "libc-bin or some other package that provides it, "
- "or it's not in your PATH?")
diff --git a/server/venv/lib/python3.7/site-packages/easy_install.py b/server/venv/lib/python3.7/site-packages/easy_install.py
deleted file mode 100644
index d87e984..0000000
--- a/server/venv/lib/python3.7/site-packages/easy_install.py
+++ /dev/null
@@ -1,5 +0,0 @@
-"""Run the EasyInstall command"""
-
-if __name__ == '__main__':
- from setuptools.command.easy_install import main
- main()
diff --git a/server/venv/lib/python3.7/site-packages/flask/__init__.py b/server/venv/lib/python3.7/site-packages/flask/__init__.py
deleted file mode 100644
index 687475b..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/__init__.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask
- ~~~~~
-
- A microframework based on Werkzeug. It's extensively documented
- and follows best practice patterns.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-# utilities we import from Werkzeug and Jinja2 that are unused
-# in the module but are exported as public interface.
-from jinja2 import escape
-from jinja2 import Markup
-from werkzeug.exceptions import abort
-from werkzeug.utils import redirect
-
-from . import json
-from ._compat import json_available
-from .app import Flask
-from .app import Request
-from .app import Response
-from .blueprints import Blueprint
-from .config import Config
-from .ctx import after_this_request
-from .ctx import copy_current_request_context
-from .ctx import has_app_context
-from .ctx import has_request_context
-from .globals import _app_ctx_stack
-from .globals import _request_ctx_stack
-from .globals import current_app
-from .globals import g
-from .globals import request
-from .globals import session
-from .helpers import flash
-from .helpers import get_flashed_messages
-from .helpers import get_template_attribute
-from .helpers import make_response
-from .helpers import safe_join
-from .helpers import send_file
-from .helpers import send_from_directory
-from .helpers import stream_with_context
-from .helpers import url_for
-from .json import jsonify
-from .signals import appcontext_popped
-from .signals import appcontext_pushed
-from .signals import appcontext_tearing_down
-from .signals import before_render_template
-from .signals import got_request_exception
-from .signals import message_flashed
-from .signals import request_finished
-from .signals import request_started
-from .signals import request_tearing_down
-from .signals import signals_available
-from .signals import template_rendered
-from .templating import render_template
-from .templating import render_template_string
-
-__version__ = "1.1.1"
diff --git a/server/venv/lib/python3.7/site-packages/flask/__main__.py b/server/venv/lib/python3.7/site-packages/flask/__main__.py
deleted file mode 100644
index f61dbc0..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/__main__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.__main__
- ~~~~~~~~~~~~~~
-
- Alias for flask.run for the command line.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-
-if __name__ == "__main__":
- from .cli import main
-
- main(as_module=True)
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/__init__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/__init__.cpython-37.pyc
deleted file mode 100644
index fa5c1d6..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/__init__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/__main__.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/__main__.cpython-37.pyc
deleted file mode 100644
index ea3f85c..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/__main__.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/_compat.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/_compat.cpython-37.pyc
deleted file mode 100644
index 4102b39..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/_compat.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/app.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/app.cpython-37.pyc
deleted file mode 100644
index af0395c..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/app.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/blueprints.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/blueprints.cpython-37.pyc
deleted file mode 100644
index 1ba9382..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/blueprints.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/cli.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/cli.cpython-37.pyc
deleted file mode 100644
index ac996aa..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/cli.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/config.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/config.cpython-37.pyc
deleted file mode 100644
index 2ca0992..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/config.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/ctx.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/ctx.cpython-37.pyc
deleted file mode 100644
index 5f47caf..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/ctx.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/debughelpers.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/debughelpers.cpython-37.pyc
deleted file mode 100644
index bbcfd8f..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/debughelpers.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/globals.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/globals.cpython-37.pyc
deleted file mode 100644
index 2556cd1..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/globals.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/helpers.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/helpers.cpython-37.pyc
deleted file mode 100644
index 95a3791..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/helpers.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/logging.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/logging.cpython-37.pyc
deleted file mode 100644
index 783e550..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/logging.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/sessions.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/sessions.cpython-37.pyc
deleted file mode 100644
index be237aa..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/sessions.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/signals.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/signals.cpython-37.pyc
deleted file mode 100644
index 158c69d..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/signals.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/templating.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/templating.cpython-37.pyc
deleted file mode 100644
index 1c272af..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/templating.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/testing.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/testing.cpython-37.pyc
deleted file mode 100644
index 4274c3e..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/testing.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/views.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/views.cpython-37.pyc
deleted file mode 100644
index ed26f32..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/views.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/__pycache__/wrappers.cpython-37.pyc b/server/venv/lib/python3.7/site-packages/flask/__pycache__/wrappers.cpython-37.pyc
deleted file mode 100644
index fc4bbb3..0000000
Binary files a/server/venv/lib/python3.7/site-packages/flask/__pycache__/wrappers.cpython-37.pyc and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/flask/_compat.py b/server/venv/lib/python3.7/site-packages/flask/_compat.py
deleted file mode 100644
index 76c442c..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/_compat.py
+++ /dev/null
@@ -1,145 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask._compat
- ~~~~~~~~~~~~~
-
- Some py2/py3 compatibility support based on a stripped down
- version of six so we don't have to depend on a specific version
- of it.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import sys
-
-PY2 = sys.version_info[0] == 2
-_identity = lambda x: x
-
-try: # Python 2
- text_type = unicode
- string_types = (str, unicode)
- integer_types = (int, long)
-except NameError: # Python 3
- text_type = str
- string_types = (str,)
- integer_types = (int,)
-
-if not PY2:
- iterkeys = lambda d: iter(d.keys())
- itervalues = lambda d: iter(d.values())
- iteritems = lambda d: iter(d.items())
-
- from inspect import getfullargspec as getargspec
- from io import StringIO
- import collections.abc as collections_abc
-
- def reraise(tp, value, tb=None):
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
-
- implements_to_string = _identity
-
-else:
- iterkeys = lambda d: d.iterkeys()
- itervalues = lambda d: d.itervalues()
- iteritems = lambda d: d.iteritems()
-
- from inspect import getargspec
- from cStringIO import StringIO
- import collections as collections_abc
-
- exec("def reraise(tp, value, tb=None):\n raise tp, value, tb")
-
- def implements_to_string(cls):
- cls.__unicode__ = cls.__str__
- cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
- return cls
-
-
-def with_metaclass(meta, *bases):
- """Create a base class with a metaclass."""
- # This requires a bit of explanation: the basic idea is to make a
- # dummy metaclass for one level of class instantiation that replaces
- # itself with the actual metaclass.
- class metaclass(type):
- def __new__(metacls, name, this_bases, d):
- return meta(name, bases, d)
-
- return type.__new__(metaclass, "temporary_class", (), {})
-
-
-# Certain versions of pypy have a bug where clearing the exception stack
-# breaks the __exit__ function in a very peculiar way. The second level of
-# exception blocks is necessary because pypy seems to forget to check if an
-# exception happened until the next bytecode instruction?
-#
-# Relevant PyPy bugfix commit:
-# https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301
-# According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later
-# versions.
-#
-# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug.
-BROKEN_PYPY_CTXMGR_EXIT = False
-if hasattr(sys, "pypy_version_info"):
-
- class _Mgr(object):
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- if hasattr(sys, "exc_clear"):
- # Python 3 (PyPy3) doesn't have exc_clear
- sys.exc_clear()
-
- try:
- try:
- with _Mgr():
- raise AssertionError()
- except: # noqa: B001
- # We intentionally use a bare except here. See the comment above
- # regarding a pypy bug as to why.
- raise
- except TypeError:
- BROKEN_PYPY_CTXMGR_EXIT = True
- except AssertionError:
- pass
-
-
-try:
- from os import fspath
-except ImportError:
- # Backwards compatibility as proposed in PEP 0519:
- # https://www.python.org/dev/peps/pep-0519/#backwards-compatibility
- def fspath(path):
- return path.__fspath__() if hasattr(path, "__fspath__") else path
-
-
-class _DeprecatedBool(object):
- def __init__(self, name, version, value):
- self.message = "'{}' is deprecated and will be removed in version {}.".format(
- name, version
- )
- self.value = value
-
- def _warn(self):
- import warnings
-
- warnings.warn(self.message, DeprecationWarning, stacklevel=2)
-
- def __eq__(self, other):
- self._warn()
- return other == self.value
-
- def __ne__(self, other):
- self._warn()
- return other != self.value
-
- def __bool__(self):
- self._warn()
- return self.value
-
- __nonzero__ = __bool__
-
-
-json_available = _DeprecatedBool("flask.json_available", "2.0.0", True)
diff --git a/server/venv/lib/python3.7/site-packages/flask/app.py b/server/venv/lib/python3.7/site-packages/flask/app.py
deleted file mode 100644
index e596fe5..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/app.py
+++ /dev/null
@@ -1,2466 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.app
- ~~~~~~~~~
-
- This module implements the central WSGI application object.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import os
-import sys
-import warnings
-from datetime import timedelta
-from functools import update_wrapper
-from itertools import chain
-from threading import Lock
-
-from werkzeug.datastructures import Headers
-from werkzeug.datastructures import ImmutableDict
-from werkzeug.exceptions import BadRequest
-from werkzeug.exceptions import BadRequestKeyError
-from werkzeug.exceptions import default_exceptions
-from werkzeug.exceptions import HTTPException
-from werkzeug.exceptions import InternalServerError
-from werkzeug.exceptions import MethodNotAllowed
-from werkzeug.routing import BuildError
-from werkzeug.routing import Map
-from werkzeug.routing import RequestRedirect
-from werkzeug.routing import RoutingException
-from werkzeug.routing import Rule
-from werkzeug.wrappers import BaseResponse
-
-from . import cli
-from . import json
-from ._compat import integer_types
-from ._compat import reraise
-from ._compat import string_types
-from ._compat import text_type
-from .config import Config
-from .config import ConfigAttribute
-from .ctx import _AppCtxGlobals
-from .ctx import AppContext
-from .ctx import RequestContext
-from .globals import _request_ctx_stack
-from .globals import g
-from .globals import request
-from .globals import session
-from .helpers import _endpoint_from_view_func
-from .helpers import _PackageBoundObject
-from .helpers import find_package
-from .helpers import get_debug_flag
-from .helpers import get_env
-from .helpers import get_flashed_messages
-from .helpers import get_load_dotenv
-from .helpers import locked_cached_property
-from .helpers import url_for
-from .json import jsonify
-from .logging import create_logger
-from .sessions import SecureCookieSessionInterface
-from .signals import appcontext_tearing_down
-from .signals import got_request_exception
-from .signals import request_finished
-from .signals import request_started
-from .signals import request_tearing_down
-from .templating import _default_template_ctx_processor
-from .templating import DispatchingJinjaLoader
-from .templating import Environment
-from .wrappers import Request
-from .wrappers import Response
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-def _make_timedelta(value):
- if not isinstance(value, timedelta):
- return timedelta(seconds=value)
- return value
-
-
-def setupmethod(f):
- """Wraps a method so that it performs a check in debug mode if the
- first request was already handled.
- """
-
- def wrapper_func(self, *args, **kwargs):
- if self.debug and self._got_first_request:
- raise AssertionError(
- "A setup function was called after the "
- "first request was handled. This usually indicates a bug "
- "in the application where a module was not imported "
- "and decorators or other functionality was called too late.\n"
- "To fix this make sure to import all your view modules, "
- "database models and everything related at a central place "
- "before the application starts serving requests."
- )
- return f(self, *args, **kwargs)
-
- return update_wrapper(wrapper_func, f)
-
-
-class Flask(_PackageBoundObject):
- """The flask object implements a WSGI application and acts as the central
- object. It is passed the name of the module or package of the
- application. Once it is created it will act as a central registry for
- the view functions, the URL rules, template configuration and much more.
-
- The name of the package is used to resolve resources from inside the
- package or the folder the module is contained in depending on if the
- package parameter resolves to an actual python package (a folder with
- an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
-
- For more information about resource loading, see :func:`open_resource`.
-
- Usually you create a :class:`Flask` instance in your main module or
- in the :file:`__init__.py` file of your package like this::
-
- from flask import Flask
- app = Flask(__name__)
-
- .. admonition:: About the First Parameter
-
- The idea of the first parameter is to give Flask an idea of what
- belongs to your application. This name is used to find resources
- on the filesystem, can be used by extensions to improve debugging
- information and a lot more.
-
- So it's important what you provide there. If you are using a single
- module, `__name__` is always the correct value. If you however are
- using a package, it's usually recommended to hardcode the name of
- your package there.
-
- For example if your application is defined in :file:`yourapplication/app.py`
- you should create it with one of the two versions below::
-
- app = Flask('yourapplication')
- app = Flask(__name__.split('.')[0])
-
- Why is that? The application will work even with `__name__`, thanks
- to how resources are looked up. However it will make debugging more
- painful. Certain extensions can make assumptions based on the
- import name of your application. For example the Flask-SQLAlchemy
- extension will look for the code in your application that triggered
- an SQL query in debug mode. If the import name is not properly set
- up, that debugging information is lost. (For example it would only
- pick up SQL queries in `yourapplication.app` and not
- `yourapplication.views.frontend`)
-
- .. versionadded:: 0.7
- The `static_url_path`, `static_folder`, and `template_folder`
- parameters were added.
-
- .. versionadded:: 0.8
- The `instance_path` and `instance_relative_config` parameters were
- added.
-
- .. versionadded:: 0.11
- The `root_path` parameter was added.
-
- .. versionadded:: 1.0
- The ``host_matching`` and ``static_host`` parameters were added.
-
- .. versionadded:: 1.0
- The ``subdomain_matching`` parameter was added. Subdomain
- matching needs to be enabled manually now. Setting
- :data:`SERVER_NAME` does not implicitly enable it.
-
- :param import_name: the name of the application package
- :param static_url_path: can be used to specify a different path for the
- static files on the web. Defaults to the name
- of the `static_folder` folder.
- :param static_folder: the folder with static files that should be served
- at `static_url_path`. Defaults to the ``'static'``
- folder in the root path of the application.
- :param static_host: the host to use when adding the static route.
- Defaults to None. Required when using ``host_matching=True``
- with a ``static_folder`` configured.
- :param host_matching: set ``url_map.host_matching`` attribute.
- Defaults to False.
- :param subdomain_matching: consider the subdomain relative to
- :data:`SERVER_NAME` when matching routes. Defaults to False.
- :param template_folder: the folder that contains the templates that should
- be used by the application. Defaults to
- ``'templates'`` folder in the root path of the
- application.
- :param instance_path: An alternative instance path for the application.
- By default the folder ``'instance'`` next to the
- package or module is assumed to be the instance
- path.
- :param instance_relative_config: if set to ``True`` relative filenames
- for loading the config are assumed to
- be relative to the instance path instead
- of the application root.
- :param root_path: Flask by default will automatically calculate the path
- to the root of the application. In certain situations
- this cannot be achieved (for instance if the package
- is a Python 3 namespace package) and needs to be
- manually defined.
- """
-
- #: The class that is used for request objects. See :class:`~flask.Request`
- #: for more information.
- request_class = Request
-
- #: The class that is used for response objects. See
- #: :class:`~flask.Response` for more information.
- response_class = Response
-
- #: The class that is used for the Jinja environment.
- #:
- #: .. versionadded:: 0.11
- jinja_environment = Environment
-
- #: The class that is used for the :data:`~flask.g` instance.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Store arbitrary attributes on flask.g.
- #: 2. Add a property for lazy per-request database connectors.
- #: 3. Return None instead of AttributeError on unexpected attributes.
- #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
- #:
- #: In Flask 0.9 this property was called `request_globals_class` but it
- #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
- #: flask.g object is now application context scoped.
- #:
- #: .. versionadded:: 0.10
- app_ctx_globals_class = _AppCtxGlobals
-
- #: The class that is used for the ``config`` attribute of this app.
- #: Defaults to :class:`~flask.Config`.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Default values for certain config options.
- #: 2. Access to config values through attributes in addition to keys.
- #:
- #: .. versionadded:: 0.11
- config_class = Config
-
- #: The testing flag. Set this to ``True`` to enable the test mode of
- #: Flask extensions (and in the future probably also Flask itself).
- #: For example this might activate test helpers that have an
- #: additional runtime cost which should not be enabled by default.
- #:
- #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the
- #: default it's implicitly enabled.
- #:
- #: This attribute can also be configured from the config with the
- #: ``TESTING`` configuration key. Defaults to ``False``.
- testing = ConfigAttribute("TESTING")
-
- #: If a secret key is set, cryptographic components can use this to
- #: sign cookies and other things. Set this to a complex random value
- #: when you want to use the secure cookie for instance.
- #:
- #: This attribute can also be configured from the config with the
- #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
- secret_key = ConfigAttribute("SECRET_KEY")
-
- #: The secure cookie uses this for the name of the session cookie.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
- session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
-
- #: A :class:`~datetime.timedelta` which is used to set the expiration
- #: date of a permanent session. The default is 31 days which makes a
- #: permanent session survive for roughly one month.
- #:
- #: This attribute can also be configured from the config with the
- #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
- #: ``timedelta(days=31)``
- permanent_session_lifetime = ConfigAttribute(
- "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
- )
-
- #: A :class:`~datetime.timedelta` which is used as default cache_timeout
- #: for the :func:`send_file` functions. The default is 12 hours.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration
- #: variable can also be set with an integer value used as seconds.
- #: Defaults to ``timedelta(hours=12)``
- send_file_max_age_default = ConfigAttribute(
- "SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
- )
-
- #: Enable this if you want to use the X-Sendfile feature. Keep in
- #: mind that the server has to support this. This only affects files
- #: sent with the :func:`send_file` method.
- #:
- #: .. versionadded:: 0.2
- #:
- #: This attribute can also be configured from the config with the
- #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
- use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
-
- #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
- #:
- #: .. versionadded:: 0.10
- json_encoder = json.JSONEncoder
-
- #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`.
- #:
- #: .. versionadded:: 0.10
- json_decoder = json.JSONDecoder
-
- #: Options that are passed to the Jinja environment in
- #: :meth:`create_jinja_environment`. Changing these options after
- #: the environment is created (accessing :attr:`jinja_env`) will
- #: have no effect.
- #:
- #: .. versionchanged:: 1.1.0
- #: This is a ``dict`` instead of an ``ImmutableDict`` to allow
- #: easier configuration.
- #:
- jinja_options = {"extensions": ["jinja2.ext.autoescape", "jinja2.ext.with_"]}
-
- #: Default configuration parameters.
- default_config = ImmutableDict(
- {
- "ENV": None,
- "DEBUG": None,
- "TESTING": False,
- "PROPAGATE_EXCEPTIONS": None,
- "PRESERVE_CONTEXT_ON_EXCEPTION": None,
- "SECRET_KEY": None,
- "PERMANENT_SESSION_LIFETIME": timedelta(days=31),
- "USE_X_SENDFILE": False,
- "SERVER_NAME": None,
- "APPLICATION_ROOT": "/",
- "SESSION_COOKIE_NAME": "session",
- "SESSION_COOKIE_DOMAIN": None,
- "SESSION_COOKIE_PATH": None,
- "SESSION_COOKIE_HTTPONLY": True,
- "SESSION_COOKIE_SECURE": False,
- "SESSION_COOKIE_SAMESITE": None,
- "SESSION_REFRESH_EACH_REQUEST": True,
- "MAX_CONTENT_LENGTH": None,
- "SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=12),
- "TRAP_BAD_REQUEST_ERRORS": None,
- "TRAP_HTTP_EXCEPTIONS": False,
- "EXPLAIN_TEMPLATE_LOADING": False,
- "PREFERRED_URL_SCHEME": "http",
- "JSON_AS_ASCII": True,
- "JSON_SORT_KEYS": True,
- "JSONIFY_PRETTYPRINT_REGULAR": False,
- "JSONIFY_MIMETYPE": "application/json",
- "TEMPLATES_AUTO_RELOAD": None,
- "MAX_COOKIE_SIZE": 4093,
- }
- )
-
- #: The rule object to use for URL rules created. This is used by
- #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
- #:
- #: .. versionadded:: 0.7
- url_rule_class = Rule
-
- #: The map object to use for storing the URL rules and routing
- #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`.
- #:
- #: .. versionadded:: 1.1.0
- url_map_class = Map
-
- #: the test client that is used with when `test_client` is used.
- #:
- #: .. versionadded:: 0.7
- test_client_class = None
-
- #: The :class:`~click.testing.CliRunner` subclass, by default
- #: :class:`~flask.testing.FlaskCliRunner` that is used by
- #: :meth:`test_cli_runner`. Its ``__init__`` method should take a
- #: Flask app object as the first argument.
- #:
- #: .. versionadded:: 1.0
- test_cli_runner_class = None
-
- #: the session interface to use. By default an instance of
- #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
- #:
- #: .. versionadded:: 0.8
- session_interface = SecureCookieSessionInterface()
-
- # TODO remove the next three attrs when Sphinx :inherited-members: works
- # https://github.com/sphinx-doc/sphinx/issues/741
-
- #: The name of the package or module that this app belongs to. Do not
- #: change this once it is set by the constructor.
- import_name = None
-
- #: Location of the template files to be added to the template lookup.
- #: ``None`` if templates should not be added.
- template_folder = None
-
- #: Absolute path to the package on the filesystem. Used to look up
- #: resources contained in the package.
- root_path = None
-
- def __init__(
- self,
- import_name,
- static_url_path=None,
- static_folder="static",
- static_host=None,
- host_matching=False,
- subdomain_matching=False,
- template_folder="templates",
- instance_path=None,
- instance_relative_config=False,
- root_path=None,
- ):
- _PackageBoundObject.__init__(
- self, import_name, template_folder=template_folder, root_path=root_path
- )
-
- self.static_url_path = static_url_path
- self.static_folder = static_folder
-
- if instance_path is None:
- instance_path = self.auto_find_instance_path()
- elif not os.path.isabs(instance_path):
- raise ValueError(
- "If an instance path is provided it must be absolute."
- " A relative path was given instead."
- )
-
- #: Holds the path to the instance folder.
- #:
- #: .. versionadded:: 0.8
- self.instance_path = instance_path
-
- #: The configuration dictionary as :class:`Config`. This behaves
- #: exactly like a regular dictionary but supports additional methods
- #: to load a config from files.
- self.config = self.make_config(instance_relative_config)
-
- #: A dictionary of all view functions registered. The keys will
- #: be function names which are also used to generate URLs and
- #: the values are the function objects themselves.
- #: To register a view function, use the :meth:`route` decorator.
- self.view_functions = {}
-
- #: A dictionary of all registered error handlers. The key is ``None``
- #: for error handlers active on the application, otherwise the key is
- #: the name of the blueprint. Each key points to another dictionary
- #: where the key is the status code of the http exception. The
- #: special key ``None`` points to a list of tuples where the first item
- #: is the class for the instance check and the second the error handler
- #: function.
- #:
- #: To register an error handler, use the :meth:`errorhandler`
- #: decorator.
- self.error_handler_spec = {}
-
- #: A list of functions that are called when :meth:`url_for` raises a
- #: :exc:`~werkzeug.routing.BuildError`. Each function registered here
- #: is called with `error`, `endpoint` and `values`. If a function
- #: returns ``None`` or raises a :exc:`BuildError` the next function is
- #: tried.
- #:
- #: .. versionadded:: 0.9
- self.url_build_error_handlers = []
-
- #: A dictionary with lists of functions that will be called at the
- #: beginning of each request. The key of the dictionary is the name of
- #: the blueprint this function is active for, or ``None`` for all
- #: requests. To register a function, use the :meth:`before_request`
- #: decorator.
- self.before_request_funcs = {}
-
- #: A list of functions that will be called at the beginning of the
- #: first request to this instance. To register a function, use the
- #: :meth:`before_first_request` decorator.
- #:
- #: .. versionadded:: 0.8
- self.before_first_request_funcs = []
-
- #: A dictionary with lists of functions that should be called after
- #: each request. The key of the dictionary is the name of the blueprint
- #: this function is active for, ``None`` for all requests. This can for
- #: example be used to close database connections. To register a function
- #: here, use the :meth:`after_request` decorator.
- self.after_request_funcs = {}
-
- #: A dictionary with lists of functions that are called after
- #: each request, even if an exception has occurred. The key of the
- #: dictionary is the name of the blueprint this function is active for,
- #: ``None`` for all requests. These functions are not allowed to modify
- #: the request, and their return values are ignored. If an exception
- #: occurred while processing the request, it gets passed to each
- #: teardown_request function. To register a function here, use the
- #: :meth:`teardown_request` decorator.
- #:
- #: .. versionadded:: 0.7
- self.teardown_request_funcs = {}
-
- #: A list of functions that are called when the application context
- #: is destroyed. Since the application context is also torn down
- #: if the request ends this is the place to store code that disconnects
- #: from databases.
- #:
- #: .. versionadded:: 0.9
- self.teardown_appcontext_funcs = []
-
- #: A dictionary with lists of functions that are called before the
- #: :attr:`before_request_funcs` functions. The key of the dictionary is
- #: the name of the blueprint this function is active for, or ``None``
- #: for all requests. To register a function, use
- #: :meth:`url_value_preprocessor`.
- #:
- #: .. versionadded:: 0.7
- self.url_value_preprocessors = {}
-
- #: A dictionary with lists of functions that can be used as URL value
- #: preprocessors. The key ``None`` here is used for application wide
- #: callbacks, otherwise the key is the name of the blueprint.
- #: Each of these functions has the chance to modify the dictionary
- #: of URL values before they are used as the keyword arguments of the
- #: view function. For each function registered this one should also
- #: provide a :meth:`url_defaults` function that adds the parameters
- #: automatically again that were removed that way.
- #:
- #: .. versionadded:: 0.7
- self.url_default_functions = {}
-
- #: A dictionary with list of functions that are called without argument
- #: to populate the template context. The key of the dictionary is the
- #: name of the blueprint this function is active for, ``None`` for all
- #: requests. Each returns a dictionary that the template context is
- #: updated with. To register a function here, use the
- #: :meth:`context_processor` decorator.
- self.template_context_processors = {None: [_default_template_ctx_processor]}
-
- #: A list of shell context processor functions that should be run
- #: when a shell context is created.
- #:
- #: .. versionadded:: 0.11
- self.shell_context_processors = []
-
- #: all the attached blueprints in a dictionary by name. Blueprints
- #: can be attached multiple times so this dictionary does not tell
- #: you how often they got attached.
- #:
- #: .. versionadded:: 0.7
- self.blueprints = {}
- self._blueprint_order = []
-
- #: a place where extensions can store application specific state. For
- #: example this is where an extension could store database engines and
- #: similar things. For backwards compatibility extensions should register
- #: themselves like this::
- #:
- #: if not hasattr(app, 'extensions'):
- #: app.extensions = {}
- #: app.extensions['extensionname'] = SomeObject()
- #:
- #: The key must match the name of the extension module. For example in
- #: case of a "Flask-Foo" extension in `flask_foo`, the key would be
- #: ``'foo'``.
- #:
- #: .. versionadded:: 0.7
- self.extensions = {}
-
- #: The :class:`~werkzeug.routing.Map` for this instance. You can use
- #: this to change the routing converters after the class was created
- #: but before any routes are connected. Example::
- #:
- #: from werkzeug.routing import BaseConverter
- #:
- #: class ListConverter(BaseConverter):
- #: def to_python(self, value):
- #: return value.split(',')
- #: def to_url(self, values):
- #: return ','.join(super(ListConverter, self).to_url(value)
- #: for value in values)
- #:
- #: app = Flask(__name__)
- #: app.url_map.converters['list'] = ListConverter
- self.url_map = self.url_map_class()
-
- self.url_map.host_matching = host_matching
- self.subdomain_matching = subdomain_matching
-
- # tracks internally if the application already handled at least one
- # request.
- self._got_first_request = False
- self._before_request_lock = Lock()
-
- # Add a static route using the provided static_url_path, static_host,
- # and static_folder if there is a configured static_folder.
- # Note we do this without checking if static_folder exists.
- # For one, it might be created while the server is running (e.g. during
- # development). Also, Google App Engine stores static files somewhere
- if self.has_static_folder:
- assert (
- bool(static_host) == host_matching
- ), "Invalid static_host/host_matching combination"
- self.add_url_rule(
- self.static_url_path + "/",
- endpoint="static",
- host=static_host,
- view_func=self.send_static_file,
- )
-
- # Set the name of the Click group in case someone wants to add
- # the app's commands to another CLI tool.
- self.cli.name = self.name
-
- @locked_cached_property
- def name(self):
- """The name of the application. This is usually the import name
- with the difference that it's guessed from the run file if the
- import name is main. This name is used as a display name when
- Flask needs the name of the application. It can be set and overridden
- to change the value.
-
- .. versionadded:: 0.8
- """
- if self.import_name == "__main__":
- fn = getattr(sys.modules["__main__"], "__file__", None)
- if fn is None:
- return "__main__"
- return os.path.splitext(os.path.basename(fn))[0]
- return self.import_name
-
- @property
- def propagate_exceptions(self):
- """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
- value in case it's set, otherwise a sensible default is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config["PROPAGATE_EXCEPTIONS"]
- if rv is not None:
- return rv
- return self.testing or self.debug
-
- @property
- def preserve_context_on_exception(self):
- """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION``
- configuration value in case it's set, otherwise a sensible default
- is returned.
-
- .. versionadded:: 0.7
- """
- rv = self.config["PRESERVE_CONTEXT_ON_EXCEPTION"]
- if rv is not None:
- return rv
- return self.debug
-
- @locked_cached_property
- def logger(self):
- """A standard Python :class:`~logging.Logger` for the app, with
- the same name as :attr:`name`.
-
- In debug mode, the logger's :attr:`~logging.Logger.level` will
- be set to :data:`~logging.DEBUG`.
-
- If there are no handlers configured, a default handler will be
- added. See :doc:`/logging` for more information.
-
- .. versionchanged:: 1.1.0
- The logger takes the same name as :attr:`name` rather than
- hard-coding ``"flask.app"``.
-
- .. versionchanged:: 1.0.0
- Behavior was simplified. The logger is always named
- ``"flask.app"``. The level is only set during configuration,
- it doesn't check ``app.debug`` each time. Only one format is
- used, not different ones depending on ``app.debug``. No
- handlers are removed, and a handler is only added if no
- handlers are already configured.
-
- .. versionadded:: 0.3
- """
- return create_logger(self)
-
- @locked_cached_property
- def jinja_env(self):
- """The Jinja environment used to load templates.
-
- The environment is created the first time this property is
- accessed. Changing :attr:`jinja_options` after that will have no
- effect.
- """
- return self.create_jinja_environment()
-
- @property
- def got_first_request(self):
- """This attribute is set to ``True`` if the application started
- handling the first request.
-
- .. versionadded:: 0.8
- """
- return self._got_first_request
-
- def make_config(self, instance_relative=False):
- """Used to create the config attribute by the Flask constructor.
- The `instance_relative` parameter is passed in from the constructor
- of Flask (there named `instance_relative_config`) and indicates if
- the config should be relative to the instance path or the root path
- of the application.
-
- .. versionadded:: 0.8
- """
- root_path = self.root_path
- if instance_relative:
- root_path = self.instance_path
- defaults = dict(self.default_config)
- defaults["ENV"] = get_env()
- defaults["DEBUG"] = get_debug_flag()
- return self.config_class(root_path, defaults)
-
- def auto_find_instance_path(self):
- """Tries to locate the instance path if it was not provided to the
- constructor of the application class. It will basically calculate
- the path to a folder named ``instance`` next to your main file or
- the package.
-
- .. versionadded:: 0.8
- """
- prefix, package_path = find_package(self.import_name)
- if prefix is None:
- return os.path.join(package_path, "instance")
- return os.path.join(prefix, "var", self.name + "-instance")
-
- def open_instance_resource(self, resource, mode="rb"):
- """Opens a resource from the application's instance folder
- (:attr:`instance_path`). Otherwise works like
- :meth:`open_resource`. Instance resources can also be opened for
- writing.
-
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: resource file opening mode, default is 'rb'.
- """
- return open(os.path.join(self.instance_path, resource), mode)
-
- @property
- def templates_auto_reload(self):
- """Reload templates when they are changed. Used by
- :meth:`create_jinja_environment`.
-
- This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If
- not set, it will be enabled in debug mode.
-
- .. versionadded:: 1.0
- This property was added but the underlying config and behavior
- already existed.
- """
- rv = self.config["TEMPLATES_AUTO_RELOAD"]
- return rv if rv is not None else self.debug
-
- @templates_auto_reload.setter
- def templates_auto_reload(self, value):
- self.config["TEMPLATES_AUTO_RELOAD"] = value
-
- def create_jinja_environment(self):
- """Create the Jinja environment based on :attr:`jinja_options`
- and the various Jinja-related methods of the app. Changing
- :attr:`jinja_options` after this will have no effect. Also adds
- Flask-related globals and filters to the environment.
-
- .. versionchanged:: 0.11
- ``Environment.auto_reload`` set in accordance with
- ``TEMPLATES_AUTO_RELOAD`` configuration option.
-
- .. versionadded:: 0.5
- """
- options = dict(self.jinja_options)
-
- if "autoescape" not in options:
- options["autoescape"] = self.select_jinja_autoescape
-
- if "auto_reload" not in options:
- options["auto_reload"] = self.templates_auto_reload
-
- rv = self.jinja_environment(self, **options)
- rv.globals.update(
- url_for=url_for,
- get_flashed_messages=get_flashed_messages,
- config=self.config,
- # request, session and g are normally added with the
- # context processor for efficiency reasons but for imported
- # templates we also want the proxies in there.
- request=request,
- session=session,
- g=g,
- )
- rv.filters["tojson"] = json.tojson_filter
- return rv
-
- def create_global_jinja_loader(self):
- """Creates the loader for the Jinja2 environment. Can be used to
- override just the loader and keeping the rest unchanged. It's
- discouraged to override this function. Instead one should override
- the :meth:`jinja_loader` function instead.
-
- The global loader dispatches between the loaders of the application
- and the individual blueprints.
-
- .. versionadded:: 0.7
- """
- return DispatchingJinjaLoader(self)
-
- def select_jinja_autoescape(self, filename):
- """Returns ``True`` if autoescaping should be active for the given
- template name. If no template name is given, returns `True`.
-
- .. versionadded:: 0.5
- """
- if filename is None:
- return True
- return filename.endswith((".html", ".htm", ".xml", ".xhtml"))
-
- def update_template_context(self, context):
- """Update the template context with some commonly used variables.
- This injects request, session, config and g into the template
- context as well as everything template context processors want
- to inject. Note that the as of Flask 0.6, the original values
- in the context will not be overridden if a context processor
- decides to return a value with the same key.
-
- :param context: the context as a dictionary that is updated in place
- to add extra variables.
- """
- funcs = self.template_context_processors[None]
- reqctx = _request_ctx_stack.top
- if reqctx is not None:
- bp = reqctx.request.blueprint
- if bp is not None and bp in self.template_context_processors:
- funcs = chain(funcs, self.template_context_processors[bp])
- orig_ctx = context.copy()
- for func in funcs:
- context.update(func())
- # make sure the original values win. This makes it possible to
- # easier add new variables in context processors without breaking
- # existing views.
- context.update(orig_ctx)
-
- def make_shell_context(self):
- """Returns the shell context for an interactive shell for this
- application. This runs all the registered shell context
- processors.
-
- .. versionadded:: 0.11
- """
- rv = {"app": self, "g": g}
- for processor in self.shell_context_processors:
- rv.update(processor())
- return rv
-
- #: What environment the app is running in. Flask and extensions may
- #: enable behaviors based on the environment, such as enabling debug
- #: mode. This maps to the :data:`ENV` config key. This is set by the
- #: :envvar:`FLASK_ENV` environment variable and may not behave as
- #: expected if set in code.
- #:
- #: **Do not enable development when deploying in production.**
- #:
- #: Default: ``'production'``
- env = ConfigAttribute("ENV")
-
- @property
- def debug(self):
- """Whether debug mode is enabled. When using ``flask run`` to start
- the development server, an interactive debugger will be shown for
- unhandled exceptions, and the server will be reloaded when code
- changes. This maps to the :data:`DEBUG` config key. This is
- enabled when :attr:`env` is ``'development'`` and is overridden
- by the ``FLASK_DEBUG`` environment variable. It may not behave as
- expected if set in code.
-
- **Do not enable debug mode when deploying in production.**
-
- Default: ``True`` if :attr:`env` is ``'development'``, or
- ``False`` otherwise.
- """
- return self.config["DEBUG"]
-
- @debug.setter
- def debug(self, value):
- self.config["DEBUG"] = value
- self.jinja_env.auto_reload = self.templates_auto_reload
-
- def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
- """Runs the application on a local development server.
-
- Do not use ``run()`` in a production setting. It is not intended to
- meet security and performance requirements for a production server.
- Instead, see :ref:`deployment` for WSGI server recommendations.
-
- If the :attr:`debug` flag is set the server will automatically reload
- for code changes and show a debugger in case an exception happened.
-
- If you want to run the application in debug mode, but disable the
- code execution on the interactive debugger, you can pass
- ``use_evalex=False`` as parameter. This will keep the debugger's
- traceback screen active, but disable code execution.
-
- It is not recommended to use this function for development with
- automatic reloading as this is badly supported. Instead you should
- be using the :command:`flask` command line script's ``run`` support.
-
- .. admonition:: Keep in Mind
-
- Flask will suppress any server error with a generic error page
- unless it is in debug mode. As such to enable just the
- interactive debugger without the code reloading, you have to
- invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
- Setting ``use_debugger`` to ``True`` without being in debug mode
- won't catch any exceptions because there won't be any to
- catch.
-
- :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
- have the server available externally as well. Defaults to
- ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable
- if present.
- :param port: the port of the webserver. Defaults to ``5000`` or the
- port defined in the ``SERVER_NAME`` config variable if present.
- :param debug: if given, enable or disable debug mode. See
- :attr:`debug`.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param options: the options to be forwarded to the underlying Werkzeug
- server. See :func:`werkzeug.serving.run_simple` for more
- information.
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment
- variables from :file:`.env` and :file:`.flaskenv` files.
-
- If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG`
- environment variables will override :attr:`env` and
- :attr:`debug`.
-
- Threaded mode is enabled by default.
-
- .. versionchanged:: 0.10
- The default port is now picked from the ``SERVER_NAME``
- variable.
- """
- # Change this into a no-op if the server is invoked from the
- # command line. Have a look at cli.py for more information.
- if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
- from .debughelpers import explain_ignored_app_run
-
- explain_ignored_app_run()
- return
-
- if get_load_dotenv(load_dotenv):
- cli.load_dotenv()
-
- # if set, let env vars override previous values
- if "FLASK_ENV" in os.environ:
- self.env = get_env()
- self.debug = get_debug_flag()
- elif "FLASK_DEBUG" in os.environ:
- self.debug = get_debug_flag()
-
- # debug passed to method overrides all other sources
- if debug is not None:
- self.debug = bool(debug)
-
- _host = "127.0.0.1"
- _port = 5000
- server_name = self.config.get("SERVER_NAME")
- sn_host, sn_port = None, None
-
- if server_name:
- sn_host, _, sn_port = server_name.partition(":")
-
- host = host or sn_host or _host
- # pick the first value that's not None (0 is allowed)
- port = int(next((p for p in (port, sn_port) if p is not None), _port))
-
- options.setdefault("use_reloader", self.debug)
- options.setdefault("use_debugger", self.debug)
- options.setdefault("threaded", True)
-
- cli.show_server_banner(self.env, self.debug, self.name, False)
-
- from werkzeug.serving import run_simple
-
- try:
- run_simple(host, port, self, **options)
- finally:
- # reset the first request information if the development server
- # reset normally. This makes it possible to restart the server
- # without reloader and that stuff from an interactive shell.
- self._got_first_request = False
-
- def test_client(self, use_cookies=True, **kwargs):
- """Creates a test client for this application. For information
- about unit testing head over to :ref:`testing`.
-
- Note that if you are testing for assertions or exceptions in your
- application code, you must set ``app.testing = True`` in order for the
- exceptions to propagate to the test client. Otherwise, the exception
- will be handled by the application (not visible to the test client) and
- the only indication of an AssertionError or other exception will be a
- 500 status code response to the test client. See the :attr:`testing`
- attribute. For example::
-
- app.testing = True
- client = app.test_client()
-
- The test client can be used in a ``with`` block to defer the closing down
- of the context until the end of the ``with`` block. This is useful if
- you want to access the context locals for testing::
-
- with app.test_client() as c:
- rv = c.get('/?vodka=42')
- assert request.args['vodka'] == '42'
-
- Additionally, you may pass optional keyword arguments that will then
- be passed to the application's :attr:`test_client_class` constructor.
- For example::
-
- from flask.testing import FlaskClient
-
- class CustomClient(FlaskClient):
- def __init__(self, *args, **kwargs):
- self._authentication = kwargs.pop("authentication")
- super(CustomClient,self).__init__( *args, **kwargs)
-
- app.test_client_class = CustomClient
- client = app.test_client(authentication='Basic ....')
-
- See :class:`~flask.testing.FlaskClient` for more information.
-
- .. versionchanged:: 0.4
- added support for ``with`` block usage for the client.
-
- .. versionadded:: 0.7
- The `use_cookies` parameter was added as well as the ability
- to override the client to be used by setting the
- :attr:`test_client_class` attribute.
-
- .. versionchanged:: 0.11
- Added `**kwargs` to support passing additional keyword arguments to
- the constructor of :attr:`test_client_class`.
- """
- cls = self.test_client_class
- if cls is None:
- from .testing import FlaskClient as cls
- return cls(self, self.response_class, use_cookies=use_cookies, **kwargs)
-
- def test_cli_runner(self, **kwargs):
- """Create a CLI runner for testing CLI commands.
- See :ref:`testing-cli`.
-
- Returns an instance of :attr:`test_cli_runner_class`, by default
- :class:`~flask.testing.FlaskCliRunner`. The Flask app object is
- passed as the first argument.
-
- .. versionadded:: 1.0
- """
- cls = self.test_cli_runner_class
-
- if cls is None:
- from .testing import FlaskCliRunner as cls
-
- return cls(self, **kwargs)
-
- def open_session(self, request):
- """Creates or opens a new session. Default implementation stores all
- session data in a signed cookie. This requires that the
- :attr:`secret_key` is set. Instead of overriding this method
- we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.open_session``
- instead.
-
- :param request: an instance of :attr:`request_class`.
- """
-
- warnings.warn(
- DeprecationWarning(
- '"open_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.open_session" instead.'
- )
- )
- return self.session_interface.open_session(self, request)
-
- def save_session(self, session, response):
- """Saves the session if it needs updates. For the default
- implementation, check :meth:`open_session`. Instead of overriding this
- method we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.save_session``
- instead.
-
- :param session: the session to be saved (a
- :class:`~werkzeug.contrib.securecookie.SecureCookie`
- object)
- :param response: an instance of :attr:`response_class`
- """
-
- warnings.warn(
- DeprecationWarning(
- '"save_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.save_session" instead.'
- )
- )
- return self.session_interface.save_session(self, session, response)
-
- def make_null_session(self):
- """Creates a new instance of a missing session. Instead of overriding
- this method we recommend replacing the :class:`session_interface`.
-
- .. deprecated: 1.0
- Will be removed in 1.1. Use ``session_interface.make_null_session``
- instead.
-
- .. versionadded:: 0.7
- """
-
- warnings.warn(
- DeprecationWarning(
- '"make_null_session" is deprecated and will be removed in 1.1. Use'
- ' "session_interface.make_null_session" instead.'
- )
- )
- return self.session_interface.make_null_session(self)
-
- @setupmethod
- def register_blueprint(self, blueprint, **options):
- """Register a :class:`~flask.Blueprint` on the application. Keyword
- arguments passed to this method will override the defaults set on the
- blueprint.
-
- Calls the blueprint's :meth:`~flask.Blueprint.register` method after
- recording the blueprint in the application's :attr:`blueprints`.
-
- :param blueprint: The blueprint to register.
- :param url_prefix: Blueprint routes will be prefixed with this.
- :param subdomain: Blueprint routes will match on this subdomain.
- :param url_defaults: Blueprint routes will use these default values for
- view arguments.
- :param options: Additional keyword arguments are passed to
- :class:`~flask.blueprints.BlueprintSetupState`. They can be
- accessed in :meth:`~flask.Blueprint.record` callbacks.
-
- .. versionadded:: 0.7
- """
- first_registration = False
-
- if blueprint.name in self.blueprints:
- assert self.blueprints[blueprint.name] is blueprint, (
- "A name collision occurred between blueprints %r and %r. Both"
- ' share the same name "%s". Blueprints that are created on the'
- " fly need unique names."
- % (blueprint, self.blueprints[blueprint.name], blueprint.name)
- )
- else:
- self.blueprints[blueprint.name] = blueprint
- self._blueprint_order.append(blueprint)
- first_registration = True
-
- blueprint.register(self, options, first_registration)
-
- def iter_blueprints(self):
- """Iterates over all blueprints by the order they were registered.
-
- .. versionadded:: 0.11
- """
- return iter(self._blueprint_order)
-
- @setupmethod
- def add_url_rule(
- self,
- rule,
- endpoint=None,
- view_func=None,
- provide_automatic_options=None,
- **options
- ):
- """Connects a URL rule. Works exactly like the :meth:`route`
- decorator. If a view_func is provided it will be registered with the
- endpoint.
-
- Basically this example::
-
- @app.route('/')
- def index():
- pass
-
- Is equivalent to the following::
-
- def index():
- pass
- app.add_url_rule('/', 'index', index)
-
- If the view_func is not provided you will need to connect the endpoint
- to a view function like so::
-
- app.view_functions['index'] = index
-
- Internally :meth:`route` invokes :meth:`add_url_rule` so if you want
- to customize the behavior via subclassing you only need to change
- this method.
-
- For more information refer to :ref:`url-route-registrations`.
-
- .. versionchanged:: 0.2
- `view_func` parameter added.
-
- .. versionchanged:: 0.6
- ``OPTIONS`` is added automatically as method.
-
- :param rule: the URL rule as string
- :param endpoint: the endpoint for the registered URL rule. Flask
- itself assumes the name of the view function as
- endpoint
- :param view_func: the function to call when serving a request to the
- provided endpoint
- :param provide_automatic_options: controls whether the ``OPTIONS``
- method should be added automatically. This can also be controlled
- by setting the ``view_func.provide_automatic_options = False``
- before adding the rule.
- :param options: the options to be forwarded to the underlying
- :class:`~werkzeug.routing.Rule` object. A change
- to Werkzeug is handling of method options. methods
- is a list of methods this rule should be limited
- to (``GET``, ``POST`` etc.). By default a rule
- just listens for ``GET`` (and implicitly ``HEAD``).
- Starting with Flask 0.6, ``OPTIONS`` is implicitly
- added and handled by the standard request handling.
- """
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func)
- options["endpoint"] = endpoint
- methods = options.pop("methods", None)
-
- # if the methods are not given and the view_func object knows its
- # methods we can use that instead. If neither exists, we go with
- # a tuple of only ``GET`` as default.
- if methods is None:
- methods = getattr(view_func, "methods", None) or ("GET",)
- if isinstance(methods, string_types):
- raise TypeError(
- "Allowed methods have to be iterables of strings, "
- 'for example: @app.route(..., methods=["POST"])'
- )
- methods = set(item.upper() for item in methods)
-
- # Methods that should always be added
- required_methods = set(getattr(view_func, "required_methods", ()))
-
- # starting with Flask 0.8 the view_func object can disable and
- # force-enable the automatic options handling.
- if provide_automatic_options is None:
- provide_automatic_options = getattr(
- view_func, "provide_automatic_options", None
- )
-
- if provide_automatic_options is None:
- if "OPTIONS" not in methods:
- provide_automatic_options = True
- required_methods.add("OPTIONS")
- else:
- provide_automatic_options = False
-
- # Add the required methods now.
- methods |= required_methods
-
- rule = self.url_rule_class(rule, methods=methods, **options)
- rule.provide_automatic_options = provide_automatic_options
-
- self.url_map.add(rule)
- if view_func is not None:
- old_func = self.view_functions.get(endpoint)
- if old_func is not None and old_func != view_func:
- raise AssertionError(
- "View function mapping is overwriting an "
- "existing endpoint function: %s" % endpoint
- )
- self.view_functions[endpoint] = view_func
-
- def route(self, rule, **options):
- """A decorator that is used to register a view function for a
- given URL rule. This does the same thing as :meth:`add_url_rule`
- but is intended for decorator usage::
-
- @app.route('/')
- def index():
- return 'Hello World'
-
- For more information refer to :ref:`url-route-registrations`.
-
- :param rule: the URL rule as string
- :param endpoint: the endpoint for the registered URL rule. Flask
- itself assumes the name of the view function as
- endpoint
- :param options: the options to be forwarded to the underlying
- :class:`~werkzeug.routing.Rule` object. A change
- to Werkzeug is handling of method options. methods
- is a list of methods this rule should be limited
- to (``GET``, ``POST`` etc.). By default a rule
- just listens for ``GET`` (and implicitly ``HEAD``).
- Starting with Flask 0.6, ``OPTIONS`` is implicitly
- added and handled by the standard request handling.
- """
-
- def decorator(f):
- endpoint = options.pop("endpoint", None)
- self.add_url_rule(rule, endpoint, f, **options)
- return f
-
- return decorator
-
- @setupmethod
- def endpoint(self, endpoint):
- """A decorator to register a function as an endpoint.
- Example::
-
- @app.endpoint('example.endpoint')
- def example():
- return "example"
-
- :param endpoint: the name of the endpoint
- """
-
- def decorator(f):
- self.view_functions[endpoint] = f
- return f
-
- return decorator
-
- @staticmethod
- def _get_exc_class_and_code(exc_class_or_code):
- """Get the exception class being handled. For HTTP status codes
- or ``HTTPException`` subclasses, return both the exception and
- status code.
-
- :param exc_class_or_code: Any exception class, or an HTTP status
- code as an integer.
- """
- if isinstance(exc_class_or_code, integer_types):
- exc_class = default_exceptions[exc_class_or_code]
- else:
- exc_class = exc_class_or_code
-
- assert issubclass(exc_class, Exception)
-
- if issubclass(exc_class, HTTPException):
- return exc_class, exc_class.code
- else:
- return exc_class, None
-
- @setupmethod
- def errorhandler(self, code_or_exception):
- """Register a function to handle errors by code or exception class.
-
- A decorator that is used to register a function given an
- error code. Example::
-
- @app.errorhandler(404)
- def page_not_found(error):
- return 'This page does not exist', 404
-
- You can also register handlers for arbitrary exceptions::
-
- @app.errorhandler(DatabaseError)
- def special_exception_handler(error):
- return 'Database connection failed', 500
-
- .. versionadded:: 0.7
- Use :meth:`register_error_handler` instead of modifying
- :attr:`error_handler_spec` directly, for application wide error
- handlers.
-
- .. versionadded:: 0.7
- One can now additionally also register custom exception types
- that do not necessarily have to be a subclass of the
- :class:`~werkzeug.exceptions.HTTPException` class.
-
- :param code_or_exception: the code as integer for the handler, or
- an arbitrary exception
- """
-
- def decorator(f):
- self._register_error_handler(None, code_or_exception, f)
- return f
-
- return decorator
-
- @setupmethod
- def register_error_handler(self, code_or_exception, f):
- """Alternative error attach function to the :meth:`errorhandler`
- decorator that is more straightforward to use for non decorator
- usage.
-
- .. versionadded:: 0.7
- """
- self._register_error_handler(None, code_or_exception, f)
-
- @setupmethod
- def _register_error_handler(self, key, code_or_exception, f):
- """
- :type key: None|str
- :type code_or_exception: int|T<=Exception
- :type f: callable
- """
- if isinstance(code_or_exception, HTTPException): # old broken behavior
- raise ValueError(
- "Tried to register a handler for an exception instance {0!r}."
- " Handlers can only be registered for exception classes or"
- " HTTP error codes.".format(code_or_exception)
- )
-
- try:
- exc_class, code = self._get_exc_class_and_code(code_or_exception)
- except KeyError:
- raise KeyError(
- "'{0}' is not a recognized HTTP error code. Use a subclass of"
- " HTTPException with that code instead.".format(code_or_exception)
- )
-
- handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
- handlers[exc_class] = f
-
- @setupmethod
- def template_filter(self, name=None):
- """A decorator that is used to register custom template filter.
- You can specify a name for the filter, otherwise the function
- name will be used. Example::
-
- @app.template_filter()
- def reverse(s):
- return s[::-1]
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_template_filter(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_filter(self, f, name=None):
- """Register a custom template filter. Works exactly like the
- :meth:`template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- self.jinja_env.filters[name or f.__name__] = f
-
- @setupmethod
- def template_test(self, name=None):
- """A decorator that is used to register custom template test.
- You can specify a name for the test, otherwise the function
- name will be used. Example::
-
- @app.template_test()
- def is_prime(n):
- if n == 2:
- return True
- for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
- if n % i == 0:
- return False
- return True
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_template_test(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_test(self, f, name=None):
- """Register a custom template test. Works exactly like the
- :meth:`template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- self.jinja_env.tests[name or f.__name__] = f
-
- @setupmethod
- def template_global(self, name=None):
- """A decorator that is used to register a custom template global function.
- You can specify a name for the global function, otherwise the function
- name will be used. Example::
-
- @app.template_global()
- def double(n):
- return 2 * n
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_template_global(f, name=name)
- return f
-
- return decorator
-
- @setupmethod
- def add_template_global(self, f, name=None):
- """Register a custom template global function. Works exactly like the
- :meth:`template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- self.jinja_env.globals[name or f.__name__] = f
-
- @setupmethod
- def before_request(self, f):
- """Registers a function to run before each request.
-
- For example, this can be used to open a database connection, or to load
- the logged in user from the session.
-
- The function will be called without any arguments. If it returns a
- non-None value, the value is handled as if it was the return value from
- the view, and further request handling is stopped.
- """
- self.before_request_funcs.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def before_first_request(self, f):
- """Registers a function to be run before the first request to this
- instance of the application.
-
- The function will be called without any arguments and its return
- value is ignored.
-
- .. versionadded:: 0.8
- """
- self.before_first_request_funcs.append(f)
- return f
-
- @setupmethod
- def after_request(self, f):
- """Register a function to be run after each request.
-
- Your function must take one parameter, an instance of
- :attr:`response_class` and return a new response object or the
- same (see :meth:`process_response`).
-
- As of Flask 0.7 this function might not be executed at the end of the
- request in case an unhandled exception occurred.
- """
- self.after_request_funcs.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def teardown_request(self, f):
- """Register a function to be run at the end of each request,
- regardless of whether there was an exception or not. These functions
- are executed when the request context is popped, even if not an
- actual request was performed.
-
- Example::
-
- ctx = app.test_request_context()
- ctx.push()
- ...
- ctx.pop()
-
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the request context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
-
- Generally teardown functions must take every necessary step to avoid
- that they will fail. If they do execute code that might fail they
- will have to surround the execution of these code by try/except
- statements and log occurring errors.
-
- When a teardown function was called because of an exception it will
- be passed an error object.
-
- The return values of teardown functions are ignored.
-
- .. admonition:: Debug Note
-
- In debug mode Flask will not tear down a request on an exception
- immediately. Instead it will keep it alive so that the interactive
- debugger can still access it. This behavior can be controlled
- by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
- """
- self.teardown_request_funcs.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def teardown_appcontext(self, f):
- """Registers a function to be called when the application context
- ends. These functions are typically also called when the request
- context is popped.
-
- Example::
-
- ctx = app.app_context()
- ctx.push()
- ...
- ctx.pop()
-
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the app context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
-
- Since a request context typically also manages an application
- context it would also be called when you pop a request context.
-
- When a teardown function was called because of an unhandled exception
- it will be passed an error object. If an :meth:`errorhandler` is
- registered, it will handle the exception and the teardown will not
- receive it.
-
- The return values of teardown functions are ignored.
-
- .. versionadded:: 0.9
- """
- self.teardown_appcontext_funcs.append(f)
- return f
-
- @setupmethod
- def context_processor(self, f):
- """Registers a template context processor function."""
- self.template_context_processors[None].append(f)
- return f
-
- @setupmethod
- def shell_context_processor(self, f):
- """Registers a shell context processor function.
-
- .. versionadded:: 0.11
- """
- self.shell_context_processors.append(f)
- return f
-
- @setupmethod
- def url_value_preprocessor(self, f):
- """Register a URL value preprocessor function for all view
- functions in the application. These functions will be called before the
- :meth:`before_request` functions.
-
- The function can modify the values captured from the matched url before
- they are passed to the view. For example, this can be used to pop a
- common language code value and place it in ``g`` rather than pass it to
- every view.
-
- The function is passed the endpoint name and values dict. The return
- value is ignored.
- """
- self.url_value_preprocessors.setdefault(None, []).append(f)
- return f
-
- @setupmethod
- def url_defaults(self, f):
- """Callback function for URL defaults for all view functions of the
- application. It's called with the endpoint and values and should
- update the values passed in place.
- """
- self.url_default_functions.setdefault(None, []).append(f)
- return f
-
- def _find_error_handler(self, e):
- """Return a registered error handler for an exception in this order:
- blueprint handler for a specific code, app handler for a specific code,
- blueprint handler for an exception class, app handler for an exception
- class, or ``None`` if a suitable handler is not found.
- """
- exc_class, code = self._get_exc_class_and_code(type(e))
-
- for name, c in (
- (request.blueprint, code),
- (None, code),
- (request.blueprint, None),
- (None, None),
- ):
- handler_map = self.error_handler_spec.setdefault(name, {}).get(c)
-
- if not handler_map:
- continue
-
- for cls in exc_class.__mro__:
- handler = handler_map.get(cls)
-
- if handler is not None:
- return handler
-
- def handle_http_exception(self, e):
- """Handles an HTTP exception. By default this will invoke the
- registered error handlers and fall back to returning the
- exception as response.
-
- .. versionchanged:: 1.0.3
- ``RoutingException``, used internally for actions such as
- slash redirects during routing, is not passed to error
- handlers.
-
- .. versionchanged:: 1.0
- Exceptions are looked up by code *and* by MRO, so
- ``HTTPExcpetion`` subclasses can be handled with a catch-all
- handler for the base ``HTTPException``.
-
- .. versionadded:: 0.3
- """
- # Proxy exceptions don't have error codes. We want to always return
- # those unchanged as errors
- if e.code is None:
- return e
-
- # RoutingExceptions are used internally to trigger routing
- # actions, such as slash redirects raising RequestRedirect. They
- # are not raised or handled in user code.
- if isinstance(e, RoutingException):
- return e
-
- handler = self._find_error_handler(e)
- if handler is None:
- return e
- return handler(e)
-
- def trap_http_exception(self, e):
- """Checks if an HTTP exception should be trapped or not. By default
- this will return ``False`` for all exceptions except for a bad request
- key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It
- also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``.
-
- This is called for all HTTP exceptions raised by a view function.
- If it returns ``True`` for any exception the error handler for this
- exception is not called and it shows up as regular exception in the
- traceback. This is helpful for debugging implicitly raised HTTP
- exceptions.
-
- .. versionchanged:: 1.0
- Bad request errors are not trapped by default in debug mode.
-
- .. versionadded:: 0.8
- """
- if self.config["TRAP_HTTP_EXCEPTIONS"]:
- return True
-
- trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"]
-
- # if unset, trap key errors in debug mode
- if (
- trap_bad_request is None
- and self.debug
- and isinstance(e, BadRequestKeyError)
- ):
- return True
-
- if trap_bad_request:
- return isinstance(e, BadRequest)
-
- return False
-
- def handle_user_exception(self, e):
- """This method is called whenever an exception occurs that
- should be handled. A special case is :class:`~werkzeug
- .exceptions.HTTPException` which is forwarded to the
- :meth:`handle_http_exception` method. This function will either
- return a response value or reraise the exception with the same
- traceback.
-
- .. versionchanged:: 1.0
- Key errors raised from request data like ``form`` show the
- bad key in debug mode rather than a generic bad request
- message.
-
- .. versionadded:: 0.7
- """
- exc_type, exc_value, tb = sys.exc_info()
- assert exc_value is e
- # ensure not to trash sys.exc_info() at that point in case someone
- # wants the traceback preserved in handle_http_exception. Of course
- # we cannot prevent users from trashing it themselves in a custom
- # trap_http_exception method so that's their fault then.
-
- if isinstance(e, BadRequestKeyError):
- if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]:
- e.show_exception = True
-
- # Werkzeug < 0.15 doesn't add the KeyError to the 400
- # message, add it in manually.
- # TODO: clean up once Werkzeug >= 0.15.5 is required
- if e.args[0] not in e.get_description():
- e.description = "KeyError: '{}'".format(*e.args)
- elif not hasattr(BadRequestKeyError, "show_exception"):
- e.args = ()
-
- if isinstance(e, HTTPException) and not self.trap_http_exception(e):
- return self.handle_http_exception(e)
-
- handler = self._find_error_handler(e)
-
- if handler is None:
- reraise(exc_type, exc_value, tb)
- return handler(e)
-
- def handle_exception(self, e):
- """Handle an exception that did not have an error handler
- associated with it, or that was raised from an error handler.
- This always causes a 500 ``InternalServerError``.
-
- Always sends the :data:`got_request_exception` signal.
-
- If :attr:`propagate_exceptions` is ``True``, such as in debug
- mode, the error will be re-raised so that the debugger can
- display it. Otherwise, the original exception is logged, and
- an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
-
- If an error handler is registered for ``InternalServerError`` or
- ``500``, it will be used. For consistency, the handler will
- always receive the ``InternalServerError``. The original
- unhandled exception is available as ``e.original_exception``.
-
- .. note::
- Prior to Werkzeug 1.0.0, ``InternalServerError`` will not
- always have an ``original_exception`` attribute. Use
- ``getattr(e, "original_exception", None)`` to simulate the
- behavior for compatibility.
-
- .. versionchanged:: 1.1.0
- Always passes the ``InternalServerError`` instance to the
- handler, setting ``original_exception`` to the unhandled
- error.
-
- .. versionchanged:: 1.1.0
- ``after_request`` functions and other finalization is done
- even for the default 500 response when there is no handler.
-
- .. versionadded:: 0.3
- """
- exc_type, exc_value, tb = sys.exc_info()
- got_request_exception.send(self, exception=e)
-
- if self.propagate_exceptions:
- # if we want to repropagate the exception, we can attempt to
- # raise it with the whole traceback in case we can do that
- # (the function was actually called from the except part)
- # otherwise, we just raise the error again
- if exc_value is e:
- reraise(exc_type, exc_value, tb)
- else:
- raise e
-
- self.log_exception((exc_type, exc_value, tb))
- server_error = InternalServerError()
- # TODO: pass as param when Werkzeug>=1.0.0 is required
- # TODO: also remove note about this from docstring and docs
- server_error.original_exception = e
- handler = self._find_error_handler(server_error)
-
- if handler is not None:
- server_error = handler(server_error)
-
- return self.finalize_request(server_error, from_error_handler=True)
-
- def log_exception(self, exc_info):
- """Logs an exception. This is called by :meth:`handle_exception`
- if debugging is disabled and right before the handler is called.
- The default implementation logs the exception as error on the
- :attr:`logger`.
-
- .. versionadded:: 0.8
- """
- self.logger.error(
- "Exception on %s [%s]" % (request.path, request.method), exc_info=exc_info
- )
-
- def raise_routing_exception(self, request):
- """Exceptions that are recording during routing are reraised with
- this method. During debug we are not reraising redirect requests
- for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
- a different error instead to help debug situations.
-
- :internal:
- """
- if (
- not self.debug
- or not isinstance(request.routing_exception, RequestRedirect)
- or request.method in ("GET", "HEAD", "OPTIONS")
- ):
- raise request.routing_exception
-
- from .debughelpers import FormDataRoutingRedirect
-
- raise FormDataRoutingRedirect(request)
-
- def dispatch_request(self):
- """Does the request dispatching. Matches the URL and returns the
- return value of the view or error handler. This does not have to
- be a response object. In order to convert the return value to a
- proper response object, call :func:`make_response`.
-
- .. versionchanged:: 0.7
- This no longer does the exception handling, this code was
- moved to the new :meth:`full_dispatch_request`.
- """
- req = _request_ctx_stack.top.request
- if req.routing_exception is not None:
- self.raise_routing_exception(req)
- rule = req.url_rule
- # if we provide automatic options for this URL and the
- # request came with the OPTIONS method, reply automatically
- if (
- getattr(rule, "provide_automatic_options", False)
- and req.method == "OPTIONS"
- ):
- return self.make_default_options_response()
- # otherwise dispatch to the handler for that endpoint
- return self.view_functions[rule.endpoint](**req.view_args)
-
- def full_dispatch_request(self):
- """Dispatches the request and on top of that performs request
- pre and postprocessing as well as HTTP exception catching and
- error handling.
-
- .. versionadded:: 0.7
- """
- self.try_trigger_before_first_request_functions()
- try:
- request_started.send(self)
- rv = self.preprocess_request()
- if rv is None:
- rv = self.dispatch_request()
- except Exception as e:
- rv = self.handle_user_exception(e)
- return self.finalize_request(rv)
-
- def finalize_request(self, rv, from_error_handler=False):
- """Given the return value from a view function this finalizes
- the request by converting it into a response and invoking the
- postprocessing functions. This is invoked for both normal
- request dispatching as well as error handlers.
-
- Because this means that it might be called as a result of a
- failure a special safe mode is available which can be enabled
- with the `from_error_handler` flag. If enabled, failures in
- response processing will be logged and otherwise ignored.
-
- :internal:
- """
- response = self.make_response(rv)
- try:
- response = self.process_response(response)
- request_finished.send(self, response=response)
- except Exception:
- if not from_error_handler:
- raise
- self.logger.exception(
- "Request finalizing failed with an error while handling an error"
- )
- return response
-
- def try_trigger_before_first_request_functions(self):
- """Called before each request and will ensure that it triggers
- the :attr:`before_first_request_funcs` and only exactly once per
- application instance (which means process usually).
-
- :internal:
- """
- if self._got_first_request:
- return
- with self._before_request_lock:
- if self._got_first_request:
- return
- for func in self.before_first_request_funcs:
- func()
- self._got_first_request = True
-
- def make_default_options_response(self):
- """This method is called to create the default ``OPTIONS`` response.
- This can be changed through subclassing to change the default
- behavior of ``OPTIONS`` responses.
-
- .. versionadded:: 0.7
- """
- adapter = _request_ctx_stack.top.url_adapter
- if hasattr(adapter, "allowed_methods"):
- methods = adapter.allowed_methods()
- else:
- # fallback for Werkzeug < 0.7
- methods = []
- try:
- adapter.match(method="--")
- except MethodNotAllowed as e:
- methods = e.valid_methods
- except HTTPException:
- pass
- rv = self.response_class()
- rv.allow.update(methods)
- return rv
-
- def should_ignore_error(self, error):
- """This is called to figure out if an error should be ignored
- or not as far as the teardown system is concerned. If this
- function returns ``True`` then the teardown handlers will not be
- passed the error.
-
- .. versionadded:: 0.10
- """
- return False
-
- def make_response(self, rv):
- """Convert the return value from a view function to an instance of
- :attr:`response_class`.
-
- :param rv: the return value from the view function. The view function
- must return a response. Returning ``None``, or the view ending
- without returning, is not allowed. The following types are allowed
- for ``view_rv``:
-
- ``str`` (``unicode`` in Python 2)
- A response object is created with the string encoded to UTF-8
- as the body.
-
- ``bytes`` (``str`` in Python 2)
- A response object is created with the bytes as the body.
-
- ``dict``
- A dictionary that will be jsonify'd before being returned.
-
- ``tuple``
- Either ``(body, status, headers)``, ``(body, status)``, or
- ``(body, headers)``, where ``body`` is any of the other types
- allowed here, ``status`` is a string or an integer, and
- ``headers`` is a dictionary or a list of ``(key, value)``
- tuples. If ``body`` is a :attr:`response_class` instance,
- ``status`` overwrites the exiting value and ``headers`` are
- extended.
-
- :attr:`response_class`
- The object is returned unchanged.
-
- other :class:`~werkzeug.wrappers.Response` class
- The object is coerced to :attr:`response_class`.
-
- :func:`callable`
- The function is called as a WSGI application. The result is
- used to create a response object.
-
- .. versionchanged:: 0.9
- Previously a tuple was interpreted as the arguments for the
- response object.
- """
-
- status = headers = None
-
- # unpack tuple returns
- if isinstance(rv, tuple):
- len_rv = len(rv)
-
- # a 3-tuple is unpacked directly
- if len_rv == 3:
- rv, status, headers = rv
- # decide if a 2-tuple has status or headers
- elif len_rv == 2:
- if isinstance(rv[1], (Headers, dict, tuple, list)):
- rv, headers = rv
- else:
- rv, status = rv
- # other sized tuples are not allowed
- else:
- raise TypeError(
- "The view function did not return a valid response tuple."
- " The tuple must have the form (body, status, headers),"
- " (body, status), or (body, headers)."
- )
-
- # the body must not be None
- if rv is None:
- raise TypeError(
- "The view function did not return a valid response. The"
- " function either returned None or ended without a return"
- " statement."
- )
-
- # make sure the body is an instance of the response class
- if not isinstance(rv, self.response_class):
- if isinstance(rv, (text_type, bytes, bytearray)):
- # let the response class set the status and headers instead of
- # waiting to do it manually, so that the class can handle any
- # special logic
- rv = self.response_class(rv, status=status, headers=headers)
- status = headers = None
- elif isinstance(rv, dict):
- rv = jsonify(rv)
- elif isinstance(rv, BaseResponse) or callable(rv):
- # evaluate a WSGI callable, or coerce a different response
- # class to the correct type
- try:
- rv = self.response_class.force_type(rv, request.environ)
- except TypeError as e:
- new_error = TypeError(
- "{e}\nThe view function did not return a valid"
- " response. The return type must be a string, dict, tuple,"
- " Response instance, or WSGI callable, but it was a"
- " {rv.__class__.__name__}.".format(e=e, rv=rv)
- )
- reraise(TypeError, new_error, sys.exc_info()[2])
- else:
- raise TypeError(
- "The view function did not return a valid"
- " response. The return type must be a string, dict, tuple,"
- " Response instance, or WSGI callable, but it was a"
- " {rv.__class__.__name__}.".format(rv=rv)
- )
-
- # prefer the status if it was provided
- if status is not None:
- if isinstance(status, (text_type, bytes, bytearray)):
- rv.status = status
- else:
- rv.status_code = status
-
- # extend existing headers with provided headers
- if headers:
- rv.headers.extend(headers)
-
- return rv
-
- def create_url_adapter(self, request):
- """Creates a URL adapter for the given request. The URL adapter
- is created at a point where the request context is not yet set
- up so the request is passed explicitly.
-
- .. versionadded:: 0.6
-
- .. versionchanged:: 0.9
- This can now also be called without a request object when the
- URL adapter is created for the application context.
-
- .. versionchanged:: 1.0
- :data:`SERVER_NAME` no longer implicitly enables subdomain
- matching. Use :attr:`subdomain_matching` instead.
- """
- if request is not None:
- # If subdomain matching is disabled (the default), use the
- # default subdomain in all cases. This should be the default
- # in Werkzeug but it currently does not have that feature.
- subdomain = (
- (self.url_map.default_subdomain or None)
- if not self.subdomain_matching
- else None
- )
- return self.url_map.bind_to_environ(
- request.environ,
- server_name=self.config["SERVER_NAME"],
- subdomain=subdomain,
- )
- # We need at the very least the server name to be set for this
- # to work.
- if self.config["SERVER_NAME"] is not None:
- return self.url_map.bind(
- self.config["SERVER_NAME"],
- script_name=self.config["APPLICATION_ROOT"],
- url_scheme=self.config["PREFERRED_URL_SCHEME"],
- )
-
- def inject_url_defaults(self, endpoint, values):
- """Injects the URL defaults for the given endpoint directly into
- the values dictionary passed. This is used internally and
- automatically called on URL building.
-
- .. versionadded:: 0.7
- """
- funcs = self.url_default_functions.get(None, ())
- if "." in endpoint:
- bp = endpoint.rsplit(".", 1)[0]
- funcs = chain(funcs, self.url_default_functions.get(bp, ()))
- for func in funcs:
- func(endpoint, values)
-
- def handle_url_build_error(self, error, endpoint, values):
- """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`.
- """
- exc_type, exc_value, tb = sys.exc_info()
- for handler in self.url_build_error_handlers:
- try:
- rv = handler(error, endpoint, values)
- if rv is not None:
- return rv
- except BuildError as e:
- # make error available outside except block (py3)
- error = e
-
- # At this point we want to reraise the exception. If the error is
- # still the same one we can reraise it with the original traceback,
- # otherwise we raise it from here.
- if error is exc_value:
- reraise(exc_type, exc_value, tb)
- raise error
-
- def preprocess_request(self):
- """Called before the request is dispatched. Calls
- :attr:`url_value_preprocessors` registered with the app and the
- current blueprint (if any). Then calls :attr:`before_request_funcs`
- registered with the app and the blueprint.
-
- If any :meth:`before_request` handler returns a non-None value, the
- value is handled as if it was the return value from the view, and
- further request handling is stopped.
- """
-
- bp = _request_ctx_stack.top.request.blueprint
-
- funcs = self.url_value_preprocessors.get(None, ())
- if bp is not None and bp in self.url_value_preprocessors:
- funcs = chain(funcs, self.url_value_preprocessors[bp])
- for func in funcs:
- func(request.endpoint, request.view_args)
-
- funcs = self.before_request_funcs.get(None, ())
- if bp is not None and bp in self.before_request_funcs:
- funcs = chain(funcs, self.before_request_funcs[bp])
- for func in funcs:
- rv = func()
- if rv is not None:
- return rv
-
- def process_response(self, response):
- """Can be overridden in order to modify the response object
- before it's sent to the WSGI server. By default this will
- call all the :meth:`after_request` decorated functions.
-
- .. versionchanged:: 0.5
- As of Flask 0.5 the functions registered for after request
- execution are called in reverse order of registration.
-
- :param response: a :attr:`response_class` object.
- :return: a new response object or the same, has to be an
- instance of :attr:`response_class`.
- """
- ctx = _request_ctx_stack.top
- bp = ctx.request.blueprint
- funcs = ctx._after_request_functions
- if bp is not None and bp in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
- if None in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[None]))
- for handler in funcs:
- response = handler(response)
- if not self.session_interface.is_null_session(ctx.session):
- self.session_interface.save_session(self, ctx.session, response)
- return response
-
- def do_teardown_request(self, exc=_sentinel):
- """Called after the request is dispatched and the response is
- returned, right before the request context is popped.
-
- This calls all functions decorated with
- :meth:`teardown_request`, and :meth:`Blueprint.teardown_request`
- if a blueprint handled the request. Finally, the
- :data:`request_tearing_down` signal is sent.
-
- This is called by
- :meth:`RequestContext.pop() `,
- which may be delayed during testing to maintain access to
- resources.
-
- :param exc: An unhandled exception raised while dispatching the
- request. Detected from the current exception information if
- not passed. Passed to each teardown function.
-
- .. versionchanged:: 0.9
- Added the ``exc`` argument.
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- funcs = reversed(self.teardown_request_funcs.get(None, ()))
- bp = _request_ctx_stack.top.request.blueprint
- if bp is not None and bp in self.teardown_request_funcs:
- funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
- for func in funcs:
- func(exc)
- request_tearing_down.send(self, exc=exc)
-
- def do_teardown_appcontext(self, exc=_sentinel):
- """Called right before the application context is popped.
-
- When handling a request, the application context is popped
- after the request context. See :meth:`do_teardown_request`.
-
- This calls all functions decorated with
- :meth:`teardown_appcontext`. Then the
- :data:`appcontext_tearing_down` signal is sent.
-
- This is called by
- :meth:`AppContext.pop() `.
-
- .. versionadded:: 0.9
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- for func in reversed(self.teardown_appcontext_funcs):
- func(exc)
- appcontext_tearing_down.send(self, exc=exc)
-
- def app_context(self):
- """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``
- block to push the context, which will make :data:`current_app`
- point at this application.
-
- An application context is automatically pushed by
- :meth:`RequestContext.push() `
- when handling a request, and when running a CLI command. Use
- this to manually create a context outside of these situations.
-
- ::
-
- with app.app_context():
- init_db()
-
- See :doc:`/appcontext`.
-
- .. versionadded:: 0.9
- """
- return AppContext(self)
-
- def request_context(self, environ):
- """Create a :class:`~flask.ctx.RequestContext` representing a
- WSGI environment. Use a ``with`` block to push the context,
- which will make :data:`request` point at this request.
-
- See :doc:`/reqcontext`.
-
- Typically you should not call this from your own code. A request
- context is automatically pushed by the :meth:`wsgi_app` when
- handling a request. Use :meth:`test_request_context` to create
- an environment and context instead of this method.
-
- :param environ: a WSGI environment
- """
- return RequestContext(self, environ)
-
- def test_request_context(self, *args, **kwargs):
- """Create a :class:`~flask.ctx.RequestContext` for a WSGI
- environment created from the given values. This is mostly useful
- during testing, where you may want to run a function that uses
- request data without dispatching a full request.
-
- See :doc:`/reqcontext`.
-
- Use a ``with`` block to push the context, which will make
- :data:`request` point at the request for the created
- environment. ::
-
- with test_request_context(...):
- generate_report()
-
- When using the shell, it may be easier to push and pop the
- context manually to avoid indentation. ::
-
- ctx = app.test_request_context(...)
- ctx.push()
- ...
- ctx.pop()
-
- Takes the same arguments as Werkzeug's
- :class:`~werkzeug.test.EnvironBuilder`, with some defaults from
- the application. See the linked Werkzeug docs for most of the
- available arguments. Flask-specific behavior is listed here.
-
- :param path: URL path being requested.
- :param base_url: Base URL where the app is being served, which
- ``path`` is relative to. If not given, built from
- :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
- :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
- :param subdomain: Subdomain name to append to
- :data:`SERVER_NAME`.
- :param url_scheme: Scheme to use instead of
- :data:`PREFERRED_URL_SCHEME`.
- :param data: The request body, either as a string or a dict of
- form keys and values.
- :param json: If given, this is serialized as JSON and passed as
- ``data``. Also defaults ``content_type`` to
- ``application/json``.
- :param args: other positional arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- :param kwargs: other keyword arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- """
- from .testing import EnvironBuilder
-
- builder = EnvironBuilder(self, *args, **kwargs)
-
- try:
- return self.request_context(builder.get_environ())
- finally:
- builder.close()
-
- def wsgi_app(self, environ, start_response):
- """The actual WSGI application. This is not implemented in
- :meth:`__call__` so that middlewares can be applied without
- losing a reference to the app object. Instead of doing this::
-
- app = MyMiddleware(app)
-
- It's a better idea to do this instead::
-
- app.wsgi_app = MyMiddleware(app.wsgi_app)
-
- Then you still have the original application object around and
- can continue to call methods on it.
-
- .. versionchanged:: 0.7
- Teardown events for the request and app contexts are called
- even if an unhandled error occurs. Other events may not be
- called depending on when an error occurs during dispatch.
- See :ref:`callbacks-and-errors`.
-
- :param environ: A WSGI environment.
- :param start_response: A callable accepting a status code,
- a list of headers, and an optional exception context to
- start the response.
- """
- ctx = self.request_context(environ)
- error = None
- try:
- try:
- ctx.push()
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.handle_exception(e)
- except: # noqa: B001
- error = sys.exc_info()[1]
- raise
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
-
- def __call__(self, environ, start_response):
- """The WSGI server calls the Flask application object as the
- WSGI application. This calls :meth:`wsgi_app` which can be
- wrapped to applying middleware."""
- return self.wsgi_app(environ, start_response)
-
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.name)
diff --git a/server/venv/lib/python3.7/site-packages/flask/blueprints.py b/server/venv/lib/python3.7/site-packages/flask/blueprints.py
deleted file mode 100644
index 8978104..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/blueprints.py
+++ /dev/null
@@ -1,569 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.blueprints
- ~~~~~~~~~~~~~~~~
-
- Blueprints are the recommended way to implement larger or more
- pluggable applications in Flask 0.7 and later.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-from functools import update_wrapper
-
-from .helpers import _endpoint_from_view_func
-from .helpers import _PackageBoundObject
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-class BlueprintSetupState(object):
- """Temporary holder object for registering a blueprint with the
- application. An instance of this class is created by the
- :meth:`~flask.Blueprint.make_setup_state` method and later passed
- to all register callback functions.
- """
-
- def __init__(self, blueprint, app, options, first_registration):
- #: a reference to the current application
- self.app = app
-
- #: a reference to the blueprint that created this setup state.
- self.blueprint = blueprint
-
- #: a dictionary with all options that were passed to the
- #: :meth:`~flask.Flask.register_blueprint` method.
- self.options = options
-
- #: as blueprints can be registered multiple times with the
- #: application and not everything wants to be registered
- #: multiple times on it, this attribute can be used to figure
- #: out if the blueprint was registered in the past already.
- self.first_registration = first_registration
-
- subdomain = self.options.get("subdomain")
- if subdomain is None:
- subdomain = self.blueprint.subdomain
-
- #: The subdomain that the blueprint should be active for, ``None``
- #: otherwise.
- self.subdomain = subdomain
-
- url_prefix = self.options.get("url_prefix")
- if url_prefix is None:
- url_prefix = self.blueprint.url_prefix
- #: The prefix that should be used for all URLs defined on the
- #: blueprint.
- self.url_prefix = url_prefix
-
- #: A dictionary with URL defaults that is added to each and every
- #: URL that was defined with the blueprint.
- self.url_defaults = dict(self.blueprint.url_values_defaults)
- self.url_defaults.update(self.options.get("url_defaults", ()))
-
- def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
- """A helper method to register a rule (and optionally a view function)
- to the application. The endpoint is automatically prefixed with the
- blueprint's name.
- """
- if self.url_prefix is not None:
- if rule:
- rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/")))
- else:
- rule = self.url_prefix
- options.setdefault("subdomain", self.subdomain)
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func)
- defaults = self.url_defaults
- if "defaults" in options:
- defaults = dict(defaults, **options.pop("defaults"))
- self.app.add_url_rule(
- rule,
- "%s.%s" % (self.blueprint.name, endpoint),
- view_func,
- defaults=defaults,
- **options
- )
-
-
-class Blueprint(_PackageBoundObject):
- """Represents a blueprint, a collection of routes and other
- app-related functions that can be registered on a real application
- later.
-
- A blueprint is an object that allows defining application functions
- without requiring an application object ahead of time. It uses the
- same decorators as :class:`~flask.Flask`, but defers the need for an
- application by recording them for later registration.
-
- Decorating a function with a blueprint creates a deferred function
- that is called with :class:`~flask.blueprints.BlueprintSetupState`
- when the blueprint is registered on an application.
-
- See :ref:`blueprints` for more information.
-
- .. versionchanged:: 1.1.0
- Blueprints have a ``cli`` group to register nested CLI commands.
- The ``cli_group`` parameter controls the name of the group under
- the ``flask`` command.
-
- .. versionadded:: 0.7
-
- :param name: The name of the blueprint. Will be prepended to each
- endpoint name.
- :param import_name: The name of the blueprint package, usually
- ``__name__``. This helps locate the ``root_path`` for the
- blueprint.
- :param static_folder: A folder with static files that should be
- served by the blueprint's static route. The path is relative to
- the blueprint's root path. Blueprint static files are disabled
- by default.
- :param static_url_path: The url to serve static files from.
- Defaults to ``static_folder``. If the blueprint does not have
- a ``url_prefix``, the app's static route will take precedence,
- and the blueprint's static files won't be accessible.
- :param template_folder: A folder with templates that should be added
- to the app's template search path. The path is relative to the
- blueprint's root path. Blueprint templates are disabled by
- default. Blueprint templates have a lower precedence than those
- in the app's templates folder.
- :param url_prefix: A path to prepend to all of the blueprint's URLs,
- to make them distinct from the rest of the app's routes.
- :param subdomain: A subdomain that blueprint routes will match on by
- default.
- :param url_defaults: A dict of default values that blueprint routes
- will receive by default.
- :param root_path: By default, the blueprint will automatically this
- based on ``import_name``. In certain situations this automatic
- detection can fail, so the path can be specified manually
- instead.
- """
-
- warn_on_modifications = False
- _got_registered_once = False
-
- #: Blueprint local JSON decoder class to use.
- #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_encoder`.
- json_encoder = None
- #: Blueprint local JSON decoder class to use.
- #: Set to ``None`` to use the app's :class:`~flask.app.Flask.json_decoder`.
- json_decoder = None
-
- # TODO remove the next three attrs when Sphinx :inherited-members: works
- # https://github.com/sphinx-doc/sphinx/issues/741
-
- #: The name of the package or module that this app belongs to. Do not
- #: change this once it is set by the constructor.
- import_name = None
-
- #: Location of the template files to be added to the template lookup.
- #: ``None`` if templates should not be added.
- template_folder = None
-
- #: Absolute path to the package on the filesystem. Used to look up
- #: resources contained in the package.
- root_path = None
-
- def __init__(
- self,
- name,
- import_name,
- static_folder=None,
- static_url_path=None,
- template_folder=None,
- url_prefix=None,
- subdomain=None,
- url_defaults=None,
- root_path=None,
- cli_group=_sentinel,
- ):
- _PackageBoundObject.__init__(
- self, import_name, template_folder, root_path=root_path
- )
- self.name = name
- self.url_prefix = url_prefix
- self.subdomain = subdomain
- self.static_folder = static_folder
- self.static_url_path = static_url_path
- self.deferred_functions = []
- if url_defaults is None:
- url_defaults = {}
- self.url_values_defaults = url_defaults
- self.cli_group = cli_group
-
- def record(self, func):
- """Registers a function that is called when the blueprint is
- registered on the application. This function is called with the
- state as argument as returned by the :meth:`make_setup_state`
- method.
- """
- if self._got_registered_once and self.warn_on_modifications:
- from warnings import warn
-
- warn(
- Warning(
- "The blueprint was already registered once "
- "but is getting modified now. These changes "
- "will not show up."
- )
- )
- self.deferred_functions.append(func)
-
- def record_once(self, func):
- """Works like :meth:`record` but wraps the function in another
- function that will ensure the function is only called once. If the
- blueprint is registered a second time on the application, the
- function passed is not called.
- """
-
- def wrapper(state):
- if state.first_registration:
- func(state)
-
- return self.record(update_wrapper(wrapper, func))
-
- def make_setup_state(self, app, options, first_registration=False):
- """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState`
- object that is later passed to the register callback functions.
- Subclasses can override this to return a subclass of the setup state.
- """
- return BlueprintSetupState(self, app, options, first_registration)
-
- def register(self, app, options, first_registration=False):
- """Called by :meth:`Flask.register_blueprint` to register all views
- and callbacks registered on the blueprint with the application. Creates
- a :class:`.BlueprintSetupState` and calls each :meth:`record` callback
- with it.
-
- :param app: The application this blueprint is being registered with.
- :param options: Keyword arguments forwarded from
- :meth:`~Flask.register_blueprint`.
- :param first_registration: Whether this is the first time this
- blueprint has been registered on the application.
- """
- self._got_registered_once = True
- state = self.make_setup_state(app, options, first_registration)
-
- if self.has_static_folder:
- state.add_url_rule(
- self.static_url_path + "/",
- view_func=self.send_static_file,
- endpoint="static",
- )
-
- for deferred in self.deferred_functions:
- deferred(state)
-
- cli_resolved_group = options.get("cli_group", self.cli_group)
-
- if not self.cli.commands:
- return
-
- if cli_resolved_group is None:
- app.cli.commands.update(self.cli.commands)
- elif cli_resolved_group is _sentinel:
- self.cli.name = self.name
- app.cli.add_command(self.cli)
- else:
- self.cli.name = cli_resolved_group
- app.cli.add_command(self.cli)
-
- def route(self, rule, **options):
- """Like :meth:`Flask.route` but for a blueprint. The endpoint for the
- :func:`url_for` function is prefixed with the name of the blueprint.
- """
-
- def decorator(f):
- endpoint = options.pop("endpoint", f.__name__)
- self.add_url_rule(rule, endpoint, f, **options)
- return f
-
- return decorator
-
- def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
- """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
- the :func:`url_for` function is prefixed with the name of the blueprint.
- """
- if endpoint:
- assert "." not in endpoint, "Blueprint endpoints should not contain dots"
- if view_func and hasattr(view_func, "__name__"):
- assert (
- "." not in view_func.__name__
- ), "Blueprint view function name should not contain dots"
- self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))
-
- def endpoint(self, endpoint):
- """Like :meth:`Flask.endpoint` but for a blueprint. This does not
- prefix the endpoint with the blueprint name, this has to be done
- explicitly by the user of this method. If the endpoint is prefixed
- with a `.` it will be registered to the current blueprint, otherwise
- it's an application independent endpoint.
- """
-
- def decorator(f):
- def register_endpoint(state):
- state.app.view_functions[endpoint] = f
-
- self.record_once(register_endpoint)
- return f
-
- return decorator
-
- def app_template_filter(self, name=None):
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.template_filter` but for a blueprint.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_app_template_filter(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_filter(self, f, name=None):
- """Register a custom template filter, available application wide. Like
- :meth:`Flask.add_template_filter` but for a blueprint. Works exactly
- like the :meth:`app_template_filter` decorator.
-
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
-
- def register_template(state):
- state.app.jinja_env.filters[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def app_template_test(self, name=None):
- """Register a custom template test, available application wide. Like
- :meth:`Flask.template_test` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_app_template_test(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_test(self, f, name=None):
- """Register a custom template test, available application wide. Like
- :meth:`Flask.add_template_test` but for a blueprint. Works exactly
- like the :meth:`app_template_test` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
-
- def register_template(state):
- state.app.jinja_env.tests[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def app_template_global(self, name=None):
- """Register a custom template global, available application wide. Like
- :meth:`Flask.template_global` but for a blueprint.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
-
- def decorator(f):
- self.add_app_template_global(f, name=name)
- return f
-
- return decorator
-
- def add_app_template_global(self, f, name=None):
- """Register a custom template global, available application wide. Like
- :meth:`Flask.add_template_global` but for a blueprint. Works exactly
- like the :meth:`app_template_global` decorator.
-
- .. versionadded:: 0.10
-
- :param name: the optional name of the global, otherwise the
- function name will be used.
- """
-
- def register_template(state):
- state.app.jinja_env.globals[name or f.__name__] = f
-
- self.record_once(register_template)
-
- def before_request(self, f):
- """Like :meth:`Flask.before_request` but for a blueprint. This function
- is only executed before each request that is handled by a function of
- that blueprint.
- """
- self.record_once(
- lambda s: s.app.before_request_funcs.setdefault(self.name, []).append(f)
- )
- return f
-
- def before_app_request(self, f):
- """Like :meth:`Flask.before_request`. Such a function is executed
- before each request, even if outside of a blueprint.
- """
- self.record_once(
- lambda s: s.app.before_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def before_app_first_request(self, f):
- """Like :meth:`Flask.before_first_request`. Such a function is
- executed before the first request to the application.
- """
- self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
- return f
-
- def after_request(self, f):
- """Like :meth:`Flask.after_request` but for a blueprint. This function
- is only executed after each request that is handled by a function of
- that blueprint.
- """
- self.record_once(
- lambda s: s.app.after_request_funcs.setdefault(self.name, []).append(f)
- )
- return f
-
- def after_app_request(self, f):
- """Like :meth:`Flask.after_request` but for a blueprint. Such a function
- is executed after each request, even if outside of the blueprint.
- """
- self.record_once(
- lambda s: s.app.after_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def teardown_request(self, f):
- """Like :meth:`Flask.teardown_request` but for a blueprint. This
- function is only executed when tearing down requests handled by a
- function of that blueprint. Teardown request functions are executed
- when the request context is popped, even when no actual request was
- performed.
- """
- self.record_once(
- lambda s: s.app.teardown_request_funcs.setdefault(self.name, []).append(f)
- )
- return f
-
- def teardown_app_request(self, f):
- """Like :meth:`Flask.teardown_request` but for a blueprint. Such a
- function is executed when tearing down each request, even if outside of
- the blueprint.
- """
- self.record_once(
- lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f)
- )
- return f
-
- def context_processor(self, f):
- """Like :meth:`Flask.context_processor` but for a blueprint. This
- function is only executed for requests handled by a blueprint.
- """
- self.record_once(
- lambda s: s.app.template_context_processors.setdefault(
- self.name, []
- ).append(f)
- )
- return f
-
- def app_context_processor(self, f):
- """Like :meth:`Flask.context_processor` but for a blueprint. Such a
- function is executed each request, even if outside of the blueprint.
- """
- self.record_once(
- lambda s: s.app.template_context_processors.setdefault(None, []).append(f)
- )
- return f
-
- def app_errorhandler(self, code):
- """Like :meth:`Flask.errorhandler` but for a blueprint. This
- handler is used for all requests, even if outside of the blueprint.
- """
-
- def decorator(f):
- self.record_once(lambda s: s.app.errorhandler(code)(f))
- return f
-
- return decorator
-
- def url_value_preprocessor(self, f):
- """Registers a function as URL value preprocessor for this
- blueprint. It's called before the view functions are called and
- can modify the url values provided.
- """
- self.record_once(
- lambda s: s.app.url_value_preprocessors.setdefault(self.name, []).append(f)
- )
- return f
-
- def url_defaults(self, f):
- """Callback function for URL defaults for this blueprint. It's called
- with the endpoint and values and should update the values passed
- in place.
- """
- self.record_once(
- lambda s: s.app.url_default_functions.setdefault(self.name, []).append(f)
- )
- return f
-
- def app_url_value_preprocessor(self, f):
- """Same as :meth:`url_value_preprocessor` but application wide.
- """
- self.record_once(
- lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f)
- )
- return f
-
- def app_url_defaults(self, f):
- """Same as :meth:`url_defaults` but application wide.
- """
- self.record_once(
- lambda s: s.app.url_default_functions.setdefault(None, []).append(f)
- )
- return f
-
- def errorhandler(self, code_or_exception):
- """Registers an error handler that becomes active for this blueprint
- only. Please be aware that routing does not happen local to a
- blueprint so an error handler for 404 usually is not handled by
- a blueprint unless it is caused inside a view function. Another
- special case is the 500 internal server error which is always looked
- up from the application.
-
- Otherwise works as the :meth:`~flask.Flask.errorhandler` decorator
- of the :class:`~flask.Flask` object.
- """
-
- def decorator(f):
- self.record_once(
- lambda s: s.app._register_error_handler(self.name, code_or_exception, f)
- )
- return f
-
- return decorator
-
- def register_error_handler(self, code_or_exception, f):
- """Non-decorator version of the :meth:`errorhandler` error attach
- function, akin to the :meth:`~flask.Flask.register_error_handler`
- application-wide function of the :class:`~flask.Flask` object but
- for error handlers limited to this blueprint.
-
- .. versionadded:: 0.11
- """
- self.record_once(
- lambda s: s.app._register_error_handler(self.name, code_or_exception, f)
- )
diff --git a/server/venv/lib/python3.7/site-packages/flask/cli.py b/server/venv/lib/python3.7/site-packages/flask/cli.py
deleted file mode 100644
index 1158545..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/cli.py
+++ /dev/null
@@ -1,970 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.cli
- ~~~~~~~~~
-
- A simple command line application to run flask apps.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-from __future__ import print_function
-
-import ast
-import inspect
-import os
-import platform
-import re
-import sys
-import traceback
-from functools import update_wrapper
-from operator import attrgetter
-from threading import Lock
-from threading import Thread
-
-import click
-from werkzeug.utils import import_string
-
-from ._compat import getargspec
-from ._compat import itervalues
-from ._compat import reraise
-from ._compat import text_type
-from .globals import current_app
-from .helpers import get_debug_flag
-from .helpers import get_env
-from .helpers import get_load_dotenv
-
-try:
- import dotenv
-except ImportError:
- dotenv = None
-
-try:
- import ssl
-except ImportError:
- ssl = None
-
-
-class NoAppException(click.UsageError):
- """Raised if an application cannot be found or loaded."""
-
-
-def find_best_app(script_info, module):
- """Given a module instance this tries to find the best possible
- application in the module or raises an exception.
- """
- from . import Flask
-
- # Search for the most common names first.
- for attr_name in ("app", "application"):
- app = getattr(module, attr_name, None)
-
- if isinstance(app, Flask):
- return app
-
- # Otherwise find the only object that is a Flask instance.
- matches = [v for v in itervalues(module.__dict__) if isinstance(v, Flask)]
-
- if len(matches) == 1:
- return matches[0]
- elif len(matches) > 1:
- raise NoAppException(
- 'Detected multiple Flask applications in module "{module}". Use '
- '"FLASK_APP={module}:name" to specify the correct '
- "one.".format(module=module.__name__)
- )
-
- # Search for app factory functions.
- for attr_name in ("create_app", "make_app"):
- app_factory = getattr(module, attr_name, None)
-
- if inspect.isfunction(app_factory):
- try:
- app = call_factory(script_info, app_factory)
-
- if isinstance(app, Flask):
- return app
- except TypeError:
- if not _called_with_wrong_args(app_factory):
- raise
- raise NoAppException(
- 'Detected factory "{factory}" in module "{module}", but '
- "could not call it without arguments. Use "
- "\"FLASK_APP='{module}:{factory}(args)'\" to specify "
- "arguments.".format(factory=attr_name, module=module.__name__)
- )
-
- raise NoAppException(
- 'Failed to find Flask application or factory in module "{module}". '
- 'Use "FLASK_APP={module}:name to specify one.'.format(module=module.__name__)
- )
-
-
-def call_factory(script_info, app_factory, arguments=()):
- """Takes an app factory, a ``script_info` object and optionally a tuple
- of arguments. Checks for the existence of a script_info argument and calls
- the app_factory depending on that and the arguments provided.
- """
- args_spec = getargspec(app_factory)
- arg_names = args_spec.args
- arg_defaults = args_spec.defaults
-
- if "script_info" in arg_names:
- return app_factory(*arguments, script_info=script_info)
- elif arguments:
- return app_factory(*arguments)
- elif not arguments and len(arg_names) == 1 and arg_defaults is None:
- return app_factory(script_info)
-
- return app_factory()
-
-
-def _called_with_wrong_args(factory):
- """Check whether calling a function raised a ``TypeError`` because
- the call failed or because something in the factory raised the
- error.
-
- :param factory: the factory function that was called
- :return: true if the call failed
- """
- tb = sys.exc_info()[2]
-
- try:
- while tb is not None:
- if tb.tb_frame.f_code is factory.__code__:
- # in the factory, it was called successfully
- return False
-
- tb = tb.tb_next
-
- # didn't reach the factory
- return True
- finally:
- # explicitly delete tb as it is circular referenced
- # https://docs.python.org/2/library/sys.html#sys.exc_info
- del tb
-
-
-def find_app_by_string(script_info, module, app_name):
- """Checks if the given string is a variable name or a function. If it is a
- function, it checks for specified arguments and whether it takes a
- ``script_info`` argument and calls the function with the appropriate
- arguments.
- """
- from . import Flask
-
- match = re.match(r"^ *([^ ()]+) *(?:\((.*?) *,? *\))? *$", app_name)
-
- if not match:
- raise NoAppException(
- '"{name}" is not a valid variable name or function '
- "expression.".format(name=app_name)
- )
-
- name, args = match.groups()
-
- try:
- attr = getattr(module, name)
- except AttributeError as e:
- raise NoAppException(e.args[0])
-
- if inspect.isfunction(attr):
- if args:
- try:
- args = ast.literal_eval("({args},)".format(args=args))
- except (ValueError, SyntaxError) as e:
- raise NoAppException(
- "Could not parse the arguments in "
- '"{app_name}".'.format(e=e, app_name=app_name)
- )
- else:
- args = ()
-
- try:
- app = call_factory(script_info, attr, args)
- except TypeError as e:
- if not _called_with_wrong_args(attr):
- raise
-
- raise NoAppException(
- '{e}\nThe factory "{app_name}" in module "{module}" could not '
- "be called with the specified arguments.".format(
- e=e, app_name=app_name, module=module.__name__
- )
- )
- else:
- app = attr
-
- if isinstance(app, Flask):
- return app
-
- raise NoAppException(
- "A valid Flask application was not obtained from "
- '"{module}:{app_name}".'.format(module=module.__name__, app_name=app_name)
- )
-
-
-def prepare_import(path):
- """Given a filename this will try to calculate the python path, add it
- to the search path and return the actual module name that is expected.
- """
- path = os.path.realpath(path)
-
- fname, ext = os.path.splitext(path)
- if ext == ".py":
- path = fname
-
- if os.path.basename(path) == "__init__":
- path = os.path.dirname(path)
-
- module_name = []
-
- # move up until outside package structure (no __init__.py)
- while True:
- path, name = os.path.split(path)
- module_name.append(name)
-
- if not os.path.exists(os.path.join(path, "__init__.py")):
- break
-
- if sys.path[0] != path:
- sys.path.insert(0, path)
-
- return ".".join(module_name[::-1])
-
-
-def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
- __traceback_hide__ = True # noqa: F841
-
- try:
- __import__(module_name)
- except ImportError:
- # Reraise the ImportError if it occurred within the imported module.
- # Determine this by checking whether the trace has a depth > 1.
- if sys.exc_info()[-1].tb_next:
- raise NoAppException(
- 'While importing "{name}", an ImportError was raised:'
- "\n\n{tb}".format(name=module_name, tb=traceback.format_exc())
- )
- elif raise_if_not_found:
- raise NoAppException('Could not import "{name}".'.format(name=module_name))
- else:
- return
-
- module = sys.modules[module_name]
-
- if app_name is None:
- return find_best_app(script_info, module)
- else:
- return find_app_by_string(script_info, module, app_name)
-
-
-def get_version(ctx, param, value):
- if not value or ctx.resilient_parsing:
- return
-
- import werkzeug
- from . import __version__
-
- message = "Python %(python)s\nFlask %(flask)s\nWerkzeug %(werkzeug)s"
- click.echo(
- message
- % {
- "python": platform.python_version(),
- "flask": __version__,
- "werkzeug": werkzeug.__version__,
- },
- color=ctx.color,
- )
- ctx.exit()
-
-
-version_option = click.Option(
- ["--version"],
- help="Show the flask version",
- expose_value=False,
- callback=get_version,
- is_flag=True,
- is_eager=True,
-)
-
-
-class DispatchingApp(object):
- """Special application that dispatches to a Flask application which
- is imported by name in a background thread. If an error happens
- it is recorded and shown as part of the WSGI handling which in case
- of the Werkzeug debugger means that it shows up in the browser.
- """
-
- def __init__(self, loader, use_eager_loading=False):
- self.loader = loader
- self._app = None
- self._lock = Lock()
- self._bg_loading_exc_info = None
- if use_eager_loading:
- self._load_unlocked()
- else:
- self._load_in_background()
-
- def _load_in_background(self):
- def _load_app():
- __traceback_hide__ = True # noqa: F841
- with self._lock:
- try:
- self._load_unlocked()
- except Exception:
- self._bg_loading_exc_info = sys.exc_info()
-
- t = Thread(target=_load_app, args=())
- t.start()
-
- def _flush_bg_loading_exception(self):
- __traceback_hide__ = True # noqa: F841
- exc_info = self._bg_loading_exc_info
- if exc_info is not None:
- self._bg_loading_exc_info = None
- reraise(*exc_info)
-
- def _load_unlocked(self):
- __traceback_hide__ = True # noqa: F841
- self._app = rv = self.loader()
- self._bg_loading_exc_info = None
- return rv
-
- def __call__(self, environ, start_response):
- __traceback_hide__ = True # noqa: F841
- if self._app is not None:
- return self._app(environ, start_response)
- self._flush_bg_loading_exception()
- with self._lock:
- if self._app is not None:
- rv = self._app
- else:
- rv = self._load_unlocked()
- return rv(environ, start_response)
-
-
-class ScriptInfo(object):
- """Helper object to deal with Flask applications. This is usually not
- necessary to interface with as it's used internally in the dispatching
- to click. In future versions of Flask this object will most likely play
- a bigger role. Typically it's created automatically by the
- :class:`FlaskGroup` but you can also manually create it and pass it
- onwards as click object.
- """
-
- def __init__(self, app_import_path=None, create_app=None, set_debug_flag=True):
- #: Optionally the import path for the Flask application.
- self.app_import_path = app_import_path or os.environ.get("FLASK_APP")
- #: Optionally a function that is passed the script info to create
- #: the instance of the application.
- self.create_app = create_app
- #: A dictionary with arbitrary data that can be associated with
- #: this script info.
- self.data = {}
- self.set_debug_flag = set_debug_flag
- self._loaded_app = None
-
- def load_app(self):
- """Loads the Flask app (if not yet loaded) and returns it. Calling
- this multiple times will just result in the already loaded app to
- be returned.
- """
- __traceback_hide__ = True # noqa: F841
-
- if self._loaded_app is not None:
- return self._loaded_app
-
- app = None
-
- if self.create_app is not None:
- app = call_factory(self, self.create_app)
- else:
- if self.app_import_path:
- path, name = (
- re.split(r":(?![\\/])", self.app_import_path, 1) + [None]
- )[:2]
- import_name = prepare_import(path)
- app = locate_app(self, import_name, name)
- else:
- for path in ("wsgi.py", "app.py"):
- import_name = prepare_import(path)
- app = locate_app(self, import_name, None, raise_if_not_found=False)
-
- if app:
- break
-
- if not app:
- raise NoAppException(
- "Could not locate a Flask application. You did not provide "
- 'the "FLASK_APP" environment variable, and a "wsgi.py" or '
- '"app.py" module was not found in the current directory.'
- )
-
- if self.set_debug_flag:
- # Update the app's debug flag through the descriptor so that
- # other values repopulate as well.
- app.debug = get_debug_flag()
-
- self._loaded_app = app
- return app
-
-
-pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True)
-
-
-def with_appcontext(f):
- """Wraps a callback so that it's guaranteed to be executed with the
- script's application context. If callbacks are registered directly
- to the ``app.cli`` object then they are wrapped with this function
- by default unless it's disabled.
- """
-
- @click.pass_context
- def decorator(__ctx, *args, **kwargs):
- with __ctx.ensure_object(ScriptInfo).load_app().app_context():
- return __ctx.invoke(f, *args, **kwargs)
-
- return update_wrapper(decorator, f)
-
-
-class AppGroup(click.Group):
- """This works similar to a regular click :class:`~click.Group` but it
- changes the behavior of the :meth:`command` decorator so that it
- automatically wraps the functions in :func:`with_appcontext`.
-
- Not to be confused with :class:`FlaskGroup`.
- """
-
- def command(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it wraps callbacks in :func:`with_appcontext`
- unless it's disabled by passing ``with_appcontext=False``.
- """
- wrap_for_ctx = kwargs.pop("with_appcontext", True)
-
- def decorator(f):
- if wrap_for_ctx:
- f = with_appcontext(f)
- return click.Group.command(self, *args, **kwargs)(f)
-
- return decorator
-
- def group(self, *args, **kwargs):
- """This works exactly like the method of the same name on a regular
- :class:`click.Group` but it defaults the group class to
- :class:`AppGroup`.
- """
- kwargs.setdefault("cls", AppGroup)
- return click.Group.group(self, *args, **kwargs)
-
-
-class FlaskGroup(AppGroup):
- """Special subclass of the :class:`AppGroup` group that supports
- loading more commands from the configured Flask app. Normally a
- developer does not have to interface with this class but there are
- some very advanced use cases for which it makes sense to create an
- instance of this.
-
- For information as of why this is useful see :ref:`custom-scripts`.
-
- :param add_default_commands: if this is True then the default run and
- shell commands will be added.
- :param add_version_option: adds the ``--version`` option.
- :param create_app: an optional callback that is passed the script info and
- returns the loaded app.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param set_debug_flag: Set the app's debug flag based on the active
- environment
-
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment variables
- from :file:`.env` and :file:`.flaskenv` files.
- """
-
- def __init__(
- self,
- add_default_commands=True,
- create_app=None,
- add_version_option=True,
- load_dotenv=True,
- set_debug_flag=True,
- **extra
- ):
- params = list(extra.pop("params", None) or ())
-
- if add_version_option:
- params.append(version_option)
-
- AppGroup.__init__(self, params=params, **extra)
- self.create_app = create_app
- self.load_dotenv = load_dotenv
- self.set_debug_flag = set_debug_flag
-
- if add_default_commands:
- self.add_command(run_command)
- self.add_command(shell_command)
- self.add_command(routes_command)
-
- self._loaded_plugin_commands = False
-
- def _load_plugin_commands(self):
- if self._loaded_plugin_commands:
- return
- try:
- import pkg_resources
- except ImportError:
- self._loaded_plugin_commands = True
- return
-
- for ep in pkg_resources.iter_entry_points("flask.commands"):
- self.add_command(ep.load(), ep.name)
- self._loaded_plugin_commands = True
-
- def get_command(self, ctx, name):
- self._load_plugin_commands()
-
- # We load built-in commands first as these should always be the
- # same no matter what the app does. If the app does want to
- # override this it needs to make a custom instance of this group
- # and not attach the default commands.
- #
- # This also means that the script stays functional in case the
- # application completely fails.
- rv = AppGroup.get_command(self, ctx, name)
- if rv is not None:
- return rv
-
- info = ctx.ensure_object(ScriptInfo)
- try:
- rv = info.load_app().cli.get_command(ctx, name)
- if rv is not None:
- return rv
- except NoAppException:
- pass
-
- def list_commands(self, ctx):
- self._load_plugin_commands()
-
- # The commands available is the list of both the application (if
- # available) plus the builtin commands.
- rv = set(click.Group.list_commands(self, ctx))
- info = ctx.ensure_object(ScriptInfo)
- try:
- rv.update(info.load_app().cli.list_commands(ctx))
- except Exception:
- # Here we intentionally swallow all exceptions as we don't
- # want the help page to break if the app does not exist.
- # If someone attempts to use the command we try to create
- # the app again and this will give us the error.
- # However, we will not do so silently because that would confuse
- # users.
- traceback.print_exc()
- return sorted(rv)
-
- def main(self, *args, **kwargs):
- # Set a global flag that indicates that we were invoked from the
- # command line interface. This is detected by Flask.run to make the
- # call into a no-op. This is necessary to avoid ugly errors when the
- # script that is loaded here also attempts to start a server.
- os.environ["FLASK_RUN_FROM_CLI"] = "true"
-
- if get_load_dotenv(self.load_dotenv):
- load_dotenv()
-
- obj = kwargs.get("obj")
-
- if obj is None:
- obj = ScriptInfo(
- create_app=self.create_app, set_debug_flag=self.set_debug_flag
- )
-
- kwargs["obj"] = obj
- kwargs.setdefault("auto_envvar_prefix", "FLASK")
- return super(FlaskGroup, self).main(*args, **kwargs)
-
-
-def _path_is_ancestor(path, other):
- """Take ``other`` and remove the length of ``path`` from it. Then join it
- to ``path``. If it is the original value, ``path`` is an ancestor of
- ``other``."""
- return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other
-
-
-def load_dotenv(path=None):
- """Load "dotenv" files in order of precedence to set environment variables.
-
- If an env var is already set it is not overwritten, so earlier files in the
- list are preferred over later files.
-
- Changes the current working directory to the location of the first file
- found, with the assumption that it is in the top level project directory
- and will be where the Python path should import local packages from.
-
- This is a no-op if `python-dotenv`_ is not installed.
-
- .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
-
- :param path: Load the file at this location instead of searching.
- :return: ``True`` if a file was loaded.
-
- .. versionchanged:: 1.1.0
- Returns ``False`` when python-dotenv is not installed, or when
- the given path isn't a file.
-
- .. versionadded:: 1.0
- """
- if dotenv is None:
- if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"):
- click.secho(
- " * Tip: There are .env or .flaskenv files present."
- ' Do "pip install python-dotenv" to use them.',
- fg="yellow",
- err=True,
- )
-
- return False
-
- # if the given path specifies the actual file then return True,
- # else False
- if path is not None:
- if os.path.isfile(path):
- return dotenv.load_dotenv(path)
-
- return False
-
- new_dir = None
-
- for name in (".env", ".flaskenv"):
- path = dotenv.find_dotenv(name, usecwd=True)
-
- if not path:
- continue
-
- if new_dir is None:
- new_dir = os.path.dirname(path)
-
- dotenv.load_dotenv(path)
-
- if new_dir and os.getcwd() != new_dir:
- os.chdir(new_dir)
-
- return new_dir is not None # at least one file was located and loaded
-
-
-def show_server_banner(env, debug, app_import_path, eager_loading):
- """Show extra startup messages the first time the server is run,
- ignoring the reloader.
- """
- if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
- return
-
- if app_import_path is not None:
- message = ' * Serving Flask app "{0}"'.format(app_import_path)
-
- if not eager_loading:
- message += " (lazy loading)"
-
- click.echo(message)
-
- click.echo(" * Environment: {0}".format(env))
-
- if env == "production":
- click.secho(
- " WARNING: This is a development server. "
- "Do not use it in a production deployment.",
- fg="red",
- )
- click.secho(" Use a production WSGI server instead.", dim=True)
-
- if debug is not None:
- click.echo(" * Debug mode: {0}".format("on" if debug else "off"))
-
-
-class CertParamType(click.ParamType):
- """Click option type for the ``--cert`` option. Allows either an
- existing file, the string ``'adhoc'``, or an import for a
- :class:`~ssl.SSLContext` object.
- """
-
- name = "path"
-
- def __init__(self):
- self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True)
-
- def convert(self, value, param, ctx):
- if ssl is None:
- raise click.BadParameter(
- 'Using "--cert" requires Python to be compiled with SSL support.',
- ctx,
- param,
- )
-
- try:
- return self.path_type(value, param, ctx)
- except click.BadParameter:
- value = click.STRING(value, param, ctx).lower()
-
- if value == "adhoc":
- try:
- import OpenSSL # noqa: F401
- except ImportError:
- raise click.BadParameter(
- "Using ad-hoc certificates requires pyOpenSSL.", ctx, param
- )
-
- return value
-
- obj = import_string(value, silent=True)
-
- if sys.version_info < (2, 7, 9):
- if obj:
- return obj
- else:
- if isinstance(obj, ssl.SSLContext):
- return obj
-
- raise
-
-
-def _validate_key(ctx, param, value):
- """The ``--key`` option must be specified when ``--cert`` is a file.
- Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed.
- """
- cert = ctx.params.get("cert")
- is_adhoc = cert == "adhoc"
-
- if sys.version_info < (2, 7, 9):
- is_context = cert and not isinstance(cert, (text_type, bytes))
- else:
- is_context = isinstance(cert, ssl.SSLContext)
-
- if value is not None:
- if is_adhoc:
- raise click.BadParameter(
- 'When "--cert" is "adhoc", "--key" is not used.', ctx, param
- )
-
- if is_context:
- raise click.BadParameter(
- 'When "--cert" is an SSLContext object, "--key is not used.', ctx, param
- )
-
- if not cert:
- raise click.BadParameter('"--cert" must also be specified.', ctx, param)
-
- ctx.params["cert"] = cert, value
-
- else:
- if cert and not (is_adhoc or is_context):
- raise click.BadParameter('Required when using "--cert".', ctx, param)
-
- return value
-
-
-class SeparatedPathType(click.Path):
- """Click option type that accepts a list of values separated by the
- OS's path separator (``:``, ``;`` on Windows). Each value is
- validated as a :class:`click.Path` type.
- """
-
- def convert(self, value, param, ctx):
- items = self.split_envvar_value(value)
- super_convert = super(SeparatedPathType, self).convert
- return [super_convert(item, param, ctx) for item in items]
-
-
-@click.command("run", short_help="Run a development server.")
-@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.")
-@click.option("--port", "-p", default=5000, help="The port to bind to.")
-@click.option(
- "--cert", type=CertParamType(), help="Specify a certificate file to use HTTPS."
-)
-@click.option(
- "--key",
- type=click.Path(exists=True, dir_okay=False, resolve_path=True),
- callback=_validate_key,
- expose_value=False,
- help="The key file to use when specifying a certificate.",
-)
-@click.option(
- "--reload/--no-reload",
- default=None,
- help="Enable or disable the reloader. By default the reloader "
- "is active if debug is enabled.",
-)
-@click.option(
- "--debugger/--no-debugger",
- default=None,
- help="Enable or disable the debugger. By default the debugger "
- "is active if debug is enabled.",
-)
-@click.option(
- "--eager-loading/--lazy-loader",
- default=None,
- help="Enable or disable eager loading. By default eager "
- "loading is enabled if the reloader is disabled.",
-)
-@click.option(
- "--with-threads/--without-threads",
- default=True,
- help="Enable or disable multithreading.",
-)
-@click.option(
- "--extra-files",
- default=None,
- type=SeparatedPathType(),
- help=(
- "Extra files that trigger a reload on change. Multiple paths"
- " are separated by '{}'.".format(os.path.pathsep)
- ),
-)
-@pass_script_info
-def run_command(
- info, host, port, reload, debugger, eager_loading, with_threads, cert, extra_files
-):
- """Run a local development server.
-
- This server is for development purposes only. It does not provide
- the stability, security, or performance of production WSGI servers.
-
- The reloader and debugger are enabled by default if
- FLASK_ENV=development or FLASK_DEBUG=1.
- """
- debug = get_debug_flag()
-
- if reload is None:
- reload = debug
-
- if debugger is None:
- debugger = debug
-
- if eager_loading is None:
- eager_loading = not reload
-
- show_server_banner(get_env(), debug, info.app_import_path, eager_loading)
- app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
-
- from werkzeug.serving import run_simple
-
- run_simple(
- host,
- port,
- app,
- use_reloader=reload,
- use_debugger=debugger,
- threaded=with_threads,
- ssl_context=cert,
- extra_files=extra_files,
- )
-
-
-@click.command("shell", short_help="Run a shell in the app context.")
-@with_appcontext
-def shell_command():
- """Run an interactive Python shell in the context of a given
- Flask application. The application will populate the default
- namespace of this shell according to it's configuration.
-
- This is useful for executing small snippets of management code
- without having to manually configure the application.
- """
- import code
- from .globals import _app_ctx_stack
-
- app = _app_ctx_stack.top.app
- banner = "Python %s on %s\nApp: %s [%s]\nInstance: %s" % (
- sys.version,
- sys.platform,
- app.import_name,
- app.env,
- app.instance_path,
- )
- ctx = {}
-
- # Support the regular Python interpreter startup script if someone
- # is using it.
- startup = os.environ.get("PYTHONSTARTUP")
- if startup and os.path.isfile(startup):
- with open(startup, "r") as f:
- eval(compile(f.read(), startup, "exec"), ctx)
-
- ctx.update(app.make_shell_context())
-
- code.interact(banner=banner, local=ctx)
-
-
-@click.command("routes", short_help="Show the routes for the app.")
-@click.option(
- "--sort",
- "-s",
- type=click.Choice(("endpoint", "methods", "rule", "match")),
- default="endpoint",
- help=(
- 'Method to sort routes by. "match" is the order that Flask will match '
- "routes when dispatching a request."
- ),
-)
-@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.")
-@with_appcontext
-def routes_command(sort, all_methods):
- """Show all registered routes with endpoints and methods."""
-
- rules = list(current_app.url_map.iter_rules())
- if not rules:
- click.echo("No routes were registered.")
- return
-
- ignored_methods = set(() if all_methods else ("HEAD", "OPTIONS"))
-
- if sort in ("endpoint", "rule"):
- rules = sorted(rules, key=attrgetter(sort))
- elif sort == "methods":
- rules = sorted(rules, key=lambda rule: sorted(rule.methods))
-
- rule_methods = [", ".join(sorted(rule.methods - ignored_methods)) for rule in rules]
-
- headers = ("Endpoint", "Methods", "Rule")
- widths = (
- max(len(rule.endpoint) for rule in rules),
- max(len(methods) for methods in rule_methods),
- max(len(rule.rule) for rule in rules),
- )
- widths = [max(len(h), w) for h, w in zip(headers, widths)]
- row = "{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}".format(*widths)
-
- click.echo(row.format(*headers).strip())
- click.echo(row.format(*("-" * width for width in widths)))
-
- for rule, methods in zip(rules, rule_methods):
- click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip())
-
-
-cli = FlaskGroup(
- help="""\
-A general utility script for Flask applications.
-
-Provides commands from Flask, extensions, and the application. Loads the
-application defined in the FLASK_APP environment variable, or from a wsgi.py
-file. Setting the FLASK_ENV environment variable to 'development' will enable
-debug mode.
-
-\b
- {prefix}{cmd} FLASK_APP=hello.py
- {prefix}{cmd} FLASK_ENV=development
- {prefix}flask run
-""".format(
- cmd="export" if os.name == "posix" else "set",
- prefix="$ " if os.name == "posix" else "> ",
- )
-)
-
-
-def main(as_module=False):
- cli.main(prog_name="python -m flask" if as_module else None)
-
-
-if __name__ == "__main__":
- main(as_module=True)
diff --git a/server/venv/lib/python3.7/site-packages/flask/config.py b/server/venv/lib/python3.7/site-packages/flask/config.py
deleted file mode 100644
index 809de33..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/config.py
+++ /dev/null
@@ -1,269 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.config
- ~~~~~~~~~~~~
-
- Implements the configuration related objects.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import errno
-import os
-import types
-
-from werkzeug.utils import import_string
-
-from . import json
-from ._compat import iteritems
-from ._compat import string_types
-
-
-class ConfigAttribute(object):
- """Makes an attribute forward to the config"""
-
- def __init__(self, name, get_converter=None):
- self.__name__ = name
- self.get_converter = get_converter
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- rv = obj.config[self.__name__]
- if self.get_converter is not None:
- rv = self.get_converter(rv)
- return rv
-
- def __set__(self, obj, value):
- obj.config[self.__name__] = value
-
-
-class Config(dict):
- """Works exactly like a dict but provides ways to fill it from files
- or special dictionaries. There are two common patterns to populate the
- config.
-
- Either you can fill the config from a config file::
-
- app.config.from_pyfile('yourconfig.cfg')
-
- Or alternatively you can define the configuration options in the
- module that calls :meth:`from_object` or provide an import path to
- a module that should be loaded. It is also possible to tell it to
- use the same module and with that provide the configuration values
- just before the call::
-
- DEBUG = True
- SECRET_KEY = 'development key'
- app.config.from_object(__name__)
-
- In both cases (loading from any Python file or loading from modules),
- only uppercase keys are added to the config. This makes it possible to use
- lowercase values in the config file for temporary values that are not added
- to the config or to define the config keys in the same file that implements
- the application.
-
- Probably the most interesting way to load configurations is from an
- environment variable pointing to a file::
-
- app.config.from_envvar('YOURAPPLICATION_SETTINGS')
-
- In this case before launching the application you have to set this
- environment variable to the file you want to use. On Linux and OS X
- use the export statement::
-
- export YOURAPPLICATION_SETTINGS='/path/to/config/file'
-
- On windows use `set` instead.
-
- :param root_path: path to which files are read relative from. When the
- config object is created by the application, this is
- the application's :attr:`~flask.Flask.root_path`.
- :param defaults: an optional dictionary of default values
- """
-
- def __init__(self, root_path, defaults=None):
- dict.__init__(self, defaults or {})
- self.root_path = root_path
-
- def from_envvar(self, variable_name, silent=False):
- """Loads a configuration from an environment variable pointing to
- a configuration file. This is basically just a shortcut with nicer
- error messages for this line of code::
-
- app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
-
- :param variable_name: name of the environment variable
- :param silent: set to ``True`` if you want silent failure for missing
- files.
- :return: bool. ``True`` if able to load config, ``False`` otherwise.
- """
- rv = os.environ.get(variable_name)
- if not rv:
- if silent:
- return False
- raise RuntimeError(
- "The environment variable %r is not set "
- "and as such configuration could not be "
- "loaded. Set this variable and make it "
- "point to a configuration file" % variable_name
- )
- return self.from_pyfile(rv, silent=silent)
-
- def from_pyfile(self, filename, silent=False):
- """Updates the values in the config from a Python file. This function
- behaves as if the file was imported as module with the
- :meth:`from_object` function.
-
- :param filename: the filename of the config. This can either be an
- absolute filename or a filename relative to the
- root path.
- :param silent: set to ``True`` if you want silent failure for missing
- files.
-
- .. versionadded:: 0.7
- `silent` parameter.
- """
- filename = os.path.join(self.root_path, filename)
- d = types.ModuleType("config")
- d.__file__ = filename
- try:
- with open(filename, mode="rb") as config_file:
- exec(compile(config_file.read(), filename, "exec"), d.__dict__)
- except IOError as e:
- if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR):
- return False
- e.strerror = "Unable to load configuration file (%s)" % e.strerror
- raise
- self.from_object(d)
- return True
-
- def from_object(self, obj):
- """Updates the values from the given object. An object can be of one
- of the following two types:
-
- - a string: in this case the object with that name will be imported
- - an actual object reference: that object is used directly
-
- Objects are usually either modules or classes. :meth:`from_object`
- loads only the uppercase attributes of the module/class. A ``dict``
- object will not work with :meth:`from_object` because the keys of a
- ``dict`` are not attributes of the ``dict`` class.
-
- Example of module-based configuration::
-
- app.config.from_object('yourapplication.default_config')
- from yourapplication import default_config
- app.config.from_object(default_config)
-
- Nothing is done to the object before loading. If the object is a
- class and has ``@property`` attributes, it needs to be
- instantiated before being passed to this method.
-
- You should not use this function to load the actual configuration but
- rather configuration defaults. The actual config should be loaded
- with :meth:`from_pyfile` and ideally from a location not within the
- package because the package might be installed system wide.
-
- See :ref:`config-dev-prod` for an example of class-based configuration
- using :meth:`from_object`.
-
- :param obj: an import name or object
- """
- if isinstance(obj, string_types):
- obj = import_string(obj)
- for key in dir(obj):
- if key.isupper():
- self[key] = getattr(obj, key)
-
- def from_json(self, filename, silent=False):
- """Updates the values in the config from a JSON file. This function
- behaves as if the JSON object was a dictionary and passed to the
- :meth:`from_mapping` function.
-
- :param filename: the filename of the JSON file. This can either be an
- absolute filename or a filename relative to the
- root path.
- :param silent: set to ``True`` if you want silent failure for missing
- files.
-
- .. versionadded:: 0.11
- """
- filename = os.path.join(self.root_path, filename)
-
- try:
- with open(filename) as json_file:
- obj = json.loads(json_file.read())
- except IOError as e:
- if silent and e.errno in (errno.ENOENT, errno.EISDIR):
- return False
- e.strerror = "Unable to load configuration file (%s)" % e.strerror
- raise
- return self.from_mapping(obj)
-
- def from_mapping(self, *mapping, **kwargs):
- """Updates the config like :meth:`update` ignoring items with non-upper
- keys.
-
- .. versionadded:: 0.11
- """
- mappings = []
- if len(mapping) == 1:
- if hasattr(mapping[0], "items"):
- mappings.append(mapping[0].items())
- else:
- mappings.append(mapping[0])
- elif len(mapping) > 1:
- raise TypeError(
- "expected at most 1 positional argument, got %d" % len(mapping)
- )
- mappings.append(kwargs.items())
- for mapping in mappings:
- for (key, value) in mapping:
- if key.isupper():
- self[key] = value
- return True
-
- def get_namespace(self, namespace, lowercase=True, trim_namespace=True):
- """Returns a dictionary containing a subset of configuration options
- that match the specified namespace/prefix. Example usage::
-
- app.config['IMAGE_STORE_TYPE'] = 'fs'
- app.config['IMAGE_STORE_PATH'] = '/var/app/images'
- app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com'
- image_store_config = app.config.get_namespace('IMAGE_STORE_')
-
- The resulting dictionary `image_store_config` would look like::
-
- {
- 'type': 'fs',
- 'path': '/var/app/images',
- 'base_url': 'http://img.website.com'
- }
-
- This is often useful when configuration options map directly to
- keyword arguments in functions or class constructors.
-
- :param namespace: a configuration namespace
- :param lowercase: a flag indicating if the keys of the resulting
- dictionary should be lowercase
- :param trim_namespace: a flag indicating if the keys of the resulting
- dictionary should not include the namespace
-
- .. versionadded:: 0.11
- """
- rv = {}
- for k, v in iteritems(self):
- if not k.startswith(namespace):
- continue
- if trim_namespace:
- key = k[len(namespace) :]
- else:
- key = k
- if lowercase:
- key = key.lower()
- rv[key] = v
- return rv
-
- def __repr__(self):
- return "<%s %s>" % (self.__class__.__name__, dict.__repr__(self))
diff --git a/server/venv/lib/python3.7/site-packages/flask/ctx.py b/server/venv/lib/python3.7/site-packages/flask/ctx.py
deleted file mode 100644
index 172f6a0..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/ctx.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.ctx
- ~~~~~~~~~
-
- Implements the objects required to keep the context.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import sys
-from functools import update_wrapper
-
-from werkzeug.exceptions import HTTPException
-
-from ._compat import BROKEN_PYPY_CTXMGR_EXIT
-from ._compat import reraise
-from .globals import _app_ctx_stack
-from .globals import _request_ctx_stack
-from .signals import appcontext_popped
-from .signals import appcontext_pushed
-
-
-# a singleton sentinel value for parameter defaults
-_sentinel = object()
-
-
-class _AppCtxGlobals(object):
- """A plain object. Used as a namespace for storing data during an
- application context.
-
- Creating an app context automatically creates this object, which is
- made available as the :data:`g` proxy.
-
- .. describe:: 'key' in g
-
- Check whether an attribute is present.
-
- .. versionadded:: 0.10
-
- .. describe:: iter(g)
-
- Return an iterator over the attribute names.
-
- .. versionadded:: 0.10
- """
-
- def get(self, name, default=None):
- """Get an attribute by name, or a default value. Like
- :meth:`dict.get`.
-
- :param name: Name of attribute to get.
- :param default: Value to return if the attribute is not present.
-
- .. versionadded:: 0.10
- """
- return self.__dict__.get(name, default)
-
- def pop(self, name, default=_sentinel):
- """Get and remove an attribute by name. Like :meth:`dict.pop`.
-
- :param name: Name of attribute to pop.
- :param default: Value to return if the attribute is not present,
- instead of raise a ``KeyError``.
-
- .. versionadded:: 0.11
- """
- if default is _sentinel:
- return self.__dict__.pop(name)
- else:
- return self.__dict__.pop(name, default)
-
- def setdefault(self, name, default=None):
- """Get the value of an attribute if it is present, otherwise
- set and return a default value. Like :meth:`dict.setdefault`.
-
- :param name: Name of attribute to get.
- :param: default: Value to set and return if the attribute is not
- present.
-
- .. versionadded:: 0.11
- """
- return self.__dict__.setdefault(name, default)
-
- def __contains__(self, item):
- return item in self.__dict__
-
- def __iter__(self):
- return iter(self.__dict__)
-
- def __repr__(self):
- top = _app_ctx_stack.top
- if top is not None:
- return "" % top.app.name
- return object.__repr__(self)
-
-
-def after_this_request(f):
- """Executes a function after this request. This is useful to modify
- response objects. The function is passed the response object and has
- to return the same or a new one.
-
- Example::
-
- @app.route('/')
- def index():
- @after_this_request
- def add_header(response):
- response.headers['X-Foo'] = 'Parachute'
- return response
- return 'Hello World!'
-
- This is more useful if a function other than the view function wants to
- modify a response. For instance think of a decorator that wants to add
- some headers without converting the return value into a response object.
-
- .. versionadded:: 0.9
- """
- _request_ctx_stack.top._after_request_functions.append(f)
- return f
-
-
-def copy_current_request_context(f):
- """A helper function that decorates a function to retain the current
- request context. This is useful when working with greenlets. The moment
- the function is decorated a copy of the request context is created and
- then pushed when the function is called. The current session is also
- included in the copied request context.
-
- Example::
-
- import gevent
- from flask import copy_current_request_context
-
- @app.route('/')
- def index():
- @copy_current_request_context
- def do_some_work():
- # do some work here, it can access flask.request or
- # flask.session like you would otherwise in the view function.
- ...
- gevent.spawn(do_some_work)
- return 'Regular response'
-
- .. versionadded:: 0.10
- """
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError(
- "This decorator can only be used at local scopes "
- "when a request context is on the stack. For instance within "
- "view functions."
- )
- reqctx = top.copy()
-
- def wrapper(*args, **kwargs):
- with reqctx:
- return f(*args, **kwargs)
-
- return update_wrapper(wrapper, f)
-
-
-def has_request_context():
- """If you have code that wants to test if a request context is there or
- not this function can be used. For instance, you may want to take advantage
- of request information if the request object is available, but fail
- silently if it is unavailable.
-
- ::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and has_request_context():
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- Alternatively you can also just test any of the context bound objects
- (such as :class:`request` or :class:`g`) for truthness::
-
- class User(db.Model):
-
- def __init__(self, username, remote_addr=None):
- self.username = username
- if remote_addr is None and request:
- remote_addr = request.remote_addr
- self.remote_addr = remote_addr
-
- .. versionadded:: 0.7
- """
- return _request_ctx_stack.top is not None
-
-
-def has_app_context():
- """Works like :func:`has_request_context` but for the application
- context. You can also just do a boolean check on the
- :data:`current_app` object instead.
-
- .. versionadded:: 0.9
- """
- return _app_ctx_stack.top is not None
-
-
-class AppContext(object):
- """The application context binds an application object implicitly
- to the current thread or greenlet, similar to how the
- :class:`RequestContext` binds request information. The application
- context is also implicitly created if a request context is created
- but the application is not on top of the individual application
- context.
- """
-
- def __init__(self, app):
- self.app = app
- self.url_adapter = app.create_url_adapter(None)
- self.g = app.app_ctx_globals_class()
-
- # Like request context, app contexts can be pushed multiple times
- # but there a basic "refcount" is enough to track them.
- self._refcnt = 0
-
- def push(self):
- """Binds the app context to the current context."""
- self._refcnt += 1
- if hasattr(sys, "exc_clear"):
- sys.exc_clear()
- _app_ctx_stack.push(self)
- appcontext_pushed.send(self.app)
-
- def pop(self, exc=_sentinel):
- """Pops the app context."""
- try:
- self._refcnt -= 1
- if self._refcnt <= 0:
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_appcontext(exc)
- finally:
- rv = _app_ctx_stack.pop()
- assert rv is self, "Popped wrong app context. (%r instead of %r)" % (rv, self)
- appcontext_popped.send(self.app)
-
- def __enter__(self):
- self.push()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.pop(exc_value)
-
- if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
- reraise(exc_type, exc_value, tb)
-
-
-class RequestContext(object):
- """The request context contains all request relevant information. It is
- created at the beginning of the request and pushed to the
- `_request_ctx_stack` and removed at the end of it. It will create the
- URL adapter and request object for the WSGI environment provided.
-
- Do not attempt to use this class directly, instead use
- :meth:`~flask.Flask.test_request_context` and
- :meth:`~flask.Flask.request_context` to create this object.
-
- When the request context is popped, it will evaluate all the
- functions registered on the application for teardown execution
- (:meth:`~flask.Flask.teardown_request`).
-
- The request context is automatically popped at the end of the request
- for you. In debug mode the request context is kept around if
- exceptions happen so that interactive debuggers have a chance to
- introspect the data. With 0.4 this can also be forced for requests
- that did not fail and outside of ``DEBUG`` mode. By setting
- ``'flask._preserve_context'`` to ``True`` on the WSGI environment the
- context will not pop itself at the end of the request. This is used by
- the :meth:`~flask.Flask.test_client` for example to implement the
- deferred cleanup functionality.
-
- You might find this helpful for unittests where you need the
- information from the context local around for a little longer. Make
- sure to properly :meth:`~werkzeug.LocalStack.pop` the stack yourself in
- that situation, otherwise your unittests will leak memory.
- """
-
- def __init__(self, app, environ, request=None, session=None):
- self.app = app
- if request is None:
- request = app.request_class(environ)
- self.request = request
- self.url_adapter = None
- try:
- self.url_adapter = app.create_url_adapter(self.request)
- except HTTPException as e:
- self.request.routing_exception = e
- self.flashes = None
- self.session = session
-
- # Request contexts can be pushed multiple times and interleaved with
- # other request contexts. Now only if the last level is popped we
- # get rid of them. Additionally if an application context is missing
- # one is created implicitly so for each level we add this information
- self._implicit_app_ctx_stack = []
-
- # indicator if the context was preserved. Next time another context
- # is pushed the preserved context is popped.
- self.preserved = False
-
- # remembers the exception for pop if there is one in case the context
- # preservation kicks in.
- self._preserved_exc = None
-
- # Functions that should be executed after the request on the response
- # object. These will be called before the regular "after_request"
- # functions.
- self._after_request_functions = []
-
- @property
- def g(self):
- return _app_ctx_stack.top.g
-
- @g.setter
- def g(self, value):
- _app_ctx_stack.top.g = value
-
- def copy(self):
- """Creates a copy of this request context with the same request object.
- This can be used to move a request context to a different greenlet.
- Because the actual request object is the same this cannot be used to
- move a request context to a different thread unless access to the
- request object is locked.
-
- .. versionadded:: 0.10
-
- .. versionchanged:: 1.1
- The current session object is used instead of reloading the original
- data. This prevents `flask.session` pointing to an out-of-date object.
- """
- return self.__class__(
- self.app,
- environ=self.request.environ,
- request=self.request,
- session=self.session,
- )
-
- def match_request(self):
- """Can be overridden by a subclass to hook into the matching
- of the request.
- """
- try:
- result = self.url_adapter.match(return_rule=True)
- self.request.url_rule, self.request.view_args = result
- except HTTPException as e:
- self.request.routing_exception = e
-
- def push(self):
- """Binds the request context to the current context."""
- # If an exception occurs in debug mode or if context preservation is
- # activated under exception situations exactly one context stays
- # on the stack. The rationale is that you want to access that
- # information under debug situations. However if someone forgets to
- # pop that context again we want to make sure that on the next push
- # it's invalidated, otherwise we run at risk that something leaks
- # memory. This is usually only a problem in test suite since this
- # functionality is not active in production environments.
- top = _request_ctx_stack.top
- if top is not None and top.preserved:
- top.pop(top._preserved_exc)
-
- # Before we push the request context we have to ensure that there
- # is an application context.
- app_ctx = _app_ctx_stack.top
- if app_ctx is None or app_ctx.app != self.app:
- app_ctx = self.app.app_context()
- app_ctx.push()
- self._implicit_app_ctx_stack.append(app_ctx)
- else:
- self._implicit_app_ctx_stack.append(None)
-
- if hasattr(sys, "exc_clear"):
- sys.exc_clear()
-
- _request_ctx_stack.push(self)
-
- # Open the session at the moment that the request context is available.
- # This allows a custom open_session method to use the request context.
- # Only open a new session if this is the first time the request was
- # pushed, otherwise stream_with_context loses the session.
- if self.session is None:
- session_interface = self.app.session_interface
- self.session = session_interface.open_session(self.app, self.request)
-
- if self.session is None:
- self.session = session_interface.make_null_session(self.app)
-
- if self.url_adapter is not None:
- self.match_request()
-
- def pop(self, exc=_sentinel):
- """Pops the request context and unbinds it by doing that. This will
- also trigger the execution of functions registered by the
- :meth:`~flask.Flask.teardown_request` decorator.
-
- .. versionchanged:: 0.9
- Added the `exc` argument.
- """
- app_ctx = self._implicit_app_ctx_stack.pop()
-
- try:
- clear_request = False
- if not self._implicit_app_ctx_stack:
- self.preserved = False
- self._preserved_exc = None
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- self.app.do_teardown_request(exc)
-
- # If this interpreter supports clearing the exception information
- # we do that now. This will only go into effect on Python 2.x,
- # on 3.x it disappears automatically at the end of the exception
- # stack.
- if hasattr(sys, "exc_clear"):
- sys.exc_clear()
-
- request_close = getattr(self.request, "close", None)
- if request_close is not None:
- request_close()
- clear_request = True
- finally:
- rv = _request_ctx_stack.pop()
-
- # get rid of circular dependencies at the end of the request
- # so that we don't require the GC to be active.
- if clear_request:
- rv.request.environ["werkzeug.request"] = None
-
- # Get rid of the app as well if necessary.
- if app_ctx is not None:
- app_ctx.pop(exc)
-
- assert rv is self, "Popped wrong request context. (%r instead of %r)" % (
- rv,
- self,
- )
-
- def auto_pop(self, exc):
- if self.request.environ.get("flask._preserve_context") or (
- exc is not None and self.app.preserve_context_on_exception
- ):
- self.preserved = True
- self._preserved_exc = exc
- else:
- self.pop(exc)
-
- def __enter__(self):
- self.push()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- # do not pop the request stack if we are in debug mode and an
- # exception happened. This will allow the debugger to still
- # access the request object in the interactive shell. Furthermore
- # the context can be force kept alive for the test client.
- # See flask.testing for how this works.
- self.auto_pop(exc_value)
-
- if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
- reraise(exc_type, exc_value, tb)
-
- def __repr__(self):
- return "<%s '%s' [%s] of %s>" % (
- self.__class__.__name__,
- self.request.url,
- self.request.method,
- self.app.name,
- )
diff --git a/server/venv/lib/python3.7/site-packages/flask/debughelpers.py b/server/venv/lib/python3.7/site-packages/flask/debughelpers.py
deleted file mode 100644
index e475bd1..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/debughelpers.py
+++ /dev/null
@@ -1,183 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.debughelpers
- ~~~~~~~~~~~~~~~~~~
-
- Various helpers to make the development experience better.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import os
-from warnings import warn
-
-from ._compat import implements_to_string
-from ._compat import text_type
-from .app import Flask
-from .blueprints import Blueprint
-from .globals import _request_ctx_stack
-
-
-class UnexpectedUnicodeError(AssertionError, UnicodeError):
- """Raised in places where we want some better error reporting for
- unexpected unicode or binary data.
- """
-
-
-@implements_to_string
-class DebugFilesKeyError(KeyError, AssertionError):
- """Raised from request.files during debugging. The idea is that it can
- provide a better error message than just a generic KeyError/BadRequest.
- """
-
- def __init__(self, request, key):
- form_matches = request.form.getlist(key)
- buf = [
- 'You tried to access the file "%s" in the request.files '
- "dictionary but it does not exist. The mimetype for the request "
- 'is "%s" instead of "multipart/form-data" which means that no '
- "file contents were transmitted. To fix this error you should "
- 'provide enctype="multipart/form-data" in your form.'
- % (key, request.mimetype)
- ]
- if form_matches:
- buf.append(
- "\n\nThe browser instead transmitted some file names. "
- "This was submitted: %s" % ", ".join('"%s"' % x for x in form_matches)
- )
- self.msg = "".join(buf)
-
- def __str__(self):
- return self.msg
-
-
-class FormDataRoutingRedirect(AssertionError):
- """This exception is raised by Flask in debug mode if it detects a
- redirect caused by the routing system when the request method is not
- GET, HEAD or OPTIONS. Reasoning: form data will be dropped.
- """
-
- def __init__(self, request):
- exc = request.routing_exception
- buf = [
- "A request was sent to this URL (%s) but a redirect was "
- 'issued automatically by the routing system to "%s".'
- % (request.url, exc.new_url)
- ]
-
- # In case just a slash was appended we can be extra helpful
- if request.base_url + "/" == exc.new_url.split("?")[0]:
- buf.append(
- " The URL was defined with a trailing slash so "
- "Flask will automatically redirect to the URL "
- "with the trailing slash if it was accessed "
- "without one."
- )
-
- buf.append(
- " Make sure to directly send your %s-request to this URL "
- "since we can't make browsers or HTTP clients redirect "
- "with form data reliably or without user interaction." % request.method
- )
- buf.append("\n\nNote: this exception is only raised in debug mode")
- AssertionError.__init__(self, "".join(buf).encode("utf-8"))
-
-
-def attach_enctype_error_multidict(request):
- """Since Flask 0.8 we're monkeypatching the files object in case a
- request is detected that does not use multipart form data but the files
- object is accessed.
- """
- oldcls = request.files.__class__
-
- class newcls(oldcls):
- def __getitem__(self, key):
- try:
- return oldcls.__getitem__(self, key)
- except KeyError:
- if key not in request.form:
- raise
- raise DebugFilesKeyError(request, key)
-
- newcls.__name__ = oldcls.__name__
- newcls.__module__ = oldcls.__module__
- request.files.__class__ = newcls
-
-
-def _dump_loader_info(loader):
- yield "class: %s.%s" % (type(loader).__module__, type(loader).__name__)
- for key, value in sorted(loader.__dict__.items()):
- if key.startswith("_"):
- continue
- if isinstance(value, (tuple, list)):
- if not all(isinstance(x, (str, text_type)) for x in value):
- continue
- yield "%s:" % key
- for item in value:
- yield " - %s" % item
- continue
- elif not isinstance(value, (str, text_type, int, float, bool)):
- continue
- yield "%s: %r" % (key, value)
-
-
-def explain_template_loading_attempts(app, template, attempts):
- """This should help developers understand what failed"""
- info = ['Locating template "%s":' % template]
- total_found = 0
- blueprint = None
- reqctx = _request_ctx_stack.top
- if reqctx is not None and reqctx.request.blueprint is not None:
- blueprint = reqctx.request.blueprint
-
- for idx, (loader, srcobj, triple) in enumerate(attempts):
- if isinstance(srcobj, Flask):
- src_info = 'application "%s"' % srcobj.import_name
- elif isinstance(srcobj, Blueprint):
- src_info = 'blueprint "%s" (%s)' % (srcobj.name, srcobj.import_name)
- else:
- src_info = repr(srcobj)
-
- info.append("% 5d: trying loader of %s" % (idx + 1, src_info))
-
- for line in _dump_loader_info(loader):
- info.append(" %s" % line)
-
- if triple is None:
- detail = "no match"
- else:
- detail = "found (%r)" % (triple[1] or "")
- total_found += 1
- info.append(" -> %s" % detail)
-
- seems_fishy = False
- if total_found == 0:
- info.append("Error: the template could not be found.")
- seems_fishy = True
- elif total_found > 1:
- info.append("Warning: multiple loaders returned a match for the template.")
- seems_fishy = True
-
- if blueprint is not None and seems_fishy:
- info.append(
- " The template was looked up from an endpoint that "
- 'belongs to the blueprint "%s".' % blueprint
- )
- info.append(" Maybe you did not place a template in the right folder?")
- info.append(" See http://flask.pocoo.org/docs/blueprints/#templates")
-
- app.logger.info("\n".join(info))
-
-
-def explain_ignored_app_run():
- if os.environ.get("WERKZEUG_RUN_MAIN") != "true":
- warn(
- Warning(
- "Silently ignoring app.run() because the "
- "application is run from the flask command line "
- "executable. Consider putting app.run() behind an "
- 'if __name__ == "__main__" guard to silence this '
- "warning."
- ),
- stacklevel=3,
- )
diff --git a/server/venv/lib/python3.7/site-packages/flask/globals.py b/server/venv/lib/python3.7/site-packages/flask/globals.py
deleted file mode 100644
index 6d32dcf..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/globals.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.globals
- ~~~~~~~~~~~~~
-
- Defines all the global objects that are proxies to the current
- active context.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-from functools import partial
-
-from werkzeug.local import LocalProxy
-from werkzeug.local import LocalStack
-
-
-_request_ctx_err_msg = """\
-Working outside of request context.
-
-This typically means that you attempted to use functionality that needed
-an active HTTP request. Consult the documentation on testing for
-information about how to avoid this problem.\
-"""
-_app_ctx_err_msg = """\
-Working outside of application context.
-
-This typically means that you attempted to use functionality that needed
-to interface with the current application object in some way. To solve
-this, set up an application context with app.app_context(). See the
-documentation for more information.\
-"""
-
-
-def _lookup_req_object(name):
- top = _request_ctx_stack.top
- if top is None:
- raise RuntimeError(_request_ctx_err_msg)
- return getattr(top, name)
-
-
-def _lookup_app_object(name):
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return getattr(top, name)
-
-
-def _find_app():
- top = _app_ctx_stack.top
- if top is None:
- raise RuntimeError(_app_ctx_err_msg)
- return top.app
-
-
-# context locals
-_request_ctx_stack = LocalStack()
-_app_ctx_stack = LocalStack()
-current_app = LocalProxy(_find_app)
-request = LocalProxy(partial(_lookup_req_object, "request"))
-session = LocalProxy(partial(_lookup_req_object, "session"))
-g = LocalProxy(partial(_lookup_app_object, "g"))
diff --git a/server/venv/lib/python3.7/site-packages/flask/helpers.py b/server/venv/lib/python3.7/site-packages/flask/helpers.py
deleted file mode 100644
index 3f401a5..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/helpers.py
+++ /dev/null
@@ -1,1153 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
- flask.helpers
- ~~~~~~~~~~~~~
-
- Implements various helpers.
-
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
-"""
-import io
-import mimetypes
-import os
-import pkgutil
-import posixpath
-import socket
-import sys
-import unicodedata
-from functools import update_wrapper
-from threading import RLock
-from time import time
-from zlib import adler32
-
-from jinja2 import FileSystemLoader
-from werkzeug.datastructures import Headers
-from werkzeug.exceptions import BadRequest
-from werkzeug.exceptions import NotFound
-from werkzeug.exceptions import RequestedRangeNotSatisfiable
-from werkzeug.routing import BuildError
-from werkzeug.urls import url_quote
-from werkzeug.wsgi import wrap_file
-
-from ._compat import fspath
-from ._compat import PY2
-from ._compat import string_types
-from ._compat import text_type
-from .globals import _app_ctx_stack
-from .globals import _request_ctx_stack
-from .globals import current_app
-from .globals import request
-from .globals import session
-from .signals import message_flashed
-
-# sentinel
-_missing = object()
-
-
-# what separators does this operating system provide that are not a slash?
-# this is used by the send_from_directory function to ensure that nobody is
-# able to access files from outside the filesystem.
-_os_alt_seps = list(
- sep for sep in [os.path.sep, os.path.altsep] if sep not in (None, "/")
-)
-
-
-def get_env():
- """Get the environment the app is running in, indicated by the
- :envvar:`FLASK_ENV` environment variable. The default is
- ``'production'``.
- """
- return os.environ.get("FLASK_ENV") or "production"
-
-
-def get_debug_flag():
- """Get whether debug mode should be enabled for the app, indicated
- by the :envvar:`FLASK_DEBUG` environment variable. The default is
- ``True`` if :func:`.get_env` returns ``'development'``, or ``False``
- otherwise.
- """
- val = os.environ.get("FLASK_DEBUG")
-
- if not val:
- return get_env() == "development"
-
- return val.lower() not in ("0", "false", "no")
-
-
-def get_load_dotenv(default=True):
- """Get whether the user has disabled loading dotenv files by setting
- :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load the
- files.
-
- :param default: What to return if the env var isn't set.
- """
- val = os.environ.get("FLASK_SKIP_DOTENV")
-
- if not val:
- return default
-
- return val.lower() in ("0", "false", "no")
-
-
-def _endpoint_from_view_func(view_func):
- """Internal helper that returns the default endpoint for a given
- function. This always is the function name.
- """
- assert view_func is not None, "expected view func if endpoint is not provided."
- return view_func.__name__
-
-
-def stream_with_context(generator_or_function):
- """Request contexts disappear when the response is started on the server.
- This is done for efficiency reasons and to make it less likely to encounter
- memory leaks with badly written WSGI middlewares. The downside is that if
- you are using streamed responses, the generator cannot access request bound
- information any more.
-
- This function however can help you keep the context around for longer::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- @stream_with_context
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(generate())
-
- Alternatively it can also be used around a specific generator::
-
- from flask import stream_with_context, request, Response
-
- @app.route('/stream')
- def streamed_response():
- def generate():
- yield 'Hello '
- yield request.args['name']
- yield '!'
- return Response(stream_with_context(generate()))
-
- .. versionadded:: 0.9
- """
- try:
- gen = iter(generator_or_function)
- except TypeError:
-
- def decorator(*args, **kwargs):
- gen = generator_or_function(*args, **kwargs)
- return stream_with_context(gen)
-
- return update_wrapper(decorator, generator_or_function)
-
- def generator():
- ctx = _request_ctx_stack.top
- if ctx is None:
- raise RuntimeError(
- "Attempted to stream with context but "
- "there was no context in the first place to keep around."
- )
- with ctx:
- # Dummy sentinel. Has to be inside the context block or we're
- # not actually keeping the context around.
- yield None
-
- # The try/finally is here so that if someone passes a WSGI level
- # iterator in we're still running the cleanup logic. Generators
- # don't need that because they are closed on their destruction
- # automatically.
- try:
- for item in gen:
- yield item
- finally:
- if hasattr(gen, "close"):
- gen.close()
-
- # The trick is to start the generator. Then the code execution runs until
- # the first dummy None is yielded at which point the context was already
- # pushed. This item is discarded. Then when the iteration continues the
- # real generator is executed.
- wrapped_g = generator()
- next(wrapped_g)
- return wrapped_g
-
-
-def make_response(*args):
- """Sometimes it is necessary to set additional headers in a view. Because
- views do not have to return response objects but can return a value that
- is converted into a response object by Flask itself, it becomes tricky to
- add headers to it. This function can be called instead of using a return
- and you will get a response object which you can use to attach headers.
-
- If view looked like this and you want to add a new header::
-
- def index():
- return render_template('index.html', foo=42)
-
- You can now do something like this::
-
- def index():
- response = make_response(render_template('index.html', foo=42))
- response.headers['X-Parachutes'] = 'parachutes are cool'
- return response
-
- This function accepts the very same arguments you can return from a
- view function. This for example creates a response with a 404 error
- code::
-
- response = make_response(render_template('not_found.html'), 404)
-
- The other use case of this function is to force the return value of a
- view function into a response which is helpful with view
- decorators::
-
- response = make_response(view_function())
- response.headers['X-Parachutes'] = 'parachutes are cool'
-
- Internally this function does the following things:
-
- - if no arguments are passed, it creates a new response argument
- - if one argument is passed, :meth:`flask.Flask.make_response`
- is invoked with it.
- - if more than one argument is passed, the arguments are passed
- to the :meth:`flask.Flask.make_response` function as tuple.
-
- .. versionadded:: 0.6
- """
- if not args:
- return current_app.response_class()
- if len(args) == 1:
- args = args[0]
- return current_app.make_response(args)
-
-
-def url_for(endpoint, **values):
- """Generates a URL to the given endpoint with the method provided.
-
- Variable arguments that are unknown to the target endpoint are appended
- to the generated URL as query arguments. If the value of a query argument
- is ``None``, the whole pair is skipped. In case blueprints are active
- you can shortcut references to the same blueprint by prefixing the
- local endpoint with a dot (``.``).
-
- This will reference the index function local to the current blueprint::
-
- url_for('.index')
-
- For more information, head over to the :ref:`Quickstart `.
-
- Configuration values ``APPLICATION_ROOT`` and ``SERVER_NAME`` are only used when
- generating URLs outside of a request context.
-
- To integrate applications, :class:`Flask` has a hook to intercept URL build
- errors through :attr:`Flask.url_build_error_handlers`. The `url_for`
- function results in a :exc:`~werkzeug.routing.BuildError` when the current
- app does not have a URL for the given endpoint and values. When it does, the
- :data:`~flask.current_app` calls its :attr:`~Flask.url_build_error_handlers` if
- it is not ``None``, which can return a string to use as the result of
- `url_for` (instead of `url_for`'s default to raise the
- :exc:`~werkzeug.routing.BuildError` exception) or re-raise the exception.
- An example::
-
- def external_url_handler(error, endpoint, values):
- "Looks up an external URL when `url_for` cannot build a URL."
- # This is an example of hooking the build_error_handler.
- # Here, lookup_url is some utility function you've built
- # which looks up the endpoint in some external URL registry.
- url = lookup_url(endpoint, **values)
- if url is None:
- # External lookup did not have a URL.
- # Re-raise the BuildError, in context of original traceback.
- exc_type, exc_value, tb = sys.exc_info()
- if exc_value is error:
- raise exc_type, exc_value, tb
- else:
- raise error
- # url_for will use this result, instead of raising BuildError.
- return url
-
- app.url_build_error_handlers.append(external_url_handler)
-
- Here, `error` is the instance of :exc:`~werkzeug.routing.BuildError`, and
- `endpoint` and `values` are the arguments passed into `url_for`. Note
- that this is for building URLs outside the current application, and not for
- handling 404 NotFound errors.
-
- .. versionadded:: 0.10
- The `_scheme` parameter was added.
-
- .. versionadded:: 0.9
- The `_anchor` and `_method` parameters were added.
-
- .. versionadded:: 0.9
- Calls :meth:`Flask.handle_build_error` on
- :exc:`~werkzeug.routing.BuildError`.
-
- :param endpoint: the endpoint of the URL (name of the function)
- :param values: the variable arguments of the URL rule
- :param _external: if set to ``True``, an absolute URL is generated. Server
- address can be changed via ``SERVER_NAME`` configuration variable which
- falls back to the `Host` header, then to the IP and port of the request.
- :param _scheme: a string specifying the desired URL scheme. The `_external`
- parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default
- behavior uses the same scheme as the current request, or
- ``PREFERRED_URL_SCHEME`` from the :ref:`app configuration ` if no
- request context is available. As of Werkzeug 0.10, this also can be set
- to an empty string to build protocol-relative URLs.
- :param _anchor: if provided this is added as anchor to the URL.
- :param _method: if provided this explicitly specifies an HTTP method.
- """
- appctx = _app_ctx_stack.top
- reqctx = _request_ctx_stack.top
-
- if appctx is None:
- raise RuntimeError(
- "Attempted to generate a URL without the application context being"
- " pushed. This has to be executed when application context is"
- " available."
- )
-
- # If request specific information is available we have some extra
- # features that support "relative" URLs.
- if reqctx is not None:
- url_adapter = reqctx.url_adapter
- blueprint_name = request.blueprint
-
- if endpoint[:1] == ".":
- if blueprint_name is not None:
- endpoint = blueprint_name + endpoint
- else:
- endpoint = endpoint[1:]
-
- external = values.pop("_external", False)
-
- # Otherwise go with the url adapter from the appctx and make
- # the URLs external by default.
- else:
- url_adapter = appctx.url_adapter
-
- if url_adapter is None:
- raise RuntimeError(
- "Application was not able to create a URL adapter for request"
- " independent URL generation. You might be able to fix this by"
- " setting the SERVER_NAME config variable."
- )
-
- external = values.pop("_external", True)
-
- anchor = values.pop("_anchor", None)
- method = values.pop("_method", None)
- scheme = values.pop("_scheme", None)
- appctx.app.inject_url_defaults(endpoint, values)
-
- # This is not the best way to deal with this but currently the
- # underlying Werkzeug router does not support overriding the scheme on
- # a per build call basis.
- old_scheme = None
- if scheme is not None:
- if not external:
- raise ValueError("When specifying _scheme, _external must be True")
- old_scheme = url_adapter.url_scheme
- url_adapter.url_scheme = scheme
-
- try:
- try:
- rv = url_adapter.build(
- endpoint, values, method=method, force_external=external
- )
- finally:
- if old_scheme is not None:
- url_adapter.url_scheme = old_scheme
- except BuildError as error:
- # We need to inject the values again so that the app callback can
- # deal with that sort of stuff.
- values["_external"] = external
- values["_anchor"] = anchor
- values["_method"] = method
- values["_scheme"] = scheme
- return appctx.app.handle_url_build_error(error, endpoint, values)
-
- if anchor is not None:
- rv += "#" + url_quote(anchor)
- return rv
-
-
-def get_template_attribute(template_name, attribute):
- """Loads a macro (or variable) a template exports. This can be used to
- invoke a macro from within Python code. If you for example have a
- template named :file:`_cider.html` with the following contents:
-
- .. sourcecode:: html+jinja
-
- {% macro hello(name) %}Hello {{ name }}!{% endmacro %}
-
- You can access this from Python code like this::
-
- hello = get_template_attribute('_cider.html', 'hello')
- return hello('World')
-
- .. versionadded:: 0.2
-
- :param template_name: the name of the template
- :param attribute: the name of the variable of macro to access
- """
- return getattr(current_app.jinja_env.get_template(template_name).module, attribute)
-
-
-def flash(message, category="message"):
- """Flashes a message to the next request. In order to remove the
- flashed message from the session and to display it to the user,
- the template has to call :func:`get_flashed_messages`.
-
- .. versionchanged:: 0.3
- `category` parameter added.
-
- :param message: the message to be flashed.
- :param category: the category for the message. The following values
- are recommended: ``'message'`` for any kind of message,
- ``'error'`` for errors, ``'info'`` for information
- messages and ``'warning'`` for warnings. However any
- kind of string can be used as category.
- """
- # Original implementation:
- #
- # session.setdefault('_flashes', []).append((category, message))
- #
- # This assumed that changes made to mutable structures in the session are
- # always in sync with the session object, which is not true for session
- # implementations that use external storage for keeping their keys/values.
- flashes = session.get("_flashes", [])
- flashes.append((category, message))
- session["_flashes"] = flashes
- message_flashed.send(
- current_app._get_current_object(), message=message, category=category
- )
-
-
-def get_flashed_messages(with_categories=False, category_filter=()):
- """Pulls all flashed messages from the session and returns them.
- Further calls in the same request to the function will return
- the same messages. By default just the messages are returned,
- but when `with_categories` is set to ``True``, the return value will
- be a list of tuples in the form ``(category, message)`` instead.
-
- Filter the flashed messages to one or more categories by providing those
- categories in `category_filter`. This allows rendering categories in
- separate html blocks. The `with_categories` and `category_filter`
- arguments are distinct:
-
- * `with_categories` controls whether categories are returned with message
- text (``True`` gives a tuple, where ``False`` gives just the message text).
- * `category_filter` filters the messages down to only those matching the
- provided categories.
-
- See :ref:`message-flashing-pattern` for examples.
-
- .. versionchanged:: 0.3
- `with_categories` parameter added.
-
- .. versionchanged:: 0.9
- `category_filter` parameter added.
-
- :param with_categories: set to ``True`` to also receive categories.
- :param category_filter: whitelist of categories to limit return values
- """
- flashes = _request_ctx_stack.top.flashes
- if flashes is None:
- _request_ctx_stack.top.flashes = flashes = (
- session.pop("_flashes") if "_flashes" in session else []
- )
- if category_filter:
- flashes = list(filter(lambda f: f[0] in category_filter, flashes))
- if not with_categories:
- return [x[1] for x in flashes]
- return flashes
-
-
-def send_file(
- filename_or_fp,
- mimetype=None,
- as_attachment=False,
- attachment_filename=None,
- add_etags=True,
- cache_timeout=None,
- conditional=False,
- last_modified=None,
-):
- """Sends the contents of a file to the client. This will use the
- most efficient method available and configured. By default it will
- try to use the WSGI server's file_wrapper support. Alternatively
- you can set the application's :attr:`~Flask.use_x_sendfile` attribute
- to ``True`` to directly emit an ``X-Sendfile`` header. This however
- requires support of the underlying webserver for ``X-Sendfile``.
-
- By default it will try to guess the mimetype for you, but you can
- also explicitly provide one. For extra security you probably want
- to send certain files as attachment (HTML for instance). The mimetype
- guessing requires a `filename` or an `attachment_filename` to be
- provided.
-
- ETags will also be attached automatically if a `filename` is provided. You
- can turn this off by setting `add_etags=False`.
-
- If `conditional=True` and `filename` is provided, this method will try to
- upgrade the response stream to support range requests. This will allow
- the request to be answered with partial content response.
-
- Please never pass filenames to this function from user sources;
- you should use :func:`send_from_directory` instead.
-
- .. versionadded:: 0.2
-
- .. versionadded:: 0.5
- The `add_etags`, `cache_timeout` and `conditional` parameters were
- added. The default behavior is now to attach etags.
-
- .. versionchanged:: 0.7
- mimetype guessing and etag support for file objects was
- deprecated because it was unreliable. Pass a filename if you are
- able to, otherwise attach an etag yourself. This functionality
- will be removed in Flask 1.0
-
- .. versionchanged:: 0.9
- cache_timeout pulls its default from application config, when None.
-
- .. versionchanged:: 0.12
- The filename is no longer automatically inferred from file objects. If
- you want to use automatic mimetype and etag support, pass a filepath via
- `filename_or_fp` or `attachment_filename`.
-
- .. versionchanged:: 0.12
- The `attachment_filename` is preferred over `filename` for MIME-type
- detection.
-
- .. versionchanged:: 1.0
- UTF-8 filenames, as specified in `RFC 2231`_, are supported.
-
- .. _RFC 2231: https://tools.ietf.org/html/rfc2231#section-4
-
- .. versionchanged:: 1.0.3
- Filenames are encoded with ASCII instead of Latin-1 for broader
- compatibility with WSGI servers.
-
- .. versionchanged:: 1.1
- Filename may be a :class:`~os.PathLike` object.
-
- .. versionadded:: 1.1
- Partial content supports :class:`~io.BytesIO`.
-
- :param filename_or_fp: the filename of the file to send.
- This is relative to the :attr:`~Flask.root_path`
- if a relative path is specified.
- Alternatively a file object might be provided in
- which case ``X-Sendfile`` might not work and fall
- back to the traditional method. Make sure that the
- file pointer is positioned at the start of data to
- send before calling :func:`send_file`.
- :param mimetype: the mimetype of the file if provided. If a file path is
- given, auto detection happens as fallback, otherwise an
- error will be raised.
- :param as_attachment: set to ``True`` if you want to send this file with
- a ``Content-Disposition: attachment`` header.
- :param attachment_filename: the filename for the attachment if it
- differs from the file's filename.
- :param add_etags: set to ``False`` to disable attaching of etags.
- :param conditional: set to ``True`` to enable conditional responses.
-
- :param cache_timeout: the timeout in seconds for the headers. When ``None``
- (default), this value is set by
- :meth:`~Flask.get_send_file_max_age` of
- :data:`~flask.current_app`.
- :param last_modified: set the ``Last-Modified`` header to this value,
- a :class:`~datetime.datetime` or timestamp.
- If a file was passed, this overrides its mtime.
- """
- mtime = None
- fsize = None
-
- if hasattr(filename_or_fp, "__fspath__"):
- filename_or_fp = fspath(filename_or_fp)
-
- if isinstance(filename_or_fp, string_types):
- filename = filename_or_fp
- if not os.path.isabs(filename):
- filename = os.path.join(current_app.root_path, filename)
- file = None
- if attachment_filename is None:
- attachment_filename = os.path.basename(filename)
- else:
- file = filename_or_fp
- filename = None
-
- if mimetype is None:
- if attachment_filename is not None:
- mimetype = (
- mimetypes.guess_type(attachment_filename)[0]
- or "application/octet-stream"
- )
-
- if mimetype is None:
- raise ValueError(
- "Unable to infer MIME-type because no filename is available. "
- "Please set either `attachment_filename`, pass a filepath to "
- "`filename_or_fp` or set your own MIME-type via `mimetype`."
- )
-
- headers = Headers()
- if as_attachment:
- if attachment_filename is None:
- raise TypeError("filename unavailable, required for sending as attachment")
-
- if not isinstance(attachment_filename, text_type):
- attachment_filename = attachment_filename.decode("utf-8")
-
- try:
- attachment_filename = attachment_filename.encode("ascii")
- except UnicodeEncodeError:
- filenames = {
- "filename": unicodedata.normalize("NFKD", attachment_filename).encode(
- "ascii", "ignore"
- ),
- "filename*": "UTF-8''%s" % url_quote(attachment_filename, safe=b""),
- }
- else:
- filenames = {"filename": attachment_filename}
-
- headers.add("Content-Disposition", "attachment", **filenames)
-
- if current_app.use_x_sendfile and filename:
- if file is not None:
- file.close()
- headers["X-Sendfile"] = filename
- fsize = os.path.getsize(filename)
- headers["Content-Length"] = fsize
- data = None
- else:
- if file is None:
- file = open(filename, "rb")
- mtime = os.path.getmtime(filename)
- fsize = os.path.getsize(filename)
- headers["Content-Length"] = fsize
- elif isinstance(file, io.BytesIO):
- try:
- fsize = file.getbuffer().nbytes
- except AttributeError:
- # Python 2 doesn't have getbuffer
- fsize = len(file.getvalue())
- headers["Content-Length"] = fsize
- data = wrap_file(request.environ, file)
-
- rv = current_app.response_class(
- data, mimetype=mimetype, headers=headers, direct_passthrough=True
- )
-
- if last_modified is not None:
- rv.last_modified = last_modified
- elif mtime is not None:
- rv.last_modified = mtime
-
- rv.cache_control.public = True
- if cache_timeout is None:
- cache_timeout = current_app.get_send_file_max_age(filename)
- if cache_timeout is not None:
- rv.cache_control.max_age = cache_timeout
- rv.expires = int(time() + cache_timeout)
-
- if add_etags and filename is not None:
- from warnings import warn
-
- try:
- rv.set_etag(
- "%s-%s-%s"
- % (
- os.path.getmtime(filename),
- os.path.getsize(filename),
- adler32(
- filename.encode("utf-8")
- if isinstance(filename, text_type)
- else filename
- )
- & 0xFFFFFFFF,
- )
- )
- except OSError:
- warn(
- "Access %s failed, maybe it does not exist, so ignore etags in "
- "headers" % filename,
- stacklevel=2,
- )
-
- if conditional:
- try:
- rv = rv.make_conditional(request, accept_ranges=True, complete_length=fsize)
- except RequestedRangeNotSatisfiable:
- if file is not None:
- file.close()
- raise
- # make sure we don't send x-sendfile for servers that
- # ignore the 304 status code for x-sendfile.
- if rv.status_code == 304:
- rv.headers.pop("x-sendfile", None)
- return rv
-
-
-def safe_join(directory, *pathnames):
- """Safely join `directory` and zero or more untrusted `pathnames`
- components.
-
- Example usage::
-
- @app.route('/wiki/')
- def wiki_page(filename):
- filename = safe_join(app.config['WIKI_FOLDER'], filename)
- with open(filename, 'rb') as fd:
- content = fd.read() # Read and process the file content...
-
- :param directory: the trusted base directory.
- :param pathnames: the untrusted pathnames relative to that directory.
- :raises: :class:`~werkzeug.exceptions.NotFound` if one or more passed
- paths fall out of its boundaries.
- """
-
- parts = [directory]
-
- for filename in pathnames:
- if filename != "":
- filename = posixpath.normpath(filename)
-
- if (
- any(sep in filename for sep in _os_alt_seps)
- or os.path.isabs(filename)
- or filename == ".."
- or filename.startswith("../")
- ):
- raise NotFound()
-
- parts.append(filename)
-
- return posixpath.join(*parts)
-
-
-def send_from_directory(directory, filename, **options):
- """Send a file from a given directory with :func:`send_file`. This
- is a secure way to quickly expose static files from an upload folder
- or something similar.
-
- Example usage::
-
- @app.route('/uploads/')
- def download_file(filename):
- return send_from_directory(app.config['UPLOAD_FOLDER'],
- filename, as_attachment=True)
-
- .. admonition:: Sending files and Performance
-
- It is strongly recommended to activate either ``X-Sendfile`` support in
- your webserver or (if no authentication happens) to tell the webserver
- to serve files for the given path on its own without calling into the
- web application for improved performance.
-
- .. versionadded:: 0.5
-
- :param directory: the directory where all the files are stored.
- :param filename: the filename relative to that directory to
- download.
- :param options: optional keyword arguments that are directly
- forwarded to :func:`send_file`.
- """
- filename = fspath(filename)
- directory = fspath(directory)
- filename = safe_join(directory, filename)
- if not os.path.isabs(filename):
- filename = os.path.join(current_app.root_path, filename)
- try:
- if not os.path.isfile(filename):
- raise NotFound()
- except (TypeError, ValueError):
- raise BadRequest()
- options.setdefault("conditional", True)
- return send_file(filename, **options)
-
-
-def get_root_path(import_name):
- """Returns the path to a package or cwd if that cannot be found. This
- returns the path of a package or the folder that contains a module.
-
- Not to be confused with the package path returned by :func:`find_package`.
- """
- # Module already imported and has a file attribute. Use that first.
- mod = sys.modules.get(import_name)
- if mod is not None and hasattr(mod, "__file__"):
- return os.path.dirname(os.path.abspath(mod.__file__))
-
- # Next attempt: check the loader.
- loader = pkgutil.get_loader(import_name)
-
- # Loader does not exist or we're referring to an unloaded main module
- # or a main module without path (interactive sessions), go with the
- # current working directory.
- if loader is None or import_name == "__main__":
- return os.getcwd()
-
- # For .egg, zipimporter does not have get_filename until Python 2.7.
- # Some other loaders might exhibit the same behavior.
- if hasattr(loader, "get_filename"):
- filepath = loader.get_filename(import_name)
- else:
- # Fall back to imports.
- __import__(import_name)
- mod = sys.modules[import_name]
- filepath = getattr(mod, "__file__", None)
-
- # If we don't have a filepath it might be because we are a
- # namespace package. In this case we pick the root path from the
- # first module that is contained in our package.
- if filepath is None:
- raise RuntimeError(
- "No root path can be found for the provided "
- 'module "%s". This can happen because the '
- "module came from an import hook that does "
- "not provide file name information or because "
- "it's a namespace package. In this case "
- "the root path needs to be explicitly "
- "provided." % import_name
- )
-
- # filepath is import_name.py for a module, or __init__.py for a package.
- return os.path.dirname(os.path.abspath(filepath))
-
-
-def _matching_loader_thinks_module_is_package(loader, mod_name):
- """Given the loader that loaded a module and the module this function
- attempts to figure out if the given module is actually a package.
- """
- # If the loader can tell us if something is a package, we can
- # directly ask the loader.
- if hasattr(loader, "is_package"):
- return loader.is_package(mod_name)
- # importlib's namespace loaders do not have this functionality but
- # all the modules it loads are packages, so we can take advantage of
- # this information.
- elif (
- loader.__class__.__module__ == "_frozen_importlib"
- and loader.__class__.__name__ == "NamespaceLoader"
- ):
- return True
- # Otherwise we need to fail with an error that explains what went
- # wrong.
- raise AttributeError(
- (
- "%s.is_package() method is missing but is required by Flask of "
- "PEP 302 import hooks. If you do not use import hooks and "
- "you encounter this error please file a bug against Flask."
- )
- % loader.__class__.__name__
- )
-
-
-def _find_package_path(root_mod_name):
- """Find the path where the module's root exists in"""
- if sys.version_info >= (3, 4):
- import importlib.util
-
- try:
- spec = importlib.util.find_spec(root_mod_name)
- if spec is None:
- raise ValueError("not found")
- # ImportError: the machinery told us it does not exist
- # ValueError:
- # - the module name was invalid
- # - the module name is __main__
- # - *we* raised `ValueError` due to `spec` being `None`
- except (ImportError, ValueError):
- pass # handled below
- else:
- # namespace package
- if spec.origin in {"namespace", None}:
- return os.path.dirname(next(iter(spec.submodule_search_locations)))
- # a package (with __init__.py)
- elif spec.submodule_search_locations:
- return os.path.dirname(os.path.dirname(spec.origin))
- # just a normal module
- else:
- return os.path.dirname(spec.origin)
-
- # we were unable to find the `package_path` using PEP 451 loaders
- loader = pkgutil.get_loader(root_mod_name)
- if loader is None or root_mod_name == "__main__":
- # import name is not found, or interactive/main module
- return os.getcwd()
- else:
- # For .egg, zipimporter does not have get_filename until Python 2.7.
- if hasattr(loader, "get_filename"):
- filename = loader.get_filename(root_mod_name)
- elif hasattr(loader, "archive"):
- # zipimporter's loader.archive points to the .egg or .zip
- # archive filename is dropped in call to dirname below.
- filename = loader.archive
- else:
- # At least one loader is missing both get_filename and archive:
- # Google App Engine's HardenedModulesHook
- #
- # Fall back to imports.
- __import__(root_mod_name)
- filename = sys.modules[root_mod_name].__file__
- package_path = os.path.abspath(os.path.dirname(filename))
-
- # In case the root module is a package we need to chop of the
- # rightmost part. This needs to go through a helper function
- # because of python 3.3 namespace packages.
- if _matching_loader_thinks_module_is_package(loader, root_mod_name):
- package_path = os.path.dirname(package_path)
-
- return package_path
-
-
-def find_package(import_name):
- """Finds a package and returns the prefix (or None if the package is
- not installed) as well as the folder that contains the package or
- module as a tuple. The package path returned is the module that would
- have to be added to the pythonpath in order to make it possible to
- import the module. The prefix is the path below which a UNIX like
- folder structure exists (lib, share etc.).
- """
- root_mod_name, _, _ = import_name.partition(".")
- package_path = _find_package_path(root_mod_name)
- site_parent, site_folder = os.path.split(package_path)
- py_prefix = os.path.abspath(sys.prefix)
- if package_path.startswith(py_prefix):
- return py_prefix, package_path
- elif site_folder.lower() == "site-packages":
- parent, folder = os.path.split(site_parent)
- # Windows like installations
- if folder.lower() == "lib":
- base_dir = parent
- # UNIX like installations
- elif os.path.basename(parent).lower() == "lib":
- base_dir = os.path.dirname(parent)
- else:
- base_dir = site_parent
- return base_dir, package_path
- return None, package_path
-
-
-class locked_cached_property(object):
- """A decorator that converts a function into a lazy property. The
- function wrapped is called the first time to retrieve the result
- and then that calculated result is used the next time you access
- the value. Works like the one in Werkzeug but has a lock for
- thread safety.
- """
-
- def __init__(self, func, name=None, doc=None):
- self.__name__ = name or func.__name__
- self.__module__ = func.__module__
- self.__doc__ = doc or func.__doc__
- self.func = func
- self.lock = RLock()
-
- def __get__(self, obj, type=None):
- if obj is None:
- return self
- with self.lock:
- value = obj.__dict__.get(self.__name__, _missing)
- if value is _missing:
- value = self.func(obj)
- obj.__dict__[self.__name__] = value
- return value
-
-
-class _PackageBoundObject(object):
- #: The name of the package or module that this app belongs to. Do not
- #: change this once it is set by the constructor.
- import_name = None
-
- #: Location of the template files to be added to the template lookup.
- #: ``None`` if templates should not be added.
- template_folder = None
-
- #: Absolute path to the package on the filesystem. Used to look up
- #: resources contained in the package.
- root_path = None
-
- def __init__(self, import_name, template_folder=None, root_path=None):
- self.import_name = import_name
- self.template_folder = template_folder
-
- if root_path is None:
- root_path = get_root_path(self.import_name)
-
- self.root_path = root_path
- self._static_folder = None
- self._static_url_path = None
-
- # circular import
- from .cli import AppGroup
-
- #: The Click command group for registration of CLI commands
- #: on the application and associated blueprints. These commands
- #: are accessible via the :command:`flask` command once the
- #: application has been discovered and blueprints registered.
- self.cli = AppGroup()
-
- @property
- def static_folder(self):
- """The absolute path to the configured static folder."""
- if self._static_folder is not None:
- return os.path.join(self.root_path, self._static_folder)
-
- @static_folder.setter
- def static_folder(self, value):
- self._static_folder = value
-
- @property
- def static_url_path(self):
- """The URL prefix that the static route will be accessible from.
-
- If it was not configured during init, it is derived from
- :attr:`static_folder`.
- """
- if self._static_url_path is not None:
- return self._static_url_path
-
- if self.static_folder is not None:
- basename = os.path.basename(self.static_folder)
- return ("/" + basename).rstrip("/")
-
- @static_url_path.setter
- def static_url_path(self, value):
- if value is not None:
- value = value.rstrip("/")
-
- self._static_url_path = value
-
- @property
- def has_static_folder(self):
- """This is ``True`` if the package bound object's container has a
- folder for static files.
-
- .. versionadded:: 0.5
- """
- return self.static_folder is not None
-
- @locked_cached_property
- def jinja_loader(self):
- """The Jinja loader for this package bound object.
-
- .. versionadded:: 0.5
- """
- if self.template_folder is not None:
- return FileSystemLoader(os.path.join(self.root_path, self.template_folder))
-
- def get_send_file_max_age(self, filename):
- """Provides default cache_timeout for the :func:`send_file` functions.
-
- By default, this function returns ``SEND_FILE_MAX_AGE_DEFAULT`` from
- the configuration of :data:`~flask.current_app`.
-
- Static file functions such as :func:`send_from_directory` use this
- function, and :func:`send_file` calls this function on
- :data:`~flask.current_app` when the given cache_timeout is ``None``. If a
- cache_timeout is given in :func:`send_file`, that timeout is used;
- otherwise, this method is called.
-
- This allows subclasses to change the behavior when sending files based
- on the filename. For example, to set the cache timeout for .js files
- to 60 seconds::
-
- class MyFlask(flask.Flask):
- def get_send_file_max_age(self, name):
- if name.lower().endswith('.js'):
- return 60
- return flask.Flask.get_send_file_max_age(self, name)
-
- .. versionadded:: 0.9
- """
- return total_seconds(current_app.send_file_max_age_default)
-
- def send_static_file(self, filename):
- """Function used internally to send static files from the static
- folder to the browser.
-
- .. versionadded:: 0.5
- """
- if not self.has_static_folder:
- raise RuntimeError("No static folder for this object")
- # Ensure get_send_file_max_age is called in all cases.
- # Here, we ensure get_send_file_max_age is called for Blueprints.
- cache_timeout = self.get_send_file_max_age(filename)
- return send_from_directory(
- self.static_folder, filename, cache_timeout=cache_timeout
- )
-
- def open_resource(self, resource, mode="rb"):
- """Opens a resource from the application's resource folder. To see
- how this works, consider the following folder structure::
-
- /myapplication.py
- /schema.sql
- /static
- /style.css
- /templates
- /layout.html
- /index.html
-
- If you want to open the :file:`schema.sql` file you would do the
- following::
-
- with app.open_resource('schema.sql') as f:
- contents = f.read()
- do_something_with(contents)
-
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: Open file in this mode. Only reading is supported,
- valid values are "r" (or "rt") and "rb".
- """
- if mode not in {"r", "rt", "rb"}:
- raise ValueError("Resources can only be opened for reading")
-
- return open(os.path.join(self.root_path, resource), mode)
-
-
-def total_seconds(td):
- """Returns the total seconds from a timedelta object.
-
- :param timedelta td: the timedelta to be converted in seconds
-
- :returns: number of seconds
- :rtype: int
- """
- return td.days * 60 * 60 * 24 + td.seconds
-
-
-def is_ip(value):
- """Determine if the given string is an IP address.
-
- Python 2 on Windows doesn't provide ``inet_pton``, so this only
- checks IPv4 addresses in that environment.
-
- :param value: value to check
- :type value: str
-
- :return: True if string is an IP address
- :rtype: bool
- """
- if PY2 and os.name == "nt":
- try:
- socket.inet_aton(value)
- return True
- except socket.error:
- return False
-
- for family in (socket.AF_INET, socket.AF_INET6):
- try:
- socket.inet_pton(family, value)
- except socket.error:
- pass
- else:
- return True
-
- return False
diff --git a/server/venv/lib/python3.7/site-packages/flask/json/__init__.py b/server/venv/lib/python3.7/site-packages/flask/json/__init__.py
deleted file mode 100644
index a141068..0000000
--- a/server/venv/lib/python3.7/site-packages/flask/json/__init__.py
+++ /dev/null
@@ -1,376 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-flask.json
-~~~~~~~~~~
-
-:copyright: 2010 Pallets
-:license: BSD-3-Clause
-"""
-import codecs
-import io
-import uuid
-from datetime import date
-from datetime import datetime
-
-from itsdangerous import json as _json
-from jinja2 import Markup
-from werkzeug.http import http_date
-
-from .._compat import PY2
-from .._compat import text_type
-from ..globals import current_app
-from ..globals import request
-
-try:
- import dataclasses
-except ImportError:
- dataclasses = None
-
-# Figure out if simplejson escapes slashes. This behavior was changed
-# from one version to another without reason.
-_slash_escape = "\\/" not in _json.dumps("/")
-
-
-__all__ = [
- "dump",
- "dumps",
- "load",
- "loads",
- "htmlsafe_dump",
- "htmlsafe_dumps",
- "JSONDecoder",
- "JSONEncoder",
- "jsonify",
-]
-
-
-def _wrap_reader_for_text(fp, encoding):
- if isinstance(fp.read(0), bytes):
- fp = io.TextIOWrapper(io.BufferedReader(fp), encoding)
- return fp
-
-
-def _wrap_writer_for_text(fp, encoding):
- try:
- fp.write("")
- except TypeError:
- fp = io.TextIOWrapper(fp, encoding)
- return fp
-
-
-class JSONEncoder(_json.JSONEncoder):
- """The default Flask JSON encoder. This one extends the default
- encoder by also supporting ``datetime``, ``UUID``, ``dataclasses``,
- and ``Markup`` objects.
-
- ``datetime`` objects are serialized as RFC 822 datetime strings.
- This is the same as the HTTP date format.
-
- In order to support more data types, override the :meth:`default`
- method.
- """
-
- def default(self, o):
- """Implement this method in a subclass such that it returns a
- serializable object for ``o``, or calls the base implementation (to
- raise a :exc:`TypeError`).
-
- For example, to support arbitrary iterators, you could implement
- default like this::
-
- def default(self, o):
- try:
- iterable = iter(o)
- except TypeError:
- pass
- else:
- return list(iterable)
- return JSONEncoder.default(self, o)
- """
- if isinstance(o, datetime):
- return http_date(o.utctimetuple())
- if isinstance(o, date):
- return http_date(o.timetuple())
- if isinstance(o, uuid.UUID):
- return str(o)
- if dataclasses and dataclasses.is_dataclass(o):
- return dataclasses.asdict(o)
- if hasattr(o, "__html__"):
- return text_type(o.__html__())
- return _json.JSONEncoder.default(self, o)
-
-
-class JSONDecoder(_json.JSONDecoder):
- """The default JSON decoder. This one does not change the behavior from
- the default simplejson decoder. Consult the :mod:`json` documentation
- for more information. This decoder is not only used for the load
- functions of this module but also :attr:`~flask.Request`.
- """
-
-
-def _dump_arg_defaults(kwargs, app=None):
- """Inject default arguments for dump functions."""
- if app is None:
- app = current_app
-
- if app:
- bp = app.blueprints.get(request.blueprint) if request else None
- kwargs.setdefault(
- "cls", bp.json_encoder if bp and bp.json_encoder else app.json_encoder
- )
-
- if not app.config["JSON_AS_ASCII"]:
- kwargs.setdefault("ensure_ascii", False)
-
- kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"])
- else:
- kwargs.setdefault("sort_keys", True)
- kwargs.setdefault("cls", JSONEncoder)
-
-
-def _load_arg_defaults(kwargs, app=None):
- """Inject default arguments for load functions."""
- if app is None:
- app = current_app
-
- if app:
- bp = app.blueprints.get(request.blueprint) if request else None
- kwargs.setdefault(
- "cls", bp.json_decoder if bp and bp.json_decoder else app.json_decoder
- )
- else:
- kwargs.setdefault("cls", JSONDecoder)
-
-
-def detect_encoding(data):
- """Detect which UTF codec was used to encode the given bytes.
-
- The latest JSON standard (:rfc:`8259`) suggests that only UTF-8 is
- accepted. Older documents allowed 8, 16, or 32. 16 and 32 can be big
- or little endian. Some editors or libraries may prepend a BOM.
-
- :param data: Bytes in unknown UTF encoding.
- :return: UTF encoding name
- """
- head = data[:4]
-
- if head[:3] == codecs.BOM_UTF8:
- return "utf-8-sig"
-
- if b"\x00" not in head:
- return "utf-8"
-
- if head in (codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE):
- return "utf-32"
-
- if head[:2] in (codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE):
- return "utf-16"
-
- if len(head) == 4:
- if head[:3] == b"\x00\x00\x00":
- return "utf-32-be"
-
- if head[::2] == b"\x00\x00":
- return "utf-16-be"
-
- if head[1:] == b"\x00\x00\x00":
- return "utf-32-le"
-
- if head[1::2] == b"\x00\x00":
- return "utf-16-le"
-
- if len(head) == 2:
- return "utf-16-be" if head.startswith(b"\x00") else "utf-16-le"
-
- return "utf-8"
-
-
-def dumps(obj, app=None, **kwargs):
- """Serialize ``obj`` to a JSON-formatted string. If there is an
- app context pushed, use the current app's configured encoder
- (:attr:`~flask.Flask.json_encoder`), or fall back to the default
- :class:`JSONEncoder`.
-
- Takes the same arguments as the built-in :func:`json.dumps`, and
- does some extra configuration based on the application. If the
- simplejson package is installed, it is preferred.
-
- :param obj: Object to serialize to JSON.
- :param app: App instance to use to configure the JSON encoder.
- Uses ``current_app`` if not given, and falls back to the default
- encoder when not in an app context.
- :param kwargs: Extra arguments passed to :func:`json.dumps`.
-
- .. versionchanged:: 1.0.3
-
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
- rv = _json.dumps(obj, **kwargs)
- if encoding is not None and isinstance(rv, text_type):
- rv = rv.encode(encoding)
- return rv
-
-
-def dump(obj, fp, app=None, **kwargs):
- """Like :func:`dumps` but writes into a file object."""
- _dump_arg_defaults(kwargs, app=app)
- encoding = kwargs.pop("encoding", None)
- if encoding is not None:
- fp = _wrap_writer_for_text(fp, encoding)
- _json.dump(obj, fp, **kwargs)
-
-
-def loads(s, app=None, **kwargs):
- """Deserialize an object from a JSON-formatted string ``s``. If
- there is an app context pushed, use the current app's configured
- decoder (:attr:`~flask.Flask.json_decoder`), or fall back to the
- default :class:`JSONDecoder`.
-
- Takes the same arguments as the built-in :func:`json.loads`, and
- does some extra configuration based on the application. If the
- simplejson package is installed, it is preferred.
-
- :param s: JSON string to deserialize.
- :param app: App instance to use to configure the JSON decoder.
- Uses ``current_app`` if not given, and falls back to the default
- encoder when not in an app context.
- :param kwargs: Extra arguments passed to :func:`json.dumps`.
-
- .. versionchanged:: 1.0.3
-
- ``app`` can be passed directly, rather than requiring an app
- context for configuration.
- """
- _load_arg_defaults(kwargs, app=app)
- if isinstance(s, bytes):
- encoding = kwargs.pop("encoding", None)
- if encoding is None:
- encoding = detect_encoding(s)
- s = s.decode(encoding)
- return _json.loads(s, **kwargs)
-
-
-def load(fp, app=None, **kwargs):
- """Like :func:`loads` but reads from a file object."""
- _load_arg_defaults(kwargs, app=app)
- if not PY2:
- fp = _wrap_reader_for_text(fp, kwargs.pop("encoding", None) or "utf-8")
- return _json.load(fp, **kwargs)
-
-
-def htmlsafe_dumps(obj, **kwargs):
- """Works exactly like :func:`dumps` but is safe for use in ``
-"""
-
-
-# Style definitions for the HTML template
-STYLE_INCLUDE = """
-
-"""
-
-
-# HTML template for HTMLWriter
-DISPLAY_TEMPLATE = """
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-"""
-
-
-INCLUDED_FRAMES = """
- for (var i=0; i<{Nframes}; i++){{
- frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) +
- ".{frame_format}";
- }}
-"""
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_cm.py b/server/venv/lib/python3.7/site-packages/matplotlib/_cm.py
deleted file mode 100644
index 4de5e7c..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_cm.py
+++ /dev/null
@@ -1,1426 +0,0 @@
-"""
-Nothing here but dictionaries for generating LinearSegmentedColormaps,
-and a dictionary of these dictionaries.
-
-Documentation for each is in pyplot.colormaps(). Please update this
-with the purpose and type of your colormap if you add data for one here.
-"""
-
-from functools import partial
-
-import numpy as np
-
-_binary_data = {
- 'red': ((0., 1., 1.), (1., 0., 0.)),
- 'green': ((0., 1., 1.), (1., 0., 0.)),
- 'blue': ((0., 1., 1.), (1., 0., 0.))
- }
-
-_autumn_data = {'red': ((0., 1.0, 1.0), (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
- 'blue': ((0., 0., 0.), (1.0, 0., 0.))}
-
-_bone_data = {'red': ((0., 0., 0.),
- (0.746032, 0.652778, 0.652778),
- (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.),
- (0.365079, 0.319444, 0.319444),
- (0.746032, 0.777778, 0.777778),
- (1.0, 1.0, 1.0)),
- 'blue': ((0., 0., 0.),
- (0.365079, 0.444444, 0.444444),
- (1.0, 1.0, 1.0))}
-
-_cool_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)),
- 'green': ((0., 1., 1.), (1.0, 0., 0.)),
- 'blue': ((0., 1., 1.), (1.0, 1., 1.))}
-
-_copper_data = {'red': ((0., 0., 0.),
- (0.809524, 1.000000, 1.000000),
- (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.),
- (1.0, 0.7812, 0.7812)),
- 'blue': ((0., 0., 0.),
- (1.0, 0.4975, 0.4975))}
-
-def _flag_red(x): return 0.75 * np.sin((x * 31.5 + 0.25) * np.pi) + 0.5
-def _flag_green(x): return np.sin(x * 31.5 * np.pi)
-def _flag_blue(x): return 0.75 * np.sin((x * 31.5 - 0.25) * np.pi) + 0.5
-_flag_data = {'red': _flag_red, 'green': _flag_green, 'blue': _flag_blue}
-
-def _prism_red(x): return 0.75 * np.sin((x * 20.9 + 0.25) * np.pi) + 0.67
-def _prism_green(x): return 0.75 * np.sin((x * 20.9 - 0.25) * np.pi) + 0.33
-def _prism_blue(x): return -1.1 * np.sin((x * 20.9) * np.pi)
-_prism_data = {'red': _prism_red, 'green': _prism_green, 'blue': _prism_blue}
-
-def _ch_helper(gamma, s, r, h, p0, p1, x):
- """Helper function for generating picklable cubehelix color maps."""
- # Apply gamma factor to emphasise low or high intensity values
- xg = x ** gamma
- # Calculate amplitude and angle of deviation from the black to white
- # diagonal in the plane of constant perceived intensity.
- a = h * xg * (1 - xg) / 2
- phi = 2 * np.pi * (s / 3 + r * x)
- return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi))
-
-def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0):
- """
- Return custom data dictionary of (r,g,b) conversion functions, which can be
- used with :func:`register_cmap`, for the cubehelix color scheme.
-
- Unlike most other color schemes cubehelix was designed by D.A. Green to
- be monotonically increasing in terms of perceived brightness.
- Also, when printed on a black and white postscript printer, the scheme
- results in a greyscale with monotonically increasing brightness.
- This color scheme is named cubehelix because the r,g,b values produced
- can be visualised as a squashed helix around the diagonal in the
- r,g,b color cube.
-
- For a unit color cube (i.e. 3-D coordinates for r,g,b each in the
- range 0 to 1) the color scheme starts at (r,g,b) = (0,0,0), i.e. black,
- and finishes at (r,g,b) = (1,1,1), i.e. white. For some fraction *x*,
- between 0 and 1, the color is the corresponding grey value at that
- fraction along the black to white diagonal (x,x,x) plus a color
- element. This color element is calculated in a plane of constant
- perceived intensity and controlled by the following parameters.
-
- Optional keyword arguments:
-
- ========= =======================================================
- Keyword Description
- ========= =======================================================
- gamma gamma factor to emphasise either low intensity values
- (gamma < 1), or high intensity values (gamma > 1);
- defaults to 1.0.
- s the start color; defaults to 0.5 (i.e. purple).
- r the number of r,g,b rotations in color that are made
- from the start to the end of the color scheme; defaults
- to -1.5 (i.e. -> B -> G -> R -> B).
- h the hue parameter which controls how saturated the
- colors are. If this parameter is zero then the color
- scheme is purely a greyscale; defaults to 1.0.
- ========= =======================================================
- """
- return {'red': partial(_ch_helper, gamma, s, r, h, -0.14861, 1.78277),
- 'green': partial(_ch_helper, gamma, s, r, h, -0.29227, -0.90649),
- 'blue': partial(_ch_helper, gamma, s, r, h, 1.97294, 0.0)}
-
-_cubehelix_data = cubehelix()
-
-_bwr_data = ((0.0, 0.0, 1.0), (1.0, 1.0, 1.0), (1.0, 0.0, 0.0))
-_brg_data = ((0.0, 0.0, 1.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0))
-
-# Gnuplot palette functions
-def _g0(x): return 0
-def _g1(x): return 0.5
-def _g2(x): return 1
-def _g3(x): return x
-def _g4(x): return x ** 2
-def _g5(x): return x ** 3
-def _g6(x): return x ** 4
-def _g7(x): return np.sqrt(x)
-def _g8(x): return np.sqrt(np.sqrt(x))
-def _g9(x): return np.sin(x * np.pi / 2)
-def _g10(x): return np.cos(x * np.pi / 2)
-def _g11(x): return np.abs(x - 0.5)
-def _g12(x): return (2 * x - 1) ** 2
-def _g13(x): return np.sin(x * np.pi)
-def _g14(x): return np.abs(np.cos(x * np.pi))
-def _g15(x): return np.sin(x * 2 * np.pi)
-def _g16(x): return np.cos(x * 2 * np.pi)
-def _g17(x): return np.abs(np.sin(x * 2 * np.pi))
-def _g18(x): return np.abs(np.cos(x * 2 * np.pi))
-def _g19(x): return np.abs(np.sin(x * 4 * np.pi))
-def _g20(x): return np.abs(np.cos(x * 4 * np.pi))
-def _g21(x): return 3 * x
-def _g22(x): return 3 * x - 1
-def _g23(x): return 3 * x - 2
-def _g24(x): return np.abs(3 * x - 1)
-def _g25(x): return np.abs(3 * x - 2)
-def _g26(x): return (3 * x - 1) / 2
-def _g27(x): return (3 * x - 2) / 2
-def _g28(x): return np.abs((3 * x - 1) / 2)
-def _g29(x): return np.abs((3 * x - 2) / 2)
-def _g30(x): return x / 0.32 - 0.78125
-def _g31(x): return 2 * x - 0.84
-def _g32(x):
- ret = np.zeros(len(x))
- m = (x < 0.25)
- ret[m] = 4 * x[m]
- m = (x >= 0.25) & (x < 0.92)
- ret[m] = -2 * x[m] + 1.84
- m = (x >= 0.92)
- ret[m] = x[m] / 0.08 - 11.5
- return ret
-def _g33(x): return np.abs(2 * x - 0.5)
-def _g34(x): return 2 * x
-def _g35(x): return 2 * x - 0.5
-def _g36(x): return 2 * x - 1
-
-gfunc = {i: globals()["_g{}".format(i)] for i in range(37)}
-
-_gnuplot_data = {
- 'red': gfunc[7],
- 'green': gfunc[5],
- 'blue': gfunc[15],
-}
-
-_gnuplot2_data = {
- 'red': gfunc[30],
- 'green': gfunc[31],
- 'blue': gfunc[32],
-}
-
-_ocean_data = {
- 'red': gfunc[23],
- 'green': gfunc[28],
- 'blue': gfunc[3],
-}
-
-_afmhot_data = {
- 'red': gfunc[34],
- 'green': gfunc[35],
- 'blue': gfunc[36],
-}
-
-_rainbow_data = {
- 'red': gfunc[33],
- 'green': gfunc[13],
- 'blue': gfunc[10],
-}
-
-_seismic_data = (
- (0.0, 0.0, 0.3), (0.0, 0.0, 1.0),
- (1.0, 1.0, 1.0), (1.0, 0.0, 0.0),
- (0.5, 0.0, 0.0))
-
-_terrain_data = (
- (0.00, (0.2, 0.2, 0.6)),
- (0.15, (0.0, 0.6, 1.0)),
- (0.25, (0.0, 0.8, 0.4)),
- (0.50, (1.0, 1.0, 0.6)),
- (0.75, (0.5, 0.36, 0.33)),
- (1.00, (1.0, 1.0, 1.0)))
-
-_gray_data = {'red': ((0., 0, 0), (1., 1, 1)),
- 'green': ((0., 0, 0), (1., 1, 1)),
- 'blue': ((0., 0, 0), (1., 1, 1))}
-
-_hot_data = {'red': ((0., 0.0416, 0.0416),
- (0.365079, 1.000000, 1.000000),
- (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.),
- (0.365079, 0.000000, 0.000000),
- (0.746032, 1.000000, 1.000000),
- (1.0, 1.0, 1.0)),
- 'blue': ((0., 0., 0.),
- (0.746032, 0.000000, 0.000000),
- (1.0, 1.0, 1.0))}
-
-_hsv_data = {'red': ((0., 1., 1.),
- (0.158730, 1.000000, 1.000000),
- (0.174603, 0.968750, 0.968750),
- (0.333333, 0.031250, 0.031250),
- (0.349206, 0.000000, 0.000000),
- (0.666667, 0.000000, 0.000000),
- (0.682540, 0.031250, 0.031250),
- (0.841270, 0.968750, 0.968750),
- (0.857143, 1.000000, 1.000000),
- (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.),
- (0.158730, 0.937500, 0.937500),
- (0.174603, 1.000000, 1.000000),
- (0.507937, 1.000000, 1.000000),
- (0.666667, 0.062500, 0.062500),
- (0.682540, 0.000000, 0.000000),
- (1.0, 0., 0.)),
- 'blue': ((0., 0., 0.),
- (0.333333, 0.000000, 0.000000),
- (0.349206, 0.062500, 0.062500),
- (0.507937, 1.000000, 1.000000),
- (0.841270, 1.000000, 1.000000),
- (0.857143, 0.937500, 0.937500),
- (1.0, 0.09375, 0.09375))}
-
-_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1),
- (1, 0.5, 0.5)),
- 'green': ((0., 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1),
- (0.91, 0, 0), (1, 0, 0)),
- 'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1),
- (0.65, 0, 0), (1, 0, 0))}
-
-_pink_data = {'red': ((0., 0.1178, 0.1178), (0.015873, 0.195857, 0.195857),
- (0.031746, 0.250661, 0.250661),
- (0.047619, 0.295468, 0.295468),
- (0.063492, 0.334324, 0.334324),
- (0.079365, 0.369112, 0.369112),
- (0.095238, 0.400892, 0.400892),
- (0.111111, 0.430331, 0.430331),
- (0.126984, 0.457882, 0.457882),
- (0.142857, 0.483867, 0.483867),
- (0.158730, 0.508525, 0.508525),
- (0.174603, 0.532042, 0.532042),
- (0.190476, 0.554563, 0.554563),
- (0.206349, 0.576204, 0.576204),
- (0.222222, 0.597061, 0.597061),
- (0.238095, 0.617213, 0.617213),
- (0.253968, 0.636729, 0.636729),
- (0.269841, 0.655663, 0.655663),
- (0.285714, 0.674066, 0.674066),
- (0.301587, 0.691980, 0.691980),
- (0.317460, 0.709441, 0.709441),
- (0.333333, 0.726483, 0.726483),
- (0.349206, 0.743134, 0.743134),
- (0.365079, 0.759421, 0.759421),
- (0.380952, 0.766356, 0.766356),
- (0.396825, 0.773229, 0.773229),
- (0.412698, 0.780042, 0.780042),
- (0.428571, 0.786796, 0.786796),
- (0.444444, 0.793492, 0.793492),
- (0.460317, 0.800132, 0.800132),
- (0.476190, 0.806718, 0.806718),
- (0.492063, 0.813250, 0.813250),
- (0.507937, 0.819730, 0.819730),
- (0.523810, 0.826160, 0.826160),
- (0.539683, 0.832539, 0.832539),
- (0.555556, 0.838870, 0.838870),
- (0.571429, 0.845154, 0.845154),
- (0.587302, 0.851392, 0.851392),
- (0.603175, 0.857584, 0.857584),
- (0.619048, 0.863731, 0.863731),
- (0.634921, 0.869835, 0.869835),
- (0.650794, 0.875897, 0.875897),
- (0.666667, 0.881917, 0.881917),
- (0.682540, 0.887896, 0.887896),
- (0.698413, 0.893835, 0.893835),
- (0.714286, 0.899735, 0.899735),
- (0.730159, 0.905597, 0.905597),
- (0.746032, 0.911421, 0.911421),
- (0.761905, 0.917208, 0.917208),
- (0.777778, 0.922958, 0.922958),
- (0.793651, 0.928673, 0.928673),
- (0.809524, 0.934353, 0.934353),
- (0.825397, 0.939999, 0.939999),
- (0.841270, 0.945611, 0.945611),
- (0.857143, 0.951190, 0.951190),
- (0.873016, 0.956736, 0.956736),
- (0.888889, 0.962250, 0.962250),
- (0.904762, 0.967733, 0.967733),
- (0.920635, 0.973185, 0.973185),
- (0.936508, 0.978607, 0.978607),
- (0.952381, 0.983999, 0.983999),
- (0.968254, 0.989361, 0.989361),
- (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.), (0.015873, 0.102869, 0.102869),
- (0.031746, 0.145479, 0.145479),
- (0.047619, 0.178174, 0.178174),
- (0.063492, 0.205738, 0.205738),
- (0.079365, 0.230022, 0.230022),
- (0.095238, 0.251976, 0.251976),
- (0.111111, 0.272166, 0.272166),
- (0.126984, 0.290957, 0.290957),
- (0.142857, 0.308607, 0.308607),
- (0.158730, 0.325300, 0.325300),
- (0.174603, 0.341178, 0.341178),
- (0.190476, 0.356348, 0.356348),
- (0.206349, 0.370899, 0.370899),
- (0.222222, 0.384900, 0.384900),
- (0.238095, 0.398410, 0.398410),
- (0.253968, 0.411476, 0.411476),
- (0.269841, 0.424139, 0.424139),
- (0.285714, 0.436436, 0.436436),
- (0.301587, 0.448395, 0.448395),
- (0.317460, 0.460044, 0.460044),
- (0.333333, 0.471405, 0.471405),
- (0.349206, 0.482498, 0.482498),
- (0.365079, 0.493342, 0.493342),
- (0.380952, 0.517549, 0.517549),
- (0.396825, 0.540674, 0.540674),
- (0.412698, 0.562849, 0.562849),
- (0.428571, 0.584183, 0.584183),
- (0.444444, 0.604765, 0.604765),
- (0.460317, 0.624669, 0.624669),
- (0.476190, 0.643958, 0.643958),
- (0.492063, 0.662687, 0.662687),
- (0.507937, 0.680900, 0.680900),
- (0.523810, 0.698638, 0.698638),
- (0.539683, 0.715937, 0.715937),
- (0.555556, 0.732828, 0.732828),
- (0.571429, 0.749338, 0.749338),
- (0.587302, 0.765493, 0.765493),
- (0.603175, 0.781313, 0.781313),
- (0.619048, 0.796819, 0.796819),
- (0.634921, 0.812029, 0.812029),
- (0.650794, 0.826960, 0.826960),
- (0.666667, 0.841625, 0.841625),
- (0.682540, 0.856040, 0.856040),
- (0.698413, 0.870216, 0.870216),
- (0.714286, 0.884164, 0.884164),
- (0.730159, 0.897896, 0.897896),
- (0.746032, 0.911421, 0.911421),
- (0.761905, 0.917208, 0.917208),
- (0.777778, 0.922958, 0.922958),
- (0.793651, 0.928673, 0.928673),
- (0.809524, 0.934353, 0.934353),
- (0.825397, 0.939999, 0.939999),
- (0.841270, 0.945611, 0.945611),
- (0.857143, 0.951190, 0.951190),
- (0.873016, 0.956736, 0.956736),
- (0.888889, 0.962250, 0.962250),
- (0.904762, 0.967733, 0.967733),
- (0.920635, 0.973185, 0.973185),
- (0.936508, 0.978607, 0.978607),
- (0.952381, 0.983999, 0.983999),
- (0.968254, 0.989361, 0.989361),
- (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)),
- 'blue': ((0., 0., 0.), (0.015873, 0.102869, 0.102869),
- (0.031746, 0.145479, 0.145479),
- (0.047619, 0.178174, 0.178174),
- (0.063492, 0.205738, 0.205738),
- (0.079365, 0.230022, 0.230022),
- (0.095238, 0.251976, 0.251976),
- (0.111111, 0.272166, 0.272166),
- (0.126984, 0.290957, 0.290957),
- (0.142857, 0.308607, 0.308607),
- (0.158730, 0.325300, 0.325300),
- (0.174603, 0.341178, 0.341178),
- (0.190476, 0.356348, 0.356348),
- (0.206349, 0.370899, 0.370899),
- (0.222222, 0.384900, 0.384900),
- (0.238095, 0.398410, 0.398410),
- (0.253968, 0.411476, 0.411476),
- (0.269841, 0.424139, 0.424139),
- (0.285714, 0.436436, 0.436436),
- (0.301587, 0.448395, 0.448395),
- (0.317460, 0.460044, 0.460044),
- (0.333333, 0.471405, 0.471405),
- (0.349206, 0.482498, 0.482498),
- (0.365079, 0.493342, 0.493342),
- (0.380952, 0.503953, 0.503953),
- (0.396825, 0.514344, 0.514344),
- (0.412698, 0.524531, 0.524531),
- (0.428571, 0.534522, 0.534522),
- (0.444444, 0.544331, 0.544331),
- (0.460317, 0.553966, 0.553966),
- (0.476190, 0.563436, 0.563436),
- (0.492063, 0.572750, 0.572750),
- (0.507937, 0.581914, 0.581914),
- (0.523810, 0.590937, 0.590937),
- (0.539683, 0.599824, 0.599824),
- (0.555556, 0.608581, 0.608581),
- (0.571429, 0.617213, 0.617213),
- (0.587302, 0.625727, 0.625727),
- (0.603175, 0.634126, 0.634126),
- (0.619048, 0.642416, 0.642416),
- (0.634921, 0.650600, 0.650600),
- (0.650794, 0.658682, 0.658682),
- (0.666667, 0.666667, 0.666667),
- (0.682540, 0.674556, 0.674556),
- (0.698413, 0.682355, 0.682355),
- (0.714286, 0.690066, 0.690066),
- (0.730159, 0.697691, 0.697691),
- (0.746032, 0.705234, 0.705234),
- (0.761905, 0.727166, 0.727166),
- (0.777778, 0.748455, 0.748455),
- (0.793651, 0.769156, 0.769156),
- (0.809524, 0.789314, 0.789314),
- (0.825397, 0.808969, 0.808969),
- (0.841270, 0.828159, 0.828159),
- (0.857143, 0.846913, 0.846913),
- (0.873016, 0.865261, 0.865261),
- (0.888889, 0.883229, 0.883229),
- (0.904762, 0.900837, 0.900837),
- (0.920635, 0.918109, 0.918109),
- (0.936508, 0.935061, 0.935061),
- (0.952381, 0.951711, 0.951711),
- (0.968254, 0.968075, 0.968075),
- (0.984127, 0.984167, 0.984167), (1.0, 1.0, 1.0))}
-
-_spring_data = {'red': ((0., 1., 1.), (1.0, 1.0, 1.0)),
- 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
- 'blue': ((0., 1., 1.), (1.0, 0.0, 0.0))}
-
-
-_summer_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)),
- 'green': ((0., 0.5, 0.5), (1.0, 1.0, 1.0)),
- 'blue': ((0., 0.4, 0.4), (1.0, 0.4, 0.4))}
-
-
-_winter_data = {'red': ((0., 0., 0.), (1.0, 0.0, 0.0)),
- 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
- 'blue': ((0., 1., 1.), (1.0, 0.5, 0.5))}
-
-_nipy_spectral_data = {
- 'red': [(0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667),
- (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0),
- (0.20, 0.0, 0.0), (0.25, 0.0, 0.0),
- (0.30, 0.0, 0.0), (0.35, 0.0, 0.0),
- (0.40, 0.0, 0.0), (0.45, 0.0, 0.0),
- (0.50, 0.0, 0.0), (0.55, 0.0, 0.0),
- (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333),
- (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0),
- (0.80, 1.0, 1.0), (0.85, 1.0, 1.0),
- (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80),
- (1.0, 0.80, 0.80)],
- 'green': [(0.0, 0.0, 0.0), (0.05, 0.0, 0.0),
- (0.10, 0.0, 0.0), (0.15, 0.0, 0.0),
- (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667),
- (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667),
- (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000),
- (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667),
- (0.60, 1.0, 1.0), (0.65, 1.0, 1.0),
- (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000),
- (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0),
- (0.90, 0.0, 0.0), (0.95, 0.0, 0.0),
- (1.0, 0.80, 0.80)],
- 'blue': [(0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333),
- (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667),
- (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667),
- (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667),
- (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0),
- (0.5, 0.0, 0.0), (0.55, 0.0, 0.0),
- (0.60, 0.0, 0.0), (0.65, 0.0, 0.0),
- (0.70, 0.0, 0.0), (0.75, 0.0, 0.0),
- (0.80, 0.0, 0.0), (0.85, 0.0, 0.0),
- (0.90, 0.0, 0.0), (0.95, 0.0, 0.0),
- (1.0, 0.80, 0.80)],
-}
-
-
-# 34 colormaps based on color specifications and designs
-# developed by Cynthia Brewer (http://colorbrewer.org).
-# The ColorBrewer palettes have been included under the terms
-# of an Apache-stype license (for details, see the file
-# LICENSE_COLORBREWER in the license directory of the matplotlib
-# source distribution).
-
-# RGB values taken from Brewer's Excel sheet, divided by 255
-
-_Blues_data = (
- (0.96862745098039216, 0.98431372549019602, 1.0 ),
- (0.87058823529411766, 0.92156862745098034, 0.96862745098039216),
- (0.77647058823529413, 0.85882352941176465, 0.93725490196078431),
- (0.61960784313725492, 0.792156862745098 , 0.88235294117647056),
- (0.41960784313725491, 0.68235294117647061, 0.83921568627450982),
- (0.25882352941176473, 0.5725490196078431 , 0.77647058823529413),
- (0.12941176470588237, 0.44313725490196076, 0.70980392156862748),
- (0.03137254901960784, 0.31764705882352939, 0.61176470588235299),
- (0.03137254901960784, 0.18823529411764706, 0.41960784313725491)
- )
-
-_BrBG_data = (
- (0.32941176470588235, 0.18823529411764706, 0.0196078431372549 ),
- (0.5490196078431373 , 0.31764705882352939, 0.0392156862745098 ),
- (0.74901960784313726, 0.50588235294117645, 0.17647058823529413),
- (0.87450980392156863, 0.76078431372549016, 0.49019607843137253),
- (0.96470588235294119, 0.90980392156862744, 0.76470588235294112),
- (0.96078431372549022, 0.96078431372549022, 0.96078431372549022),
- (0.7803921568627451 , 0.91764705882352937, 0.89803921568627454),
- (0.50196078431372548, 0.80392156862745101, 0.75686274509803919),
- (0.20784313725490197, 0.59215686274509804, 0.5607843137254902 ),
- (0.00392156862745098, 0.4 , 0.36862745098039218),
- (0.0 , 0.23529411764705882, 0.18823529411764706)
- )
-
-_BuGn_data = (
- (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807),
- (0.89803921568627454, 0.96078431372549022, 0.97647058823529409),
- (0.8 , 0.92549019607843142, 0.90196078431372551),
- (0.6 , 0.84705882352941175, 0.78823529411764703),
- (0.4 , 0.76078431372549016, 0.64313725490196083),
- (0.25490196078431371, 0.68235294117647061, 0.46274509803921571),
- (0.13725490196078433, 0.54509803921568623, 0.27058823529411763),
- (0.0 , 0.42745098039215684, 0.17254901960784313),
- (0.0 , 0.26666666666666666, 0.10588235294117647)
- )
-
-_BuPu_data = (
- (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807),
- (0.8784313725490196 , 0.92549019607843142, 0.95686274509803926),
- (0.74901960784313726, 0.82745098039215681, 0.90196078431372551),
- (0.61960784313725492, 0.73725490196078436, 0.85490196078431369),
- (0.5490196078431373 , 0.58823529411764708, 0.77647058823529413),
- (0.5490196078431373 , 0.41960784313725491, 0.69411764705882351),
- (0.53333333333333333, 0.25490196078431371, 0.61568627450980395),
- (0.50588235294117645, 0.05882352941176471, 0.48627450980392156),
- (0.30196078431372547, 0.0 , 0.29411764705882354)
- )
-
-_GnBu_data = (
- (0.96862745098039216, 0.9882352941176471 , 0.94117647058823528),
- (0.8784313725490196 , 0.95294117647058818, 0.85882352941176465),
- (0.8 , 0.92156862745098034, 0.77254901960784317),
- (0.6588235294117647 , 0.8666666666666667 , 0.70980392156862748),
- (0.4823529411764706 , 0.8 , 0.7686274509803922 ),
- (0.30588235294117649, 0.70196078431372544, 0.82745098039215681),
- (0.16862745098039217, 0.5490196078431373 , 0.74509803921568629),
- (0.03137254901960784, 0.40784313725490196, 0.67450980392156867),
- (0.03137254901960784, 0.25098039215686274, 0.50588235294117645)
- )
-
-_Greens_data = (
- (0.96862745098039216, 0.9882352941176471 , 0.96078431372549022),
- (0.89803921568627454, 0.96078431372549022, 0.8784313725490196 ),
- (0.7803921568627451 , 0.9137254901960784 , 0.75294117647058822),
- (0.63137254901960782, 0.85098039215686272, 0.60784313725490191),
- (0.45490196078431372, 0.7686274509803922 , 0.46274509803921571),
- (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116),
- (0.13725490196078433, 0.54509803921568623, 0.27058823529411763),
- (0.0 , 0.42745098039215684, 0.17254901960784313),
- (0.0 , 0.26666666666666666, 0.10588235294117647)
- )
-
-_Greys_data = (
- (1.0 , 1.0 , 1.0 ),
- (0.94117647058823528, 0.94117647058823528, 0.94117647058823528),
- (0.85098039215686272, 0.85098039215686272, 0.85098039215686272),
- (0.74117647058823533, 0.74117647058823533, 0.74117647058823533),
- (0.58823529411764708, 0.58823529411764708, 0.58823529411764708),
- (0.45098039215686275, 0.45098039215686275, 0.45098039215686275),
- (0.32156862745098042, 0.32156862745098042, 0.32156862745098042),
- (0.14509803921568629, 0.14509803921568629, 0.14509803921568629),
- (0.0 , 0.0 , 0.0 )
- )
-
-_Oranges_data = (
- (1.0 , 0.96078431372549022, 0.92156862745098034),
- (0.99607843137254903, 0.90196078431372551, 0.80784313725490198),
- (0.99215686274509807, 0.81568627450980391, 0.63529411764705879),
- (0.99215686274509807, 0.68235294117647061, 0.41960784313725491),
- (0.99215686274509807, 0.55294117647058827, 0.23529411764705882),
- (0.94509803921568625, 0.41176470588235292, 0.07450980392156863),
- (0.85098039215686272, 0.28235294117647058, 0.00392156862745098),
- (0.65098039215686276, 0.21176470588235294, 0.01176470588235294),
- (0.49803921568627452, 0.15294117647058825, 0.01568627450980392)
- )
-
-_OrRd_data = (
- (1.0 , 0.96862745098039216, 0.92549019607843142),
- (0.99607843137254903, 0.90980392156862744, 0.78431372549019607),
- (0.99215686274509807, 0.83137254901960789, 0.61960784313725492),
- (0.99215686274509807, 0.73333333333333328, 0.51764705882352946),
- (0.9882352941176471 , 0.55294117647058827, 0.34901960784313724),
- (0.93725490196078431, 0.396078431372549 , 0.28235294117647058),
- (0.84313725490196079, 0.18823529411764706, 0.12156862745098039),
- (0.70196078431372544, 0.0 , 0.0 ),
- (0.49803921568627452, 0.0 , 0.0 )
- )
-
-_PiYG_data = (
- (0.55686274509803924, 0.00392156862745098, 0.32156862745098042),
- (0.77254901960784317, 0.10588235294117647, 0.49019607843137253),
- (0.87058823529411766, 0.46666666666666667, 0.68235294117647061),
- (0.94509803921568625, 0.71372549019607845, 0.85490196078431369),
- (0.99215686274509807, 0.8784313725490196 , 0.93725490196078431),
- (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
- (0.90196078431372551, 0.96078431372549022, 0.81568627450980391),
- (0.72156862745098038, 0.88235294117647056, 0.52549019607843139),
- (0.49803921568627452, 0.73725490196078436, 0.25490196078431371),
- (0.30196078431372547, 0.5725490196078431 , 0.12941176470588237),
- (0.15294117647058825, 0.39215686274509803, 0.09803921568627451)
- )
-
-_PRGn_data = (
- (0.25098039215686274, 0.0 , 0.29411764705882354),
- (0.46274509803921571, 0.16470588235294117, 0.51372549019607838),
- (0.6 , 0.4392156862745098 , 0.6705882352941176 ),
- (0.76078431372549016, 0.6470588235294118 , 0.81176470588235294),
- (0.90588235294117647, 0.83137254901960789, 0.90980392156862744),
- (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
- (0.85098039215686272, 0.94117647058823528, 0.82745098039215681),
- (0.65098039215686276, 0.85882352941176465, 0.62745098039215685),
- (0.35294117647058826, 0.68235294117647061, 0.38039215686274508),
- (0.10588235294117647, 0.47058823529411764, 0.21568627450980393),
- (0.0 , 0.26666666666666666, 0.10588235294117647)
- )
-
-_PuBu_data = (
- (1.0 , 0.96862745098039216, 0.98431372549019602),
- (0.92549019607843142, 0.90588235294117647, 0.94901960784313721),
- (0.81568627450980391, 0.81960784313725488, 0.90196078431372551),
- (0.65098039215686276, 0.74117647058823533, 0.85882352941176465),
- (0.45490196078431372, 0.66274509803921566, 0.81176470588235294),
- (0.21176470588235294, 0.56470588235294117, 0.75294117647058822),
- (0.0196078431372549 , 0.4392156862745098 , 0.69019607843137254),
- (0.01568627450980392, 0.35294117647058826, 0.55294117647058827),
- (0.00784313725490196, 0.2196078431372549 , 0.34509803921568627)
- )
-
-_PuBuGn_data = (
- (1.0 , 0.96862745098039216, 0.98431372549019602),
- (0.92549019607843142, 0.88627450980392153, 0.94117647058823528),
- (0.81568627450980391, 0.81960784313725488, 0.90196078431372551),
- (0.65098039215686276, 0.74117647058823533, 0.85882352941176465),
- (0.40392156862745099, 0.66274509803921566, 0.81176470588235294),
- (0.21176470588235294, 0.56470588235294117, 0.75294117647058822),
- (0.00784313725490196, 0.50588235294117645, 0.54117647058823526),
- (0.00392156862745098, 0.42352941176470588, 0.34901960784313724),
- (0.00392156862745098, 0.27450980392156865, 0.21176470588235294)
- )
-
-_PuOr_data = (
- (0.49803921568627452, 0.23137254901960785, 0.03137254901960784),
- (0.70196078431372544, 0.34509803921568627, 0.02352941176470588),
- (0.8784313725490196 , 0.50980392156862742, 0.07843137254901961),
- (0.99215686274509807, 0.72156862745098038, 0.38823529411764707),
- (0.99607843137254903, 0.8784313725490196 , 0.71372549019607845),
- (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
- (0.84705882352941175, 0.85490196078431369, 0.92156862745098034),
- (0.69803921568627447, 0.6705882352941176 , 0.82352941176470584),
- (0.50196078431372548, 0.45098039215686275, 0.67450980392156867),
- (0.32941176470588235, 0.15294117647058825, 0.53333333333333333),
- (0.17647058823529413, 0.0 , 0.29411764705882354)
- )
-
-_PuRd_data = (
- (0.96862745098039216, 0.95686274509803926, 0.97647058823529409),
- (0.90588235294117647, 0.88235294117647056, 0.93725490196078431),
- (0.83137254901960789, 0.72549019607843135, 0.85490196078431369),
- (0.78823529411764703, 0.58039215686274515, 0.7803921568627451 ),
- (0.87450980392156863, 0.396078431372549 , 0.69019607843137254),
- (0.90588235294117647, 0.16078431372549021, 0.54117647058823526),
- (0.80784313725490198, 0.07058823529411765, 0.33725490196078434),
- (0.59607843137254901, 0.0 , 0.2627450980392157 ),
- (0.40392156862745099, 0.0 , 0.12156862745098039)
- )
-
-_Purples_data = (
- (0.9882352941176471 , 0.98431372549019602, 0.99215686274509807),
- (0.93725490196078431, 0.92941176470588238, 0.96078431372549022),
- (0.85490196078431369, 0.85490196078431369, 0.92156862745098034),
- (0.73725490196078436, 0.74117647058823533, 0.86274509803921573),
- (0.61960784313725492, 0.60392156862745094, 0.78431372549019607),
- (0.50196078431372548, 0.49019607843137253, 0.72941176470588232),
- (0.41568627450980394, 0.31764705882352939, 0.63921568627450975),
- (0.32941176470588235, 0.15294117647058825, 0.5607843137254902 ),
- (0.24705882352941178, 0.0 , 0.49019607843137253)
- )
-
-_RdBu_data = (
- (0.40392156862745099, 0.0 , 0.12156862745098039),
- (0.69803921568627447, 0.09411764705882353, 0.16862745098039217),
- (0.83921568627450982, 0.37647058823529411, 0.30196078431372547),
- (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742),
- (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ),
- (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
- (0.81960784313725488, 0.89803921568627454, 0.94117647058823528),
- (0.5725490196078431 , 0.77254901960784317, 0.87058823529411766),
- (0.2627450980392157 , 0.57647058823529407, 0.76470588235294112),
- (0.12941176470588237, 0.4 , 0.67450980392156867),
- (0.0196078431372549 , 0.18823529411764706, 0.38039215686274508)
- )
-
-_RdGy_data = (
- (0.40392156862745099, 0.0 , 0.12156862745098039),
- (0.69803921568627447, 0.09411764705882353, 0.16862745098039217),
- (0.83921568627450982, 0.37647058823529411, 0.30196078431372547),
- (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742),
- (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ),
- (1.0 , 1.0 , 1.0 ),
- (0.8784313725490196 , 0.8784313725490196 , 0.8784313725490196 ),
- (0.72941176470588232, 0.72941176470588232, 0.72941176470588232),
- (0.52941176470588236, 0.52941176470588236, 0.52941176470588236),
- (0.30196078431372547, 0.30196078431372547, 0.30196078431372547),
- (0.10196078431372549, 0.10196078431372549, 0.10196078431372549)
- )
-
-_RdPu_data = (
- (1.0 , 0.96862745098039216, 0.95294117647058818),
- (0.99215686274509807, 0.8784313725490196 , 0.86666666666666667),
- (0.9882352941176471 , 0.77254901960784317, 0.75294117647058822),
- (0.98039215686274506, 0.62352941176470589, 0.70980392156862748),
- (0.96862745098039216, 0.40784313725490196, 0.63137254901960782),
- (0.86666666666666667, 0.20392156862745098, 0.59215686274509804),
- (0.68235294117647061, 0.00392156862745098, 0.49411764705882355),
- (0.47843137254901963, 0.00392156862745098, 0.46666666666666667),
- (0.28627450980392155, 0.0 , 0.41568627450980394)
- )
-
-_RdYlBu_data = (
- (0.6470588235294118 , 0.0 , 0.14901960784313725),
- (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825),
- (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
- (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
- (0.99607843137254903, 0.8784313725490196 , 0.56470588235294117),
- (1.0 , 1.0 , 0.74901960784313726),
- (0.8784313725490196 , 0.95294117647058818 , 0.97254901960784312),
- (0.6705882352941176 , 0.85098039215686272 , 0.9137254901960784 ),
- (0.45490196078431372, 0.67843137254901964 , 0.81960784313725488),
- (0.27058823529411763, 0.45882352941176469 , 0.70588235294117652),
- (0.19215686274509805, 0.21176470588235294 , 0.58431372549019611)
- )
-
-_RdYlGn_data = (
- (0.6470588235294118 , 0.0 , 0.14901960784313725),
- (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825),
- (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
- (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
- (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623),
- (1.0 , 1.0 , 0.74901960784313726),
- (0.85098039215686272, 0.93725490196078431 , 0.54509803921568623),
- (0.65098039215686276, 0.85098039215686272 , 0.41568627450980394),
- (0.4 , 0.74117647058823533 , 0.38823529411764707),
- (0.10196078431372549, 0.59607843137254901 , 0.31372549019607843),
- (0.0 , 0.40784313725490196 , 0.21568627450980393)
- )
-
-_Reds_data = (
- (1.0 , 0.96078431372549022 , 0.94117647058823528),
- (0.99607843137254903, 0.8784313725490196 , 0.82352941176470584),
- (0.9882352941176471 , 0.73333333333333328 , 0.63137254901960782),
- (0.9882352941176471 , 0.5725490196078431 , 0.44705882352941179),
- (0.98431372549019602, 0.41568627450980394 , 0.29019607843137257),
- (0.93725490196078431, 0.23137254901960785 , 0.17254901960784313),
- (0.79607843137254897, 0.094117647058823528, 0.11372549019607843),
- (0.6470588235294118 , 0.058823529411764705, 0.08235294117647058),
- (0.40392156862745099, 0.0 , 0.05098039215686274)
- )
-
-_Spectral_data = (
- (0.61960784313725492, 0.003921568627450980, 0.25882352941176473),
- (0.83529411764705885, 0.24313725490196078 , 0.30980392156862746),
- (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
- (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
- (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623),
- (1.0 , 1.0 , 0.74901960784313726),
- (0.90196078431372551, 0.96078431372549022 , 0.59607843137254901),
- (0.6705882352941176 , 0.8666666666666667 , 0.64313725490196083),
- (0.4 , 0.76078431372549016 , 0.6470588235294118 ),
- (0.19607843137254902, 0.53333333333333333 , 0.74117647058823533),
- (0.36862745098039218, 0.30980392156862746 , 0.63529411764705879)
- )
-
-_YlGn_data = (
- (1.0 , 1.0 , 0.89803921568627454),
- (0.96862745098039216, 0.9882352941176471 , 0.72549019607843135),
- (0.85098039215686272, 0.94117647058823528 , 0.63921568627450975),
- (0.67843137254901964, 0.8666666666666667 , 0.55686274509803924),
- (0.47058823529411764, 0.77647058823529413 , 0.47450980392156861),
- (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116),
- (0.13725490196078433, 0.51764705882352946 , 0.2627450980392157 ),
- (0.0 , 0.40784313725490196 , 0.21568627450980393),
- (0.0 , 0.27058823529411763 , 0.16078431372549021)
- )
-
-_YlGnBu_data = (
- (1.0 , 1.0 , 0.85098039215686272),
- (0.92941176470588238, 0.97254901960784312 , 0.69411764705882351),
- (0.7803921568627451 , 0.9137254901960784 , 0.70588235294117652),
- (0.49803921568627452, 0.80392156862745101 , 0.73333333333333328),
- (0.25490196078431371, 0.71372549019607845 , 0.7686274509803922 ),
- (0.11372549019607843, 0.56862745098039214 , 0.75294117647058822),
- (0.13333333333333333, 0.36862745098039218 , 0.6588235294117647 ),
- (0.14509803921568629, 0.20392156862745098 , 0.58039215686274515),
- (0.03137254901960784, 0.11372549019607843 , 0.34509803921568627)
- )
-
-_YlOrBr_data = (
- (1.0 , 1.0 , 0.89803921568627454),
- (1.0 , 0.96862745098039216 , 0.73725490196078436),
- (0.99607843137254903, 0.8901960784313725 , 0.56862745098039214),
- (0.99607843137254903, 0.7686274509803922 , 0.30980392156862746),
- (0.99607843137254903, 0.6 , 0.16078431372549021),
- (0.92549019607843142, 0.4392156862745098 , 0.07843137254901961),
- (0.8 , 0.29803921568627451 , 0.00784313725490196),
- (0.6 , 0.20392156862745098 , 0.01568627450980392),
- (0.4 , 0.14509803921568629 , 0.02352941176470588)
- )
-
-_YlOrRd_data = (
- (1.0 , 1.0 , 0.8 ),
- (1.0 , 0.92941176470588238 , 0.62745098039215685),
- (0.99607843137254903, 0.85098039215686272 , 0.46274509803921571),
- (0.99607843137254903, 0.69803921568627447 , 0.29803921568627451),
- (0.99215686274509807, 0.55294117647058827 , 0.23529411764705882),
- (0.9882352941176471 , 0.30588235294117649 , 0.16470588235294117),
- (0.8901960784313725 , 0.10196078431372549 , 0.10980392156862745),
- (0.74117647058823533, 0.0 , 0.14901960784313725),
- (0.50196078431372548, 0.0 , 0.14901960784313725)
- )
-
-
-# ColorBrewer's qualitative maps, implemented using ListedColormap
-# for use with mpl.colors.NoNorm
-
-_Accent_data = (
- (0.49803921568627452, 0.78823529411764703, 0.49803921568627452),
- (0.74509803921568629, 0.68235294117647061, 0.83137254901960789),
- (0.99215686274509807, 0.75294117647058822, 0.52549019607843139),
- (1.0, 1.0, 0.6 ),
- (0.2196078431372549, 0.42352941176470588, 0.69019607843137254),
- (0.94117647058823528, 0.00784313725490196, 0.49803921568627452),
- (0.74901960784313726, 0.35686274509803922, 0.09019607843137254),
- (0.4, 0.4, 0.4 ),
- )
-
-_Dark2_data = (
- (0.10588235294117647, 0.61960784313725492, 0.46666666666666667),
- (0.85098039215686272, 0.37254901960784315, 0.00784313725490196),
- (0.45882352941176469, 0.4392156862745098, 0.70196078431372544),
- (0.90588235294117647, 0.16078431372549021, 0.54117647058823526),
- (0.4, 0.65098039215686276, 0.11764705882352941),
- (0.90196078431372551, 0.6705882352941176, 0.00784313725490196),
- (0.65098039215686276, 0.46274509803921571, 0.11372549019607843),
- (0.4, 0.4, 0.4 ),
- )
-
-_Paired_data = (
- (0.65098039215686276, 0.80784313725490198, 0.8901960784313725 ),
- (0.12156862745098039, 0.47058823529411764, 0.70588235294117652),
- (0.69803921568627447, 0.87450980392156863, 0.54117647058823526),
- (0.2, 0.62745098039215685, 0.17254901960784313),
- (0.98431372549019602, 0.60392156862745094, 0.6 ),
- (0.8901960784313725, 0.10196078431372549, 0.10980392156862745),
- (0.99215686274509807, 0.74901960784313726, 0.43529411764705883),
- (1.0, 0.49803921568627452, 0.0 ),
- (0.792156862745098, 0.69803921568627447, 0.83921568627450982),
- (0.41568627450980394, 0.23921568627450981, 0.60392156862745094),
- (1.0, 1.0, 0.6 ),
- (0.69411764705882351, 0.34901960784313724, 0.15686274509803921),
- )
-
-_Pastel1_data = (
- (0.98431372549019602, 0.70588235294117652, 0.68235294117647061),
- (0.70196078431372544, 0.80392156862745101, 0.8901960784313725 ),
- (0.8, 0.92156862745098034, 0.77254901960784317),
- (0.87058823529411766, 0.79607843137254897, 0.89411764705882357),
- (0.99607843137254903, 0.85098039215686272, 0.65098039215686276),
- (1.0, 1.0, 0.8 ),
- (0.89803921568627454, 0.84705882352941175, 0.74117647058823533),
- (0.99215686274509807, 0.85490196078431369, 0.92549019607843142),
- (0.94901960784313721, 0.94901960784313721, 0.94901960784313721),
- )
-
-_Pastel2_data = (
- (0.70196078431372544, 0.88627450980392153, 0.80392156862745101),
- (0.99215686274509807, 0.80392156862745101, 0.67450980392156867),
- (0.79607843137254897, 0.83529411764705885, 0.90980392156862744),
- (0.95686274509803926, 0.792156862745098, 0.89411764705882357),
- (0.90196078431372551, 0.96078431372549022, 0.78823529411764703),
- (1.0, 0.94901960784313721, 0.68235294117647061),
- (0.94509803921568625, 0.88627450980392153, 0.8 ),
- (0.8, 0.8, 0.8 ),
- )
-
-_Set1_data = (
- (0.89411764705882357, 0.10196078431372549, 0.10980392156862745),
- (0.21568627450980393, 0.49411764705882355, 0.72156862745098038),
- (0.30196078431372547, 0.68627450980392157, 0.29019607843137257),
- (0.59607843137254901, 0.30588235294117649, 0.63921568627450975),
- (1.0, 0.49803921568627452, 0.0 ),
- (1.0, 1.0, 0.2 ),
- (0.65098039215686276, 0.33725490196078434, 0.15686274509803921),
- (0.96862745098039216, 0.50588235294117645, 0.74901960784313726),
- (0.6, 0.6, 0.6),
- )
-
-_Set2_data = (
- (0.4, 0.76078431372549016, 0.6470588235294118 ),
- (0.9882352941176471, 0.55294117647058827, 0.3843137254901961 ),
- (0.55294117647058827, 0.62745098039215685, 0.79607843137254897),
- (0.90588235294117647, 0.54117647058823526, 0.76470588235294112),
- (0.65098039215686276, 0.84705882352941175, 0.32941176470588235),
- (1.0, 0.85098039215686272, 0.18431372549019609),
- (0.89803921568627454, 0.7686274509803922, 0.58039215686274515),
- (0.70196078431372544, 0.70196078431372544, 0.70196078431372544),
- )
-
-_Set3_data = (
- (0.55294117647058827, 0.82745098039215681, 0.7803921568627451 ),
- (1.0, 1.0, 0.70196078431372544),
- (0.74509803921568629, 0.72941176470588232, 0.85490196078431369),
- (0.98431372549019602, 0.50196078431372548, 0.44705882352941179),
- (0.50196078431372548, 0.69411764705882351, 0.82745098039215681),
- (0.99215686274509807, 0.70588235294117652, 0.3843137254901961 ),
- (0.70196078431372544, 0.87058823529411766, 0.41176470588235292),
- (0.9882352941176471, 0.80392156862745101, 0.89803921568627454),
- (0.85098039215686272, 0.85098039215686272, 0.85098039215686272),
- (0.73725490196078436, 0.50196078431372548, 0.74117647058823533),
- (0.8, 0.92156862745098034, 0.77254901960784317),
- (1.0, 0.92941176470588238, 0.43529411764705883),
- )
-
-
-# The next 7 palettes are from the Yorick scientific visualization package,
-# an evolution of the GIST package, both by David H. Munro.
-# They are released under a BSD-like license (see LICENSE_YORICK in
-# the license directory of the matplotlib source distribution).
-#
-# Most palette functions have been reduced to simple function descriptions
-# by Reinier Heeres, since the rgb components were mostly straight lines.
-# gist_earth_data and gist_ncar_data were simplified by a script and some
-# manual effort.
-
-_gist_earth_data = \
-{'red': (
-(0.0, 0.0, 0.0000),
-(0.2824, 0.1882, 0.1882),
-(0.4588, 0.2714, 0.2714),
-(0.5490, 0.4719, 0.4719),
-(0.6980, 0.7176, 0.7176),
-(0.7882, 0.7553, 0.7553),
-(1.0000, 0.9922, 0.9922),
-), 'green': (
-(0.0, 0.0, 0.0000),
-(0.0275, 0.0000, 0.0000),
-(0.1098, 0.1893, 0.1893),
-(0.1647, 0.3035, 0.3035),
-(0.2078, 0.3841, 0.3841),
-(0.2824, 0.5020, 0.5020),
-(0.5216, 0.6397, 0.6397),
-(0.6980, 0.7171, 0.7171),
-(0.7882, 0.6392, 0.6392),
-(0.7922, 0.6413, 0.6413),
-(0.8000, 0.6447, 0.6447),
-(0.8078, 0.6481, 0.6481),
-(0.8157, 0.6549, 0.6549),
-(0.8667, 0.6991, 0.6991),
-(0.8745, 0.7103, 0.7103),
-(0.8824, 0.7216, 0.7216),
-(0.8902, 0.7323, 0.7323),
-(0.8980, 0.7430, 0.7430),
-(0.9412, 0.8275, 0.8275),
-(0.9569, 0.8635, 0.8635),
-(0.9647, 0.8816, 0.8816),
-(0.9961, 0.9733, 0.9733),
-(1.0000, 0.9843, 0.9843),
-), 'blue': (
-(0.0, 0.0, 0.0000),
-(0.0039, 0.1684, 0.1684),
-(0.0078, 0.2212, 0.2212),
-(0.0275, 0.4329, 0.4329),
-(0.0314, 0.4549, 0.4549),
-(0.2824, 0.5004, 0.5004),
-(0.4667, 0.2748, 0.2748),
-(0.5451, 0.3205, 0.3205),
-(0.7843, 0.3961, 0.3961),
-(0.8941, 0.6651, 0.6651),
-(1.0000, 0.9843, 0.9843),
-)}
-
-_gist_gray_data = {
- 'red': gfunc[3],
- 'green': gfunc[3],
- 'blue': gfunc[3],
-}
-
-def _gist_heat_red(x): return 1.5 * x
-def _gist_heat_green(x): return 2 * x - 1
-def _gist_heat_blue(x): return 4 * x - 3
-_gist_heat_data = {
- 'red': _gist_heat_red, 'green': _gist_heat_green, 'blue': _gist_heat_blue}
-
-_gist_ncar_data = \
-{'red': (
-(0.0, 0.0, 0.0000),
-(0.3098, 0.0000, 0.0000),
-(0.3725, 0.3993, 0.3993),
-(0.4235, 0.5003, 0.5003),
-(0.5333, 1.0000, 1.0000),
-(0.7922, 1.0000, 1.0000),
-(0.8471, 0.6218, 0.6218),
-(0.8980, 0.9235, 0.9235),
-(1.0000, 0.9961, 0.9961),
-), 'green': (
-(0.0, 0.0, 0.0000),
-(0.0510, 0.3722, 0.3722),
-(0.1059, 0.0000, 0.0000),
-(0.1569, 0.7202, 0.7202),
-(0.1608, 0.7537, 0.7537),
-(0.1647, 0.7752, 0.7752),
-(0.2157, 1.0000, 1.0000),
-(0.2588, 0.9804, 0.9804),
-(0.2706, 0.9804, 0.9804),
-(0.3176, 1.0000, 1.0000),
-(0.3686, 0.8081, 0.8081),
-(0.4275, 1.0000, 1.0000),
-(0.5216, 1.0000, 1.0000),
-(0.6314, 0.7292, 0.7292),
-(0.6863, 0.2796, 0.2796),
-(0.7451, 0.0000, 0.0000),
-(0.7922, 0.0000, 0.0000),
-(0.8431, 0.1753, 0.1753),
-(0.8980, 0.5000, 0.5000),
-(1.0000, 0.9725, 0.9725),
-), 'blue': (
-(0.0, 0.5020, 0.5020),
-(0.0510, 0.0222, 0.0222),
-(0.1098, 1.0000, 1.0000),
-(0.2039, 1.0000, 1.0000),
-(0.2627, 0.6145, 0.6145),
-(0.3216, 0.0000, 0.0000),
-(0.4157, 0.0000, 0.0000),
-(0.4745, 0.2342, 0.2342),
-(0.5333, 0.0000, 0.0000),
-(0.5804, 0.0000, 0.0000),
-(0.6314, 0.0549, 0.0549),
-(0.6902, 0.0000, 0.0000),
-(0.7373, 0.0000, 0.0000),
-(0.7922, 0.9738, 0.9738),
-(0.8000, 1.0000, 1.0000),
-(0.8431, 1.0000, 1.0000),
-(0.8980, 0.9341, 0.9341),
-(1.0000, 0.9961, 0.9961),
-)}
-
-_gist_rainbow_data = (
- (0.000, (1.00, 0.00, 0.16)),
- (0.030, (1.00, 0.00, 0.00)),
- (0.215, (1.00, 1.00, 0.00)),
- (0.400, (0.00, 1.00, 0.00)),
- (0.586, (0.00, 1.00, 1.00)),
- (0.770, (0.00, 0.00, 1.00)),
- (0.954, (1.00, 0.00, 1.00)),
- (1.000, (1.00, 0.00, 0.75))
-)
-
-_gist_stern_data = {
- 'red': (
- (0.000, 0.000, 0.000), (0.0547, 1.000, 1.000),
- (0.250, 0.027, 0.250), # (0.2500, 0.250, 0.250),
- (1.000, 1.000, 1.000)),
- 'green': ((0, 0, 0), (1, 1, 1)),
- 'blue': (
- (0.000, 0.000, 0.000), (0.500, 1.000, 1.000),
- (0.735, 0.000, 0.000), (1.000, 1.000, 1.000))
-}
-
-def _gist_yarg(x): return 1 - x
-_gist_yarg_data = {'red': _gist_yarg, 'green': _gist_yarg, 'blue': _gist_yarg}
-
-# This bipolar color map was generated from CoolWarmFloat33.csv of
-# "Diverging Color Maps for Scientific Visualization" by Kenneth Moreland.
-#
-_coolwarm_data = {
- 'red': [
- (0.0, 0.2298057, 0.2298057),
- (0.03125, 0.26623388, 0.26623388),
- (0.0625, 0.30386891, 0.30386891),
- (0.09375, 0.342804478, 0.342804478),
- (0.125, 0.38301334, 0.38301334),
- (0.15625, 0.424369608, 0.424369608),
- (0.1875, 0.46666708, 0.46666708),
- (0.21875, 0.509635204, 0.509635204),
- (0.25, 0.552953156, 0.552953156),
- (0.28125, 0.596262162, 0.596262162),
- (0.3125, 0.639176211, 0.639176211),
- (0.34375, 0.681291281, 0.681291281),
- (0.375, 0.722193294, 0.722193294),
- (0.40625, 0.761464949, 0.761464949),
- (0.4375, 0.798691636, 0.798691636),
- (0.46875, 0.833466556, 0.833466556),
- (0.5, 0.865395197, 0.865395197),
- (0.53125, 0.897787179, 0.897787179),
- (0.5625, 0.924127593, 0.924127593),
- (0.59375, 0.944468518, 0.944468518),
- (0.625, 0.958852946, 0.958852946),
- (0.65625, 0.96732803, 0.96732803),
- (0.6875, 0.969954137, 0.969954137),
- (0.71875, 0.966811177, 0.966811177),
- (0.75, 0.958003065, 0.958003065),
- (0.78125, 0.943660866, 0.943660866),
- (0.8125, 0.923944917, 0.923944917),
- (0.84375, 0.89904617, 0.89904617),
- (0.875, 0.869186849, 0.869186849),
- (0.90625, 0.834620542, 0.834620542),
- (0.9375, 0.795631745, 0.795631745),
- (0.96875, 0.752534934, 0.752534934),
- (1.0, 0.705673158, 0.705673158)],
- 'green': [
- (0.0, 0.298717966, 0.298717966),
- (0.03125, 0.353094838, 0.353094838),
- (0.0625, 0.406535296, 0.406535296),
- (0.09375, 0.458757618, 0.458757618),
- (0.125, 0.50941904, 0.50941904),
- (0.15625, 0.558148092, 0.558148092),
- (0.1875, 0.604562568, 0.604562568),
- (0.21875, 0.648280772, 0.648280772),
- (0.25, 0.688929332, 0.688929332),
- (0.28125, 0.726149107, 0.726149107),
- (0.3125, 0.759599947, 0.759599947),
- (0.34375, 0.788964712, 0.788964712),
- (0.375, 0.813952739, 0.813952739),
- (0.40625, 0.834302879, 0.834302879),
- (0.4375, 0.849786142, 0.849786142),
- (0.46875, 0.860207984, 0.860207984),
- (0.5, 0.86541021, 0.86541021),
- (0.53125, 0.848937047, 0.848937047),
- (0.5625, 0.827384882, 0.827384882),
- (0.59375, 0.800927443, 0.800927443),
- (0.625, 0.769767752, 0.769767752),
- (0.65625, 0.734132809, 0.734132809),
- (0.6875, 0.694266682, 0.694266682),
- (0.71875, 0.650421156, 0.650421156),
- (0.75, 0.602842431, 0.602842431),
- (0.78125, 0.551750968, 0.551750968),
- (0.8125, 0.49730856, 0.49730856),
- (0.84375, 0.439559467, 0.439559467),
- (0.875, 0.378313092, 0.378313092),
- (0.90625, 0.312874446, 0.312874446),
- (0.9375, 0.24128379, 0.24128379),
- (0.96875, 0.157246067, 0.157246067),
- (1.0, 0.01555616, 0.01555616)],
- 'blue': [
- (0.0, 0.753683153, 0.753683153),
- (0.03125, 0.801466763, 0.801466763),
- (0.0625, 0.84495867, 0.84495867),
- (0.09375, 0.883725899, 0.883725899),
- (0.125, 0.917387822, 0.917387822),
- (0.15625, 0.945619588, 0.945619588),
- (0.1875, 0.968154911, 0.968154911),
- (0.21875, 0.98478814, 0.98478814),
- (0.25, 0.995375608, 0.995375608),
- (0.28125, 0.999836203, 0.999836203),
- (0.3125, 0.998151185, 0.998151185),
- (0.34375, 0.990363227, 0.990363227),
- (0.375, 0.976574709, 0.976574709),
- (0.40625, 0.956945269, 0.956945269),
- (0.4375, 0.931688648, 0.931688648),
- (0.46875, 0.901068838, 0.901068838),
- (0.5, 0.865395561, 0.865395561),
- (0.53125, 0.820880546, 0.820880546),
- (0.5625, 0.774508472, 0.774508472),
- (0.59375, 0.726736146, 0.726736146),
- (0.625, 0.678007945, 0.678007945),
- (0.65625, 0.628751763, 0.628751763),
- (0.6875, 0.579375448, 0.579375448),
- (0.71875, 0.530263762, 0.530263762),
- (0.75, 0.481775914, 0.481775914),
- (0.78125, 0.434243684, 0.434243684),
- (0.8125, 0.387970225, 0.387970225),
- (0.84375, 0.343229596, 0.343229596),
- (0.875, 0.300267182, 0.300267182),
- (0.90625, 0.259301199, 0.259301199),
- (0.9375, 0.220525627, 0.220525627),
- (0.96875, 0.184115123, 0.184115123),
- (1.0, 0.150232812, 0.150232812)]
- }
-
-# Implementation of Carey Rappaport's CMRmap.
-# See `A Color Map for Effective Black-and-White Rendering of Color-Scale
-# Images' by Carey Rappaport
-# http://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m
-_CMRmap_data = {'red': ((0.000, 0.00, 0.00),
- (0.125, 0.15, 0.15),
- (0.250, 0.30, 0.30),
- (0.375, 0.60, 0.60),
- (0.500, 1.00, 1.00),
- (0.625, 0.90, 0.90),
- (0.750, 0.90, 0.90),
- (0.875, 0.90, 0.90),
- (1.000, 1.00, 1.00)),
- 'green': ((0.000, 0.00, 0.00),
- (0.125, 0.15, 0.15),
- (0.250, 0.15, 0.15),
- (0.375, 0.20, 0.20),
- (0.500, 0.25, 0.25),
- (0.625, 0.50, 0.50),
- (0.750, 0.75, 0.75),
- (0.875, 0.90, 0.90),
- (1.000, 1.00, 1.00)),
- 'blue': ((0.000, 0.00, 0.00),
- (0.125, 0.50, 0.50),
- (0.250, 0.75, 0.75),
- (0.375, 0.50, 0.50),
- (0.500, 0.15, 0.15),
- (0.625, 0.00, 0.00),
- (0.750, 0.10, 0.10),
- (0.875, 0.50, 0.50),
- (1.000, 1.00, 1.00))}
-
-
-# An MIT licensed, colorblind-friendly heatmap from Wistia:
-# https://github.com/wistia/heatmap-palette
-# http://wistia.com/blog/heatmaps-for-colorblindness
-#
-# >>> import matplotlib.colors as c
-# >>> colors = ["#e4ff7a", "#ffe81a", "#ffbd00", "#ffa000", "#fc7f00"]
-# >>> cm = c.LinearSegmentedColormap.from_list('wistia', colors)
-# >>> _wistia_data = cm._segmentdata
-# >>> del _wistia_data['alpha']
-#
-_wistia_data = {
- 'red': [(0.0, 0.8941176470588236, 0.8941176470588236),
- (0.25, 1.0, 1.0),
- (0.5, 1.0, 1.0),
- (0.75, 1.0, 1.0),
- (1.0, 0.9882352941176471, 0.9882352941176471)],
- 'green': [(0.0, 1.0, 1.0),
- (0.25, 0.9098039215686274, 0.9098039215686274),
- (0.5, 0.7411764705882353, 0.7411764705882353),
- (0.75, 0.6274509803921569, 0.6274509803921569),
- (1.0, 0.4980392156862745, 0.4980392156862745)],
- 'blue': [(0.0, 0.47843137254901963, 0.47843137254901963),
- (0.25, 0.10196078431372549, 0.10196078431372549),
- (0.5, 0.0, 0.0),
- (0.75, 0.0, 0.0),
- (1.0, 0.0, 0.0)],
-}
-
-
-# Categorical palettes from Vega:
-# https://github.com/vega/vega/wiki/Scales
-# (divided by 255)
-#
-
-_tab10_data = (
- (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4
- (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e
- (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c
- (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728
- (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd
- (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b
- (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2
- (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f
- (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22
- (0.09019607843137255, 0.7450980392156863, 0.8117647058823529), # 17becf
-)
-
-_tab20_data = (
- (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4
- (0.6823529411764706, 0.7803921568627451, 0.9098039215686274 ), # aec7e8
- (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e
- (1.0, 0.7333333333333333, 0.47058823529411764 ), # ffbb78
- (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c
- (0.596078431372549, 0.8745098039215686, 0.5411764705882353 ), # 98df8a
- (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728
- (1.0, 0.596078431372549, 0.5882352941176471 ), # ff9896
- (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd
- (0.7725490196078432, 0.6901960784313725, 0.8352941176470589 ), # c5b0d5
- (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b
- (0.7686274509803922, 0.611764705882353, 0.5803921568627451 ), # c49c94
- (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2
- (0.9686274509803922, 0.7137254901960784, 0.8235294117647058 ), # f7b6d2
- (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f
- (0.7803921568627451, 0.7803921568627451, 0.7803921568627451 ), # c7c7c7
- (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22
- (0.8588235294117647, 0.8588235294117647, 0.5529411764705883 ), # dbdb8d
- (0.09019607843137255, 0.7450980392156863, 0.8117647058823529 ), # 17becf
- (0.6196078431372549, 0.8549019607843137, 0.8980392156862745), # 9edae5
-)
-
-_tab20b_data = (
- (0.2235294117647059, 0.23137254901960785, 0.4745098039215686 ), # 393b79
- (0.3215686274509804, 0.32941176470588235, 0.6392156862745098 ), # 5254a3
- (0.4196078431372549, 0.43137254901960786, 0.8117647058823529 ), # 6b6ecf
- (0.611764705882353, 0.6196078431372549, 0.8705882352941177 ), # 9c9ede
- (0.38823529411764707, 0.4745098039215686, 0.2235294117647059 ), # 637939
- (0.5490196078431373, 0.6352941176470588, 0.3215686274509804 ), # 8ca252
- (0.7098039215686275, 0.8117647058823529, 0.4196078431372549 ), # b5cf6b
- (0.807843137254902, 0.8588235294117647, 0.611764705882353 ), # cedb9c
- (0.5490196078431373, 0.42745098039215684, 0.19215686274509805), # 8c6d31
- (0.7411764705882353, 0.6196078431372549, 0.2235294117647059 ), # bd9e39
- (0.9058823529411765, 0.7294117647058823, 0.3215686274509804 ), # e7ba52
- (0.9058823529411765, 0.796078431372549, 0.5803921568627451 ), # e7cb94
- (0.5176470588235295, 0.23529411764705882, 0.2235294117647059 ), # 843c39
- (0.6784313725490196, 0.28627450980392155, 0.2901960784313726 ), # ad494a
- (0.8392156862745098, 0.3803921568627451, 0.4196078431372549 ), # d6616b
- (0.9058823529411765, 0.5882352941176471, 0.611764705882353 ), # e7969c
- (0.4823529411764706, 0.2549019607843137, 0.45098039215686275), # 7b4173
- (0.6470588235294118, 0.3176470588235294, 0.5803921568627451 ), # a55194
- (0.807843137254902, 0.42745098039215684, 0.7411764705882353 ), # ce6dbd
- (0.8705882352941177, 0.6196078431372549, 0.8392156862745098 ), # de9ed6
-)
-
-_tab20c_data = (
- (0.19215686274509805, 0.5098039215686274, 0.7411764705882353 ), # 3182bd
- (0.4196078431372549, 0.6823529411764706, 0.8392156862745098 ), # 6baed6
- (0.6196078431372549, 0.792156862745098, 0.8823529411764706 ), # 9ecae1
- (0.7764705882352941, 0.8588235294117647, 0.9372549019607843 ), # c6dbef
- (0.9019607843137255, 0.3333333333333333, 0.050980392156862744), # e6550d
- (0.9921568627450981, 0.5529411764705883, 0.23529411764705882 ), # fd8d3c
- (0.9921568627450981, 0.6823529411764706, 0.4196078431372549 ), # fdae6b
- (0.9921568627450981, 0.8156862745098039, 0.6352941176470588 ), # fdd0a2
- (0.19215686274509805, 0.6392156862745098, 0.32941176470588235 ), # 31a354
- (0.4549019607843137, 0.7686274509803922, 0.4627450980392157 ), # 74c476
- (0.6313725490196078, 0.8509803921568627, 0.6078431372549019 ), # a1d99b
- (0.7803921568627451, 0.9137254901960784, 0.7529411764705882 ), # c7e9c0
- (0.4588235294117647, 0.4196078431372549, 0.6941176470588235 ), # 756bb1
- (0.6196078431372549, 0.6039215686274509, 0.7843137254901961 ), # 9e9ac8
- (0.7372549019607844, 0.7411764705882353, 0.8627450980392157 ), # bcbddc
- (0.8549019607843137, 0.8549019607843137, 0.9215686274509803 ), # dadaeb
- (0.38823529411764707, 0.38823529411764707, 0.38823529411764707 ), # 636363
- (0.5882352941176471, 0.5882352941176471, 0.5882352941176471 ), # 969696
- (0.7411764705882353, 0.7411764705882353, 0.7411764705882353 ), # bdbdbd
- (0.8509803921568627, 0.8509803921568627, 0.8509803921568627 ), # d9d9d9
-)
-
-
-datad = {
- 'Blues': _Blues_data,
- 'BrBG': _BrBG_data,
- 'BuGn': _BuGn_data,
- 'BuPu': _BuPu_data,
- 'CMRmap': _CMRmap_data,
- 'GnBu': _GnBu_data,
- 'Greens': _Greens_data,
- 'Greys': _Greys_data,
- 'OrRd': _OrRd_data,
- 'Oranges': _Oranges_data,
- 'PRGn': _PRGn_data,
- 'PiYG': _PiYG_data,
- 'PuBu': _PuBu_data,
- 'PuBuGn': _PuBuGn_data,
- 'PuOr': _PuOr_data,
- 'PuRd': _PuRd_data,
- 'Purples': _Purples_data,
- 'RdBu': _RdBu_data,
- 'RdGy': _RdGy_data,
- 'RdPu': _RdPu_data,
- 'RdYlBu': _RdYlBu_data,
- 'RdYlGn': _RdYlGn_data,
- 'Reds': _Reds_data,
- 'Spectral': _Spectral_data,
- 'Wistia': _wistia_data,
- 'YlGn': _YlGn_data,
- 'YlGnBu': _YlGnBu_data,
- 'YlOrBr': _YlOrBr_data,
- 'YlOrRd': _YlOrRd_data,
- 'afmhot': _afmhot_data,
- 'autumn': _autumn_data,
- 'binary': _binary_data,
- 'bone': _bone_data,
- 'brg': _brg_data,
- 'bwr': _bwr_data,
- 'cool': _cool_data,
- 'coolwarm': _coolwarm_data,
- 'copper': _copper_data,
- 'cubehelix': _cubehelix_data,
- 'flag': _flag_data,
- 'gist_earth': _gist_earth_data,
- 'gist_gray': _gist_gray_data,
- 'gist_heat': _gist_heat_data,
- 'gist_ncar': _gist_ncar_data,
- 'gist_rainbow': _gist_rainbow_data,
- 'gist_stern': _gist_stern_data,
- 'gist_yarg': _gist_yarg_data,
- 'gnuplot': _gnuplot_data,
- 'gnuplot2': _gnuplot2_data,
- 'gray': _gray_data,
- 'hot': _hot_data,
- 'hsv': _hsv_data,
- 'jet': _jet_data,
- 'nipy_spectral': _nipy_spectral_data,
- 'ocean': _ocean_data,
- 'pink': _pink_data,
- 'prism': _prism_data,
- 'rainbow': _rainbow_data,
- 'seismic': _seismic_data,
- 'spring': _spring_data,
- 'summer': _summer_data,
- 'terrain': _terrain_data,
- 'winter': _winter_data,
- # Qualitative
- 'Accent': {'listed': _Accent_data},
- 'Dark2': {'listed': _Dark2_data},
- 'Paired': {'listed': _Paired_data},
- 'Pastel1': {'listed': _Pastel1_data},
- 'Pastel2': {'listed': _Pastel2_data},
- 'Set1': {'listed': _Set1_data},
- 'Set2': {'listed': _Set2_data},
- 'Set3': {'listed': _Set3_data},
- 'tab10': {'listed': _tab10_data},
- 'tab20': {'listed': _tab20_data},
- 'tab20b': {'listed': _tab20b_data},
- 'tab20c': {'listed': _tab20c_data},
-}
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_cm_listed.py b/server/venv/lib/python3.7/site-packages/matplotlib/_cm_listed.py
deleted file mode 100644
index cd70b28..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_cm_listed.py
+++ /dev/null
@@ -1,1816 +0,0 @@
-from .colors import ListedColormap
-
-_magma_data = [[0.001462, 0.000466, 0.013866],
- [0.002258, 0.001295, 0.018331],
- [0.003279, 0.002305, 0.023708],
- [0.004512, 0.003490, 0.029965],
- [0.005950, 0.004843, 0.037130],
- [0.007588, 0.006356, 0.044973],
- [0.009426, 0.008022, 0.052844],
- [0.011465, 0.009828, 0.060750],
- [0.013708, 0.011771, 0.068667],
- [0.016156, 0.013840, 0.076603],
- [0.018815, 0.016026, 0.084584],
- [0.021692, 0.018320, 0.092610],
- [0.024792, 0.020715, 0.100676],
- [0.028123, 0.023201, 0.108787],
- [0.031696, 0.025765, 0.116965],
- [0.035520, 0.028397, 0.125209],
- [0.039608, 0.031090, 0.133515],
- [0.043830, 0.033830, 0.141886],
- [0.048062, 0.036607, 0.150327],
- [0.052320, 0.039407, 0.158841],
- [0.056615, 0.042160, 0.167446],
- [0.060949, 0.044794, 0.176129],
- [0.065330, 0.047318, 0.184892],
- [0.069764, 0.049726, 0.193735],
- [0.074257, 0.052017, 0.202660],
- [0.078815, 0.054184, 0.211667],
- [0.083446, 0.056225, 0.220755],
- [0.088155, 0.058133, 0.229922],
- [0.092949, 0.059904, 0.239164],
- [0.097833, 0.061531, 0.248477],
- [0.102815, 0.063010, 0.257854],
- [0.107899, 0.064335, 0.267289],
- [0.113094, 0.065492, 0.276784],
- [0.118405, 0.066479, 0.286321],
- [0.123833, 0.067295, 0.295879],
- [0.129380, 0.067935, 0.305443],
- [0.135053, 0.068391, 0.315000],
- [0.140858, 0.068654, 0.324538],
- [0.146785, 0.068738, 0.334011],
- [0.152839, 0.068637, 0.343404],
- [0.159018, 0.068354, 0.352688],
- [0.165308, 0.067911, 0.361816],
- [0.171713, 0.067305, 0.370771],
- [0.178212, 0.066576, 0.379497],
- [0.184801, 0.065732, 0.387973],
- [0.191460, 0.064818, 0.396152],
- [0.198177, 0.063862, 0.404009],
- [0.204935, 0.062907, 0.411514],
- [0.211718, 0.061992, 0.418647],
- [0.218512, 0.061158, 0.425392],
- [0.225302, 0.060445, 0.431742],
- [0.232077, 0.059889, 0.437695],
- [0.238826, 0.059517, 0.443256],
- [0.245543, 0.059352, 0.448436],
- [0.252220, 0.059415, 0.453248],
- [0.258857, 0.059706, 0.457710],
- [0.265447, 0.060237, 0.461840],
- [0.271994, 0.060994, 0.465660],
- [0.278493, 0.061978, 0.469190],
- [0.284951, 0.063168, 0.472451],
- [0.291366, 0.064553, 0.475462],
- [0.297740, 0.066117, 0.478243],
- [0.304081, 0.067835, 0.480812],
- [0.310382, 0.069702, 0.483186],
- [0.316654, 0.071690, 0.485380],
- [0.322899, 0.073782, 0.487408],
- [0.329114, 0.075972, 0.489287],
- [0.335308, 0.078236, 0.491024],
- [0.341482, 0.080564, 0.492631],
- [0.347636, 0.082946, 0.494121],
- [0.353773, 0.085373, 0.495501],
- [0.359898, 0.087831, 0.496778],
- [0.366012, 0.090314, 0.497960],
- [0.372116, 0.092816, 0.499053],
- [0.378211, 0.095332, 0.500067],
- [0.384299, 0.097855, 0.501002],
- [0.390384, 0.100379, 0.501864],
- [0.396467, 0.102902, 0.502658],
- [0.402548, 0.105420, 0.503386],
- [0.408629, 0.107930, 0.504052],
- [0.414709, 0.110431, 0.504662],
- [0.420791, 0.112920, 0.505215],
- [0.426877, 0.115395, 0.505714],
- [0.432967, 0.117855, 0.506160],
- [0.439062, 0.120298, 0.506555],
- [0.445163, 0.122724, 0.506901],
- [0.451271, 0.125132, 0.507198],
- [0.457386, 0.127522, 0.507448],
- [0.463508, 0.129893, 0.507652],
- [0.469640, 0.132245, 0.507809],
- [0.475780, 0.134577, 0.507921],
- [0.481929, 0.136891, 0.507989],
- [0.488088, 0.139186, 0.508011],
- [0.494258, 0.141462, 0.507988],
- [0.500438, 0.143719, 0.507920],
- [0.506629, 0.145958, 0.507806],
- [0.512831, 0.148179, 0.507648],
- [0.519045, 0.150383, 0.507443],
- [0.525270, 0.152569, 0.507192],
- [0.531507, 0.154739, 0.506895],
- [0.537755, 0.156894, 0.506551],
- [0.544015, 0.159033, 0.506159],
- [0.550287, 0.161158, 0.505719],
- [0.556571, 0.163269, 0.505230],
- [0.562866, 0.165368, 0.504692],
- [0.569172, 0.167454, 0.504105],
- [0.575490, 0.169530, 0.503466],
- [0.581819, 0.171596, 0.502777],
- [0.588158, 0.173652, 0.502035],
- [0.594508, 0.175701, 0.501241],
- [0.600868, 0.177743, 0.500394],
- [0.607238, 0.179779, 0.499492],
- [0.613617, 0.181811, 0.498536],
- [0.620005, 0.183840, 0.497524],
- [0.626401, 0.185867, 0.496456],
- [0.632805, 0.187893, 0.495332],
- [0.639216, 0.189921, 0.494150],
- [0.645633, 0.191952, 0.492910],
- [0.652056, 0.193986, 0.491611],
- [0.658483, 0.196027, 0.490253],
- [0.664915, 0.198075, 0.488836],
- [0.671349, 0.200133, 0.487358],
- [0.677786, 0.202203, 0.485819],
- [0.684224, 0.204286, 0.484219],
- [0.690661, 0.206384, 0.482558],
- [0.697098, 0.208501, 0.480835],
- [0.703532, 0.210638, 0.479049],
- [0.709962, 0.212797, 0.477201],
- [0.716387, 0.214982, 0.475290],
- [0.722805, 0.217194, 0.473316],
- [0.729216, 0.219437, 0.471279],
- [0.735616, 0.221713, 0.469180],
- [0.742004, 0.224025, 0.467018],
- [0.748378, 0.226377, 0.464794],
- [0.754737, 0.228772, 0.462509],
- [0.761077, 0.231214, 0.460162],
- [0.767398, 0.233705, 0.457755],
- [0.773695, 0.236249, 0.455289],
- [0.779968, 0.238851, 0.452765],
- [0.786212, 0.241514, 0.450184],
- [0.792427, 0.244242, 0.447543],
- [0.798608, 0.247040, 0.444848],
- [0.804752, 0.249911, 0.442102],
- [0.810855, 0.252861, 0.439305],
- [0.816914, 0.255895, 0.436461],
- [0.822926, 0.259016, 0.433573],
- [0.828886, 0.262229, 0.430644],
- [0.834791, 0.265540, 0.427671],
- [0.840636, 0.268953, 0.424666],
- [0.846416, 0.272473, 0.421631],
- [0.852126, 0.276106, 0.418573],
- [0.857763, 0.279857, 0.415496],
- [0.863320, 0.283729, 0.412403],
- [0.868793, 0.287728, 0.409303],
- [0.874176, 0.291859, 0.406205],
- [0.879464, 0.296125, 0.403118],
- [0.884651, 0.300530, 0.400047],
- [0.889731, 0.305079, 0.397002],
- [0.894700, 0.309773, 0.393995],
- [0.899552, 0.314616, 0.391037],
- [0.904281, 0.319610, 0.388137],
- [0.908884, 0.324755, 0.385308],
- [0.913354, 0.330052, 0.382563],
- [0.917689, 0.335500, 0.379915],
- [0.921884, 0.341098, 0.377376],
- [0.925937, 0.346844, 0.374959],
- [0.929845, 0.352734, 0.372677],
- [0.933606, 0.358764, 0.370541],
- [0.937221, 0.364929, 0.368567],
- [0.940687, 0.371224, 0.366762],
- [0.944006, 0.377643, 0.365136],
- [0.947180, 0.384178, 0.363701],
- [0.950210, 0.390820, 0.362468],
- [0.953099, 0.397563, 0.361438],
- [0.955849, 0.404400, 0.360619],
- [0.958464, 0.411324, 0.360014],
- [0.960949, 0.418323, 0.359630],
- [0.963310, 0.425390, 0.359469],
- [0.965549, 0.432519, 0.359529],
- [0.967671, 0.439703, 0.359810],
- [0.969680, 0.446936, 0.360311],
- [0.971582, 0.454210, 0.361030],
- [0.973381, 0.461520, 0.361965],
- [0.975082, 0.468861, 0.363111],
- [0.976690, 0.476226, 0.364466],
- [0.978210, 0.483612, 0.366025],
- [0.979645, 0.491014, 0.367783],
- [0.981000, 0.498428, 0.369734],
- [0.982279, 0.505851, 0.371874],
- [0.983485, 0.513280, 0.374198],
- [0.984622, 0.520713, 0.376698],
- [0.985693, 0.528148, 0.379371],
- [0.986700, 0.535582, 0.382210],
- [0.987646, 0.543015, 0.385210],
- [0.988533, 0.550446, 0.388365],
- [0.989363, 0.557873, 0.391671],
- [0.990138, 0.565296, 0.395122],
- [0.990871, 0.572706, 0.398714],
- [0.991558, 0.580107, 0.402441],
- [0.992196, 0.587502, 0.406299],
- [0.992785, 0.594891, 0.410283],
- [0.993326, 0.602275, 0.414390],
- [0.993834, 0.609644, 0.418613],
- [0.994309, 0.616999, 0.422950],
- [0.994738, 0.624350, 0.427397],
- [0.995122, 0.631696, 0.431951],
- [0.995480, 0.639027, 0.436607],
- [0.995810, 0.646344, 0.441361],
- [0.996096, 0.653659, 0.446213],
- [0.996341, 0.660969, 0.451160],
- [0.996580, 0.668256, 0.456192],
- [0.996775, 0.675541, 0.461314],
- [0.996925, 0.682828, 0.466526],
- [0.997077, 0.690088, 0.471811],
- [0.997186, 0.697349, 0.477182],
- [0.997254, 0.704611, 0.482635],
- [0.997325, 0.711848, 0.488154],
- [0.997351, 0.719089, 0.493755],
- [0.997351, 0.726324, 0.499428],
- [0.997341, 0.733545, 0.505167],
- [0.997285, 0.740772, 0.510983],
- [0.997228, 0.747981, 0.516859],
- [0.997138, 0.755190, 0.522806],
- [0.997019, 0.762398, 0.528821],
- [0.996898, 0.769591, 0.534892],
- [0.996727, 0.776795, 0.541039],
- [0.996571, 0.783977, 0.547233],
- [0.996369, 0.791167, 0.553499],
- [0.996162, 0.798348, 0.559820],
- [0.995932, 0.805527, 0.566202],
- [0.995680, 0.812706, 0.572645],
- [0.995424, 0.819875, 0.579140],
- [0.995131, 0.827052, 0.585701],
- [0.994851, 0.834213, 0.592307],
- [0.994524, 0.841387, 0.598983],
- [0.994222, 0.848540, 0.605696],
- [0.993866, 0.855711, 0.612482],
- [0.993545, 0.862859, 0.619299],
- [0.993170, 0.870024, 0.626189],
- [0.992831, 0.877168, 0.633109],
- [0.992440, 0.884330, 0.640099],
- [0.992089, 0.891470, 0.647116],
- [0.991688, 0.898627, 0.654202],
- [0.991332, 0.905763, 0.661309],
- [0.990930, 0.912915, 0.668481],
- [0.990570, 0.920049, 0.675675],
- [0.990175, 0.927196, 0.682926],
- [0.989815, 0.934329, 0.690198],
- [0.989434, 0.941470, 0.697519],
- [0.989077, 0.948604, 0.704863],
- [0.988717, 0.955742, 0.712242],
- [0.988367, 0.962878, 0.719649],
- [0.988033, 0.970012, 0.727077],
- [0.987691, 0.977154, 0.734536],
- [0.987387, 0.984288, 0.742002],
- [0.987053, 0.991438, 0.749504]]
-
-_inferno_data = [[0.001462, 0.000466, 0.013866],
- [0.002267, 0.001270, 0.018570],
- [0.003299, 0.002249, 0.024239],
- [0.004547, 0.003392, 0.030909],
- [0.006006, 0.004692, 0.038558],
- [0.007676, 0.006136, 0.046836],
- [0.009561, 0.007713, 0.055143],
- [0.011663, 0.009417, 0.063460],
- [0.013995, 0.011225, 0.071862],
- [0.016561, 0.013136, 0.080282],
- [0.019373, 0.015133, 0.088767],
- [0.022447, 0.017199, 0.097327],
- [0.025793, 0.019331, 0.105930],
- [0.029432, 0.021503, 0.114621],
- [0.033385, 0.023702, 0.123397],
- [0.037668, 0.025921, 0.132232],
- [0.042253, 0.028139, 0.141141],
- [0.046915, 0.030324, 0.150164],
- [0.051644, 0.032474, 0.159254],
- [0.056449, 0.034569, 0.168414],
- [0.061340, 0.036590, 0.177642],
- [0.066331, 0.038504, 0.186962],
- [0.071429, 0.040294, 0.196354],
- [0.076637, 0.041905, 0.205799],
- [0.081962, 0.043328, 0.215289],
- [0.087411, 0.044556, 0.224813],
- [0.092990, 0.045583, 0.234358],
- [0.098702, 0.046402, 0.243904],
- [0.104551, 0.047008, 0.253430],
- [0.110536, 0.047399, 0.262912],
- [0.116656, 0.047574, 0.272321],
- [0.122908, 0.047536, 0.281624],
- [0.129285, 0.047293, 0.290788],
- [0.135778, 0.046856, 0.299776],
- [0.142378, 0.046242, 0.308553],
- [0.149073, 0.045468, 0.317085],
- [0.155850, 0.044559, 0.325338],
- [0.162689, 0.043554, 0.333277],
- [0.169575, 0.042489, 0.340874],
- [0.176493, 0.041402, 0.348111],
- [0.183429, 0.040329, 0.354971],
- [0.190367, 0.039309, 0.361447],
- [0.197297, 0.038400, 0.367535],
- [0.204209, 0.037632, 0.373238],
- [0.211095, 0.037030, 0.378563],
- [0.217949, 0.036615, 0.383522],
- [0.224763, 0.036405, 0.388129],
- [0.231538, 0.036405, 0.392400],
- [0.238273, 0.036621, 0.396353],
- [0.244967, 0.037055, 0.400007],
- [0.251620, 0.037705, 0.403378],
- [0.258234, 0.038571, 0.406485],
- [0.264810, 0.039647, 0.409345],
- [0.271347, 0.040922, 0.411976],
- [0.277850, 0.042353, 0.414392],
- [0.284321, 0.043933, 0.416608],
- [0.290763, 0.045644, 0.418637],
- [0.297178, 0.047470, 0.420491],
- [0.303568, 0.049396, 0.422182],
- [0.309935, 0.051407, 0.423721],
- [0.316282, 0.053490, 0.425116],
- [0.322610, 0.055634, 0.426377],
- [0.328921, 0.057827, 0.427511],
- [0.335217, 0.060060, 0.428524],
- [0.341500, 0.062325, 0.429425],
- [0.347771, 0.064616, 0.430217],
- [0.354032, 0.066925, 0.430906],
- [0.360284, 0.069247, 0.431497],
- [0.366529, 0.071579, 0.431994],
- [0.372768, 0.073915, 0.432400],
- [0.379001, 0.076253, 0.432719],
- [0.385228, 0.078591, 0.432955],
- [0.391453, 0.080927, 0.433109],
- [0.397674, 0.083257, 0.433183],
- [0.403894, 0.085580, 0.433179],
- [0.410113, 0.087896, 0.433098],
- [0.416331, 0.090203, 0.432943],
- [0.422549, 0.092501, 0.432714],
- [0.428768, 0.094790, 0.432412],
- [0.434987, 0.097069, 0.432039],
- [0.441207, 0.099338, 0.431594],
- [0.447428, 0.101597, 0.431080],
- [0.453651, 0.103848, 0.430498],
- [0.459875, 0.106089, 0.429846],
- [0.466100, 0.108322, 0.429125],
- [0.472328, 0.110547, 0.428334],
- [0.478558, 0.112764, 0.427475],
- [0.484789, 0.114974, 0.426548],
- [0.491022, 0.117179, 0.425552],
- [0.497257, 0.119379, 0.424488],
- [0.503493, 0.121575, 0.423356],
- [0.509730, 0.123769, 0.422156],
- [0.515967, 0.125960, 0.420887],
- [0.522206, 0.128150, 0.419549],
- [0.528444, 0.130341, 0.418142],
- [0.534683, 0.132534, 0.416667],
- [0.540920, 0.134729, 0.415123],
- [0.547157, 0.136929, 0.413511],
- [0.553392, 0.139134, 0.411829],
- [0.559624, 0.141346, 0.410078],
- [0.565854, 0.143567, 0.408258],
- [0.572081, 0.145797, 0.406369],
- [0.578304, 0.148039, 0.404411],
- [0.584521, 0.150294, 0.402385],
- [0.590734, 0.152563, 0.400290],
- [0.596940, 0.154848, 0.398125],
- [0.603139, 0.157151, 0.395891],
- [0.609330, 0.159474, 0.393589],
- [0.615513, 0.161817, 0.391219],
- [0.621685, 0.164184, 0.388781],
- [0.627847, 0.166575, 0.386276],
- [0.633998, 0.168992, 0.383704],
- [0.640135, 0.171438, 0.381065],
- [0.646260, 0.173914, 0.378359],
- [0.652369, 0.176421, 0.375586],
- [0.658463, 0.178962, 0.372748],
- [0.664540, 0.181539, 0.369846],
- [0.670599, 0.184153, 0.366879],
- [0.676638, 0.186807, 0.363849],
- [0.682656, 0.189501, 0.360757],
- [0.688653, 0.192239, 0.357603],
- [0.694627, 0.195021, 0.354388],
- [0.700576, 0.197851, 0.351113],
- [0.706500, 0.200728, 0.347777],
- [0.712396, 0.203656, 0.344383],
- [0.718264, 0.206636, 0.340931],
- [0.724103, 0.209670, 0.337424],
- [0.729909, 0.212759, 0.333861],
- [0.735683, 0.215906, 0.330245],
- [0.741423, 0.219112, 0.326576],
- [0.747127, 0.222378, 0.322856],
- [0.752794, 0.225706, 0.319085],
- [0.758422, 0.229097, 0.315266],
- [0.764010, 0.232554, 0.311399],
- [0.769556, 0.236077, 0.307485],
- [0.775059, 0.239667, 0.303526],
- [0.780517, 0.243327, 0.299523],
- [0.785929, 0.247056, 0.295477],
- [0.791293, 0.250856, 0.291390],
- [0.796607, 0.254728, 0.287264],
- [0.801871, 0.258674, 0.283099],
- [0.807082, 0.262692, 0.278898],
- [0.812239, 0.266786, 0.274661],
- [0.817341, 0.270954, 0.270390],
- [0.822386, 0.275197, 0.266085],
- [0.827372, 0.279517, 0.261750],
- [0.832299, 0.283913, 0.257383],
- [0.837165, 0.288385, 0.252988],
- [0.841969, 0.292933, 0.248564],
- [0.846709, 0.297559, 0.244113],
- [0.851384, 0.302260, 0.239636],
- [0.855992, 0.307038, 0.235133],
- [0.860533, 0.311892, 0.230606],
- [0.865006, 0.316822, 0.226055],
- [0.869409, 0.321827, 0.221482],
- [0.873741, 0.326906, 0.216886],
- [0.878001, 0.332060, 0.212268],
- [0.882188, 0.337287, 0.207628],
- [0.886302, 0.342586, 0.202968],
- [0.890341, 0.347957, 0.198286],
- [0.894305, 0.353399, 0.193584],
- [0.898192, 0.358911, 0.188860],
- [0.902003, 0.364492, 0.184116],
- [0.905735, 0.370140, 0.179350],
- [0.909390, 0.375856, 0.174563],
- [0.912966, 0.381636, 0.169755],
- [0.916462, 0.387481, 0.164924],
- [0.919879, 0.393389, 0.160070],
- [0.923215, 0.399359, 0.155193],
- [0.926470, 0.405389, 0.150292],
- [0.929644, 0.411479, 0.145367],
- [0.932737, 0.417627, 0.140417],
- [0.935747, 0.423831, 0.135440],
- [0.938675, 0.430091, 0.130438],
- [0.941521, 0.436405, 0.125409],
- [0.944285, 0.442772, 0.120354],
- [0.946965, 0.449191, 0.115272],
- [0.949562, 0.455660, 0.110164],
- [0.952075, 0.462178, 0.105031],
- [0.954506, 0.468744, 0.099874],
- [0.956852, 0.475356, 0.094695],
- [0.959114, 0.482014, 0.089499],
- [0.961293, 0.488716, 0.084289],
- [0.963387, 0.495462, 0.079073],
- [0.965397, 0.502249, 0.073859],
- [0.967322, 0.509078, 0.068659],
- [0.969163, 0.515946, 0.063488],
- [0.970919, 0.522853, 0.058367],
- [0.972590, 0.529798, 0.053324],
- [0.974176, 0.536780, 0.048392],
- [0.975677, 0.543798, 0.043618],
- [0.977092, 0.550850, 0.039050],
- [0.978422, 0.557937, 0.034931],
- [0.979666, 0.565057, 0.031409],
- [0.980824, 0.572209, 0.028508],
- [0.981895, 0.579392, 0.026250],
- [0.982881, 0.586606, 0.024661],
- [0.983779, 0.593849, 0.023770],
- [0.984591, 0.601122, 0.023606],
- [0.985315, 0.608422, 0.024202],
- [0.985952, 0.615750, 0.025592],
- [0.986502, 0.623105, 0.027814],
- [0.986964, 0.630485, 0.030908],
- [0.987337, 0.637890, 0.034916],
- [0.987622, 0.645320, 0.039886],
- [0.987819, 0.652773, 0.045581],
- [0.987926, 0.660250, 0.051750],
- [0.987945, 0.667748, 0.058329],
- [0.987874, 0.675267, 0.065257],
- [0.987714, 0.682807, 0.072489],
- [0.987464, 0.690366, 0.079990],
- [0.987124, 0.697944, 0.087731],
- [0.986694, 0.705540, 0.095694],
- [0.986175, 0.713153, 0.103863],
- [0.985566, 0.720782, 0.112229],
- [0.984865, 0.728427, 0.120785],
- [0.984075, 0.736087, 0.129527],
- [0.983196, 0.743758, 0.138453],
- [0.982228, 0.751442, 0.147565],
- [0.981173, 0.759135, 0.156863],
- [0.980032, 0.766837, 0.166353],
- [0.978806, 0.774545, 0.176037],
- [0.977497, 0.782258, 0.185923],
- [0.976108, 0.789974, 0.196018],
- [0.974638, 0.797692, 0.206332],
- [0.973088, 0.805409, 0.216877],
- [0.971468, 0.813122, 0.227658],
- [0.969783, 0.820825, 0.238686],
- [0.968041, 0.828515, 0.249972],
- [0.966243, 0.836191, 0.261534],
- [0.964394, 0.843848, 0.273391],
- [0.962517, 0.851476, 0.285546],
- [0.960626, 0.859069, 0.298010],
- [0.958720, 0.866624, 0.310820],
- [0.956834, 0.874129, 0.323974],
- [0.954997, 0.881569, 0.337475],
- [0.953215, 0.888942, 0.351369],
- [0.951546, 0.896226, 0.365627],
- [0.950018, 0.903409, 0.380271],
- [0.948683, 0.910473, 0.395289],
- [0.947594, 0.917399, 0.410665],
- [0.946809, 0.924168, 0.426373],
- [0.946392, 0.930761, 0.442367],
- [0.946403, 0.937159, 0.458592],
- [0.946903, 0.943348, 0.474970],
- [0.947937, 0.949318, 0.491426],
- [0.949545, 0.955063, 0.507860],
- [0.951740, 0.960587, 0.524203],
- [0.954529, 0.965896, 0.540361],
- [0.957896, 0.971003, 0.556275],
- [0.961812, 0.975924, 0.571925],
- [0.966249, 0.980678, 0.587206],
- [0.971162, 0.985282, 0.602154],
- [0.976511, 0.989753, 0.616760],
- [0.982257, 0.994109, 0.631017],
- [0.988362, 0.998364, 0.644924]]
-
-_plasma_data = [[0.050383, 0.029803, 0.527975],
- [0.063536, 0.028426, 0.533124],
- [0.075353, 0.027206, 0.538007],
- [0.086222, 0.026125, 0.542658],
- [0.096379, 0.025165, 0.547103],
- [0.105980, 0.024309, 0.551368],
- [0.115124, 0.023556, 0.555468],
- [0.123903, 0.022878, 0.559423],
- [0.132381, 0.022258, 0.563250],
- [0.140603, 0.021687, 0.566959],
- [0.148607, 0.021154, 0.570562],
- [0.156421, 0.020651, 0.574065],
- [0.164070, 0.020171, 0.577478],
- [0.171574, 0.019706, 0.580806],
- [0.178950, 0.019252, 0.584054],
- [0.186213, 0.018803, 0.587228],
- [0.193374, 0.018354, 0.590330],
- [0.200445, 0.017902, 0.593364],
- [0.207435, 0.017442, 0.596333],
- [0.214350, 0.016973, 0.599239],
- [0.221197, 0.016497, 0.602083],
- [0.227983, 0.016007, 0.604867],
- [0.234715, 0.015502, 0.607592],
- [0.241396, 0.014979, 0.610259],
- [0.248032, 0.014439, 0.612868],
- [0.254627, 0.013882, 0.615419],
- [0.261183, 0.013308, 0.617911],
- [0.267703, 0.012716, 0.620346],
- [0.274191, 0.012109, 0.622722],
- [0.280648, 0.011488, 0.625038],
- [0.287076, 0.010855, 0.627295],
- [0.293478, 0.010213, 0.629490],
- [0.299855, 0.009561, 0.631624],
- [0.306210, 0.008902, 0.633694],
- [0.312543, 0.008239, 0.635700],
- [0.318856, 0.007576, 0.637640],
- [0.325150, 0.006915, 0.639512],
- [0.331426, 0.006261, 0.641316],
- [0.337683, 0.005618, 0.643049],
- [0.343925, 0.004991, 0.644710],
- [0.350150, 0.004382, 0.646298],
- [0.356359, 0.003798, 0.647810],
- [0.362553, 0.003243, 0.649245],
- [0.368733, 0.002724, 0.650601],
- [0.374897, 0.002245, 0.651876],
- [0.381047, 0.001814, 0.653068],
- [0.387183, 0.001434, 0.654177],
- [0.393304, 0.001114, 0.655199],
- [0.399411, 0.000859, 0.656133],
- [0.405503, 0.000678, 0.656977],
- [0.411580, 0.000577, 0.657730],
- [0.417642, 0.000564, 0.658390],
- [0.423689, 0.000646, 0.658956],
- [0.429719, 0.000831, 0.659425],
- [0.435734, 0.001127, 0.659797],
- [0.441732, 0.001540, 0.660069],
- [0.447714, 0.002080, 0.660240],
- [0.453677, 0.002755, 0.660310],
- [0.459623, 0.003574, 0.660277],
- [0.465550, 0.004545, 0.660139],
- [0.471457, 0.005678, 0.659897],
- [0.477344, 0.006980, 0.659549],
- [0.483210, 0.008460, 0.659095],
- [0.489055, 0.010127, 0.658534],
- [0.494877, 0.011990, 0.657865],
- [0.500678, 0.014055, 0.657088],
- [0.506454, 0.016333, 0.656202],
- [0.512206, 0.018833, 0.655209],
- [0.517933, 0.021563, 0.654109],
- [0.523633, 0.024532, 0.652901],
- [0.529306, 0.027747, 0.651586],
- [0.534952, 0.031217, 0.650165],
- [0.540570, 0.034950, 0.648640],
- [0.546157, 0.038954, 0.647010],
- [0.551715, 0.043136, 0.645277],
- [0.557243, 0.047331, 0.643443],
- [0.562738, 0.051545, 0.641509],
- [0.568201, 0.055778, 0.639477],
- [0.573632, 0.060028, 0.637349],
- [0.579029, 0.064296, 0.635126],
- [0.584391, 0.068579, 0.632812],
- [0.589719, 0.072878, 0.630408],
- [0.595011, 0.077190, 0.627917],
- [0.600266, 0.081516, 0.625342],
- [0.605485, 0.085854, 0.622686],
- [0.610667, 0.090204, 0.619951],
- [0.615812, 0.094564, 0.617140],
- [0.620919, 0.098934, 0.614257],
- [0.625987, 0.103312, 0.611305],
- [0.631017, 0.107699, 0.608287],
- [0.636008, 0.112092, 0.605205],
- [0.640959, 0.116492, 0.602065],
- [0.645872, 0.120898, 0.598867],
- [0.650746, 0.125309, 0.595617],
- [0.655580, 0.129725, 0.592317],
- [0.660374, 0.134144, 0.588971],
- [0.665129, 0.138566, 0.585582],
- [0.669845, 0.142992, 0.582154],
- [0.674522, 0.147419, 0.578688],
- [0.679160, 0.151848, 0.575189],
- [0.683758, 0.156278, 0.571660],
- [0.688318, 0.160709, 0.568103],
- [0.692840, 0.165141, 0.564522],
- [0.697324, 0.169573, 0.560919],
- [0.701769, 0.174005, 0.557296],
- [0.706178, 0.178437, 0.553657],
- [0.710549, 0.182868, 0.550004],
- [0.714883, 0.187299, 0.546338],
- [0.719181, 0.191729, 0.542663],
- [0.723444, 0.196158, 0.538981],
- [0.727670, 0.200586, 0.535293],
- [0.731862, 0.205013, 0.531601],
- [0.736019, 0.209439, 0.527908],
- [0.740143, 0.213864, 0.524216],
- [0.744232, 0.218288, 0.520524],
- [0.748289, 0.222711, 0.516834],
- [0.752312, 0.227133, 0.513149],
- [0.756304, 0.231555, 0.509468],
- [0.760264, 0.235976, 0.505794],
- [0.764193, 0.240396, 0.502126],
- [0.768090, 0.244817, 0.498465],
- [0.771958, 0.249237, 0.494813],
- [0.775796, 0.253658, 0.491171],
- [0.779604, 0.258078, 0.487539],
- [0.783383, 0.262500, 0.483918],
- [0.787133, 0.266922, 0.480307],
- [0.790855, 0.271345, 0.476706],
- [0.794549, 0.275770, 0.473117],
- [0.798216, 0.280197, 0.469538],
- [0.801855, 0.284626, 0.465971],
- [0.805467, 0.289057, 0.462415],
- [0.809052, 0.293491, 0.458870],
- [0.812612, 0.297928, 0.455338],
- [0.816144, 0.302368, 0.451816],
- [0.819651, 0.306812, 0.448306],
- [0.823132, 0.311261, 0.444806],
- [0.826588, 0.315714, 0.441316],
- [0.830018, 0.320172, 0.437836],
- [0.833422, 0.324635, 0.434366],
- [0.836801, 0.329105, 0.430905],
- [0.840155, 0.333580, 0.427455],
- [0.843484, 0.338062, 0.424013],
- [0.846788, 0.342551, 0.420579],
- [0.850066, 0.347048, 0.417153],
- [0.853319, 0.351553, 0.413734],
- [0.856547, 0.356066, 0.410322],
- [0.859750, 0.360588, 0.406917],
- [0.862927, 0.365119, 0.403519],
- [0.866078, 0.369660, 0.400126],
- [0.869203, 0.374212, 0.396738],
- [0.872303, 0.378774, 0.393355],
- [0.875376, 0.383347, 0.389976],
- [0.878423, 0.387932, 0.386600],
- [0.881443, 0.392529, 0.383229],
- [0.884436, 0.397139, 0.379860],
- [0.887402, 0.401762, 0.376494],
- [0.890340, 0.406398, 0.373130],
- [0.893250, 0.411048, 0.369768],
- [0.896131, 0.415712, 0.366407],
- [0.898984, 0.420392, 0.363047],
- [0.901807, 0.425087, 0.359688],
- [0.904601, 0.429797, 0.356329],
- [0.907365, 0.434524, 0.352970],
- [0.910098, 0.439268, 0.349610],
- [0.912800, 0.444029, 0.346251],
- [0.915471, 0.448807, 0.342890],
- [0.918109, 0.453603, 0.339529],
- [0.920714, 0.458417, 0.336166],
- [0.923287, 0.463251, 0.332801],
- [0.925825, 0.468103, 0.329435],
- [0.928329, 0.472975, 0.326067],
- [0.930798, 0.477867, 0.322697],
- [0.933232, 0.482780, 0.319325],
- [0.935630, 0.487712, 0.315952],
- [0.937990, 0.492667, 0.312575],
- [0.940313, 0.497642, 0.309197],
- [0.942598, 0.502639, 0.305816],
- [0.944844, 0.507658, 0.302433],
- [0.947051, 0.512699, 0.299049],
- [0.949217, 0.517763, 0.295662],
- [0.951344, 0.522850, 0.292275],
- [0.953428, 0.527960, 0.288883],
- [0.955470, 0.533093, 0.285490],
- [0.957469, 0.538250, 0.282096],
- [0.959424, 0.543431, 0.278701],
- [0.961336, 0.548636, 0.275305],
- [0.963203, 0.553865, 0.271909],
- [0.965024, 0.559118, 0.268513],
- [0.966798, 0.564396, 0.265118],
- [0.968526, 0.569700, 0.261721],
- [0.970205, 0.575028, 0.258325],
- [0.971835, 0.580382, 0.254931],
- [0.973416, 0.585761, 0.251540],
- [0.974947, 0.591165, 0.248151],
- [0.976428, 0.596595, 0.244767],
- [0.977856, 0.602051, 0.241387],
- [0.979233, 0.607532, 0.238013],
- [0.980556, 0.613039, 0.234646],
- [0.981826, 0.618572, 0.231287],
- [0.983041, 0.624131, 0.227937],
- [0.984199, 0.629718, 0.224595],
- [0.985301, 0.635330, 0.221265],
- [0.986345, 0.640969, 0.217948],
- [0.987332, 0.646633, 0.214648],
- [0.988260, 0.652325, 0.211364],
- [0.989128, 0.658043, 0.208100],
- [0.989935, 0.663787, 0.204859],
- [0.990681, 0.669558, 0.201642],
- [0.991365, 0.675355, 0.198453],
- [0.991985, 0.681179, 0.195295],
- [0.992541, 0.687030, 0.192170],
- [0.993032, 0.692907, 0.189084],
- [0.993456, 0.698810, 0.186041],
- [0.993814, 0.704741, 0.183043],
- [0.994103, 0.710698, 0.180097],
- [0.994324, 0.716681, 0.177208],
- [0.994474, 0.722691, 0.174381],
- [0.994553, 0.728728, 0.171622],
- [0.994561, 0.734791, 0.168938],
- [0.994495, 0.740880, 0.166335],
- [0.994355, 0.746995, 0.163821],
- [0.994141, 0.753137, 0.161404],
- [0.993851, 0.759304, 0.159092],
- [0.993482, 0.765499, 0.156891],
- [0.993033, 0.771720, 0.154808],
- [0.992505, 0.777967, 0.152855],
- [0.991897, 0.784239, 0.151042],
- [0.991209, 0.790537, 0.149377],
- [0.990439, 0.796859, 0.147870],
- [0.989587, 0.803205, 0.146529],
- [0.988648, 0.809579, 0.145357],
- [0.987621, 0.815978, 0.144363],
- [0.986509, 0.822401, 0.143557],
- [0.985314, 0.828846, 0.142945],
- [0.984031, 0.835315, 0.142528],
- [0.982653, 0.841812, 0.142303],
- [0.981190, 0.848329, 0.142279],
- [0.979644, 0.854866, 0.142453],
- [0.977995, 0.861432, 0.142808],
- [0.976265, 0.868016, 0.143351],
- [0.974443, 0.874622, 0.144061],
- [0.972530, 0.881250, 0.144923],
- [0.970533, 0.887896, 0.145919],
- [0.968443, 0.894564, 0.147014],
- [0.966271, 0.901249, 0.148180],
- [0.964021, 0.907950, 0.149370],
- [0.961681, 0.914672, 0.150520],
- [0.959276, 0.921407, 0.151566],
- [0.956808, 0.928152, 0.152409],
- [0.954287, 0.934908, 0.152921],
- [0.951726, 0.941671, 0.152925],
- [0.949151, 0.948435, 0.152178],
- [0.946602, 0.955190, 0.150328],
- [0.944152, 0.961916, 0.146861],
- [0.941896, 0.968590, 0.140956],
- [0.940015, 0.975158, 0.131326]]
-
-_viridis_data = [[0.267004, 0.004874, 0.329415],
- [0.268510, 0.009605, 0.335427],
- [0.269944, 0.014625, 0.341379],
- [0.271305, 0.019942, 0.347269],
- [0.272594, 0.025563, 0.353093],
- [0.273809, 0.031497, 0.358853],
- [0.274952, 0.037752, 0.364543],
- [0.276022, 0.044167, 0.370164],
- [0.277018, 0.050344, 0.375715],
- [0.277941, 0.056324, 0.381191],
- [0.278791, 0.062145, 0.386592],
- [0.279566, 0.067836, 0.391917],
- [0.280267, 0.073417, 0.397163],
- [0.280894, 0.078907, 0.402329],
- [0.281446, 0.084320, 0.407414],
- [0.281924, 0.089666, 0.412415],
- [0.282327, 0.094955, 0.417331],
- [0.282656, 0.100196, 0.422160],
- [0.282910, 0.105393, 0.426902],
- [0.283091, 0.110553, 0.431554],
- [0.283197, 0.115680, 0.436115],
- [0.283229, 0.120777, 0.440584],
- [0.283187, 0.125848, 0.444960],
- [0.283072, 0.130895, 0.449241],
- [0.282884, 0.135920, 0.453427],
- [0.282623, 0.140926, 0.457517],
- [0.282290, 0.145912, 0.461510],
- [0.281887, 0.150881, 0.465405],
- [0.281412, 0.155834, 0.469201],
- [0.280868, 0.160771, 0.472899],
- [0.280255, 0.165693, 0.476498],
- [0.279574, 0.170599, 0.479997],
- [0.278826, 0.175490, 0.483397],
- [0.278012, 0.180367, 0.486697],
- [0.277134, 0.185228, 0.489898],
- [0.276194, 0.190074, 0.493001],
- [0.275191, 0.194905, 0.496005],
- [0.274128, 0.199721, 0.498911],
- [0.273006, 0.204520, 0.501721],
- [0.271828, 0.209303, 0.504434],
- [0.270595, 0.214069, 0.507052],
- [0.269308, 0.218818, 0.509577],
- [0.267968, 0.223549, 0.512008],
- [0.266580, 0.228262, 0.514349],
- [0.265145, 0.232956, 0.516599],
- [0.263663, 0.237631, 0.518762],
- [0.262138, 0.242286, 0.520837],
- [0.260571, 0.246922, 0.522828],
- [0.258965, 0.251537, 0.524736],
- [0.257322, 0.256130, 0.526563],
- [0.255645, 0.260703, 0.528312],
- [0.253935, 0.265254, 0.529983],
- [0.252194, 0.269783, 0.531579],
- [0.250425, 0.274290, 0.533103],
- [0.248629, 0.278775, 0.534556],
- [0.246811, 0.283237, 0.535941],
- [0.244972, 0.287675, 0.537260],
- [0.243113, 0.292092, 0.538516],
- [0.241237, 0.296485, 0.539709],
- [0.239346, 0.300855, 0.540844],
- [0.237441, 0.305202, 0.541921],
- [0.235526, 0.309527, 0.542944],
- [0.233603, 0.313828, 0.543914],
- [0.231674, 0.318106, 0.544834],
- [0.229739, 0.322361, 0.545706],
- [0.227802, 0.326594, 0.546532],
- [0.225863, 0.330805, 0.547314],
- [0.223925, 0.334994, 0.548053],
- [0.221989, 0.339161, 0.548752],
- [0.220057, 0.343307, 0.549413],
- [0.218130, 0.347432, 0.550038],
- [0.216210, 0.351535, 0.550627],
- [0.214298, 0.355619, 0.551184],
- [0.212395, 0.359683, 0.551710],
- [0.210503, 0.363727, 0.552206],
- [0.208623, 0.367752, 0.552675],
- [0.206756, 0.371758, 0.553117],
- [0.204903, 0.375746, 0.553533],
- [0.203063, 0.379716, 0.553925],
- [0.201239, 0.383670, 0.554294],
- [0.199430, 0.387607, 0.554642],
- [0.197636, 0.391528, 0.554969],
- [0.195860, 0.395433, 0.555276],
- [0.194100, 0.399323, 0.555565],
- [0.192357, 0.403199, 0.555836],
- [0.190631, 0.407061, 0.556089],
- [0.188923, 0.410910, 0.556326],
- [0.187231, 0.414746, 0.556547],
- [0.185556, 0.418570, 0.556753],
- [0.183898, 0.422383, 0.556944],
- [0.182256, 0.426184, 0.557120],
- [0.180629, 0.429975, 0.557282],
- [0.179019, 0.433756, 0.557430],
- [0.177423, 0.437527, 0.557565],
- [0.175841, 0.441290, 0.557685],
- [0.174274, 0.445044, 0.557792],
- [0.172719, 0.448791, 0.557885],
- [0.171176, 0.452530, 0.557965],
- [0.169646, 0.456262, 0.558030],
- [0.168126, 0.459988, 0.558082],
- [0.166617, 0.463708, 0.558119],
- [0.165117, 0.467423, 0.558141],
- [0.163625, 0.471133, 0.558148],
- [0.162142, 0.474838, 0.558140],
- [0.160665, 0.478540, 0.558115],
- [0.159194, 0.482237, 0.558073],
- [0.157729, 0.485932, 0.558013],
- [0.156270, 0.489624, 0.557936],
- [0.154815, 0.493313, 0.557840],
- [0.153364, 0.497000, 0.557724],
- [0.151918, 0.500685, 0.557587],
- [0.150476, 0.504369, 0.557430],
- [0.149039, 0.508051, 0.557250],
- [0.147607, 0.511733, 0.557049],
- [0.146180, 0.515413, 0.556823],
- [0.144759, 0.519093, 0.556572],
- [0.143343, 0.522773, 0.556295],
- [0.141935, 0.526453, 0.555991],
- [0.140536, 0.530132, 0.555659],
- [0.139147, 0.533812, 0.555298],
- [0.137770, 0.537492, 0.554906],
- [0.136408, 0.541173, 0.554483],
- [0.135066, 0.544853, 0.554029],
- [0.133743, 0.548535, 0.553541],
- [0.132444, 0.552216, 0.553018],
- [0.131172, 0.555899, 0.552459],
- [0.129933, 0.559582, 0.551864],
- [0.128729, 0.563265, 0.551229],
- [0.127568, 0.566949, 0.550556],
- [0.126453, 0.570633, 0.549841],
- [0.125394, 0.574318, 0.549086],
- [0.124395, 0.578002, 0.548287],
- [0.123463, 0.581687, 0.547445],
- [0.122606, 0.585371, 0.546557],
- [0.121831, 0.589055, 0.545623],
- [0.121148, 0.592739, 0.544641],
- [0.120565, 0.596422, 0.543611],
- [0.120092, 0.600104, 0.542530],
- [0.119738, 0.603785, 0.541400],
- [0.119512, 0.607464, 0.540218],
- [0.119423, 0.611141, 0.538982],
- [0.119483, 0.614817, 0.537692],
- [0.119699, 0.618490, 0.536347],
- [0.120081, 0.622161, 0.534946],
- [0.120638, 0.625828, 0.533488],
- [0.121380, 0.629492, 0.531973],
- [0.122312, 0.633153, 0.530398],
- [0.123444, 0.636809, 0.528763],
- [0.124780, 0.640461, 0.527068],
- [0.126326, 0.644107, 0.525311],
- [0.128087, 0.647749, 0.523491],
- [0.130067, 0.651384, 0.521608],
- [0.132268, 0.655014, 0.519661],
- [0.134692, 0.658636, 0.517649],
- [0.137339, 0.662252, 0.515571],
- [0.140210, 0.665859, 0.513427],
- [0.143303, 0.669459, 0.511215],
- [0.146616, 0.673050, 0.508936],
- [0.150148, 0.676631, 0.506589],
- [0.153894, 0.680203, 0.504172],
- [0.157851, 0.683765, 0.501686],
- [0.162016, 0.687316, 0.499129],
- [0.166383, 0.690856, 0.496502],
- [0.170948, 0.694384, 0.493803],
- [0.175707, 0.697900, 0.491033],
- [0.180653, 0.701402, 0.488189],
- [0.185783, 0.704891, 0.485273],
- [0.191090, 0.708366, 0.482284],
- [0.196571, 0.711827, 0.479221],
- [0.202219, 0.715272, 0.476084],
- [0.208030, 0.718701, 0.472873],
- [0.214000, 0.722114, 0.469588],
- [0.220124, 0.725509, 0.466226],
- [0.226397, 0.728888, 0.462789],
- [0.232815, 0.732247, 0.459277],
- [0.239374, 0.735588, 0.455688],
- [0.246070, 0.738910, 0.452024],
- [0.252899, 0.742211, 0.448284],
- [0.259857, 0.745492, 0.444467],
- [0.266941, 0.748751, 0.440573],
- [0.274149, 0.751988, 0.436601],
- [0.281477, 0.755203, 0.432552],
- [0.288921, 0.758394, 0.428426],
- [0.296479, 0.761561, 0.424223],
- [0.304148, 0.764704, 0.419943],
- [0.311925, 0.767822, 0.415586],
- [0.319809, 0.770914, 0.411152],
- [0.327796, 0.773980, 0.406640],
- [0.335885, 0.777018, 0.402049],
- [0.344074, 0.780029, 0.397381],
- [0.352360, 0.783011, 0.392636],
- [0.360741, 0.785964, 0.387814],
- [0.369214, 0.788888, 0.382914],
- [0.377779, 0.791781, 0.377939],
- [0.386433, 0.794644, 0.372886],
- [0.395174, 0.797475, 0.367757],
- [0.404001, 0.800275, 0.362552],
- [0.412913, 0.803041, 0.357269],
- [0.421908, 0.805774, 0.351910],
- [0.430983, 0.808473, 0.346476],
- [0.440137, 0.811138, 0.340967],
- [0.449368, 0.813768, 0.335384],
- [0.458674, 0.816363, 0.329727],
- [0.468053, 0.818921, 0.323998],
- [0.477504, 0.821444, 0.318195],
- [0.487026, 0.823929, 0.312321],
- [0.496615, 0.826376, 0.306377],
- [0.506271, 0.828786, 0.300362],
- [0.515992, 0.831158, 0.294279],
- [0.525776, 0.833491, 0.288127],
- [0.535621, 0.835785, 0.281908],
- [0.545524, 0.838039, 0.275626],
- [0.555484, 0.840254, 0.269281],
- [0.565498, 0.842430, 0.262877],
- [0.575563, 0.844566, 0.256415],
- [0.585678, 0.846661, 0.249897],
- [0.595839, 0.848717, 0.243329],
- [0.606045, 0.850733, 0.236712],
- [0.616293, 0.852709, 0.230052],
- [0.626579, 0.854645, 0.223353],
- [0.636902, 0.856542, 0.216620],
- [0.647257, 0.858400, 0.209861],
- [0.657642, 0.860219, 0.203082],
- [0.668054, 0.861999, 0.196293],
- [0.678489, 0.863742, 0.189503],
- [0.688944, 0.865448, 0.182725],
- [0.699415, 0.867117, 0.175971],
- [0.709898, 0.868751, 0.169257],
- [0.720391, 0.870350, 0.162603],
- [0.730889, 0.871916, 0.156029],
- [0.741388, 0.873449, 0.149561],
- [0.751884, 0.874951, 0.143228],
- [0.762373, 0.876424, 0.137064],
- [0.772852, 0.877868, 0.131109],
- [0.783315, 0.879285, 0.125405],
- [0.793760, 0.880678, 0.120005],
- [0.804182, 0.882046, 0.114965],
- [0.814576, 0.883393, 0.110347],
- [0.824940, 0.884720, 0.106217],
- [0.835270, 0.886029, 0.102646],
- [0.845561, 0.887322, 0.099702],
- [0.855810, 0.888601, 0.097452],
- [0.866013, 0.889868, 0.095953],
- [0.876168, 0.891125, 0.095250],
- [0.886271, 0.892374, 0.095374],
- [0.896320, 0.893616, 0.096335],
- [0.906311, 0.894855, 0.098125],
- [0.916242, 0.896091, 0.100717],
- [0.926106, 0.897330, 0.104071],
- [0.935904, 0.898570, 0.108131],
- [0.945636, 0.899815, 0.112838],
- [0.955300, 0.901065, 0.118128],
- [0.964894, 0.902323, 0.123941],
- [0.974417, 0.903590, 0.130215],
- [0.983868, 0.904867, 0.136897],
- [0.993248, 0.906157, 0.143936]]
-
-_cividis_data = [[0.000000, 0.135112, 0.304751],
- [0.000000, 0.138068, 0.311105],
- [0.000000, 0.141013, 0.317579],
- [0.000000, 0.143951, 0.323982],
- [0.000000, 0.146877, 0.330479],
- [0.000000, 0.149791, 0.337065],
- [0.000000, 0.152673, 0.343704],
- [0.000000, 0.155377, 0.350500],
- [0.000000, 0.157932, 0.357521],
- [0.000000, 0.160495, 0.364534],
- [0.000000, 0.163058, 0.371608],
- [0.000000, 0.165621, 0.378769],
- [0.000000, 0.168204, 0.385902],
- [0.000000, 0.170800, 0.393100],
- [0.000000, 0.173420, 0.400353],
- [0.000000, 0.176082, 0.407577],
- [0.000000, 0.178802, 0.414764],
- [0.000000, 0.181610, 0.421859],
- [0.000000, 0.184550, 0.428802],
- [0.000000, 0.186915, 0.435532],
- [0.000000, 0.188769, 0.439563],
- [0.000000, 0.190950, 0.441085],
- [0.000000, 0.193366, 0.441561],
- [0.003602, 0.195911, 0.441564],
- [0.017852, 0.198528, 0.441248],
- [0.032110, 0.201199, 0.440785],
- [0.046205, 0.203903, 0.440196],
- [0.058378, 0.206629, 0.439531],
- [0.068968, 0.209372, 0.438863],
- [0.078624, 0.212122, 0.438105],
- [0.087465, 0.214879, 0.437342],
- [0.095645, 0.217643, 0.436593],
- [0.103401, 0.220406, 0.435790],
- [0.110658, 0.223170, 0.435067],
- [0.117612, 0.225935, 0.434308],
- [0.124291, 0.228697, 0.433547],
- [0.130669, 0.231458, 0.432840],
- [0.136830, 0.234216, 0.432148],
- [0.142852, 0.236972, 0.431404],
- [0.148638, 0.239724, 0.430752],
- [0.154261, 0.242475, 0.430120],
- [0.159733, 0.245221, 0.429528],
- [0.165113, 0.247965, 0.428908],
- [0.170362, 0.250707, 0.428325],
- [0.175490, 0.253444, 0.427790],
- [0.180503, 0.256180, 0.427299],
- [0.185453, 0.258914, 0.426788],
- [0.190303, 0.261644, 0.426329],
- [0.195057, 0.264372, 0.425924],
- [0.199764, 0.267099, 0.425497],
- [0.204385, 0.269823, 0.425126],
- [0.208926, 0.272546, 0.424809],
- [0.213431, 0.275266, 0.424480],
- [0.217863, 0.277985, 0.424206],
- [0.222264, 0.280702, 0.423914],
- [0.226598, 0.283419, 0.423678],
- [0.230871, 0.286134, 0.423498],
- [0.235120, 0.288848, 0.423304],
- [0.239312, 0.291562, 0.423167],
- [0.243485, 0.294274, 0.423014],
- [0.247605, 0.296986, 0.422917],
- [0.251675, 0.299698, 0.422873],
- [0.255731, 0.302409, 0.422814],
- [0.259740, 0.305120, 0.422810],
- [0.263738, 0.307831, 0.422789],
- [0.267693, 0.310542, 0.422821],
- [0.271639, 0.313253, 0.422837],
- [0.275513, 0.315965, 0.422979],
- [0.279411, 0.318677, 0.423031],
- [0.283240, 0.321390, 0.423211],
- [0.287065, 0.324103, 0.423373],
- [0.290884, 0.326816, 0.423517],
- [0.294669, 0.329531, 0.423716],
- [0.298421, 0.332247, 0.423973],
- [0.302169, 0.334963, 0.424213],
- [0.305886, 0.337681, 0.424512],
- [0.309601, 0.340399, 0.424790],
- [0.313287, 0.343120, 0.425120],
- [0.316941, 0.345842, 0.425512],
- [0.320595, 0.348565, 0.425889],
- [0.324250, 0.351289, 0.426250],
- [0.327875, 0.354016, 0.426670],
- [0.331474, 0.356744, 0.427144],
- [0.335073, 0.359474, 0.427605],
- [0.338673, 0.362206, 0.428053],
- [0.342246, 0.364939, 0.428559],
- [0.345793, 0.367676, 0.429127],
- [0.349341, 0.370414, 0.429685],
- [0.352892, 0.373153, 0.430226],
- [0.356418, 0.375896, 0.430823],
- [0.359916, 0.378641, 0.431501],
- [0.363446, 0.381388, 0.432075],
- [0.366923, 0.384139, 0.432796],
- [0.370430, 0.386890, 0.433428],
- [0.373884, 0.389646, 0.434209],
- [0.377371, 0.392404, 0.434890],
- [0.380830, 0.395164, 0.435653],
- [0.384268, 0.397928, 0.436475],
- [0.387705, 0.400694, 0.437305],
- [0.391151, 0.403464, 0.438096],
- [0.394568, 0.406236, 0.438986],
- [0.397991, 0.409011, 0.439848],
- [0.401418, 0.411790, 0.440708],
- [0.404820, 0.414572, 0.441642],
- [0.408226, 0.417357, 0.442570],
- [0.411607, 0.420145, 0.443577],
- [0.414992, 0.422937, 0.444578],
- [0.418383, 0.425733, 0.445560],
- [0.421748, 0.428531, 0.446640],
- [0.425120, 0.431334, 0.447692],
- [0.428462, 0.434140, 0.448864],
- [0.431817, 0.436950, 0.449982],
- [0.435168, 0.439763, 0.451134],
- [0.438504, 0.442580, 0.452341],
- [0.441810, 0.445402, 0.453659],
- [0.445148, 0.448226, 0.454885],
- [0.448447, 0.451053, 0.456264],
- [0.451759, 0.453887, 0.457582],
- [0.455072, 0.456718, 0.458976],
- [0.458366, 0.459552, 0.460457],
- [0.461616, 0.462405, 0.461969],
- [0.464947, 0.465241, 0.463395],
- [0.468254, 0.468083, 0.464908],
- [0.471501, 0.470960, 0.466357],
- [0.474812, 0.473832, 0.467681],
- [0.478186, 0.476699, 0.468845],
- [0.481622, 0.479573, 0.469767],
- [0.485141, 0.482451, 0.470384],
- [0.488697, 0.485318, 0.471008],
- [0.492278, 0.488198, 0.471453],
- [0.495913, 0.491076, 0.471751],
- [0.499552, 0.493960, 0.472032],
- [0.503185, 0.496851, 0.472305],
- [0.506866, 0.499743, 0.472432],
- [0.510540, 0.502643, 0.472550],
- [0.514226, 0.505546, 0.472640],
- [0.517920, 0.508454, 0.472707],
- [0.521643, 0.511367, 0.472639],
- [0.525348, 0.514285, 0.472660],
- [0.529086, 0.517207, 0.472543],
- [0.532829, 0.520135, 0.472401],
- [0.536553, 0.523067, 0.472352],
- [0.540307, 0.526005, 0.472163],
- [0.544069, 0.528948, 0.471947],
- [0.547840, 0.531895, 0.471704],
- [0.551612, 0.534849, 0.471439],
- [0.555393, 0.537807, 0.471147],
- [0.559181, 0.540771, 0.470829],
- [0.562972, 0.543741, 0.470488],
- [0.566802, 0.546715, 0.469988],
- [0.570607, 0.549695, 0.469593],
- [0.574417, 0.552682, 0.469172],
- [0.578236, 0.555673, 0.468724],
- [0.582087, 0.558670, 0.468118],
- [0.585916, 0.561674, 0.467618],
- [0.589753, 0.564682, 0.467090],
- [0.593622, 0.567697, 0.466401],
- [0.597469, 0.570718, 0.465821],
- [0.601354, 0.573743, 0.465074],
- [0.605211, 0.576777, 0.464441],
- [0.609105, 0.579816, 0.463638],
- [0.612977, 0.582861, 0.462950],
- [0.616852, 0.585913, 0.462237],
- [0.620765, 0.588970, 0.461351],
- [0.624654, 0.592034, 0.460583],
- [0.628576, 0.595104, 0.459641],
- [0.632506, 0.598180, 0.458668],
- [0.636412, 0.601264, 0.457818],
- [0.640352, 0.604354, 0.456791],
- [0.644270, 0.607450, 0.455886],
- [0.648222, 0.610553, 0.454801],
- [0.652178, 0.613664, 0.453689],
- [0.656114, 0.616780, 0.452702],
- [0.660082, 0.619904, 0.451534],
- [0.664055, 0.623034, 0.450338],
- [0.668008, 0.626171, 0.449270],
- [0.671991, 0.629316, 0.448018],
- [0.675981, 0.632468, 0.446736],
- [0.679979, 0.635626, 0.445424],
- [0.683950, 0.638793, 0.444251],
- [0.687957, 0.641966, 0.442886],
- [0.691971, 0.645145, 0.441491],
- [0.695985, 0.648334, 0.440072],
- [0.700008, 0.651529, 0.438624],
- [0.704037, 0.654731, 0.437147],
- [0.708067, 0.657942, 0.435647],
- [0.712105, 0.661160, 0.434117],
- [0.716177, 0.664384, 0.432386],
- [0.720222, 0.667618, 0.430805],
- [0.724274, 0.670859, 0.429194],
- [0.728334, 0.674107, 0.427554],
- [0.732422, 0.677364, 0.425717],
- [0.736488, 0.680629, 0.424028],
- [0.740589, 0.683900, 0.422131],
- [0.744664, 0.687181, 0.420393],
- [0.748772, 0.690470, 0.418448],
- [0.752886, 0.693766, 0.416472],
- [0.756975, 0.697071, 0.414659],
- [0.761096, 0.700384, 0.412638],
- [0.765223, 0.703705, 0.410587],
- [0.769353, 0.707035, 0.408516],
- [0.773486, 0.710373, 0.406422],
- [0.777651, 0.713719, 0.404112],
- [0.781795, 0.717074, 0.401966],
- [0.785965, 0.720438, 0.399613],
- [0.790116, 0.723810, 0.397423],
- [0.794298, 0.727190, 0.395016],
- [0.798480, 0.730580, 0.392597],
- [0.802667, 0.733978, 0.390153],
- [0.806859, 0.737385, 0.387684],
- [0.811054, 0.740801, 0.385198],
- [0.815274, 0.744226, 0.382504],
- [0.819499, 0.747659, 0.379785],
- [0.823729, 0.751101, 0.377043],
- [0.827959, 0.754553, 0.374292],
- [0.832192, 0.758014, 0.371529],
- [0.836429, 0.761483, 0.368747],
- [0.840693, 0.764962, 0.365746],
- [0.844957, 0.768450, 0.362741],
- [0.849223, 0.771947, 0.359729],
- [0.853515, 0.775454, 0.356500],
- [0.857809, 0.778969, 0.353259],
- [0.862105, 0.782494, 0.350011],
- [0.866421, 0.786028, 0.346571],
- [0.870717, 0.789572, 0.343333],
- [0.875057, 0.793125, 0.339685],
- [0.879378, 0.796687, 0.336241],
- [0.883720, 0.800258, 0.332599],
- [0.888081, 0.803839, 0.328770],
- [0.892440, 0.807430, 0.324968],
- [0.896818, 0.811030, 0.320982],
- [0.901195, 0.814639, 0.317021],
- [0.905589, 0.818257, 0.312889],
- [0.910000, 0.821885, 0.308594],
- [0.914407, 0.825522, 0.304348],
- [0.918828, 0.829168, 0.299960],
- [0.923279, 0.832822, 0.295244],
- [0.927724, 0.836486, 0.290611],
- [0.932180, 0.840159, 0.285880],
- [0.936660, 0.843841, 0.280876],
- [0.941147, 0.847530, 0.275815],
- [0.945654, 0.851228, 0.270532],
- [0.950178, 0.854933, 0.265085],
- [0.954725, 0.858646, 0.259365],
- [0.959284, 0.862365, 0.253563],
- [0.963872, 0.866089, 0.247445],
- [0.968469, 0.869819, 0.241310],
- [0.973114, 0.873550, 0.234677],
- [0.977780, 0.877281, 0.227954],
- [0.982497, 0.881008, 0.220878],
- [0.987293, 0.884718, 0.213336],
- [0.992218, 0.888385, 0.205468],
- [0.994847, 0.892954, 0.203445],
- [0.995249, 0.898384, 0.207561],
- [0.995503, 0.903866, 0.212370],
- [0.995737, 0.909344, 0.217772]]
-
-_twilight_data = [
- [0.88575015840754434, 0.85000924943067835, 0.8879736506427196],
- [0.88378520195539056, 0.85072940540310626, 0.88723222096949894],
- [0.88172231059285788, 0.85127594077653468, 0.88638056925514819],
- [0.8795410528270573, 0.85165675407495722, 0.8854143767924102],
- [0.87724880858965482, 0.85187028338870274, 0.88434120381311432],
- [0.87485347508575972, 0.85191526123023187, 0.88316926967613829],
- [0.87233134085124076, 0.85180165478080894, 0.88189704355001619],
- [0.86970474853509816, 0.85152403004797894, 0.88053883390003362],
- [0.86696015505333579, 0.8510896085314068, 0.87909766977173343],
- [0.86408985081463996, 0.85050391167507788, 0.87757925784892632],
- [0.86110245436899846, 0.84976754857001258, 0.87599242923439569],
- [0.85798259245670372, 0.84888934810281835, 0.87434038553446281],
- [0.85472593189256985, 0.84787488124672816, 0.8726282980930582],
- [0.85133714570857189, 0.84672735796116472, 0.87086081657350445],
- [0.84780710702577922, 0.8454546229209523, 0.86904036783694438],
- [0.8441261828674842, 0.84406482711037389, 0.86716973322690072],
- [0.84030420805957784, 0.8425605950855084, 0.865250882410458],
- [0.83634031809191178, 0.84094796518951942, 0.86328528001070159],
- [0.83222705712934408, 0.83923490627754482, 0.86127563500427884],
- [0.82796894316013536, 0.83742600751395202, 0.85922399451306786],
- [0.82357429680252847, 0.83552487764795436, 0.85713191328514948],
- [0.81904654677937527, 0.8335364929949034, 0.85500206287010105],
- [0.81438982121143089, 0.83146558694197847, 0.85283759062147024],
- [0.8095999819094809, 0.82931896673505456, 0.85064441601050367],
- [0.80469164429814577, 0.82709838780560663, 0.84842449296974021],
- [0.79967075421267997, 0.82480781812080928, 0.84618210029578533],
- [0.79454305089231114, 0.82245116226304615, 0.84392184786827984],
- [0.78931445564608915, 0.82003213188702007, 0.8416486380471222],
- [0.78399101042764918, 0.81755426400533426, 0.83936747464036732],
- [0.77857892008227592, 0.81502089378742548, 0.8370834463093898],
- [0.77308416590170936, 0.81243524735466011, 0.83480172950579679],
- [0.76751108504417864, 0.8098007598713145, 0.83252816638059668],
- [0.76186907937980286, 0.80711949387647486, 0.830266486168872],
- [0.75616443584381976, 0.80439408733477935, 0.82802138994719998],
- [0.75040346765406696, 0.80162699008965321, 0.82579737851082424],
- [0.74459247771890169, 0.79882047719583249, 0.82359867586156521],
- [0.73873771700494939, 0.79597665735031009, 0.82142922780433014],
- [0.73284543645523459, 0.79309746468844067, 0.81929263384230377],
- [0.72692177512829703, 0.7901846863592763, 0.81719217466726379],
- [0.72097280665536778, 0.78723995923452639, 0.81513073920879264],
- [0.71500403076252128, 0.78426487091581187, 0.81311116559949914],
- [0.70902078134539304, 0.78126088716070907, 0.81113591855117928],
- [0.7030297722540817, 0.77822904973358131, 0.80920618848056969],
- [0.6970365443886174, 0.77517050008066057, 0.80732335380063447],
- [0.69104641009309098, 0.77208629460678091, 0.80548841690679074],
- [0.68506446154395928, 0.7689774029354699, 0.80370206267176914],
- [0.67909554499882152, 0.76584472131395898, 0.8019646617300199],
- [0.67314422559426212, 0.76268908733890484, 0.80027628545809526],
- [0.66721479803752815, 0.7595112803730375, 0.79863674654537764],
- [0.6613112930078745, 0.75631202708719025, 0.7970456043491897],
- [0.65543692326454717, 0.75309208756768431, 0.79550271129031047],
- [0.64959573004253479, 0.74985201221941766, 0.79400674021499107],
- [0.6437910831099849, 0.7465923800833657, 0.79255653201306053],
- [0.63802586828545982, 0.74331376714033193, 0.79115100459573173],
- [0.6323027138710603, 0.74001672160131404, 0.78978892762640429],
- [0.62662402022604591, 0.73670175403699445, 0.78846901316334561],
- [0.62099193064817548, 0.73336934798923203, 0.78718994624696581],
- [0.61540846411770478, 0.73001995232739691, 0.78595022706750484],
- [0.60987543176093062, 0.72665398759758293, 0.78474835732694714],
- [0.60439434200274855, 0.7232718614323369, 0.78358295593535587],
- [0.5989665814482068, 0.71987394892246725, 0.78245259899346642],
- [0.59359335696837223, 0.7164606049658685, 0.78135588237640097],
- [0.58827579780555495, 0.71303214646458135, 0.78029141405636515],
- [0.58301487036932409, 0.70958887676997473, 0.77925781820476592],
- [0.5778116438998202, 0.70613106157153982, 0.77825345121025524],
- [0.5726668948158774, 0.7026589535425779, 0.77727702680911992],
- [0.56758117853861967, 0.69917279302646274, 0.77632748534275298],
- [0.56255515357219343, 0.69567278381629649, 0.77540359142309845],
- [0.55758940419605174, 0.69215911458254054, 0.7745041337932782],
- [0.55268450589347129, 0.68863194515166382, 0.7736279426902245],
- [0.54784098153018634, 0.68509142218509878, 0.77277386473440868],
- [0.54305932424018233, 0.68153767253065878, 0.77194079697835083],
- [0.53834015575176275, 0.67797081129095405, 0.77112734439057717],
- [0.53368389147728401, 0.67439093705212727, 0.7703325054879735],
- [0.529090861832473, 0.67079812302806219, 0.76955552292313134],
- [0.52456151470593582, 0.66719242996142225, 0.76879541714230948],
- [0.52009627392235558, 0.66357391434030388, 0.76805119403344102],
- [0.5156955988596057, 0.65994260812897998, 0.76732191489596169],
- [0.51135992541601927, 0.65629853981831865, 0.76660663780645333],
- [0.50708969576451657, 0.65264172403146448, 0.76590445660835849],
- [0.5028853540415561, 0.64897216734095264, 0.76521446718174913],
- [0.49874733661356069, 0.6452898684900934, 0.76453578734180083],
- [0.4946761847863938, 0.64159484119504429, 0.76386719002130909],
- [0.49067224938561221, 0.63788704858847078, 0.76320812763163837],
- [0.4867359599430568, 0.63416646251100506, 0.76255780085924041],
- [0.4828677867260272, 0.6304330455306234, 0.76191537149895305],
- [0.47906816236197386, 0.62668676251860134, 0.76128000375662419],
- [0.47533752394906287, 0.62292757283835809, 0.76065085571817748],
- [0.47167629518877091, 0.61915543242884641, 0.76002709227883047],
- [0.46808490970531597, 0.61537028695790286, 0.75940789891092741],
- [0.46456376716303932, 0.61157208822864151, 0.75879242623025811],
- [0.46111326647023881, 0.607760777169989, 0.75817986436807139],
- [0.45773377230160567, 0.60393630046586455, 0.75756936901859162],
- [0.45442563977552913, 0.60009859503858665, 0.75696013660606487],
- [0.45118918687617743, 0.59624762051353541, 0.75635120643246645],
- [0.44802470933589172, 0.59238331452146575, 0.75574176474107924],
- [0.44493246854215379, 0.5885055998308617, 0.7551311041857901],
- [0.44191271766696399, 0.58461441100175571, 0.75451838884410671],
- [0.43896563958048396, 0.58070969241098491, 0.75390276208285945],
- [0.43609138958356369, 0.57679137998186081, 0.7532834105961016],
- [0.43329008867358393, 0.57285941625606673, 0.75265946532566674],
- [0.43056179073057571, 0.56891374572457176, 0.75203008099312696],
- [0.42790652284925834, 0.5649543060909209, 0.75139443521914839],
- [0.42532423665011354, 0.56098104959950301, 0.75075164989005116],
- [0.42281485675772662, 0.55699392126996583, 0.75010086988227642],
- [0.42037822361396326, 0.55299287158108168, 0.7494412559451894],
- [0.41801414079233629, 0.54897785421888889, 0.74877193167001121],
- [0.4157223260454232, 0.54494882715350401, 0.74809204459000522],
- [0.41350245743314729, 0.54090574771098476, 0.74740073297543086],
- [0.41135414697304568, 0.53684857765005933, 0.74669712855065784],
- [0.4092768899914751, 0.53277730177130322, 0.74598030635707824],
- [0.40727018694219069, 0.52869188011057411, 0.74524942637581271],
- [0.40533343789303178, 0.52459228174983119, 0.74450365836708132],
- [0.40346600333905397, 0.52047847653840029, 0.74374215223567086],
- [0.40166714010896104, 0.51635044969688759, 0.7429640345324835],
- [0.39993606933454834, 0.51220818143218516, 0.74216844571317986],
- [0.3982719152586337, 0.50805166539276136, 0.74135450918099721],
- [0.39667374905665609, 0.50388089053847973, 0.74052138580516735],
- [0.39514058808207631, 0.49969585326377758, 0.73966820211715711],
- [0.39367135736822567, 0.49549655777451179, 0.738794102296364],
- [0.39226494876209317, 0.49128300332899261, 0.73789824784475078],
- [0.39092017571994903, 0.48705520251223039, 0.73697977133881254],
- [0.38963580160340855, 0.48281316715123496, 0.73603782546932739],
- [0.38841053300842432, 0.47855691131792805, 0.73507157641157261],
- [0.38724301459330251, 0.47428645933635388, 0.73408016787854391],
- [0.38613184178892102, 0.4700018340988123, 0.7330627749243106],
- [0.38507556793651387, 0.46570306719930193, 0.73201854033690505],
- [0.38407269378943537, 0.46139018782416635, 0.73094665432902683],
- [0.38312168084402748, 0.45706323581407199, 0.72984626791353258],
- [0.38222094988570376, 0.45272225034283325, 0.72871656144003782],
- [0.38136887930454161, 0.44836727669277859, 0.72755671317141346],
- [0.38056380696565623, 0.44399837208633719, 0.72636587045135315],
- [0.37980403744848751, 0.43961558821222629, 0.72514323778761092],
- [0.37908789283110761, 0.43521897612544935, 0.72388798691323131],
- [0.378413635091359, 0.43080859411413064, 0.72259931993061044],
- [0.37777949753513729, 0.4263845142616835, 0.72127639993530235],
- [0.37718371844251231, 0.42194680223454828, 0.71991841524475775],
- [0.37662448930806297, 0.41749553747893614, 0.71852454736176108],
- [0.37610001286385814, 0.41303079952477062, 0.71709396919920232],
- [0.37560846919442398, 0.40855267638072096, 0.71562585091587549],
- [0.37514802505380473, 0.4040612609993941, 0.7141193695725726],
- [0.37471686019302231, 0.3995566498711684, 0.71257368516500463],
- [0.37431313199312338, 0.39503894828283309, 0.71098796522377461],
- [0.37393499330475782, 0.39050827529375831, 0.70936134293478448],
- [0.3735806215098284, 0.38596474386057539, 0.70769297607310577],
- [0.37324816143326384, 0.38140848555753937, 0.70598200974806036],
- [0.37293578646665032, 0.37683963835219841, 0.70422755780589941],
- [0.37264166757849604, 0.37225835004836849, 0.7024287314570723],
- [0.37236397858465387, 0.36766477862108266, 0.70058463496520773],
- [0.37210089702443822, 0.36305909736982378, 0.69869434615073722],
- [0.3718506155898596, 0.35844148285875221, 0.69675695810256544],
- [0.37161133234400479, 0.3538121372967869, 0.69477149919380887],
- [0.37138124223736607, 0.34917126878479027, 0.69273703471928827],
- [0.37115856636209105, 0.34451911410230168, 0.69065253586464992],
- [0.37094151551337329, 0.33985591488818123, 0.68851703379505125],
- [0.37072833279422668, 0.33518193808489577, 0.68632948169606767],
- [0.37051738634484427, 0.33049741244307851, 0.68408888788857214],
- [0.37030682071842685, 0.32580269697872455, 0.68179411684486679],
- [0.37009487130772695, 0.3210981375964933, 0.67944405399056851],
- [0.36987980329025361, 0.31638410101153364, 0.67703755438090574],
- [0.36965987626565955, 0.31166098762951971, 0.67457344743419545],
- [0.36943334591276228, 0.30692923551862339, 0.67205052849120617],
- [0.36919847837592484, 0.30218932176507068, 0.66946754331614522],
- [0.36895355306596778, 0.29744175492366276, 0.66682322089824264],
- [0.36869682231895268, 0.29268709856150099, 0.66411625298236909],
- [0.36842655638020444, 0.28792596437778462, 0.66134526910944602],
- [0.36814101479899719, 0.28315901221182987, 0.65850888806972308],
- [0.36783843696531082, 0.27838697181297761, 0.65560566838453704],
- [0.36751707094367697, 0.27361063317090978, 0.65263411711618635],
- [0.36717513650699446, 0.26883085667326956, 0.64959272297892245],
- [0.36681085540107988, 0.26404857724525643, 0.64647991652908243],
- [0.36642243251550632, 0.25926481158628106, 0.64329409140765537],
- [0.36600853966739794, 0.25448043878086224, 0.64003361803368586],
- [0.36556698373538982, 0.24969683475296395, 0.63669675187488584],
- [0.36509579845886808, 0.24491536803550484, 0.63328173520055586],
- [0.36459308890125008, 0.24013747024823828, 0.62978680155026101],
- [0.36405693022088509, 0.23536470386204195, 0.62621013451953023],
- [0.36348537610385145, 0.23059876218396419, 0.62254988622392882],
- [0.36287643560041027, 0.22584149293287031, 0.61880417410823019],
- [0.36222809558295926, 0.22109488427338303, 0.61497112346096128],
- [0.36153829010998356, 0.21636111429594002, 0.61104880679640927],
- [0.36080493826624654, 0.21164251793458128, 0.60703532172064711],
- [0.36002681809096376, 0.20694122817889948, 0.60292845431916875],
- [0.35920088560930186, 0.20226037920758122, 0.5987265295935138],
- [0.35832489966617809, 0.197602942459778, 0.59442768517501066],
- [0.35739663292915563, 0.19297208197842461, 0.59003011251063131],
- [0.35641381143126327, 0.18837119869242164, 0.5855320765920552],
- [0.35537415306906722, 0.18380392577704466, 0.58093191431832802],
- [0.35427534960663759, 0.17927413271618647, 0.57622809660668717],
- [0.35311574421123737, 0.17478570377561287, 0.57141871523555288],
- [0.35189248608873791, 0.17034320478524959, 0.56650284911216653],
- [0.35060304441931012, 0.16595129984720861, 0.56147964703993225],
- [0.34924513554955644, 0.16161477763045118, 0.55634837474163779],
- [0.34781653238777782, 0.15733863511152979, 0.55110853452703257],
- [0.34631507175793091, 0.15312802296627787, 0.5457599924248665],
- [0.34473901574536375, 0.14898820589826409, 0.54030245920406539],
- [0.34308600291572294, 0.14492465359918028, 0.53473704282067103],
- [0.34135411074506483, 0.1409427920655632, 0.52906500940336754],
- [0.33954168752669694, 0.13704801896718169, 0.52328797535085236],
- [0.33764732090671112, 0.13324562282438077, 0.51740807573979475],
- [0.33566978565015315, 0.12954074251271822, 0.51142807215168951],
- [0.33360804901486002, 0.12593818301005921, 0.50535164796654897],
- [0.33146154891145124, 0.12244245263391232, 0.49918274588431072],
- [0.32923005203231409, 0.11905764321981127, 0.49292595612342666],
- [0.3269137124539796, 0.1157873496841953, 0.48658646495697461],
- [0.32451307931207785, 0.11263459791730848, 0.48017007211645196],
- [0.32202882276069322, 0.10960114111258401, 0.47368494725726878],
- [0.31946262395497965, 0.10668879882392659, 0.46713728801395243],
- [0.31681648089023501, 0.10389861387653518, 0.46053414662739794],
- [0.31409278414755532, 0.10123077676403242, 0.45388335612058467],
- [0.31129434479712365, 0.098684771934052201, 0.44719313715161618],
- [0.30842444457210105, 0.096259385340577736, 0.44047194882050544],
- [0.30548675819945936, 0.093952764840823738, 0.43372849999361113],
- [0.30248536364574252, 0.091761187397303601, 0.42697404043749887],
- [0.29942483960214772, 0.089682253716750038, 0.42021619665853854],
- [0.29631000388905288, 0.087713250960463951, 0.41346259134143476],
- [0.29314593096985248, 0.085850656889620708, 0.40672178082365834],
- [0.28993792445176608, 0.08409078829085731, 0.40000214725256295],
- [0.28669151388283165, 0.082429873848480689, 0.39331182532243375],
- [0.28341239797185225, 0.080864153365499375, 0.38665868550105914],
- [0.28010638576975472, 0.079389994802261526, 0.38005028528138707],
- [0.27677939615815589, 0.078003941033788216, 0.37349382846504675],
- [0.27343739342450812, 0.076702800237496066, 0.36699616136347685],
- [0.27008637749114051, 0.075483675584275545, 0.36056376228111864],
- [0.26673233211995284, 0.074344018028546205, 0.35420276066240958],
- [0.26338121807151404, 0.073281657939897077, 0.34791888996380105],
- [0.26003895187439957, 0.072294781043362205, 0.3417175669546984],
- [0.25671191651083902, 0.071380106242082242, 0.33560648984600089],
- [0.25340685873736807, 0.070533582926851829, 0.3295945757321303],
- [0.25012845306199383, 0.069758206429106989, 0.32368100685760637],
- [0.24688226237958999, 0.069053639449204451, 0.31786993834254956],
- [0.24367372557466271, 0.068419855150922693, 0.31216524050888372],
- [0.24050813332295939, 0.067857103814855602, 0.30657054493678321],
- [0.23739062429054825, 0.067365888050555517, 0.30108922184065873],
- [0.23433055727563878, 0.066935599661639394, 0.29574009929867601],
- [0.23132955273021344, 0.066576186939090592, 0.29051361067988485],
- [0.2283917709422868, 0.06628997924139618, 0.28541074411068496],
- [0.22552164337737857, 0.066078173119395595, 0.28043398847505197],
- [0.22272706739121817, 0.065933790675651943, 0.27559714652053702],
- [0.22001251100779617, 0.065857918918907604, 0.27090279994325861],
- [0.21737845072382705, 0.065859661233562045, 0.26634209349669508],
- [0.21482843531473683, 0.065940385613778491, 0.26191675992376573],
- [0.21237411048541005, 0.066085024661758446, 0.25765165093569542],
- [0.21001214221188125, 0.066308573918947178, 0.2535289048041211],
- [0.2077442377448806, 0.06661453200418091, 0.24954644291943817],
- [0.20558051999470117, 0.066990462397868739, 0.24572497420147632],
- [0.20352007949514977, 0.067444179612424215, 0.24205576625191821],
- [0.20156133764129841, 0.067983271026200248, 0.23852974228695395],
- [0.19971571438603364, 0.068592710553704722, 0.23517094067076993],
- [0.19794834061899208, 0.069314066071660657, 0.23194647381302336],
- [0.1960826032659409, 0.070321227242423623, 0.22874673279569585],
- [0.19410351363791453, 0.071608304856891569, 0.22558727307410353],
- [0.19199449184606268, 0.073182830649273306, 0.22243385243433622],
- [0.18975853639094634, 0.075019861862143766, 0.2193005075652994],
- [0.18739228342697645, 0.077102096899588329, 0.21618875376309582],
- [0.18488035509396164, 0.079425730279723883, 0.21307651648984993],
- [0.18774482037046955, 0.077251588468039312, 0.21387448578597812],
- [0.19049578401722037, 0.075311278416787641, 0.2146562337112265],
- [0.1931548636579131, 0.073606819040117955, 0.21542362939081539],
- [0.19571853588267552, 0.072157781039602742, 0.21617499187076789],
- [0.19819343656336558, 0.070974625252738788, 0.21690975060032436],
- [0.20058760685133747, 0.070064576149984209, 0.21762721310371608],
- [0.20290365333558247, 0.069435248580458964, 0.21833167885096033],
- [0.20531725273301316, 0.068919592266397572, 0.21911516689288835],
- [0.20785704662965598, 0.068484398797025281, 0.22000133917653536],
- [0.21052882914958676, 0.06812195249816172, 0.22098759107715404],
- [0.2133313859647627, 0.067830148426026665, 0.22207043213024291],
- [0.21625279838647882, 0.067616330270516389, 0.22324568672294431],
- [0.21930503925136402, 0.067465786362940039, 0.22451023616807558],
- [0.22247308588973624, 0.067388214053092838, 0.22585960379408354],
- [0.2257539681670791, 0.067382132300147474, 0.22728984778098055],
- [0.22915620278592841, 0.067434730871152565, 0.22879681433956656],
- [0.23266299920501882, 0.067557104388479783, 0.23037617493752832],
- [0.23627495835774248, 0.06774359820987802, 0.23202360805926608],
- [0.23999586188690308, 0.067985029964779953, 0.23373434258507808],
- [0.24381149720247919, 0.068289851529011875, 0.23550427698321885],
- [0.24772092990501099, 0.068653337909486523, 0.2373288009471749],
- [0.25172899728289466, 0.069064630826035506, 0.23920260612763083],
- [0.25582135547481771, 0.06953231029187984, 0.24112190491594204],
- [0.25999463887892144, 0.070053855603861875, 0.24308218808684579],
- [0.26425512207060942, 0.070616595622995437, 0.24507758869355967],
- [0.26859095948172862, 0.071226716277922458, 0.24710443563450618],
- [0.27299701518897301, 0.071883555446163511, 0.24915847093232929],
- [0.27747150809142801, 0.072582969899254779, 0.25123493995942769],
- [0.28201746297366942, 0.073315693214040967, 0.25332800295084507],
- [0.28662309235899847, 0.074088460826808866, 0.25543478673717029],
- [0.29128515387578635, 0.074899049847466703, 0.25755101595750435],
- [0.2960004726065818, 0.075745336000958424, 0.25967245030364566],
- [0.30077276812918691, 0.076617824336164764, 0.26179294097819672],
- [0.30559226007249934, 0.077521963107537312, 0.26391006692119662],
- [0.31045520848595526, 0.078456871676182177, 0.2660200572779356],
- [0.31535870009205808, 0.079420997315243186, 0.26811904076941961],
- [0.32029986557994061, 0.080412994737554838, 0.27020322893039511],
- [0.32527888860401261, 0.081428390076546092, 0.27226772884656186],
- [0.33029174471181438, 0.08246763389003825, 0.27430929404579435],
- [0.33533353224455448, 0.083532434119003962, 0.27632534356790039],
- [0.34040164359597463, 0.084622236191702671, 0.27831254595259397],
- [0.34549355713871799, 0.085736654965126335, 0.28026769921081435],
- [0.35060678246032478, 0.08687555176033529, 0.28218770540182386],
- [0.35573889947341125, 0.088038974350243354, 0.2840695897279818],
- [0.36088752387578377, 0.089227194362745205, 0.28591050458531014],
- [0.36605031412464006, 0.090440685427697898, 0.2877077458811747],
- [0.37122508431309342, 0.091679997480262732, 0.28945865397633169],
- [0.3764103053221462, 0.092945198093777909, 0.29116024157313919],
- [0.38160247377467543, 0.094238731263712183, 0.29281107506269488],
- [0.38679939079544168, 0.09556181960083443, 0.29440901248173756],
- [0.39199887556812907, 0.09691583650296684, 0.29595212005509081],
- [0.39719876876325577, 0.098302320968278623, 0.29743856476285779],
- [0.40239692379737496, 0.099722930314950553, 0.29886674369733968],
- [0.40759120392688708, 0.10117945586419633, 0.30023519507728602],
- [0.41277985630360303, 0.1026734006932461, 0.30154226437468967],
- [0.41796105205173684, 0.10420644885760968, 0.30278652039631843],
- [0.42313214269556043, 0.10578120994917611, 0.3039675809469457],
- [0.42829101315789753, 0.1073997763055258, 0.30508479060294547],
- [0.4334355841041439, 0.1090642347484701, 0.30613767928289148],
- [0.43856378187931538, 0.11077667828375456, 0.30712600062348083],
- [0.44367358645071275, 0.11253912421257944, 0.30804973095465449],
- [0.44876299173174822, 0.11435355574622549, 0.30890905921943196],
- [0.45383005086999889, 0.11622183788331528, 0.30970441249844921],
- [0.45887288947308297, 0.11814571137706886, 0.31043636979038808],
- [0.46389102840284874, 0.12012561256850712, 0.31110343446582983],
- [0.46888111384598413, 0.12216445576414045, 0.31170911458932665],
- [0.473841437035254, 0.12426354237989065, 0.31225470169927194],
- [0.47877034239726296, 0.12642401401409453, 0.31274172735821959],
- [0.48366628618847957, 0.12864679022013889, 0.31317188565991266],
- [0.48852847371852987, 0.13093210934893723, 0.31354553695453014],
- [0.49335504375145617, 0.13328091630401023, 0.31386561956734976],
- [0.49814435462074153, 0.13569380302451714, 0.314135190862664],
- [0.50289524974970612, 0.13817086581280427, 0.31435662153833671],
- [0.50760681181053691, 0.14071192654913128, 0.31453200120082569],
- [0.51227835105321762, 0.14331656120063752, 0.3146630922831542],
- [0.51690848800544464, 0.14598463068714407, 0.31475407592280041],
- [0.52149652863229956, 0.14871544765633712, 0.31480767954534428],
- [0.52604189625477482, 0.15150818660835483, 0.31482653406646727],
- [0.53054420489856446, 0.15436183633886777, 0.31481299789187128],
- [0.5350027976174474, 0.15727540775107324, 0.31477085207396532],
- [0.53941736649199057, 0.16024769309971934, 0.31470295028655965],
- [0.54378771313608565, 0.16327738551419116, 0.31461204226295625],
- [0.54811370033467621, 0.1663630904279047, 0.31450102990914708],
- [0.55239521572711914, 0.16950338809328983, 0.31437291554615371],
- [0.55663229034969341, 0.17269677158182117, 0.31423043195101424],
- [0.56082499039117173, 0.17594170887918095, 0.31407639883970623],
- [0.56497343529017696, 0.17923664950367169, 0.3139136046337036],
- [0.56907784784011428, 0.18258004462335425, 0.31374440956796529],
- [0.57313845754107873, 0.18597036007065024, 0.31357126868520002],
- [0.57715550812992045, 0.18940601489760422, 0.31339704333572083],
- [0.58112932761586555, 0.19288548904692518, 0.31322399394183942],
- [0.58506024396466882, 0.19640737049066315, 0.31305401163732732],
- [0.58894861935544707, 0.19997020971775276, 0.31288922211590126],
- [0.59279480536520257, 0.20357251410079796, 0.31273234839304942],
- [0.59659918109122367, 0.207212956082026, 0.31258523031121233],
- [0.60036213010411577, 0.21089030138947745, 0.31244934410414688],
- [0.60408401696732739, 0.21460331490206347, 0.31232652641170694],
- [0.60776523994818654, 0.21835070166659282, 0.31221903291870201],
- [0.6114062072731884, 0.22213124697023234, 0.31212881396435238],
- [0.61500723236391375, 0.22594402043981826, 0.31205680685765741],
- [0.61856865258877192, 0.22978799249179921, 0.31200463838728931],
- [0.62209079821082613, 0.2336621873300741, 0.31197383273627388],
- [0.62557416500434959, 0.23756535071152696, 0.31196698314912269],
- [0.62901892016985872, 0.24149689191922535, 0.31198447195645718],
- [0.63242534854210275, 0.24545598775548677, 0.31202765974624452],
- [0.6357937104834237, 0.24944185818822678, 0.31209793953300591],
- [0.6391243387840212, 0.25345365461983138, 0.31219689612063978],
- [0.642417577481186, 0.257490519876798, 0.31232631707560987],
- [0.64567349382645434, 0.26155203161615281, 0.31248673753935263],
- [0.64889230169458245, 0.26563755336209077, 0.31267941819570189],
- [0.65207417290277303, 0.26974650525236699, 0.31290560605819168],
- [0.65521932609327127, 0.27387826652410152, 0.3131666792687211],
- [0.6583280801134499, 0.27803210957665631, 0.3134643447952643],
- [0.66140037532601781, 0.28220778870555907, 0.31379912926498488],
- [0.66443632469878844, 0.28640483614256179, 0.31417223403606975],
- [0.66743603766369131, 0.29062280081258873, 0.31458483752056837],
- [0.67039959547676198, 0.29486126309253047, 0.31503813956872212],
- [0.67332725564817331, 0.29911962764489264, 0.31553372323982209],
- [0.67621897924409746, 0.30339762792450425, 0.3160724937230589],
- [0.67907474028157344, 0.30769497879760166, 0.31665545668946665],
- [0.68189457150944521, 0.31201133280550686, 0.31728380489244951],
- [0.68467850942494535, 0.31634634821222207, 0.31795870784057567],
- [0.68742656435169625, 0.32069970535138104, 0.31868137622277692],
- [0.6901389321505248, 0.32507091815606004, 0.31945332332898302],
- [0.69281544846764931, 0.32945984647042675, 0.3202754315314667],
- [0.69545608346891119, 0.33386622163232865, 0.32114884306985791],
- [0.6980608153581771, 0.33828976326048621, 0.32207478855218091],
- [0.70062962477242097, 0.34273019305341756, 0.32305449047765694],
- [0.70316249458814151, 0.34718723719597999, 0.32408913679491225],
- [0.70565951122610093, 0.35166052978120937, 0.32518014084085567],
- [0.70812059568420482, 0.35614985523380299, 0.32632861885644465],
- [0.7105456546582587, 0.36065500290840113, 0.32753574162788762],
- [0.71293466839773467, 0.36517570519856757, 0.3288027427038317],
- [0.71528760614847287, 0.36971170225223449, 0.3301308728723546],
- [0.71760444908133847, 0.37426272710686193, 0.33152138620958932],
- [0.71988521490549851, 0.37882848839337313, 0.33297555200245399],
- [0.7221299918421461, 0.38340864508963057, 0.33449469983585844],
- [0.72433865647781592, 0.38800301593162145, 0.33607995965691828],
- [0.72651122900227549, 0.3926113126792577, 0.3377325942005665],
- [0.72864773856716547, 0.39723324476747235, 0.33945384341064017],
- [0.73074820754845171, 0.401868526884681, 0.3412449533046818],
- [0.73281270506268747, 0.4065168468778026, 0.34310715173410822],
- [0.73484133598564938, 0.41117787004519513, 0.34504169470809071],
- [0.73683422173585866, 0.41585125850290111, 0.34704978520758401],
- [0.73879140024599266, 0.42053672992315327, 0.34913260148542435],
- [0.74071301619506091, 0.4252339389526239, 0.35129130890802607],
- [0.7425992159973317, 0.42994254036133867, 0.35352709245374592],
- [0.74445018676570673, 0.43466217184617112, 0.35584108091122535],
- [0.74626615789163442, 0.43939245044973502, 0.35823439142300639],
- [0.74804739275559562, 0.44413297780351974, 0.36070813602540136],
- [0.74979420547170472, 0.44888333481548809, 0.36326337558360278],
- [0.75150685045891663, 0.45364314496866825, 0.36590112443835765],
- [0.75318566369046569, 0.45841199172949604, 0.36862236642234769],
- [0.75483105066959544, 0.46318942799460555, 0.3714280448394211],
- [0.75644341577140706, 0.46797501437948458, 0.37431909037543515],
- [0.75802325538455839, 0.4727682731566229, 0.37729635531096678],
- [0.75957111105340058, 0.47756871222057079, 0.380360657784311],
- [0.7610876378057071, 0.48237579130289127, 0.38351275723852291],
- [0.76257333554052609, 0.48718906673415824, 0.38675335037837993],
- [0.76402885609288662, 0.49200802533379656, 0.39008308392311997],
- [0.76545492593330511, 0.49683212909727231, 0.39350254000115381],
- [0.76685228950643891, 0.5016608471009063, 0.39701221751773474],
- [0.76822176599735303, 0.50649362371287909, 0.40061257089416885],
- [0.7695642334401418, 0.5113298901696085, 0.40430398069682483],
- [0.77088091962302474, 0.51616892643469103, 0.40808667584648967],
- [0.77217257229605551, 0.5210102658711383, 0.41196089987122869],
- [0.77344021829889886, 0.52585332093451564, 0.41592679539764366],
- [0.77468494746063199, 0.53069749384776732, 0.41998440356963762],
- [0.77590790730685699, 0.53554217882461186, 0.42413367909988375],
- [0.7771103295521099, 0.54038674910561235, 0.42837450371258479],
- [0.77829345807633121, 0.54523059488426595, 0.432706647838971],
- [0.77945862731506643, 0.55007308413977274, 0.43712979856444761],
- [0.78060774749483774, 0.55491335744890613, 0.44164332426364639],
- [0.78174180478981836, 0.55975098052594863, 0.44624687186865436],
- [0.78286225264440912, 0.56458533111166875, 0.45093985823706345],
- [0.78397060836414478, 0.56941578326710418, 0.45572154742892063],
- [0.78506845019606841, 0.5742417003617839, 0.46059116206904965],
- [0.78615737132332963, 0.5790624629815756, 0.46554778281918402],
- [0.78723904108188347, 0.58387743744557208, 0.47059039582133383],
- [0.78831514045623963, 0.58868600173562435, 0.47571791879076081],
- [0.78938737766251943, 0.5934875421745599, 0.48092913815357724],
- [0.79045776847727878, 0.59828134277062461, 0.48622257801969754],
- [0.79152832843475607, 0.60306670593147205, 0.49159667021646397],
- [0.79260034304237448, 0.60784322087037024, 0.49705020621532009],
- [0.79367559698664958, 0.61261029334072192, 0.50258161291269432],
- [0.79475585972654039, 0.61736734400220705, 0.50818921213102985],
- [0.79584292379583765, 0.62211378808451145, 0.51387124091909786],
- [0.79693854719951607, 0.62684905679296699, 0.5196258425240281],
- [0.79804447815136637, 0.63157258225089552, 0.52545108144834785],
- [0.7991624518501963, 0.63628379372029187, 0.53134495942561433],
- [0.80029415389753977, 0.64098213306749863, 0.53730535185141037],
- [0.80144124292560048, 0.64566703459218766, 0.5433300863249918],
- [0.80260531146112946, 0.65033793748103852, 0.54941691584603647],
- [0.80378792531077625, 0.65499426549472628, 0.55556350867083815],
- [0.80499054790810298, 0.65963545027564163, 0.56176745110546977],
- [0.80621460526927058, 0.66426089585282289, 0.56802629178649788],
- [0.8074614045096935, 0.6688700095398864, 0.57433746373459582],
- [0.80873219170089694, 0.67346216702194517, 0.58069834805576737],
- [0.81002809466520687, 0.67803672673971815, 0.58710626908082753],
- [0.81135014011763329, 0.68259301546243389, 0.59355848909050757],
- [0.81269922039881493, 0.68713033714618876, 0.60005214820435104],
- [0.81407611046993344, 0.69164794791482131, 0.6065843782630862],
- [0.81548146627279483, 0.69614505508308089, 0.61315221209322646],
- [0.81691575775055891, 0.70062083014783982, 0.61975260637257923],
- [0.81837931164498223, 0.70507438189635097, 0.62638245478933297],
- [0.81987230650455289, 0.70950474978787481, 0.63303857040067113],
- [0.8213947205565636, 0.7139109141951604, 0.63971766697672761],
- [0.82294635110428427, 0.71829177331290062, 0.6464164243818421],
- [0.8245268129450285, 0.72264614312088882, 0.65313137915422603],
- [0.82613549710580259, 0.72697275518238258, 0.65985900156216504],
- [0.8277716072353446, 0.73127023324078089, 0.66659570204682972],
- [0.82943407816481474, 0.7355371221572935, 0.67333772009301907],
- [0.83112163529096306, 0.73977184647638616, 0.68008125203631464],
- [0.83283277185777982, 0.74397271817459876, 0.68682235874648545],
- [0.8345656905566583, 0.7481379479992134, 0.69355697649863846],
- [0.83631898844737929, 0.75226548952875261, 0.70027999028864962],
- [0.83809123476131964, 0.75635314860808633, 0.70698561390212977],
- [0.83987839884120874, 0.76039907199779677, 0.71367147811129228],
- [0.84167750766845151, 0.76440101200982946, 0.72033299387284622],
- [0.84348529222933699, 0.76835660399870176, 0.72696536998972039],
- [0.84529810731955113, 0.77226338601044719, 0.73356368240541492],
- [0.84711195507965098, 0.77611880236047159, 0.74012275762807056],
- [0.84892245563117641, 0.77992021407650147, 0.74663719293664366],
- [0.85072697023178789, 0.78366457342383888, 0.7530974636118285],
- [0.85251907207708444, 0.78734936133548439, 0.7594994148789691],
- [0.85429219611470464, 0.79097196777091994, 0.76583801477914104],
- [0.85604022314725403, 0.79452963601550608, 0.77210610037674143],
- [0.85775662943504905, 0.79801963142713928, 0.77829571667247499],
- [0.8594346370300241, 0.8014392309950078, 0.78439788751383921],
- [0.86107117027565516, 0.80478517909812231, 0.79039529663736285],
- [0.86265601051127572, 0.80805523804261525, 0.796282666437655],
- [0.86418343723941027, 0.81124644224653542, 0.80204612696863953],
- [0.86564934325605325, 0.81435544067514909, 0.80766972324164554],
- [0.86705314907048503, 0.81737804041911244, 0.81313419626911398],
- [0.86839954695818633, 0.82030875512181523, 0.81841638963128993],
- [0.86969131502613806, 0.82314158859569164, 0.82350476683173168],
- [0.87093846717297507, 0.82586857889438514, 0.82838497261149613],
- [0.87215331978454325, 0.82848052823709672, 0.8330486712880828],
- [0.87335171360916275, 0.83096715251272624, 0.83748851001197089],
- [0.87453793320260187, 0.83331972948645461, 0.84171925358069011],
- [0.87571458709961403, 0.8355302318472394, 0.84575537519027078],
- [0.87687848451614692, 0.83759238071186537, 0.84961373549150254],
- [0.87802298436649007, 0.83950165618540074, 0.85330645352458923],
- [0.87913244240792765, 0.84125554884475906, 0.85685572291039636],
- [0.88019293315695812, 0.84285224824778615, 0.86027399927156634],
- [0.88119169871341951, 0.84429066717717349, 0.86356595168669881],
- [0.88211542489401606, 0.84557007254559347, 0.86673765046233331],
- [0.88295168595448525, 0.84668970275699273, 0.86979617048190971],
- [0.88369127145898041, 0.84764891761519268, 0.87274147101441557],
- [0.88432713054113543, 0.84844741572055415, 0.87556785228242973],
- [0.88485138159908572, 0.84908426422893801, 0.87828235285372469],
- [0.88525897972630474, 0.84955892810989209, 0.88088414794024839],
- [0.88554714811952384, 0.84987174283631584, 0.88336206121170946],
- [0.88571155122845646, 0.85002186115856315, 0.88572538990087124]]
-
-_twilight_shifted_data = (_twilight_data[len(_twilight_data)//2:] +
- _twilight_data[:len(_twilight_data)//2])
-_twilight_shifted_data.reverse()
-
-cmaps = {}
-for (name, data) in (('magma', _magma_data),
- ('inferno', _inferno_data),
- ('plasma', _plasma_data),
- ('viridis', _viridis_data),
- ('cividis', _cividis_data),
- ('twilight', _twilight_data),
- ('twilight_shifted', _twilight_shifted_data)):
-
- cmaps[name] = ListedColormap(data, name=name)
- # generate reversed colormap
- name = name + '_r'
- cmaps[name] = ListedColormap(list(reversed(data)), name=name)
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_color_data.py b/server/venv/lib/python3.7/site-packages/matplotlib/_color_data.py
deleted file mode 100644
index 32420fe..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_color_data.py
+++ /dev/null
@@ -1,1144 +0,0 @@
-from collections import OrderedDict
-
-
-BASE_COLORS = {
- 'b': (0, 0, 1),
- 'g': (0, 0.5, 0),
- 'r': (1, 0, 0),
- 'c': (0, 0.75, 0.75),
- 'm': (0.75, 0, 0.75),
- 'y': (0.75, 0.75, 0),
- 'k': (0, 0, 0),
- 'w': (1, 1, 1)}
-
-
-# These colors are from Tableau
-TABLEAU_COLORS = (
- ('blue', '#1f77b4'),
- ('orange', '#ff7f0e'),
- ('green', '#2ca02c'),
- ('red', '#d62728'),
- ('purple', '#9467bd'),
- ('brown', '#8c564b'),
- ('pink', '#e377c2'),
- ('gray', '#7f7f7f'),
- ('olive', '#bcbd22'),
- ('cyan', '#17becf'),
-)
-
-# Normalize name to "tab:" to avoid name collisions.
-TABLEAU_COLORS = OrderedDict(
- ('tab:' + name, value) for name, value in TABLEAU_COLORS)
-
-# This mapping of color names -> hex values is taken from
-# a survey run by Randall Munroe see:
-# http://blog.xkcd.com/2010/05/03/color-survey-results/
-# for more details. The results are hosted at
-# https://xkcd.com/color/rgb.txt
-#
-# License: http://creativecommons.org/publicdomain/zero/1.0/
-XKCD_COLORS = {
- 'cloudy blue': '#acc2d9',
- 'dark pastel green': '#56ae57',
- 'dust': '#b2996e',
- 'electric lime': '#a8ff04',
- 'fresh green': '#69d84f',
- 'light eggplant': '#894585',
- 'nasty green': '#70b23f',
- 'really light blue': '#d4ffff',
- 'tea': '#65ab7c',
- 'warm purple': '#952e8f',
- 'yellowish tan': '#fcfc81',
- 'cement': '#a5a391',
- 'dark grass green': '#388004',
- 'dusty teal': '#4c9085',
- 'grey teal': '#5e9b8a',
- 'macaroni and cheese': '#efb435',
- 'pinkish tan': '#d99b82',
- 'spruce': '#0a5f38',
- 'strong blue': '#0c06f7',
- 'toxic green': '#61de2a',
- 'windows blue': '#3778bf',
- 'blue blue': '#2242c7',
- 'blue with a hint of purple': '#533cc6',
- 'booger': '#9bb53c',
- 'bright sea green': '#05ffa6',
- 'dark green blue': '#1f6357',
- 'deep turquoise': '#017374',
- 'green teal': '#0cb577',
- 'strong pink': '#ff0789',
- 'bland': '#afa88b',
- 'deep aqua': '#08787f',
- 'lavender pink': '#dd85d7',
- 'light moss green': '#a6c875',
- 'light seafoam green': '#a7ffb5',
- 'olive yellow': '#c2b709',
- 'pig pink': '#e78ea5',
- 'deep lilac': '#966ebd',
- 'desert': '#ccad60',
- 'dusty lavender': '#ac86a8',
- 'purpley grey': '#947e94',
- 'purply': '#983fb2',
- 'candy pink': '#ff63e9',
- 'light pastel green': '#b2fba5',
- 'boring green': '#63b365',
- 'kiwi green': '#8ee53f',
- 'light grey green': '#b7e1a1',
- 'orange pink': '#ff6f52',
- 'tea green': '#bdf8a3',
- 'very light brown': '#d3b683',
- 'egg shell': '#fffcc4',
- 'eggplant purple': '#430541',
- 'powder pink': '#ffb2d0',
- 'reddish grey': '#997570',
- 'baby shit brown': '#ad900d',
- 'liliac': '#c48efd',
- 'stormy blue': '#507b9c',
- 'ugly brown': '#7d7103',
- 'custard': '#fffd78',
- 'darkish pink': '#da467d',
- 'deep brown': '#410200',
- 'greenish beige': '#c9d179',
- 'manilla': '#fffa86',
- 'off blue': '#5684ae',
- 'battleship grey': '#6b7c85',
- 'browny green': '#6f6c0a',
- 'bruise': '#7e4071',
- 'kelley green': '#009337',
- 'sickly yellow': '#d0e429',
- 'sunny yellow': '#fff917',
- 'azul': '#1d5dec',
- 'darkgreen': '#054907',
- 'green/yellow': '#b5ce08',
- 'lichen': '#8fb67b',
- 'light light green': '#c8ffb0',
- 'pale gold': '#fdde6c',
- 'sun yellow': '#ffdf22',
- 'tan green': '#a9be70',
- 'burple': '#6832e3',
- 'butterscotch': '#fdb147',
- 'toupe': '#c7ac7d',
- 'dark cream': '#fff39a',
- 'indian red': '#850e04',
- 'light lavendar': '#efc0fe',
- 'poison green': '#40fd14',
- 'baby puke green': '#b6c406',
- 'bright yellow green': '#9dff00',
- 'charcoal grey': '#3c4142',
- 'squash': '#f2ab15',
- 'cinnamon': '#ac4f06',
- 'light pea green': '#c4fe82',
- 'radioactive green': '#2cfa1f',
- 'raw sienna': '#9a6200',
- 'baby purple': '#ca9bf7',
- 'cocoa': '#875f42',
- 'light royal blue': '#3a2efe',
- 'orangeish': '#fd8d49',
- 'rust brown': '#8b3103',
- 'sand brown': '#cba560',
- 'swamp': '#698339',
- 'tealish green': '#0cdc73',
- 'burnt siena': '#b75203',
- 'camo': '#7f8f4e',
- 'dusk blue': '#26538d',
- 'fern': '#63a950',
- 'old rose': '#c87f89',
- 'pale light green': '#b1fc99',
- 'peachy pink': '#ff9a8a',
- 'rosy pink': '#f6688e',
- 'light bluish green': '#76fda8',
- 'light bright green': '#53fe5c',
- 'light neon green': '#4efd54',
- 'light seafoam': '#a0febf',
- 'tiffany blue': '#7bf2da',
- 'washed out green': '#bcf5a6',
- 'browny orange': '#ca6b02',
- 'nice blue': '#107ab0',
- 'sapphire': '#2138ab',
- 'greyish teal': '#719f91',
- 'orangey yellow': '#fdb915',
- 'parchment': '#fefcaf',
- 'straw': '#fcf679',
- 'very dark brown': '#1d0200',
- 'terracota': '#cb6843',
- 'ugly blue': '#31668a',
- 'clear blue': '#247afd',
- 'creme': '#ffffb6',
- 'foam green': '#90fda9',
- 'grey/green': '#86a17d',
- 'light gold': '#fddc5c',
- 'seafoam blue': '#78d1b6',
- 'topaz': '#13bbaf',
- 'violet pink': '#fb5ffc',
- 'wintergreen': '#20f986',
- 'yellow tan': '#ffe36e',
- 'dark fuchsia': '#9d0759',
- 'indigo blue': '#3a18b1',
- 'light yellowish green': '#c2ff89',
- 'pale magenta': '#d767ad',
- 'rich purple': '#720058',
- 'sunflower yellow': '#ffda03',
- 'green/blue': '#01c08d',
- 'leather': '#ac7434',
- 'racing green': '#014600',
- 'vivid purple': '#9900fa',
- 'dark royal blue': '#02066f',
- 'hazel': '#8e7618',
- 'muted pink': '#d1768f',
- 'booger green': '#96b403',
- 'canary': '#fdff63',
- 'cool grey': '#95a3a6',
- 'dark taupe': '#7f684e',
- 'darkish purple': '#751973',
- 'true green': '#089404',
- 'coral pink': '#ff6163',
- 'dark sage': '#598556',
- 'dark slate blue': '#214761',
- 'flat blue': '#3c73a8',
- 'mushroom': '#ba9e88',
- 'rich blue': '#021bf9',
- 'dirty purple': '#734a65',
- 'greenblue': '#23c48b',
- 'icky green': '#8fae22',
- 'light khaki': '#e6f2a2',
- 'warm blue': '#4b57db',
- 'dark hot pink': '#d90166',
- 'deep sea blue': '#015482',
- 'carmine': '#9d0216',
- 'dark yellow green': '#728f02',
- 'pale peach': '#ffe5ad',
- 'plum purple': '#4e0550',
- 'golden rod': '#f9bc08',
- 'neon red': '#ff073a',
- 'old pink': '#c77986',
- 'very pale blue': '#d6fffe',
- 'blood orange': '#fe4b03',
- 'grapefruit': '#fd5956',
- 'sand yellow': '#fce166',
- 'clay brown': '#b2713d',
- 'dark blue grey': '#1f3b4d',
- 'flat green': '#699d4c',
- 'light green blue': '#56fca2',
- 'warm pink': '#fb5581',
- 'dodger blue': '#3e82fc',
- 'gross green': '#a0bf16',
- 'ice': '#d6fffa',
- 'metallic blue': '#4f738e',
- 'pale salmon': '#ffb19a',
- 'sap green': '#5c8b15',
- 'algae': '#54ac68',
- 'bluey grey': '#89a0b0',
- 'greeny grey': '#7ea07a',
- 'highlighter green': '#1bfc06',
- 'light light blue': '#cafffb',
- 'light mint': '#b6ffbb',
- 'raw umber': '#a75e09',
- 'vivid blue': '#152eff',
- 'deep lavender': '#8d5eb7',
- 'dull teal': '#5f9e8f',
- 'light greenish blue': '#63f7b4',
- 'mud green': '#606602',
- 'pinky': '#fc86aa',
- 'red wine': '#8c0034',
- 'shit green': '#758000',
- 'tan brown': '#ab7e4c',
- 'darkblue': '#030764',
- 'rosa': '#fe86a4',
- 'lipstick': '#d5174e',
- 'pale mauve': '#fed0fc',
- 'claret': '#680018',
- 'dandelion': '#fedf08',
- 'orangered': '#fe420f',
- 'poop green': '#6f7c00',
- 'ruby': '#ca0147',
- 'dark': '#1b2431',
- 'greenish turquoise': '#00fbb0',
- 'pastel red': '#db5856',
- 'piss yellow': '#ddd618',
- 'bright cyan': '#41fdfe',
- 'dark coral': '#cf524e',
- 'algae green': '#21c36f',
- 'darkish red': '#a90308',
- 'reddy brown': '#6e1005',
- 'blush pink': '#fe828c',
- 'camouflage green': '#4b6113',
- 'lawn green': '#4da409',
- 'putty': '#beae8a',
- 'vibrant blue': '#0339f8',
- 'dark sand': '#a88f59',
- 'purple/blue': '#5d21d0',
- 'saffron': '#feb209',
- 'twilight': '#4e518b',
- 'warm brown': '#964e02',
- 'bluegrey': '#85a3b2',
- 'bubble gum pink': '#ff69af',
- 'duck egg blue': '#c3fbf4',
- 'greenish cyan': '#2afeb7',
- 'petrol': '#005f6a',
- 'royal': '#0c1793',
- 'butter': '#ffff81',
- 'dusty orange': '#f0833a',
- 'off yellow': '#f1f33f',
- 'pale olive green': '#b1d27b',
- 'orangish': '#fc824a',
- 'leaf': '#71aa34',
- 'light blue grey': '#b7c9e2',
- 'dried blood': '#4b0101',
- 'lightish purple': '#a552e6',
- 'rusty red': '#af2f0d',
- 'lavender blue': '#8b88f8',
- 'light grass green': '#9af764',
- 'light mint green': '#a6fbb2',
- 'sunflower': '#ffc512',
- 'velvet': '#750851',
- 'brick orange': '#c14a09',
- 'lightish red': '#fe2f4a',
- 'pure blue': '#0203e2',
- 'twilight blue': '#0a437a',
- 'violet red': '#a50055',
- 'yellowy brown': '#ae8b0c',
- 'carnation': '#fd798f',
- 'muddy yellow': '#bfac05',
- 'dark seafoam green': '#3eaf76',
- 'deep rose': '#c74767',
- 'dusty red': '#b9484e',
- 'grey/blue': '#647d8e',
- 'lemon lime': '#bffe28',
- 'purple/pink': '#d725de',
- 'brown yellow': '#b29705',
- 'purple brown': '#673a3f',
- 'wisteria': '#a87dc2',
- 'banana yellow': '#fafe4b',
- 'lipstick red': '#c0022f',
- 'water blue': '#0e87cc',
- 'brown grey': '#8d8468',
- 'vibrant purple': '#ad03de',
- 'baby green': '#8cff9e',
- 'barf green': '#94ac02',
- 'eggshell blue': '#c4fff7',
- 'sandy yellow': '#fdee73',
- 'cool green': '#33b864',
- 'pale': '#fff9d0',
- 'blue/grey': '#758da3',
- 'hot magenta': '#f504c9',
- 'greyblue': '#77a1b5',
- 'purpley': '#8756e4',
- 'baby shit green': '#889717',
- 'brownish pink': '#c27e79',
- 'dark aquamarine': '#017371',
- 'diarrhea': '#9f8303',
- 'light mustard': '#f7d560',
- 'pale sky blue': '#bdf6fe',
- 'turtle green': '#75b84f',
- 'bright olive': '#9cbb04',
- 'dark grey blue': '#29465b',
- 'greeny brown': '#696006',
- 'lemon green': '#adf802',
- 'light periwinkle': '#c1c6fc',
- 'seaweed green': '#35ad6b',
- 'sunshine yellow': '#fffd37',
- 'ugly purple': '#a442a0',
- 'medium pink': '#f36196',
- 'puke brown': '#947706',
- 'very light pink': '#fff4f2',
- 'viridian': '#1e9167',
- 'bile': '#b5c306',
- 'faded yellow': '#feff7f',
- 'very pale green': '#cffdbc',
- 'vibrant green': '#0add08',
- 'bright lime': '#87fd05',
- 'spearmint': '#1ef876',
- 'light aquamarine': '#7bfdc7',
- 'light sage': '#bcecac',
- 'yellowgreen': '#bbf90f',
- 'baby poo': '#ab9004',
- 'dark seafoam': '#1fb57a',
- 'deep teal': '#00555a',
- 'heather': '#a484ac',
- 'rust orange': '#c45508',
- 'dirty blue': '#3f829d',
- 'fern green': '#548d44',
- 'bright lilac': '#c95efb',
- 'weird green': '#3ae57f',
- 'peacock blue': '#016795',
- 'avocado green': '#87a922',
- 'faded orange': '#f0944d',
- 'grape purple': '#5d1451',
- 'hot green': '#25ff29',
- 'lime yellow': '#d0fe1d',
- 'mango': '#ffa62b',
- 'shamrock': '#01b44c',
- 'bubblegum': '#ff6cb5',
- 'purplish brown': '#6b4247',
- 'vomit yellow': '#c7c10c',
- 'pale cyan': '#b7fffa',
- 'key lime': '#aeff6e',
- 'tomato red': '#ec2d01',
- 'lightgreen': '#76ff7b',
- 'merlot': '#730039',
- 'night blue': '#040348',
- 'purpleish pink': '#df4ec8',
- 'apple': '#6ecb3c',
- 'baby poop green': '#8f9805',
- 'green apple': '#5edc1f',
- 'heliotrope': '#d94ff5',
- 'yellow/green': '#c8fd3d',
- 'almost black': '#070d0d',
- 'cool blue': '#4984b8',
- 'leafy green': '#51b73b',
- 'mustard brown': '#ac7e04',
- 'dusk': '#4e5481',
- 'dull brown': '#876e4b',
- 'frog green': '#58bc08',
- 'vivid green': '#2fef10',
- 'bright light green': '#2dfe54',
- 'fluro green': '#0aff02',
- 'kiwi': '#9cef43',
- 'seaweed': '#18d17b',
- 'navy green': '#35530a',
- 'ultramarine blue': '#1805db',
- 'iris': '#6258c4',
- 'pastel orange': '#ff964f',
- 'yellowish orange': '#ffab0f',
- 'perrywinkle': '#8f8ce7',
- 'tealish': '#24bca8',
- 'dark plum': '#3f012c',
- 'pear': '#cbf85f',
- 'pinkish orange': '#ff724c',
- 'midnight purple': '#280137',
- 'light urple': '#b36ff6',
- 'dark mint': '#48c072',
- 'greenish tan': '#bccb7a',
- 'light burgundy': '#a8415b',
- 'turquoise blue': '#06b1c4',
- 'ugly pink': '#cd7584',
- 'sandy': '#f1da7a',
- 'electric pink': '#ff0490',
- 'muted purple': '#805b87',
- 'mid green': '#50a747',
- 'greyish': '#a8a495',
- 'neon yellow': '#cfff04',
- 'banana': '#ffff7e',
- 'carnation pink': '#ff7fa7',
- 'tomato': '#ef4026',
- 'sea': '#3c9992',
- 'muddy brown': '#886806',
- 'turquoise green': '#04f489',
- 'buff': '#fef69e',
- 'fawn': '#cfaf7b',
- 'muted blue': '#3b719f',
- 'pale rose': '#fdc1c5',
- 'dark mint green': '#20c073',
- 'amethyst': '#9b5fc0',
- 'blue/green': '#0f9b8e',
- 'chestnut': '#742802',
- 'sick green': '#9db92c',
- 'pea': '#a4bf20',
- 'rusty orange': '#cd5909',
- 'stone': '#ada587',
- 'rose red': '#be013c',
- 'pale aqua': '#b8ffeb',
- 'deep orange': '#dc4d01',
- 'earth': '#a2653e',
- 'mossy green': '#638b27',
- 'grassy green': '#419c03',
- 'pale lime green': '#b1ff65',
- 'light grey blue': '#9dbcd4',
- 'pale grey': '#fdfdfe',
- 'asparagus': '#77ab56',
- 'blueberry': '#464196',
- 'purple red': '#990147',
- 'pale lime': '#befd73',
- 'greenish teal': '#32bf84',
- 'caramel': '#af6f09',
- 'deep magenta': '#a0025c',
- 'light peach': '#ffd8b1',
- 'milk chocolate': '#7f4e1e',
- 'ocher': '#bf9b0c',
- 'off green': '#6ba353',
- 'purply pink': '#f075e6',
- 'lightblue': '#7bc8f6',
- 'dusky blue': '#475f94',
- 'golden': '#f5bf03',
- 'light beige': '#fffeb6',
- 'butter yellow': '#fffd74',
- 'dusky purple': '#895b7b',
- 'french blue': '#436bad',
- 'ugly yellow': '#d0c101',
- 'greeny yellow': '#c6f808',
- 'orangish red': '#f43605',
- 'shamrock green': '#02c14d',
- 'orangish brown': '#b25f03',
- 'tree green': '#2a7e19',
- 'deep violet': '#490648',
- 'gunmetal': '#536267',
- 'blue/purple': '#5a06ef',
- 'cherry': '#cf0234',
- 'sandy brown': '#c4a661',
- 'warm grey': '#978a84',
- 'dark indigo': '#1f0954',
- 'midnight': '#03012d',
- 'bluey green': '#2bb179',
- 'grey pink': '#c3909b',
- 'soft purple': '#a66fb5',
- 'blood': '#770001',
- 'brown red': '#922b05',
- 'medium grey': '#7d7f7c',
- 'berry': '#990f4b',
- 'poo': '#8f7303',
- 'purpley pink': '#c83cb9',
- 'light salmon': '#fea993',
- 'snot': '#acbb0d',
- 'easter purple': '#c071fe',
- 'light yellow green': '#ccfd7f',
- 'dark navy blue': '#00022e',
- 'drab': '#828344',
- 'light rose': '#ffc5cb',
- 'rouge': '#ab1239',
- 'purplish red': '#b0054b',
- 'slime green': '#99cc04',
- 'baby poop': '#937c00',
- 'irish green': '#019529',
- 'pink/purple': '#ef1de7',
- 'dark navy': '#000435',
- 'greeny blue': '#42b395',
- 'light plum': '#9d5783',
- 'pinkish grey': '#c8aca9',
- 'dirty orange': '#c87606',
- 'rust red': '#aa2704',
- 'pale lilac': '#e4cbff',
- 'orangey red': '#fa4224',
- 'primary blue': '#0804f9',
- 'kermit green': '#5cb200',
- 'brownish purple': '#76424e',
- 'murky green': '#6c7a0e',
- 'wheat': '#fbdd7e',
- 'very dark purple': '#2a0134',
- 'bottle green': '#044a05',
- 'watermelon': '#fd4659',
- 'deep sky blue': '#0d75f8',
- 'fire engine red': '#fe0002',
- 'yellow ochre': '#cb9d06',
- 'pumpkin orange': '#fb7d07',
- 'pale olive': '#b9cc81',
- 'light lilac': '#edc8ff',
- 'lightish green': '#61e160',
- 'carolina blue': '#8ab8fe',
- 'mulberry': '#920a4e',
- 'shocking pink': '#fe02a2',
- 'auburn': '#9a3001',
- 'bright lime green': '#65fe08',
- 'celadon': '#befdb7',
- 'pinkish brown': '#b17261',
- 'poo brown': '#885f01',
- 'bright sky blue': '#02ccfe',
- 'celery': '#c1fd95',
- 'dirt brown': '#836539',
- 'strawberry': '#fb2943',
- 'dark lime': '#84b701',
- 'copper': '#b66325',
- 'medium brown': '#7f5112',
- 'muted green': '#5fa052',
- "robin's egg": '#6dedfd',
- 'bright aqua': '#0bf9ea',
- 'bright lavender': '#c760ff',
- 'ivory': '#ffffcb',
- 'very light purple': '#f6cefc',
- 'light navy': '#155084',
- 'pink red': '#f5054f',
- 'olive brown': '#645403',
- 'poop brown': '#7a5901',
- 'mustard green': '#a8b504',
- 'ocean green': '#3d9973',
- 'very dark blue': '#000133',
- 'dusty green': '#76a973',
- 'light navy blue': '#2e5a88',
- 'minty green': '#0bf77d',
- 'adobe': '#bd6c48',
- 'barney': '#ac1db8',
- 'jade green': '#2baf6a',
- 'bright light blue': '#26f7fd',
- 'light lime': '#aefd6c',
- 'dark khaki': '#9b8f55',
- 'orange yellow': '#ffad01',
- 'ocre': '#c69c04',
- 'maize': '#f4d054',
- 'faded pink': '#de9dac',
- 'british racing green': '#05480d',
- 'sandstone': '#c9ae74',
- 'mud brown': '#60460f',
- 'light sea green': '#98f6b0',
- 'robin egg blue': '#8af1fe',
- 'aqua marine': '#2ee8bb',
- 'dark sea green': '#11875d',
- 'soft pink': '#fdb0c0',
- 'orangey brown': '#b16002',
- 'cherry red': '#f7022a',
- 'burnt yellow': '#d5ab09',
- 'brownish grey': '#86775f',
- 'camel': '#c69f59',
- 'purplish grey': '#7a687f',
- 'marine': '#042e60',
- 'greyish pink': '#c88d94',
- 'pale turquoise': '#a5fbd5',
- 'pastel yellow': '#fffe71',
- 'bluey purple': '#6241c7',
- 'canary yellow': '#fffe40',
- 'faded red': '#d3494e',
- 'sepia': '#985e2b',
- 'coffee': '#a6814c',
- 'bright magenta': '#ff08e8',
- 'mocha': '#9d7651',
- 'ecru': '#feffca',
- 'purpleish': '#98568d',
- 'cranberry': '#9e003a',
- 'darkish green': '#287c37',
- 'brown orange': '#b96902',
- 'dusky rose': '#ba6873',
- 'melon': '#ff7855',
- 'sickly green': '#94b21c',
- 'silver': '#c5c9c7',
- 'purply blue': '#661aee',
- 'purpleish blue': '#6140ef',
- 'hospital green': '#9be5aa',
- 'shit brown': '#7b5804',
- 'mid blue': '#276ab3',
- 'amber': '#feb308',
- 'easter green': '#8cfd7e',
- 'soft blue': '#6488ea',
- 'cerulean blue': '#056eee',
- 'golden brown': '#b27a01',
- 'bright turquoise': '#0ffef9',
- 'red pink': '#fa2a55',
- 'red purple': '#820747',
- 'greyish brown': '#7a6a4f',
- 'vermillion': '#f4320c',
- 'russet': '#a13905',
- 'steel grey': '#6f828a',
- 'lighter purple': '#a55af4',
- 'bright violet': '#ad0afd',
- 'prussian blue': '#004577',
- 'slate green': '#658d6d',
- 'dirty pink': '#ca7b80',
- 'dark blue green': '#005249',
- 'pine': '#2b5d34',
- 'yellowy green': '#bff128',
- 'dark gold': '#b59410',
- 'bluish': '#2976bb',
- 'darkish blue': '#014182',
- 'dull red': '#bb3f3f',
- 'pinky red': '#fc2647',
- 'bronze': '#a87900',
- 'pale teal': '#82cbb2',
- 'military green': '#667c3e',
- 'barbie pink': '#fe46a5',
- 'bubblegum pink': '#fe83cc',
- 'pea soup green': '#94a617',
- 'dark mustard': '#a88905',
- 'shit': '#7f5f00',
- 'medium purple': '#9e43a2',
- 'very dark green': '#062e03',
- 'dirt': '#8a6e45',
- 'dusky pink': '#cc7a8b',
- 'red violet': '#9e0168',
- 'lemon yellow': '#fdff38',
- 'pistachio': '#c0fa8b',
- 'dull yellow': '#eedc5b',
- 'dark lime green': '#7ebd01',
- 'denim blue': '#3b5b92',
- 'teal blue': '#01889f',
- 'lightish blue': '#3d7afd',
- 'purpley blue': '#5f34e7',
- 'light indigo': '#6d5acf',
- 'swamp green': '#748500',
- 'brown green': '#706c11',
- 'dark maroon': '#3c0008',
- 'hot purple': '#cb00f5',
- 'dark forest green': '#002d04',
- 'faded blue': '#658cbb',
- 'drab green': '#749551',
- 'light lime green': '#b9ff66',
- 'snot green': '#9dc100',
- 'yellowish': '#faee66',
- 'light blue green': '#7efbb3',
- 'bordeaux': '#7b002c',
- 'light mauve': '#c292a1',
- 'ocean': '#017b92',
- 'marigold': '#fcc006',
- 'muddy green': '#657432',
- 'dull orange': '#d8863b',
- 'steel': '#738595',
- 'electric purple': '#aa23ff',
- 'fluorescent green': '#08ff08',
- 'yellowish brown': '#9b7a01',
- 'blush': '#f29e8e',
- 'soft green': '#6fc276',
- 'bright orange': '#ff5b00',
- 'lemon': '#fdff52',
- 'purple grey': '#866f85',
- 'acid green': '#8ffe09',
- 'pale lavender': '#eecffe',
- 'violet blue': '#510ac9',
- 'light forest green': '#4f9153',
- 'burnt red': '#9f2305',
- 'khaki green': '#728639',
- 'cerise': '#de0c62',
- 'faded purple': '#916e99',
- 'apricot': '#ffb16d',
- 'dark olive green': '#3c4d03',
- 'grey brown': '#7f7053',
- 'green grey': '#77926f',
- 'true blue': '#010fcc',
- 'pale violet': '#ceaefa',
- 'periwinkle blue': '#8f99fb',
- 'light sky blue': '#c6fcff',
- 'blurple': '#5539cc',
- 'green brown': '#544e03',
- 'bluegreen': '#017a79',
- 'bright teal': '#01f9c6',
- 'brownish yellow': '#c9b003',
- 'pea soup': '#929901',
- 'forest': '#0b5509',
- 'barney purple': '#a00498',
- 'ultramarine': '#2000b1',
- 'purplish': '#94568c',
- 'puke yellow': '#c2be0e',
- 'bluish grey': '#748b97',
- 'dark periwinkle': '#665fd1',
- 'dark lilac': '#9c6da5',
- 'reddish': '#c44240',
- 'light maroon': '#a24857',
- 'dusty purple': '#825f87',
- 'terra cotta': '#c9643b',
- 'avocado': '#90b134',
- 'marine blue': '#01386a',
- 'teal green': '#25a36f',
- 'slate grey': '#59656d',
- 'lighter green': '#75fd63',
- 'electric green': '#21fc0d',
- 'dusty blue': '#5a86ad',
- 'golden yellow': '#fec615',
- 'bright yellow': '#fffd01',
- 'light lavender': '#dfc5fe',
- 'umber': '#b26400',
- 'poop': '#7f5e00',
- 'dark peach': '#de7e5d',
- 'jungle green': '#048243',
- 'eggshell': '#ffffd4',
- 'denim': '#3b638c',
- 'yellow brown': '#b79400',
- 'dull purple': '#84597e',
- 'chocolate brown': '#411900',
- 'wine red': '#7b0323',
- 'neon blue': '#04d9ff',
- 'dirty green': '#667e2c',
- 'light tan': '#fbeeac',
- 'ice blue': '#d7fffe',
- 'cadet blue': '#4e7496',
- 'dark mauve': '#874c62',
- 'very light blue': '#d5ffff',
- 'grey purple': '#826d8c',
- 'pastel pink': '#ffbacd',
- 'very light green': '#d1ffbd',
- 'dark sky blue': '#448ee4',
- 'evergreen': '#05472a',
- 'dull pink': '#d5869d',
- 'aubergine': '#3d0734',
- 'mahogany': '#4a0100',
- 'reddish orange': '#f8481c',
- 'deep green': '#02590f',
- 'vomit green': '#89a203',
- 'purple pink': '#e03fd8',
- 'dusty pink': '#d58a94',
- 'faded green': '#7bb274',
- 'camo green': '#526525',
- 'pinky purple': '#c94cbe',
- 'pink purple': '#db4bda',
- 'brownish red': '#9e3623',
- 'dark rose': '#b5485d',
- 'mud': '#735c12',
- 'brownish': '#9c6d57',
- 'emerald green': '#028f1e',
- 'pale brown': '#b1916e',
- 'dull blue': '#49759c',
- 'burnt umber': '#a0450e',
- 'medium green': '#39ad48',
- 'clay': '#b66a50',
- 'light aqua': '#8cffdb',
- 'light olive green': '#a4be5c',
- 'brownish orange': '#cb7723',
- 'dark aqua': '#05696b',
- 'purplish pink': '#ce5dae',
- 'dark salmon': '#c85a53',
- 'greenish grey': '#96ae8d',
- 'jade': '#1fa774',
- 'ugly green': '#7a9703',
- 'dark beige': '#ac9362',
- 'emerald': '#01a049',
- 'pale red': '#d9544d',
- 'light magenta': '#fa5ff7',
- 'sky': '#82cafc',
- 'light cyan': '#acfffc',
- 'yellow orange': '#fcb001',
- 'reddish purple': '#910951',
- 'reddish pink': '#fe2c54',
- 'orchid': '#c875c4',
- 'dirty yellow': '#cdc50a',
- 'orange red': '#fd411e',
- 'deep red': '#9a0200',
- 'orange brown': '#be6400',
- 'cobalt blue': '#030aa7',
- 'neon pink': '#fe019a',
- 'rose pink': '#f7879a',
- 'greyish purple': '#887191',
- 'raspberry': '#b00149',
- 'aqua green': '#12e193',
- 'salmon pink': '#fe7b7c',
- 'tangerine': '#ff9408',
- 'brownish green': '#6a6e09',
- 'red brown': '#8b2e16',
- 'greenish brown': '#696112',
- 'pumpkin': '#e17701',
- 'pine green': '#0a481e',
- 'charcoal': '#343837',
- 'baby pink': '#ffb7ce',
- 'cornflower': '#6a79f7',
- 'blue violet': '#5d06e9',
- 'chocolate': '#3d1c02',
- 'greyish green': '#82a67d',
- 'scarlet': '#be0119',
- 'green yellow': '#c9ff27',
- 'dark olive': '#373e02',
- 'sienna': '#a9561e',
- 'pastel purple': '#caa0ff',
- 'terracotta': '#ca6641',
- 'aqua blue': '#02d8e9',
- 'sage green': '#88b378',
- 'blood red': '#980002',
- 'deep pink': '#cb0162',
- 'grass': '#5cac2d',
- 'moss': '#769958',
- 'pastel blue': '#a2bffe',
- 'bluish green': '#10a674',
- 'green blue': '#06b48b',
- 'dark tan': '#af884a',
- 'greenish blue': '#0b8b87',
- 'pale orange': '#ffa756',
- 'vomit': '#a2a415',
- 'forrest green': '#154406',
- 'dark lavender': '#856798',
- 'dark violet': '#34013f',
- 'purple blue': '#632de9',
- 'dark cyan': '#0a888a',
- 'olive drab': '#6f7632',
- 'pinkish': '#d46a7e',
- 'cobalt': '#1e488f',
- 'neon purple': '#bc13fe',
- 'light turquoise': '#7ef4cc',
- 'apple green': '#76cd26',
- 'dull green': '#74a662',
- 'wine': '#80013f',
- 'powder blue': '#b1d1fc',
- 'off white': '#ffffe4',
- 'electric blue': '#0652ff',
- 'dark turquoise': '#045c5a',
- 'blue purple': '#5729ce',
- 'azure': '#069af3',
- 'bright red': '#ff000d',
- 'pinkish red': '#f10c45',
- 'cornflower blue': '#5170d7',
- 'light olive': '#acbf69',
- 'grape': '#6c3461',
- 'greyish blue': '#5e819d',
- 'purplish blue': '#601ef9',
- 'yellowish green': '#b0dd16',
- 'greenish yellow': '#cdfd02',
- 'medium blue': '#2c6fbb',
- 'dusty rose': '#c0737a',
- 'light violet': '#d6b4fc',
- 'midnight blue': '#020035',
- 'bluish purple': '#703be7',
- 'red orange': '#fd3c06',
- 'dark magenta': '#960056',
- 'greenish': '#40a368',
- 'ocean blue': '#03719c',
- 'coral': '#fc5a50',
- 'cream': '#ffffc2',
- 'reddish brown': '#7f2b0a',
- 'burnt sienna': '#b04e0f',
- 'brick': '#a03623',
- 'sage': '#87ae73',
- 'grey green': '#789b73',
- 'white': '#ffffff',
- "robin's egg blue": '#98eff9',
- 'moss green': '#658b38',
- 'steel blue': '#5a7d9a',
- 'eggplant': '#380835',
- 'light yellow': '#fffe7a',
- 'leaf green': '#5ca904',
- 'light grey': '#d8dcd6',
- 'puke': '#a5a502',
- 'pinkish purple': '#d648d7',
- 'sea blue': '#047495',
- 'pale purple': '#b790d4',
- 'slate blue': '#5b7c99',
- 'blue grey': '#607c8e',
- 'hunter green': '#0b4008',
- 'fuchsia': '#ed0dd9',
- 'crimson': '#8c000f',
- 'pale yellow': '#ffff84',
- 'ochre': '#bf9005',
- 'mustard yellow': '#d2bd0a',
- 'light red': '#ff474c',
- 'cerulean': '#0485d1',
- 'pale pink': '#ffcfdc',
- 'deep blue': '#040273',
- 'rust': '#a83c09',
- 'light teal': '#90e4c1',
- 'slate': '#516572',
- 'goldenrod': '#fac205',
- 'dark yellow': '#d5b60a',
- 'dark grey': '#363737',
- 'army green': '#4b5d16',
- 'grey blue': '#6b8ba4',
- 'seafoam': '#80f9ad',
- 'puce': '#a57e52',
- 'spring green': '#a9f971',
- 'dark orange': '#c65102',
- 'sand': '#e2ca76',
- 'pastel green': '#b0ff9d',
- 'mint': '#9ffeb0',
- 'light orange': '#fdaa48',
- 'bright pink': '#fe01b1',
- 'chartreuse': '#c1f80a',
- 'deep purple': '#36013f',
- 'dark brown': '#341c02',
- 'taupe': '#b9a281',
- 'pea green': '#8eab12',
- 'puke green': '#9aae07',
- 'kelly green': '#02ab2e',
- 'seafoam green': '#7af9ab',
- 'blue green': '#137e6d',
- 'khaki': '#aaa662',
- 'burgundy': '#610023',
- 'dark teal': '#014d4e',
- 'brick red': '#8f1402',
- 'royal purple': '#4b006e',
- 'plum': '#580f41',
- 'mint green': '#8fff9f',
- 'gold': '#dbb40c',
- 'baby blue': '#a2cffe',
- 'yellow green': '#c0fb2d',
- 'bright purple': '#be03fd',
- 'dark red': '#840000',
- 'pale blue': '#d0fefe',
- 'grass green': '#3f9b0b',
- 'navy': '#01153e',
- 'aquamarine': '#04d8b2',
- 'burnt orange': '#c04e01',
- 'neon green': '#0cff0c',
- 'bright blue': '#0165fc',
- 'rose': '#cf6275',
- 'light pink': '#ffd1df',
- 'mustard': '#ceb301',
- 'indigo': '#380282',
- 'lime': '#aaff32',
- 'sea green': '#53fca1',
- 'periwinkle': '#8e82fe',
- 'dark pink': '#cb416b',
- 'olive green': '#677a04',
- 'peach': '#ffb07c',
- 'pale green': '#c7fdb5',
- 'light brown': '#ad8150',
- 'hot pink': '#ff028d',
- 'black': '#000000',
- 'lilac': '#cea2fd',
- 'navy blue': '#001146',
- 'royal blue': '#0504aa',
- 'beige': '#e6daa6',
- 'salmon': '#ff796c',
- 'olive': '#6e750e',
- 'maroon': '#650021',
- 'bright green': '#01ff07',
- 'dark purple': '#35063e',
- 'mauve': '#ae7181',
- 'forest green': '#06470c',
- 'aqua': '#13eac9',
- 'cyan': '#00ffff',
- 'tan': '#d1b26f',
- 'dark blue': '#00035b',
- 'lavender': '#c79fef',
- 'turquoise': '#06c2ac',
- 'dark green': '#033500',
- 'violet': '#9a0eea',
- 'light purple': '#bf77f6',
- 'lime green': '#89fe05',
- 'grey': '#929591',
- 'sky blue': '#75bbfd',
- 'yellow': '#ffff14',
- 'magenta': '#c20078',
- 'light green': '#96f97b',
- 'orange': '#f97306',
- 'teal': '#029386',
- 'light blue': '#95d0fc',
- 'red': '#e50000',
- 'brown': '#653700',
- 'pink': '#ff81c0',
- 'blue': '#0343df',
- 'green': '#15b01a',
- 'purple': '#7e1e9c'}
-
-# Normalize name to "xkcd:" to avoid name collisions.
-XKCD_COLORS = {'xkcd:' + name: value for name, value in XKCD_COLORS.items()}
-
-
-# https://drafts.csswg.org/css-color-4/#named-colors
-CSS4_COLORS = {
- 'aliceblue': '#F0F8FF',
- 'antiquewhite': '#FAEBD7',
- 'aqua': '#00FFFF',
- 'aquamarine': '#7FFFD4',
- 'azure': '#F0FFFF',
- 'beige': '#F5F5DC',
- 'bisque': '#FFE4C4',
- 'black': '#000000',
- 'blanchedalmond': '#FFEBCD',
- 'blue': '#0000FF',
- 'blueviolet': '#8A2BE2',
- 'brown': '#A52A2A',
- 'burlywood': '#DEB887',
- 'cadetblue': '#5F9EA0',
- 'chartreuse': '#7FFF00',
- 'chocolate': '#D2691E',
- 'coral': '#FF7F50',
- 'cornflowerblue': '#6495ED',
- 'cornsilk': '#FFF8DC',
- 'crimson': '#DC143C',
- 'cyan': '#00FFFF',
- 'darkblue': '#00008B',
- 'darkcyan': '#008B8B',
- 'darkgoldenrod': '#B8860B',
- 'darkgray': '#A9A9A9',
- 'darkgreen': '#006400',
- 'darkgrey': '#A9A9A9',
- 'darkkhaki': '#BDB76B',
- 'darkmagenta': '#8B008B',
- 'darkolivegreen': '#556B2F',
- 'darkorange': '#FF8C00',
- 'darkorchid': '#9932CC',
- 'darkred': '#8B0000',
- 'darksalmon': '#E9967A',
- 'darkseagreen': '#8FBC8F',
- 'darkslateblue': '#483D8B',
- 'darkslategray': '#2F4F4F',
- 'darkslategrey': '#2F4F4F',
- 'darkturquoise': '#00CED1',
- 'darkviolet': '#9400D3',
- 'deeppink': '#FF1493',
- 'deepskyblue': '#00BFFF',
- 'dimgray': '#696969',
- 'dimgrey': '#696969',
- 'dodgerblue': '#1E90FF',
- 'firebrick': '#B22222',
- 'floralwhite': '#FFFAF0',
- 'forestgreen': '#228B22',
- 'fuchsia': '#FF00FF',
- 'gainsboro': '#DCDCDC',
- 'ghostwhite': '#F8F8FF',
- 'gold': '#FFD700',
- 'goldenrod': '#DAA520',
- 'gray': '#808080',
- 'green': '#008000',
- 'greenyellow': '#ADFF2F',
- 'grey': '#808080',
- 'honeydew': '#F0FFF0',
- 'hotpink': '#FF69B4',
- 'indianred': '#CD5C5C',
- 'indigo': '#4B0082',
- 'ivory': '#FFFFF0',
- 'khaki': '#F0E68C',
- 'lavender': '#E6E6FA',
- 'lavenderblush': '#FFF0F5',
- 'lawngreen': '#7CFC00',
- 'lemonchiffon': '#FFFACD',
- 'lightblue': '#ADD8E6',
- 'lightcoral': '#F08080',
- 'lightcyan': '#E0FFFF',
- 'lightgoldenrodyellow': '#FAFAD2',
- 'lightgray': '#D3D3D3',
- 'lightgreen': '#90EE90',
- 'lightgrey': '#D3D3D3',
- 'lightpink': '#FFB6C1',
- 'lightsalmon': '#FFA07A',
- 'lightseagreen': '#20B2AA',
- 'lightskyblue': '#87CEFA',
- 'lightslategray': '#778899',
- 'lightslategrey': '#778899',
- 'lightsteelblue': '#B0C4DE',
- 'lightyellow': '#FFFFE0',
- 'lime': '#00FF00',
- 'limegreen': '#32CD32',
- 'linen': '#FAF0E6',
- 'magenta': '#FF00FF',
- 'maroon': '#800000',
- 'mediumaquamarine': '#66CDAA',
- 'mediumblue': '#0000CD',
- 'mediumorchid': '#BA55D3',
- 'mediumpurple': '#9370DB',
- 'mediumseagreen': '#3CB371',
- 'mediumslateblue': '#7B68EE',
- 'mediumspringgreen': '#00FA9A',
- 'mediumturquoise': '#48D1CC',
- 'mediumvioletred': '#C71585',
- 'midnightblue': '#191970',
- 'mintcream': '#F5FFFA',
- 'mistyrose': '#FFE4E1',
- 'moccasin': '#FFE4B5',
- 'navajowhite': '#FFDEAD',
- 'navy': '#000080',
- 'oldlace': '#FDF5E6',
- 'olive': '#808000',
- 'olivedrab': '#6B8E23',
- 'orange': '#FFA500',
- 'orangered': '#FF4500',
- 'orchid': '#DA70D6',
- 'palegoldenrod': '#EEE8AA',
- 'palegreen': '#98FB98',
- 'paleturquoise': '#AFEEEE',
- 'palevioletred': '#DB7093',
- 'papayawhip': '#FFEFD5',
- 'peachpuff': '#FFDAB9',
- 'peru': '#CD853F',
- 'pink': '#FFC0CB',
- 'plum': '#DDA0DD',
- 'powderblue': '#B0E0E6',
- 'purple': '#800080',
- 'rebeccapurple': '#663399',
- 'red': '#FF0000',
- 'rosybrown': '#BC8F8F',
- 'royalblue': '#4169E1',
- 'saddlebrown': '#8B4513',
- 'salmon': '#FA8072',
- 'sandybrown': '#F4A460',
- 'seagreen': '#2E8B57',
- 'seashell': '#FFF5EE',
- 'sienna': '#A0522D',
- 'silver': '#C0C0C0',
- 'skyblue': '#87CEEB',
- 'slateblue': '#6A5ACD',
- 'slategray': '#708090',
- 'slategrey': '#708090',
- 'snow': '#FFFAFA',
- 'springgreen': '#00FF7F',
- 'steelblue': '#4682B4',
- 'tan': '#D2B48C',
- 'teal': '#008080',
- 'thistle': '#D8BFD8',
- 'tomato': '#FF6347',
- 'turquoise': '#40E0D0',
- 'violet': '#EE82EE',
- 'wheat': '#F5DEB3',
- 'white': '#FFFFFF',
- 'whitesmoke': '#F5F5F5',
- 'yellow': '#FFFF00',
- 'yellowgreen': '#9ACD32'}
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_constrained_layout.py b/server/venv/lib/python3.7/site-packages/matplotlib/_constrained_layout.py
deleted file mode 100644
index a2a70fd..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_constrained_layout.py
+++ /dev/null
@@ -1,744 +0,0 @@
-"""
-This module provides the routine to adjust subplot layouts so that there are
-no overlapping axes or axes decorations. All axes decorations are dealt with
-(labels, ticks, titles, ticklabels) and some dependent artists are also dealt
-with (colorbar, suptitle, legend).
-
-Layout is done via :meth:`~matplotlib.gridspec`, with one constraint per
-gridspec, so it is possible to have overlapping axes if the gridspecs
-overlap (i.e. using :meth:`~matplotlib.gridspec.GridSpecFromSubplotSpec`).
-Axes placed using ``figure.subplots()`` or ``figure.add_subplots()`` will
-participate in the layout. Axes manually placed via ``figure.add_axes()``
-will not.
-
-See Tutorial: :doc:`/tutorials/intermediate/constrainedlayout_guide`
-
-"""
-
-# Development Notes:
-
-# What gets a layoutbox:
-# - figure
-# - gridspec
-# - subplotspec
-# EITHER:
-# - axes + pos for the axes (i.e. the total area taken by axis and
-# the actual "position" argument that needs to be sent to
-# ax.set_position.)
-# - The axes layout box will also encompass the legend, and that is
-# how legends get included (axes legends, not figure legends)
-# - colorbars are siblings of the axes if they are single-axes
-# colorbars
-# OR:
-# - a gridspec can be inside a subplotspec.
-# - subplotspec
-# EITHER:
-# - axes...
-# OR:
-# - gridspec... with arbitrary nesting...
-# - colorbars are siblings of the subplotspecs if they are multi-axes
-# colorbars.
-# - suptitle:
-# - right now suptitles are just stacked atop everything else in figure.
-# Could imagine suptitles being gridspec suptitles, but not implemented
-#
-# Todo: AnchoredOffsetbox connected to gridspecs or axes. This would
-# be more general way to add extra-axes annotations.
-
-import logging
-
-import numpy as np
-
-import matplotlib.cbook as cbook
-import matplotlib._layoutbox as layoutbox
-
-_log = logging.getLogger(__name__)
-
-
-def _in_same_column(colnum0min, colnum0max, colnumCmin, colnumCmax):
- return (colnumCmin <= colnum0min <= colnumCmax
- or colnumCmin <= colnum0max <= colnumCmax)
-
-
-def _in_same_row(rownum0min, rownum0max, rownumCmin, rownumCmax):
- return (rownumCmin <= rownum0min <= rownumCmax
- or rownumCmin <= rownum0max <= rownumCmax)
-
-
-def _axes_all_finite_sized(fig):
- """
- helper function to make sure all axes in the
- figure have a finite width and height. If not, return False
- """
- for ax in fig.axes:
- if ax._layoutbox is not None:
- newpos = ax._poslayoutbox.get_rect()
- if newpos[2] <= 0 or newpos[3] <= 0:
- return False
- return True
-
-
-######################################################
-def do_constrained_layout(fig, renderer, h_pad, w_pad,
- hspace=None, wspace=None):
-
- """
- Do the constrained_layout. Called at draw time in
- ``figure.constrained_layout()``
-
- Parameters
- ----------
-
-
- fig : Figure
- is the ``figure`` instance to do the layout in.
-
- renderer : Renderer
- the renderer to use.
-
- h_pad, w_pad : float
- are in figure-normalized units, and are a padding around the axes
- elements.
-
- hspace, wspace : float
- are in fractions of the subplot sizes.
-
- """
-
- ''' Steps:
-
- 1. get a list of unique gridspecs in this figure. Each gridspec will be
- constrained separately.
- 2. Check for gaps in the gridspecs. i.e. if not every axes slot in the
- gridspec has been filled. If empty, add a ghost axis that is made so
- that it cannot be seen (though visible=True). This is needed to make
- a blank spot in the layout.
- 3. Compare the tight_bbox of each axes to its `position`, and assume that
- the difference is the space needed by the elements around the edge of
- the axes (decorations) like the title, ticklabels, x-labels, etc. This
- can include legends who overspill the axes boundaries.
- 4. Constrain gridspec elements to line up:
- a) if colnum0 != colnumC, the two subplotspecs are stacked next to
- each other, with the appropriate order.
- b) if colnum0 == colnumC, line up the left or right side of the
- _poslayoutbox (depending if it is the min or max num that is equal).
- c) do the same for rows...
- 5. The above doesn't constrain relative sizes of the _poslayoutboxes at
- all, and indeed zero-size is a solution that the solver often finds more
- convenient than expanding the sizes. Right now the solution is to compare
- subplotspec sizes (i.e. drowsC and drows0) and constrain the larger
- _poslayoutbox to be larger than the ratio of the sizes. i.e. if drows0 >
- drowsC, then ax._poslayoutbox > axc._poslayoutbox * drowsC / drows0. This
- works fine *if* the decorations are similar between the axes. If the
- larger subplotspec has much larger axes decorations, then the constraint
- above is incorrect.
-
- We need the greater than in the above, in general, rather than an equals
- sign. Consider the case of the left column having 2 rows, and the right
- column having 1 row. We want the top and bottom of the _poslayoutboxes to
- line up. So that means if there are decorations on the left column axes
- they will be smaller than half as large as the right hand axis.
-
- This can break down if the decoration size for the right hand axis (the
- margins) is very large. There must be a math way to check for this case.
-
- '''
-
- invTransFig = fig.transFigure.inverted().transform_bbox
-
- # list of unique gridspecs that contain child axes:
- gss = set()
- for ax in fig.axes:
- if hasattr(ax, 'get_subplotspec'):
- gs = ax.get_subplotspec().get_gridspec()
- if gs._layoutbox is not None:
- gss.add(gs)
- if len(gss) == 0:
- cbook._warn_external('There are no gridspecs with layoutboxes. '
- 'Possibly did not call parent GridSpec with the'
- ' figure= keyword')
-
- if fig._layoutbox.constrained_layout_called < 1:
- for gs in gss:
- # fill in any empty gridspec slots w/ ghost axes...
- _make_ghost_gridspec_slots(fig, gs)
-
- for nnn in range(2):
- # do the algorithm twice. This has to be done because decorators
- # change size after the first re-position (i.e. x/yticklabels get
- # larger/smaller). This second reposition tends to be much milder,
- # so doing twice makes things work OK.
- for ax in fig.axes:
- _log.debug(ax._layoutbox)
- if ax._layoutbox is not None:
- # make margins for each layout box based on the size of
- # the decorators.
- _make_layout_margins(ax, renderer, h_pad, w_pad)
-
- # do layout for suptitle.
- suptitle = fig._suptitle
- do_suptitle = (suptitle is not None and
- suptitle._layoutbox is not None and
- suptitle.get_in_layout())
- if do_suptitle:
- bbox = invTransFig(
- suptitle.get_window_extent(renderer=renderer))
- height = bbox.y1 - bbox.y0
- if np.isfinite(height):
- # reserve at top of figure include an h_pad above and below
- suptitle._layoutbox.edit_height(height + h_pad * 2)
-
- # OK, the above lines up ax._poslayoutbox with ax._layoutbox
- # now we need to
- # 1) arrange the subplotspecs. We do it at this level because
- # the subplotspecs are meant to contain other dependent axes
- # like colorbars or legends.
- # 2) line up the right and left side of the ax._poslayoutbox
- # that have the same subplotspec maxes.
-
- if fig._layoutbox.constrained_layout_called < 1:
- # arrange the subplotspecs... This is all done relative to each
- # other. Some subplotspecs contain axes, and others contain
- # gridspecs the ones that contain gridspecs are a set proportion
- # of their parent gridspec. The ones that contain axes are
- # not so constrained.
- figlb = fig._layoutbox
- for child in figlb.children:
- if child._is_gridspec_layoutbox():
- # This routine makes all the subplot spec containers
- # have the correct arrangement. It just stacks the
- # subplot layoutboxes in the correct order...
- _arrange_subplotspecs(child, hspace=hspace, wspace=wspace)
-
- for gs in gss:
- _align_spines(fig, gs)
-
- fig._layoutbox.constrained_layout_called += 1
- fig._layoutbox.update_variables()
-
- # check if any axes collapsed to zero. If not, don't change positions:
- if _axes_all_finite_sized(fig):
- # Now set the position of the axes...
- for ax in fig.axes:
- if ax._layoutbox is not None:
- newpos = ax._poslayoutbox.get_rect()
- # Now set the new position.
- # ax.set_position will zero out the layout for
- # this axis, allowing users to hard-code the position,
- # so this does the same w/o zeroing layout.
- ax._set_position(newpos, which='original')
- if do_suptitle:
- newpos = suptitle._layoutbox.get_rect()
- suptitle.set_y(1.0 - h_pad)
- else:
- if suptitle is not None and suptitle._layoutbox is not None:
- suptitle._layoutbox.edit_height(0)
- else:
- cbook._warn_external('constrained_layout not applied. At least '
- 'one axes collapsed to zero width or height.')
-
-
-def _make_ghost_gridspec_slots(fig, gs):
- """
- Check for unoccupied gridspec slots and make ghost axes for these
- slots... Do for each gs separately. This is a pretty big kludge
- but shouldn't have too much ill effect. The worst is that
- someone querying the figure will wonder why there are more
- axes than they thought.
- """
- nrows, ncols = gs.get_geometry()
- hassubplotspec = np.zeros(nrows * ncols, dtype=bool)
- axs = []
- for ax in fig.axes:
- if (hasattr(ax, 'get_subplotspec')
- and ax._layoutbox is not None
- and ax.get_subplotspec().get_gridspec() == gs):
- axs += [ax]
- for ax in axs:
- ss0 = ax.get_subplotspec()
- if ss0.num2 is None:
- ss0.num2 = ss0.num1
- hassubplotspec[ss0.num1:(ss0.num2 + 1)] = True
- for nn, hss in enumerate(hassubplotspec):
- if not hss:
- # this gridspec slot doesn't have an axis so we
- # make a "ghost".
- ax = fig.add_subplot(gs[nn])
- ax.set_frame_on(False)
- ax.set_xticks([])
- ax.set_yticks([])
- ax.set_facecolor((1, 0, 0, 0))
-
-
-def _make_layout_margins(ax, renderer, h_pad, w_pad):
- """
- For each axes, make a margin between the *pos* layoutbox and the
- *axes* layoutbox be a minimum size that can accommodate the
- decorations on the axis.
- """
- fig = ax.figure
- invTransFig = fig.transFigure.inverted().transform_bbox
- pos = ax.get_position(original=True)
- tightbbox = ax.get_tightbbox(renderer=renderer)
- bbox = invTransFig(tightbbox)
- # this can go wrong:
- if not (np.isfinite(bbox.width) and np.isfinite(bbox.height)):
- # just abort, this is likely a bad set of co-ordinates that
- # is transitory...
- return
- # use stored h_pad if it exists
- h_padt = ax._poslayoutbox.h_pad
- if h_padt is None:
- h_padt = h_pad
- w_padt = ax._poslayoutbox.w_pad
- if w_padt is None:
- w_padt = w_pad
- ax._poslayoutbox.edit_left_margin_min(-bbox.x0 +
- pos.x0 + w_padt)
- ax._poslayoutbox.edit_right_margin_min(bbox.x1 -
- pos.x1 + w_padt)
- ax._poslayoutbox.edit_bottom_margin_min(
- -bbox.y0 + pos.y0 + h_padt)
- ax._poslayoutbox.edit_top_margin_min(bbox.y1-pos.y1+h_padt)
- _log.debug('left %f', (-bbox.x0 + pos.x0 + w_pad))
- _log.debug('right %f', (bbox.x1 - pos.x1 + w_pad))
- _log.debug('bottom %f', (-bbox.y0 + pos.y0 + h_padt))
- _log.debug('bbox.y0 %f', bbox.y0)
- _log.debug('pos.y0 %f', pos.y0)
- # Sometimes its possible for the solver to collapse
- # rather than expand axes, so they all have zero height
- # or width. This stops that... It *should* have been
- # taken into account w/ pref_width...
- if fig._layoutbox.constrained_layout_called < 1:
- ax._poslayoutbox.constrain_height_min(20, strength='weak')
- ax._poslayoutbox.constrain_width_min(20, strength='weak')
- ax._layoutbox.constrain_height_min(20, strength='weak')
- ax._layoutbox.constrain_width_min(20, strength='weak')
- ax._poslayoutbox.constrain_top_margin(0, strength='weak')
- ax._poslayoutbox.constrain_bottom_margin(0,
- strength='weak')
- ax._poslayoutbox.constrain_right_margin(0, strength='weak')
- ax._poslayoutbox.constrain_left_margin(0, strength='weak')
-
-
-def _align_spines(fig, gs):
- """
- - Align right/left and bottom/top spines of appropriate subplots.
- - Compare size of subplotspec including height and width ratios
- and make sure that the axes spines are at least as large
- as they should be.
- """
- # for each gridspec...
- nrows, ncols = gs.get_geometry()
- width_ratios = gs.get_width_ratios()
- height_ratios = gs.get_height_ratios()
- if width_ratios is None:
- width_ratios = np.ones(ncols)
- if height_ratios is None:
- height_ratios = np.ones(nrows)
-
- # get axes in this gridspec....
- axs = []
- for ax in fig.axes:
- if (hasattr(ax, 'get_subplotspec')
- and ax._layoutbox is not None):
- if ax.get_subplotspec().get_gridspec() == gs:
- axs += [ax]
- rownummin = np.zeros(len(axs), dtype=np.int8)
- rownummax = np.zeros(len(axs), dtype=np.int8)
- colnummin = np.zeros(len(axs), dtype=np.int8)
- colnummax = np.zeros(len(axs), dtype=np.int8)
- width = np.zeros(len(axs))
- height = np.zeros(len(axs))
-
- for n, ax in enumerate(axs):
- ss0 = ax.get_subplotspec()
- if ss0.num2 is None:
- ss0.num2 = ss0.num1
- rownummin[n], colnummin[n] = divmod(ss0.num1, ncols)
- rownummax[n], colnummax[n] = divmod(ss0.num2, ncols)
- width[n] = np.sum(
- width_ratios[colnummin[n]:(colnummax[n] + 1)])
- height[n] = np.sum(
- height_ratios[rownummin[n]:(rownummax[n] + 1)])
-
- for nn, ax in enumerate(axs[:-1]):
- # now compare ax to all the axs:
- #
- # If the subplotspecs have the same colnumXmax, then line
- # up their right sides. If they have the same min, then
- # line up their left sides (and vertical equivalents).
- rownum0min, colnum0min = rownummin[nn], colnummin[nn]
- rownum0max, colnum0max = rownummax[nn], colnummax[nn]
- width0, height0 = width[nn], height[nn]
- alignleft = False
- alignright = False
- alignbot = False
- aligntop = False
- alignheight = False
- alignwidth = False
- for mm in range(nn+1, len(axs)):
- axc = axs[mm]
- rownumCmin, colnumCmin = rownummin[mm], colnummin[mm]
- rownumCmax, colnumCmax = rownummax[mm], colnummax[mm]
- widthC, heightC = width[mm], height[mm]
- # Horizontally align axes spines if they have the
- # same min or max:
- if not alignleft and colnum0min == colnumCmin:
- # we want the _poslayoutboxes to line up on left
- # side of the axes spines...
- layoutbox.align([ax._poslayoutbox,
- axc._poslayoutbox],
- 'left')
- alignleft = True
-
- if not alignright and colnum0max == colnumCmax:
- # line up right sides of _poslayoutbox
- layoutbox.align([ax._poslayoutbox,
- axc._poslayoutbox],
- 'right')
- alignright = True
- # Vertically align axes spines if they have the
- # same min or max:
- if not aligntop and rownum0min == rownumCmin:
- # line up top of _poslayoutbox
- _log.debug('rownum0min == rownumCmin')
- layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
- 'top')
- aligntop = True
-
- if not alignbot and rownum0max == rownumCmax:
- # line up bottom of _poslayoutbox
- _log.debug('rownum0max == rownumCmax')
- layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
- 'bottom')
- alignbot = True
- ###########
- # Now we make the widths and heights of position boxes
- # similar. (i.e the spine locations)
- # This allows vertically stacked subplots to have
- # different sizes if they occupy different amounts
- # of the gridspec: i.e.
- # gs = gridspec.GridSpec(3,1)
- # ax1 = gs[0,:]
- # ax2 = gs[1:,:]
- # then drows0 = 1, and drowsC = 2, and ax2
- # should be at least twice as large as ax1.
- # But it can be more than twice as large because
- # it needs less room for the labeling.
- #
- # For height, this only needs to be done if the
- # subplots share a column. For width if they
- # share a row.
-
- drowsC = (rownumCmax - rownumCmin + 1)
- drows0 = (rownum0max - rownum0min + 1)
- dcolsC = (colnumCmax - colnumCmin + 1)
- dcols0 = (colnum0max - colnum0min + 1)
-
- if not alignheight and drows0 == drowsC:
- ax._poslayoutbox.constrain_height(
- axc._poslayoutbox.height * height0 / heightC)
- alignheight = True
- elif _in_same_column(colnum0min, colnum0max,
- colnumCmin, colnumCmax):
- if height0 > heightC:
- ax._poslayoutbox.constrain_height_min(
- axc._poslayoutbox.height * height0 / heightC)
- # these constraints stop the smaller axes from
- # being allowed to go to zero height...
- axc._poslayoutbox.constrain_height_min(
- ax._poslayoutbox.height * heightC /
- (height0*1.8))
- elif height0 < heightC:
- axc._poslayoutbox.constrain_height_min(
- ax._poslayoutbox.height * heightC / height0)
- ax._poslayoutbox.constrain_height_min(
- ax._poslayoutbox.height * height0 /
- (heightC*1.8))
- # widths...
- if not alignwidth and dcols0 == dcolsC:
- ax._poslayoutbox.constrain_width(
- axc._poslayoutbox.width * width0 / widthC)
- alignwidth = True
- elif _in_same_row(rownum0min, rownum0max,
- rownumCmin, rownumCmax):
- if width0 > widthC:
- ax._poslayoutbox.constrain_width_min(
- axc._poslayoutbox.width * width0 / widthC)
- axc._poslayoutbox.constrain_width_min(
- ax._poslayoutbox.width * widthC /
- (width0*1.8))
- elif width0 < widthC:
- axc._poslayoutbox.constrain_width_min(
- ax._poslayoutbox.width * widthC / width0)
- ax._poslayoutbox.constrain_width_min(
- axc._poslayoutbox.width * width0 /
- (widthC*1.8))
-
-
-def _arrange_subplotspecs(gs, hspace=0, wspace=0):
- """
- arrange the subplotspec children of this gridspec, and then recursively
- do the same of any gridspec children of those gridspecs...
- """
- sschildren = []
- for child in gs.children:
- if child._is_subplotspec_layoutbox():
- for child2 in child.children:
- # check for gridspec children...
- if child2._is_gridspec_layoutbox():
- _arrange_subplotspecs(child2, hspace=hspace, wspace=wspace)
- sschildren += [child]
- # now arrange the subplots...
- for child0 in sschildren:
- ss0 = child0.artist
- nrows, ncols = ss0.get_gridspec().get_geometry()
- if ss0.num2 is None:
- ss0.num2 = ss0.num1
- rowNum0min, colNum0min = divmod(ss0.num1, ncols)
- rowNum0max, colNum0max = divmod(ss0.num2, ncols)
- sschildren = sschildren[1:]
- for childc in sschildren:
- ssc = childc.artist
- rowNumCmin, colNumCmin = divmod(ssc.num1, ncols)
- if ssc.num2 is None:
- ssc.num2 = ssc.num1
- rowNumCmax, colNumCmax = divmod(ssc.num2, ncols)
- # OK, this tells us the relative layout of ax
- # with axc
- thepad = wspace / ncols
- if colNum0max < colNumCmin:
- layoutbox.hstack([ss0._layoutbox, ssc._layoutbox],
- padding=thepad)
- if colNumCmax < colNum0min:
- layoutbox.hstack([ssc._layoutbox, ss0._layoutbox],
- padding=thepad)
-
- ####
- # vertical alignment
- thepad = hspace / nrows
- if rowNum0max < rowNumCmin:
- layoutbox.vstack([ss0._layoutbox,
- ssc._layoutbox],
- padding=thepad)
- if rowNumCmax < rowNum0min:
- layoutbox.vstack([ssc._layoutbox,
- ss0._layoutbox],
- padding=thepad)
-
-
-def layoutcolorbarsingle(ax, cax, shrink, aspect, location, pad=0.05):
- """
- Do the layout for a colorbar, to not overly pollute colorbar.py
-
- `pad` is in fraction of the original axis size.
- """
- axlb = ax._layoutbox
- axpos = ax._poslayoutbox
- axsslb = ax.get_subplotspec()._layoutbox
- lb = layoutbox.LayoutBox(
- parent=axsslb,
- name=axsslb.name + '.cbar',
- artist=cax)
-
- if location in ('left', 'right'):
- lbpos = layoutbox.LayoutBox(
- parent=lb,
- name=lb.name + '.pos',
- tightwidth=False,
- pos=True,
- subplot=False,
- artist=cax)
-
- if location == 'right':
- # arrange to right of parent axis
- layoutbox.hstack([axlb, lb], padding=pad * axlb.width,
- strength='strong')
- else:
- layoutbox.hstack([lb, axlb], padding=pad * axlb.width)
- # constrain the height and center...
- layoutbox.match_heights([axpos, lbpos], [1, shrink])
- layoutbox.align([axpos, lbpos], 'v_center')
- # set the width of the pos box
- lbpos.constrain_width(shrink * axpos.height * (1/aspect),
- strength='strong')
- elif location in ('bottom', 'top'):
- lbpos = layoutbox.LayoutBox(
- parent=lb,
- name=lb.name + '.pos',
- tightheight=True,
- pos=True,
- subplot=False,
- artist=cax)
-
- if location == 'bottom':
- layoutbox.vstack([axlb, lb], padding=pad * axlb.height)
- else:
- layoutbox.vstack([lb, axlb], padding=pad * axlb.height)
- # constrain the height and center...
- layoutbox.match_widths([axpos, lbpos],
- [1, shrink], strength='strong')
- layoutbox.align([axpos, lbpos], 'h_center')
- # set the height of the pos box
- lbpos.constrain_height(axpos.width * aspect * shrink,
- strength='medium')
-
- return lb, lbpos
-
-
-def _getmaxminrowcolumn(axs):
- # helper to get the min/max rows and columns of a list of axes.
- maxrow = -100000
- minrow = 1000000
- maxax = None
- minax = None
- maxcol = -100000
- mincol = 1000000
- maxax_col = None
- minax_col = None
-
- for ax in axs:
- subspec = ax.get_subplotspec()
- nrows, ncols, row_start, row_stop, col_start, col_stop = \
- subspec.get_rows_columns()
- if row_stop > maxrow:
- maxrow = row_stop
- maxax = ax
- if row_start < minrow:
- minrow = row_start
- minax = ax
- if col_stop > maxcol:
- maxcol = col_stop
- maxax_col = ax
- if col_start < mincol:
- mincol = col_start
- minax_col = ax
- return (minrow, maxrow, minax, maxax, mincol, maxcol, minax_col, maxax_col)
-
-
-def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05):
- """
- Do the layout for a colorbar, to not overly pollute colorbar.py
-
- `pad` is in fraction of the original axis size.
- """
-
- gs = parents[0].get_subplotspec().get_gridspec()
- # parent layout box....
- gslb = gs._layoutbox
-
- lb = layoutbox.LayoutBox(parent=gslb.parent,
- name=gslb.parent.name + '.cbar',
- artist=cax)
- # figure out the row and column extent of the parents.
- (minrow, maxrow, minax_row, maxax_row,
- mincol, maxcol, minax_col, maxax_col) = _getmaxminrowcolumn(parents)
-
- if location in ('left', 'right'):
- lbpos = layoutbox.LayoutBox(
- parent=lb,
- name=lb.name + '.pos',
- tightwidth=False,
- pos=True,
- subplot=False,
- artist=cax)
- for ax in parents:
- if location == 'right':
- order = [ax._layoutbox, lb]
- else:
- order = [lb, ax._layoutbox]
- layoutbox.hstack(order, padding=pad * gslb.width,
- strength='strong')
- # constrain the height and center...
- # This isn't quite right. We'd like the colorbar
- # pos to line up w/ the axes poss, not the size of the
- # gs.
-
- # Horizontal Layout: need to check all the axes in this gridspec
- for ch in gslb.children:
- subspec = ch.artist
- nrows, ncols, row_start, row_stop, col_start, col_stop = \
- subspec.get_rows_columns()
- if location == 'right':
- if col_stop <= maxcol:
- order = [subspec._layoutbox, lb]
- # arrange to right of the parents
- if col_start > maxcol:
- order = [lb, subspec._layoutbox]
- elif location == 'left':
- if col_start >= mincol:
- order = [lb, subspec._layoutbox]
- if col_stop < mincol:
- order = [subspec._layoutbox, lb]
- layoutbox.hstack(order, padding=pad * gslb.width,
- strength='strong')
-
- # Vertical layout:
- maxposlb = minax_row._poslayoutbox
- minposlb = maxax_row._poslayoutbox
- # now we want the height of the colorbar pos to be
- # set by the top and bottom of the min/max axes...
- # bottom top
- # b t
- # h = (top-bottom)*shrink
- # b = bottom + (top-bottom - h) / 2.
- lbpos.constrain_height(
- (maxposlb.top - minposlb.bottom) *
- shrink, strength='strong')
- lbpos.constrain_bottom(
- (maxposlb.top - minposlb.bottom) *
- (1 - shrink)/2 + minposlb.bottom,
- strength='strong')
-
- # set the width of the pos box
- lbpos.constrain_width(lbpos.height * (shrink / aspect),
- strength='strong')
- elif location in ('bottom', 'top'):
- lbpos = layoutbox.LayoutBox(
- parent=lb,
- name=lb.name + '.pos',
- tightheight=True,
- pos=True,
- subplot=False,
- artist=cax)
-
- for ax in parents:
- if location == 'bottom':
- order = [ax._layoutbox, lb]
- else:
- order = [lb, ax._layoutbox]
- layoutbox.vstack(order, padding=pad * gslb.width,
- strength='strong')
-
- # Vertical Layout: need to check all the axes in this gridspec
- for ch in gslb.children:
- subspec = ch.artist
- nrows, ncols, row_start, row_stop, col_start, col_stop = \
- subspec.get_rows_columns()
- if location == 'bottom':
- if row_stop <= minrow:
- order = [subspec._layoutbox, lb]
- if row_start > maxrow:
- order = [lb, subspec._layoutbox]
- elif location == 'top':
- if row_stop < minrow:
- order = [subspec._layoutbox, lb]
- if row_start >= maxrow:
- order = [lb, subspec._layoutbox]
- layoutbox.vstack(order, padding=pad * gslb.width,
- strength='strong')
-
- # Do horizontal layout...
- maxposlb = maxax_col._poslayoutbox
- minposlb = minax_col._poslayoutbox
- lbpos.constrain_width((maxposlb.right - minposlb.left) *
- shrink)
- lbpos.constrain_left(
- (maxposlb.right - minposlb.left) *
- (1-shrink)/2 + minposlb.left)
- # set the height of the pos box
- lbpos.constrain_height(lbpos.width * shrink * aspect,
- strength='medium')
-
- return lb, lbpos
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_contour.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_contour.cpython-37m-darwin.so
deleted file mode 100644
index 08c22ae..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_contour.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_image.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_image.cpython-37m-darwin.so
deleted file mode 100644
index 5ab4006..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_image.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_layoutbox.py b/server/venv/lib/python3.7/site-packages/matplotlib/_layoutbox.py
deleted file mode 100644
index 4fff13e..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_layoutbox.py
+++ /dev/null
@@ -1,732 +0,0 @@
-"""
-
-Conventions:
-
-"constrain_x" means to constrain the variable with either
-another kiwisolver variable, or a float. i.e. `constrain_width(0.2)`
-will set a constraint that the width has to be 0.2 and this constraint is
-permanent - i.e. it will not be removed if it becomes obsolete.
-
-"edit_x" means to set x to a value (just a float), and that this value can
-change. So `edit_width(0.2)` will set width to be 0.2, but `edit_width(0.3)`
-will allow it to change to 0.3 later. Note that these values are still just
-"suggestions" in `kiwisolver` parlance, and could be over-ridden by
-other constrains.
-
-"""
-
-import itertools
-import kiwisolver as kiwi
-import logging
-import numpy as np
-
-
-_log = logging.getLogger(__name__)
-
-
-# renderers can be complicated
-def get_renderer(fig):
- if fig._cachedRenderer:
- renderer = fig._cachedRenderer
- else:
- canvas = fig.canvas
- if canvas and hasattr(canvas, "get_renderer"):
- renderer = canvas.get_renderer()
- else:
- # not sure if this can happen
- # seems to with PDF...
- _log.info("constrained_layout : falling back to Agg renderer")
- from matplotlib.backends.backend_agg import FigureCanvasAgg
- canvas = FigureCanvasAgg(fig)
- renderer = canvas.get_renderer()
-
- return renderer
-
-
-class LayoutBox(object):
- """
- Basic rectangle representation using kiwi solver variables
- """
-
- def __init__(self, parent=None, name='', tightwidth=False,
- tightheight=False, artist=None,
- lower_left=(0, 0), upper_right=(1, 1), pos=False,
- subplot=False, h_pad=None, w_pad=None):
- Variable = kiwi.Variable
- self.parent = parent
- self.name = name
- sn = self.name + '_'
- if parent is None:
- self.solver = kiwi.Solver()
- self.constrained_layout_called = 0
- else:
- self.solver = parent.solver
- self.constrained_layout_called = None
- # parent wants to know about this child!
- parent.add_child(self)
- # keep track of artist associated w/ this layout. Can be none
- self.artist = artist
- # keep track if this box is supposed to be a pos that is constrained
- # by the parent.
- self.pos = pos
- # keep track of whether we need to match this subplot up with others.
- self.subplot = subplot
-
- # we need the str below for Py 2 which complains the string is unicode
- self.top = Variable(str(sn + 'top'))
- self.bottom = Variable(str(sn + 'bottom'))
- self.left = Variable(str(sn + 'left'))
- self.right = Variable(str(sn + 'right'))
-
- self.width = Variable(str(sn + 'width'))
- self.height = Variable(str(sn + 'height'))
- self.h_center = Variable(str(sn + 'h_center'))
- self.v_center = Variable(str(sn + 'v_center'))
-
- self.min_width = Variable(str(sn + 'min_width'))
- self.min_height = Variable(str(sn + 'min_height'))
- self.pref_width = Variable(str(sn + 'pref_width'))
- self.pref_height = Variable(str(sn + 'pref_height'))
- # margins are only used for axes-position layout boxes. maybe should
- # be a separate subclass:
- self.left_margin = Variable(str(sn + 'left_margin'))
- self.right_margin = Variable(str(sn + 'right_margin'))
- self.bottom_margin = Variable(str(sn + 'bottom_margin'))
- self.top_margin = Variable(str(sn + 'top_margin'))
- # mins
- self.left_margin_min = Variable(str(sn + 'left_margin_min'))
- self.right_margin_min = Variable(str(sn + 'right_margin_min'))
- self.bottom_margin_min = Variable(str(sn + 'bottom_margin_min'))
- self.top_margin_min = Variable(str(sn + 'top_margin_min'))
-
- right, top = upper_right
- left, bottom = lower_left
- self.tightheight = tightheight
- self.tightwidth = tightwidth
- self.add_constraints()
- self.children = []
- self.subplotspec = None
- if self.pos:
- self.constrain_margins()
- self.h_pad = h_pad
- self.w_pad = w_pad
-
- def constrain_margins(self):
- """
- Only do this for pos. This sets a variable distance
- margin between the position of the axes and the outer edge of
- the axes.
-
- Margins are variable because they change with the figure size.
-
- Margin minimums are set to make room for axes decorations. However,
- the margins can be larger if we are mathicng the position size to
- other axes.
- """
- sol = self.solver
-
- # left
- if not sol.hasEditVariable(self.left_margin_min):
- sol.addEditVariable(self.left_margin_min, 'strong')
- sol.suggestValue(self.left_margin_min, 0.0001)
- c = (self.left_margin == self.left - self.parent.left)
- self.solver.addConstraint(c | 'required')
- c = (self.left_margin >= self.left_margin_min)
- self.solver.addConstraint(c | 'strong')
-
- # right
- if not sol.hasEditVariable(self.right_margin_min):
- sol.addEditVariable(self.right_margin_min, 'strong')
- sol.suggestValue(self.right_margin_min, 0.0001)
- c = (self.right_margin == self.parent.right - self.right)
- self.solver.addConstraint(c | 'required')
- c = (self.right_margin >= self.right_margin_min)
- self.solver.addConstraint(c | 'required')
- # bottom
- if not sol.hasEditVariable(self.bottom_margin_min):
- sol.addEditVariable(self.bottom_margin_min, 'strong')
- sol.suggestValue(self.bottom_margin_min, 0.0001)
- c = (self.bottom_margin == self.bottom - self.parent.bottom)
- self.solver.addConstraint(c | 'required')
- c = (self.bottom_margin >= self.bottom_margin_min)
- self.solver.addConstraint(c | 'required')
- # top
- if not sol.hasEditVariable(self.top_margin_min):
- sol.addEditVariable(self.top_margin_min, 'strong')
- sol.suggestValue(self.top_margin_min, 0.0001)
- c = (self.top_margin == self.parent.top - self.top)
- self.solver.addConstraint(c | 'required')
- c = (self.top_margin >= self.top_margin_min)
- self.solver.addConstraint(c | 'required')
-
- def add_child(self, child):
- self.children += [child]
-
- def remove_child(self, child):
- try:
- self.children.remove(child)
- except ValueError:
- _log.info("Tried to remove child that doesn't belong to parent")
-
- def add_constraints(self):
- sol = self.solver
- # never let width and height go negative.
- for i in [self.min_width, self.min_height]:
- sol.addEditVariable(i, 1e9)
- sol.suggestValue(i, 0.0)
- # define relation ships between things thing width and right and left
- self.hard_constraints()
- # self.soft_constraints()
- if self.parent:
- self.parent_constrain()
- # sol.updateVariables()
-
- def parent_constrain(self):
- parent = self.parent
- hc = [self.left >= parent.left,
- self.bottom >= parent.bottom,
- self.top <= parent.top,
- self.right <= parent.right]
- for c in hc:
- self.solver.addConstraint(c | 'required')
-
- def hard_constraints(self):
- hc = [self.width == self.right - self.left,
- self.height == self.top - self.bottom,
- self.h_center == (self.left + self.right) * 0.5,
- self.v_center == (self.top + self.bottom) * 0.5,
- self.width >= self.min_width,
- self.height >= self.min_height]
- for c in hc:
- self.solver.addConstraint(c | 'required')
-
- def soft_constraints(self):
- sol = self.solver
- if self.tightwidth:
- suggest = 0.
- else:
- suggest = 20.
- c = (self.pref_width == suggest)
- for i in c:
- sol.addConstraint(i | 'required')
- if self.tightheight:
- suggest = 0.
- else:
- suggest = 20.
- c = (self.pref_height == suggest)
- for i in c:
- sol.addConstraint(i | 'required')
-
- c = [(self.width >= suggest),
- (self.height >= suggest)]
- for i in c:
- sol.addConstraint(i | 150000)
-
- def set_parent(self, parent):
- ''' replace the parent of this with the new parent
- '''
- self.parent = parent
- self.parent_constrain()
-
- def constrain_geometry(self, left, bottom, right, top, strength='strong'):
- hc = [self.left == left,
- self.right == right,
- self.bottom == bottom,
- self.top == top]
- for c in hc:
- self.solver.addConstraint(c | strength)
- # self.solver.updateVariables()
-
- def constrain_same(self, other, strength='strong'):
- """
- Make the layoutbox have same position as other layoutbox
- """
- hc = [self.left == other.left,
- self.right == other.right,
- self.bottom == other.bottom,
- self.top == other.top]
- for c in hc:
- self.solver.addConstraint(c | strength)
-
- def constrain_left_margin(self, margin, strength='strong'):
- c = (self.left == self.parent.left + margin)
- self.solver.addConstraint(c | strength)
-
- def edit_left_margin_min(self, margin):
- self.solver.suggestValue(self.left_margin_min, margin)
-
- def constrain_right_margin(self, margin, strength='strong'):
- c = (self.right == self.parent.right - margin)
- self.solver.addConstraint(c | strength)
-
- def edit_right_margin_min(self, margin):
- self.solver.suggestValue(self.right_margin_min, margin)
-
- def constrain_bottom_margin(self, margin, strength='strong'):
- c = (self.bottom == self.parent.bottom + margin)
- self.solver.addConstraint(c | strength)
-
- def edit_bottom_margin_min(self, margin):
- self.solver.suggestValue(self.bottom_margin_min, margin)
-
- def constrain_top_margin(self, margin, strength='strong'):
- c = (self.top == self.parent.top - margin)
- self.solver.addConstraint(c | strength)
-
- def edit_top_margin_min(self, margin):
- self.solver.suggestValue(self.top_margin_min, margin)
-
- def get_rect(self):
- return (self.left.value(), self.bottom.value(),
- self.width.value(), self.height.value())
-
- def update_variables(self):
- '''
- Update *all* the variables that are part of the solver this LayoutBox
- is created with
- '''
- self.solver.updateVariables()
-
- def edit_height(self, height, strength='strong'):
- '''
- Set the height of the layout box.
-
- This is done as an editable variable so that the value can change
- due to resizing.
- '''
- sol = self.solver
- for i in [self.height]:
- if not sol.hasEditVariable(i):
- sol.addEditVariable(i, strength)
- sol.suggestValue(self.height, height)
-
- def constrain_height(self, height, strength='strong'):
- '''
- Constrain the height of the layout box. height is
- either a float or a layoutbox.height.
- '''
- c = (self.height == height)
- self.solver.addConstraint(c | strength)
-
- def constrain_height_min(self, height, strength='strong'):
- c = (self.height >= height)
- self.solver.addConstraint(c | strength)
-
- def edit_width(self, width, strength='strong'):
- sol = self.solver
- for i in [self.width]:
- if not sol.hasEditVariable(i):
- sol.addEditVariable(i, strength)
- sol.suggestValue(self.width, width)
-
- def constrain_width(self, width, strength='strong'):
- '''
- Constrain the width of the layout box. `width` is
- either a float or a layoutbox.width.
- '''
- c = (self.width == width)
- self.solver.addConstraint(c | strength)
-
- def constrain_width_min(self, width, strength='strong'):
- c = (self.width >= width)
- self.solver.addConstraint(c | strength)
-
- def constrain_left(self, left, strength='strong'):
- c = (self.left == left)
- self.solver.addConstraint(c | strength)
-
- def constrain_bottom(self, bottom, strength='strong'):
- c = (self.bottom == bottom)
- self.solver.addConstraint(c | strength)
-
- def constrain_right(self, right, strength='strong'):
- c = (self.right == right)
- self.solver.addConstraint(c | strength)
-
- def constrain_top(self, top, strength='strong'):
- c = (self.top == top)
- self.solver.addConstraint(c | strength)
-
- def _is_subplotspec_layoutbox(self):
- '''
- Helper to check if this layoutbox is the layoutbox of a
- subplotspec
- '''
- name = (self.name).split('.')[-1]
- return name[:2] == 'ss'
-
- def _is_gridspec_layoutbox(self):
- '''
- Helper to check if this layoutbox is the layoutbox of a
- gridspec
- '''
- name = (self.name).split('.')[-1]
- return name[:8] == 'gridspec'
-
- def find_child_subplots(self):
- '''
- Find children of this layout box that are subplots. We want to line
- poss up, and this is an easy way to find them all.
- '''
- if self.subplot:
- subplots = [self]
- else:
- subplots = []
- for child in self.children:
- subplots += child.find_child_subplots()
- return subplots
-
- def layout_from_subplotspec(self, subspec,
- name='', artist=None, pos=False):
- ''' Make a layout box from a subplotspec. The layout box is
- constrained to be a fraction of the width/height of the parent,
- and be a fraction of the parent width/height from the left/bottom
- of the parent. Therefore the parent can move around and the
- layout for the subplot spec should move with it.
-
- The parent is *usually* the gridspec that made the subplotspec.??
- '''
- lb = LayoutBox(parent=self, name=name, artist=artist, pos=pos)
- gs = subspec.get_gridspec()
- nrows, ncols = gs.get_geometry()
- parent = self.parent
-
- # OK, now, we want to set the position of this subplotspec
- # based on its subplotspec parameters. The new gridspec will inherit.
-
- # from gridspec. prob should be new method in gridspec
- left = 0.0
- right = 1.0
- bottom = 0.0
- top = 1.0
- totWidth = right-left
- totHeight = top-bottom
- hspace = 0.
- wspace = 0.
-
- # calculate accumulated heights of columns
- cellH = totHeight / (nrows + hspace * (nrows - 1))
- sepH = hspace*cellH
-
- if gs._row_height_ratios is not None:
- netHeight = cellH * nrows
- tr = float(sum(gs._row_height_ratios))
- cellHeights = [netHeight*r/tr for r in gs._row_height_ratios]
- else:
- cellHeights = [cellH] * nrows
-
- sepHeights = [0] + ([sepH] * (nrows - 1))
- cellHs = np.add.accumulate(np.ravel(
- list(zip(sepHeights, cellHeights))))
-
- # calculate accumulated widths of rows
- cellW = totWidth/(ncols + wspace * (ncols - 1))
- sepW = wspace*cellW
-
- if gs._col_width_ratios is not None:
- netWidth = cellW * ncols
- tr = float(sum(gs._col_width_ratios))
- cellWidths = [netWidth * r / tr for r in gs._col_width_ratios]
- else:
- cellWidths = [cellW] * ncols
-
- sepWidths = [0] + ([sepW] * (ncols - 1))
- cellWs = np.add.accumulate(np.ravel(list(zip(sepWidths, cellWidths))))
-
- figTops = [top - cellHs[2 * rowNum] for rowNum in range(nrows)]
- figBottoms = [top - cellHs[2 * rowNum + 1] for rowNum in range(nrows)]
- figLefts = [left + cellWs[2 * colNum] for colNum in range(ncols)]
- figRights = [left + cellWs[2 * colNum + 1] for colNum in range(ncols)]
-
- rowNum, colNum = divmod(subspec.num1, ncols)
- figBottom = figBottoms[rowNum]
- figTop = figTops[rowNum]
- figLeft = figLefts[colNum]
- figRight = figRights[colNum]
-
- if subspec.num2 is not None:
-
- rowNum2, colNum2 = divmod(subspec.num2, ncols)
- figBottom2 = figBottoms[rowNum2]
- figTop2 = figTops[rowNum2]
- figLeft2 = figLefts[colNum2]
- figRight2 = figRights[colNum2]
-
- figBottom = min(figBottom, figBottom2)
- figLeft = min(figLeft, figLeft2)
- figTop = max(figTop, figTop2)
- figRight = max(figRight, figRight2)
- # These are numbers relative to 0,0,1,1. Need to constrain
- # relative to parent.
-
- width = figRight - figLeft
- height = figTop - figBottom
- parent = self.parent
- cs = [self.left == parent.left + parent.width * figLeft,
- self.bottom == parent.bottom + parent.height * figBottom,
- self.width == parent.width * width,
- self.height == parent.height * height]
- for c in cs:
- self.solver.addConstraint(c | 'required')
-
- return lb
-
- def __repr__(self):
- args = (self.name, self.left.value(), self.bottom.value(),
- self.right.value(), self.top.value())
- return ('LayoutBox: %25s, (left: %1.3f) (bot: %1.3f) '
- '(right: %1.3f) (top: %1.3f) ') % args
-
-
-# Utility functions that act on layoutboxes...
-def hstack(boxes, padding=0, strength='strong'):
- '''
- Stack LayoutBox instances from left to right.
- `padding` is in figure-relative units.
- '''
-
- for i in range(1, len(boxes)):
- c = (boxes[i-1].right + padding <= boxes[i].left)
- boxes[i].solver.addConstraint(c | strength)
-
-
-def hpack(boxes, padding=0, strength='strong'):
- '''
- Stack LayoutBox instances from left to right.
- '''
-
- for i in range(1, len(boxes)):
- c = (boxes[i-1].right + padding == boxes[i].left)
- boxes[i].solver.addConstraint(c | strength)
-
-
-def vstack(boxes, padding=0, strength='strong'):
- '''
- Stack LayoutBox instances from top to bottom
- '''
-
- for i in range(1, len(boxes)):
- c = (boxes[i-1].bottom - padding >= boxes[i].top)
- boxes[i].solver.addConstraint(c | strength)
-
-
-def vpack(boxes, padding=0, strength='strong'):
- '''
- Stack LayoutBox instances from top to bottom
- '''
-
- for i in range(1, len(boxes)):
- c = (boxes[i-1].bottom - padding >= boxes[i].top)
- boxes[i].solver.addConstraint(c | strength)
-
-
-def match_heights(boxes, height_ratios=None, strength='medium'):
- '''
- Stack LayoutBox instances from top to bottom
- '''
-
- if height_ratios is None:
- height_ratios = np.ones(len(boxes))
- for i in range(1, len(boxes)):
- c = (boxes[i-1].height ==
- boxes[i].height*height_ratios[i-1]/height_ratios[i])
- boxes[i].solver.addConstraint(c | strength)
-
-
-def match_widths(boxes, width_ratios=None, strength='medium'):
- '''
- Stack LayoutBox instances from top to bottom
- '''
-
- if width_ratios is None:
- width_ratios = np.ones(len(boxes))
- for i in range(1, len(boxes)):
- c = (boxes[i-1].width ==
- boxes[i].width*width_ratios[i-1]/width_ratios[i])
- boxes[i].solver.addConstraint(c | strength)
-
-
-def vstackeq(boxes, padding=0, height_ratios=None):
- vstack(boxes, padding=padding)
- match_heights(boxes, height_ratios=height_ratios)
-
-
-def hstackeq(boxes, padding=0, width_ratios=None):
- hstack(boxes, padding=padding)
- match_widths(boxes, width_ratios=width_ratios)
-
-
-def align(boxes, attr, strength='strong'):
- cons = []
- for box in boxes[1:]:
- cons = (getattr(boxes[0], attr) == getattr(box, attr))
- boxes[0].solver.addConstraint(cons | strength)
-
-
-def match_top_margins(boxes, levels=1):
- box0 = boxes[0]
- top0 = box0
- for n in range(levels):
- top0 = top0.parent
- for box in boxes[1:]:
- topb = box
- for n in range(levels):
- topb = topb.parent
- c = (box0.top-top0.top == box.top-topb.top)
- box0.solver.addConstraint(c | 'strong')
-
-
-def match_bottom_margins(boxes, levels=1):
- box0 = boxes[0]
- top0 = box0
- for n in range(levels):
- top0 = top0.parent
- for box in boxes[1:]:
- topb = box
- for n in range(levels):
- topb = topb.parent
- c = (box0.bottom-top0.bottom == box.bottom-topb.bottom)
- box0.solver.addConstraint(c | 'strong')
-
-
-def match_left_margins(boxes, levels=1):
- box0 = boxes[0]
- top0 = box0
- for n in range(levels):
- top0 = top0.parent
- for box in boxes[1:]:
- topb = box
- for n in range(levels):
- topb = topb.parent
- c = (box0.left-top0.left == box.left-topb.left)
- box0.solver.addConstraint(c | 'strong')
-
-
-def match_right_margins(boxes, levels=1):
- box0 = boxes[0]
- top0 = box0
- for n in range(levels):
- top0 = top0.parent
- for box in boxes[1:]:
- topb = box
- for n in range(levels):
- topb = topb.parent
- c = (box0.right-top0.right == box.right-topb.right)
- box0.solver.addConstraint(c | 'strong')
-
-
-def match_width_margins(boxes, levels=1):
- match_left_margins(boxes, levels=levels)
- match_right_margins(boxes, levels=levels)
-
-
-def match_height_margins(boxes, levels=1):
- match_top_margins(boxes, levels=levels)
- match_bottom_margins(boxes, levels=levels)
-
-
-def match_margins(boxes, levels=1):
- match_width_margins(boxes, levels=levels)
- match_height_margins(boxes, levels=levels)
-
-
-_layoutboxobjnum = itertools.count()
-
-
-def seq_id():
- '''
- Generate a short sequential id for layoutbox objects...
- '''
-
- global _layoutboxobjnum
-
- return ('%06d' % (next(_layoutboxobjnum)))
-
-
-def print_children(lb):
- '''
- Print the children of the layoutbox
- '''
- print(lb)
- for child in lb.children:
- print_children(child)
-
-
-def nonetree(lb):
- '''
- Make all elements in this tree none... This signals not to do any more
- layout.
- '''
- if lb is not None:
- if lb.parent is None:
- # Clear the solver. Hopefully this garbage collects.
- lb.solver.reset()
- nonechildren(lb)
- else:
- nonetree(lb.parent)
-
-
-def nonechildren(lb):
- for child in lb.children:
- nonechildren(child)
- lb.artist._layoutbox = None
- lb = None
-
-
-def print_tree(lb):
- '''
- Print the tree of layoutboxes
- '''
-
- if lb.parent is None:
- print('LayoutBox Tree\n')
- print('==============\n')
- print_children(lb)
- print('\n')
- else:
- print_tree(lb.parent)
-
-
-def plot_children(fig, box, level=0, printit=True):
- '''
- Simple plotting to show where boxes are
- '''
- import matplotlib
- import matplotlib.pyplot as plt
-
- if isinstance(fig, matplotlib.figure.Figure):
- ax = fig.add_axes([0., 0., 1., 1.])
- ax.set_facecolor([1., 1., 1., 0.7])
- ax.set_alpha(0.3)
- fig.draw(fig.canvas.get_renderer())
- else:
- ax = fig
-
- import matplotlib.patches as patches
- colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
- if printit:
- print("Level:", level)
- for child in box.children:
- if printit:
- print(child)
- ax.add_patch(
- patches.Rectangle(
- (child.left.value(), child.bottom.value()), # (x,y)
- child.width.value(), # width
- child.height.value(), # height
- fc='none',
- alpha=0.8,
- ec=colors[level]
- )
- )
- if level > 0:
- name = child.name.split('.')[-1]
- if level % 2 == 0:
- ax.text(child.left.value(), child.bottom.value(), name,
- size=12-level, color=colors[level])
- else:
- ax.text(child.right.value(), child.top.value(), name,
- ha='right', va='top', size=12-level,
- color=colors[level])
-
- plot_children(ax, child, level=level+1, printit=printit)
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_mathtext_data.py b/server/venv/lib/python3.7/site-packages/matplotlib/_mathtext_data.py
deleted file mode 100644
index baefe1b..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_mathtext_data.py
+++ /dev/null
@@ -1,2544 +0,0 @@
-"""
-font data tables for truetype and afm computer modern fonts
-"""
-
-latex_to_bakoma = {
- '\\__sqrt__' : ('cmex10', 0x70),
- '\\bigcap' : ('cmex10', 0x5c),
- '\\bigcup' : ('cmex10', 0x5b),
- '\\bigodot' : ('cmex10', 0x4b),
- '\\bigoplus' : ('cmex10', 0x4d),
- '\\bigotimes' : ('cmex10', 0x4f),
- '\\biguplus' : ('cmex10', 0x5d),
- '\\bigvee' : ('cmex10', 0x5f),
- '\\bigwedge' : ('cmex10', 0x5e),
- '\\coprod' : ('cmex10', 0x61),
- '\\int' : ('cmex10', 0x5a),
- '\\langle' : ('cmex10', 0xad),
- '\\leftangle' : ('cmex10', 0xad),
- '\\leftbrace' : ('cmex10', 0xa9),
- '\\oint' : ('cmex10', 0x49),
- '\\prod' : ('cmex10', 0x59),
- '\\rangle' : ('cmex10', 0xae),
- '\\rightangle' : ('cmex10', 0xae),
- '\\rightbrace' : ('cmex10', 0xaa),
- '\\sum' : ('cmex10', 0x58),
- '\\widehat' : ('cmex10', 0x62),
- '\\widetilde' : ('cmex10', 0x65),
- '\\{' : ('cmex10', 0xa9),
- '\\}' : ('cmex10', 0xaa),
- '{' : ('cmex10', 0xa9),
- '}' : ('cmex10', 0xaa),
-
- ',' : ('cmmi10', 0x3b),
- '.' : ('cmmi10', 0x3a),
- '/' : ('cmmi10', 0x3d),
- '<' : ('cmmi10', 0x3c),
- '>' : ('cmmi10', 0x3e),
- '\\alpha' : ('cmmi10', 0xae),
- '\\beta' : ('cmmi10', 0xaf),
- '\\chi' : ('cmmi10', 0xc2),
- '\\combiningrightarrowabove' : ('cmmi10', 0x7e),
- '\\delta' : ('cmmi10', 0xb1),
- '\\ell' : ('cmmi10', 0x60),
- '\\epsilon' : ('cmmi10', 0xb2),
- '\\eta' : ('cmmi10', 0xb4),
- '\\flat' : ('cmmi10', 0x5b),
- '\\frown' : ('cmmi10', 0x5f),
- '\\gamma' : ('cmmi10', 0xb0),
- '\\imath' : ('cmmi10', 0x7b),
- '\\iota' : ('cmmi10', 0xb6),
- '\\jmath' : ('cmmi10', 0x7c),
- '\\kappa' : ('cmmi10', 0x2219),
- '\\lambda' : ('cmmi10', 0xb8),
- '\\leftharpoondown' : ('cmmi10', 0x29),
- '\\leftharpoonup' : ('cmmi10', 0x28),
- '\\mu' : ('cmmi10', 0xb9),
- '\\natural' : ('cmmi10', 0x5c),
- '\\nu' : ('cmmi10', 0xba),
- '\\omega' : ('cmmi10', 0x21),
- '\\phi' : ('cmmi10', 0xc1),
- '\\pi' : ('cmmi10', 0xbc),
- '\\psi' : ('cmmi10', 0xc3),
- '\\rho' : ('cmmi10', 0xbd),
- '\\rightharpoondown' : ('cmmi10', 0x2b),
- '\\rightharpoonup' : ('cmmi10', 0x2a),
- '\\sharp' : ('cmmi10', 0x5d),
- '\\sigma' : ('cmmi10', 0xbe),
- '\\smile' : ('cmmi10', 0x5e),
- '\\tau' : ('cmmi10', 0xbf),
- '\\theta' : ('cmmi10', 0xb5),
- '\\triangleleft' : ('cmmi10', 0x2f),
- '\\triangleright' : ('cmmi10', 0x2e),
- '\\upsilon' : ('cmmi10', 0xc0),
- '\\varepsilon' : ('cmmi10', 0x22),
- '\\varphi' : ('cmmi10', 0x27),
- '\\varrho' : ('cmmi10', 0x25),
- '\\varsigma' : ('cmmi10', 0x26),
- '\\vartheta' : ('cmmi10', 0x23),
- '\\wp' : ('cmmi10', 0x7d),
- '\\xi' : ('cmmi10', 0xbb),
- '\\zeta' : ('cmmi10', 0xb3),
-
- '!' : ('cmr10', 0x21),
- '%' : ('cmr10', 0x25),
- '&' : ('cmr10', 0x26),
- '(' : ('cmr10', 0x28),
- ')' : ('cmr10', 0x29),
- '+' : ('cmr10', 0x2b),
- '0' : ('cmr10', 0x30),
- '1' : ('cmr10', 0x31),
- '2' : ('cmr10', 0x32),
- '3' : ('cmr10', 0x33),
- '4' : ('cmr10', 0x34),
- '5' : ('cmr10', 0x35),
- '6' : ('cmr10', 0x36),
- '7' : ('cmr10', 0x37),
- '8' : ('cmr10', 0x38),
- '9' : ('cmr10', 0x39),
- ':' : ('cmr10', 0x3a),
- ';' : ('cmr10', 0x3b),
- '=' : ('cmr10', 0x3d),
- '?' : ('cmr10', 0x3f),
- '@' : ('cmr10', 0x40),
- '[' : ('cmr10', 0x5b),
- '\\#' : ('cmr10', 0x23),
- '\\$' : ('cmr10', 0x24),
- '\\%' : ('cmr10', 0x25),
- '\\Delta' : ('cmr10', 0xa2),
- '\\Gamma' : ('cmr10', 0xa1),
- '\\Lambda' : ('cmr10', 0xa4),
- '\\Omega' : ('cmr10', 0xad),
- '\\Phi' : ('cmr10', 0xa9),
- '\\Pi' : ('cmr10', 0xa6),
- '\\Psi' : ('cmr10', 0xaa),
- '\\Sigma' : ('cmr10', 0xa7),
- '\\Theta' : ('cmr10', 0xa3),
- '\\Upsilon' : ('cmr10', 0xa8),
- '\\Xi' : ('cmr10', 0xa5),
- '\\circumflexaccent' : ('cmr10', 0x5e),
- '\\combiningacuteaccent' : ('cmr10', 0xb6),
- '\\combiningbreve' : ('cmr10', 0xb8),
- '\\combiningdiaeresis' : ('cmr10', 0xc4),
- '\\combiningdotabove' : ('cmr10', 0x5f),
- '\\combininggraveaccent' : ('cmr10', 0xb5),
- '\\combiningoverline' : ('cmr10', 0xb9),
- '\\combiningtilde' : ('cmr10', 0x7e),
- '\\leftbracket' : ('cmr10', 0x5b),
- '\\leftparen' : ('cmr10', 0x28),
- '\\rightbracket' : ('cmr10', 0x5d),
- '\\rightparen' : ('cmr10', 0x29),
- '\\widebar' : ('cmr10', 0xb9),
- ']' : ('cmr10', 0x5d),
-
- '*' : ('cmsy10', 0xa4),
- '-' : ('cmsy10', 0xa1),
- '\\Downarrow' : ('cmsy10', 0x2b),
- '\\Im' : ('cmsy10', 0x3d),
- '\\Leftarrow' : ('cmsy10', 0x28),
- '\\Leftrightarrow' : ('cmsy10', 0x2c),
- '\\P' : ('cmsy10', 0x7b),
- '\\Re' : ('cmsy10', 0x3c),
- '\\Rightarrow' : ('cmsy10', 0x29),
- '\\S' : ('cmsy10', 0x78),
- '\\Uparrow' : ('cmsy10', 0x2a),
- '\\Updownarrow' : ('cmsy10', 0x6d),
- '\\Vert' : ('cmsy10', 0x6b),
- '\\aleph' : ('cmsy10', 0x40),
- '\\approx' : ('cmsy10', 0xbc),
- '\\ast' : ('cmsy10', 0xa4),
- '\\asymp' : ('cmsy10', 0xb3),
- '\\backslash' : ('cmsy10', 0x6e),
- '\\bigcirc' : ('cmsy10', 0xb0),
- '\\bigtriangledown' : ('cmsy10', 0x35),
- '\\bigtriangleup' : ('cmsy10', 0x34),
- '\\bot' : ('cmsy10', 0x3f),
- '\\bullet' : ('cmsy10', 0xb2),
- '\\cap' : ('cmsy10', 0x5c),
- '\\cdot' : ('cmsy10', 0xa2),
- '\\circ' : ('cmsy10', 0xb1),
- '\\clubsuit' : ('cmsy10', 0x7c),
- '\\cup' : ('cmsy10', 0x5b),
- '\\dag' : ('cmsy10', 0x79),
- '\\dashv' : ('cmsy10', 0x61),
- '\\ddag' : ('cmsy10', 0x7a),
- '\\diamond' : ('cmsy10', 0xa6),
- '\\diamondsuit' : ('cmsy10', 0x7d),
- '\\div' : ('cmsy10', 0xa5),
- '\\downarrow' : ('cmsy10', 0x23),
- '\\emptyset' : ('cmsy10', 0x3b),
- '\\equiv' : ('cmsy10', 0xb4),
- '\\exists' : ('cmsy10', 0x39),
- '\\forall' : ('cmsy10', 0x38),
- '\\geq' : ('cmsy10', 0xb8),
- '\\gg' : ('cmsy10', 0xc0),
- '\\heartsuit' : ('cmsy10', 0x7e),
- '\\in' : ('cmsy10', 0x32),
- '\\infty' : ('cmsy10', 0x31),
- '\\lbrace' : ('cmsy10', 0x66),
- '\\lceil' : ('cmsy10', 0x64),
- '\\leftarrow' : ('cmsy10', 0xc3),
- '\\leftrightarrow' : ('cmsy10', 0x24),
- '\\leq' : ('cmsy10', 0x2219),
- '\\lfloor' : ('cmsy10', 0x62),
- '\\ll' : ('cmsy10', 0xbf),
- '\\mid' : ('cmsy10', 0x6a),
- '\\mp' : ('cmsy10', 0xa8),
- '\\nabla' : ('cmsy10', 0x72),
- '\\nearrow' : ('cmsy10', 0x25),
- '\\neg' : ('cmsy10', 0x3a),
- '\\ni' : ('cmsy10', 0x33),
- '\\nwarrow' : ('cmsy10', 0x2d),
- '\\odot' : ('cmsy10', 0xaf),
- '\\ominus' : ('cmsy10', 0xaa),
- '\\oplus' : ('cmsy10', 0xa9),
- '\\oslash' : ('cmsy10', 0xae),
- '\\otimes' : ('cmsy10', 0xad),
- '\\pm' : ('cmsy10', 0xa7),
- '\\prec' : ('cmsy10', 0xc1),
- '\\preceq' : ('cmsy10', 0xb9),
- '\\prime' : ('cmsy10', 0x30),
- '\\propto' : ('cmsy10', 0x2f),
- '\\rbrace' : ('cmsy10', 0x67),
- '\\rceil' : ('cmsy10', 0x65),
- '\\rfloor' : ('cmsy10', 0x63),
- '\\rightarrow' : ('cmsy10', 0x21),
- '\\searrow' : ('cmsy10', 0x26),
- '\\sim' : ('cmsy10', 0xbb),
- '\\simeq' : ('cmsy10', 0x27),
- '\\slash' : ('cmsy10', 0x36),
- '\\spadesuit' : ('cmsy10', 0xc4),
- '\\sqcap' : ('cmsy10', 0x75),
- '\\sqcup' : ('cmsy10', 0x74),
- '\\sqsubseteq' : ('cmsy10', 0x76),
- '\\sqsupseteq' : ('cmsy10', 0x77),
- '\\subset' : ('cmsy10', 0xbd),
- '\\subseteq' : ('cmsy10', 0xb5),
- '\\succ' : ('cmsy10', 0xc2),
- '\\succeq' : ('cmsy10', 0xba),
- '\\supset' : ('cmsy10', 0xbe),
- '\\supseteq' : ('cmsy10', 0xb6),
- '\\swarrow' : ('cmsy10', 0x2e),
- '\\times' : ('cmsy10', 0xa3),
- '\\to' : ('cmsy10', 0x21),
- '\\top' : ('cmsy10', 0x3e),
- '\\uparrow' : ('cmsy10', 0x22),
- '\\updownarrow' : ('cmsy10', 0x6c),
- '\\uplus' : ('cmsy10', 0x5d),
- '\\vdash' : ('cmsy10', 0x60),
- '\\vee' : ('cmsy10', 0x5f),
- '\\vert' : ('cmsy10', 0x6a),
- '\\wedge' : ('cmsy10', 0x5e),
- '\\wr' : ('cmsy10', 0x6f),
- '\\|' : ('cmsy10', 0x6b),
- '|' : ('cmsy10', 0x6a),
-
- '\\_' : ('cmtt10', 0x5f)
-}
-
-latex_to_cmex = {
- r'\__sqrt__' : 112,
- r'\bigcap' : 92,
- r'\bigcup' : 91,
- r'\bigodot' : 75,
- r'\bigoplus' : 77,
- r'\bigotimes' : 79,
- r'\biguplus' : 93,
- r'\bigvee' : 95,
- r'\bigwedge' : 94,
- r'\coprod' : 97,
- r'\int' : 90,
- r'\leftangle' : 173,
- r'\leftbrace' : 169,
- r'\oint' : 73,
- r'\prod' : 89,
- r'\rightangle' : 174,
- r'\rightbrace' : 170,
- r'\sum' : 88,
- r'\widehat' : 98,
- r'\widetilde' : 101,
-}
-
-latex_to_standard = {
- r'\cong' : ('psyr', 64),
- r'\Delta' : ('psyr', 68),
- r'\Phi' : ('psyr', 70),
- r'\Gamma' : ('psyr', 89),
- r'\alpha' : ('psyr', 97),
- r'\beta' : ('psyr', 98),
- r'\chi' : ('psyr', 99),
- r'\delta' : ('psyr', 100),
- r'\varepsilon' : ('psyr', 101),
- r'\phi' : ('psyr', 102),
- r'\gamma' : ('psyr', 103),
- r'\eta' : ('psyr', 104),
- r'\iota' : ('psyr', 105),
- r'\varpsi' : ('psyr', 106),
- r'\kappa' : ('psyr', 108),
- r'\nu' : ('psyr', 110),
- r'\pi' : ('psyr', 112),
- r'\theta' : ('psyr', 113),
- r'\rho' : ('psyr', 114),
- r'\sigma' : ('psyr', 115),
- r'\tau' : ('psyr', 116),
- r'\upsilon' : ('psyr', 117),
- r'\varpi' : ('psyr', 118),
- r'\omega' : ('psyr', 119),
- r'\xi' : ('psyr', 120),
- r'\psi' : ('psyr', 121),
- r'\zeta' : ('psyr', 122),
- r'\sim' : ('psyr', 126),
- r'\leq' : ('psyr', 163),
- r'\infty' : ('psyr', 165),
- r'\clubsuit' : ('psyr', 167),
- r'\diamondsuit' : ('psyr', 168),
- r'\heartsuit' : ('psyr', 169),
- r'\spadesuit' : ('psyr', 170),
- r'\leftrightarrow' : ('psyr', 171),
- r'\leftarrow' : ('psyr', 172),
- r'\uparrow' : ('psyr', 173),
- r'\rightarrow' : ('psyr', 174),
- r'\downarrow' : ('psyr', 175),
- r'\pm' : ('psyr', 176),
- r'\geq' : ('psyr', 179),
- r'\times' : ('psyr', 180),
- r'\propto' : ('psyr', 181),
- r'\partial' : ('psyr', 182),
- r'\bullet' : ('psyr', 183),
- r'\div' : ('psyr', 184),
- r'\neq' : ('psyr', 185),
- r'\equiv' : ('psyr', 186),
- r'\approx' : ('psyr', 187),
- r'\ldots' : ('psyr', 188),
- r'\aleph' : ('psyr', 192),
- r'\Im' : ('psyr', 193),
- r'\Re' : ('psyr', 194),
- r'\wp' : ('psyr', 195),
- r'\otimes' : ('psyr', 196),
- r'\oplus' : ('psyr', 197),
- r'\oslash' : ('psyr', 198),
- r'\cap' : ('psyr', 199),
- r'\cup' : ('psyr', 200),
- r'\supset' : ('psyr', 201),
- r'\supseteq' : ('psyr', 202),
- r'\subset' : ('psyr', 204),
- r'\subseteq' : ('psyr', 205),
- r'\in' : ('psyr', 206),
- r'\notin' : ('psyr', 207),
- r'\angle' : ('psyr', 208),
- r'\nabla' : ('psyr', 209),
- r'\textregistered' : ('psyr', 210),
- r'\copyright' : ('psyr', 211),
- r'\texttrademark' : ('psyr', 212),
- r'\Pi' : ('psyr', 213),
- r'\prod' : ('psyr', 213),
- r'\surd' : ('psyr', 214),
- r'\__sqrt__' : ('psyr', 214),
- r'\cdot' : ('psyr', 215),
- r'\urcorner' : ('psyr', 216),
- r'\vee' : ('psyr', 217),
- r'\wedge' : ('psyr', 218),
- r'\Leftrightarrow' : ('psyr', 219),
- r'\Leftarrow' : ('psyr', 220),
- r'\Uparrow' : ('psyr', 221),
- r'\Rightarrow' : ('psyr', 222),
- r'\Downarrow' : ('psyr', 223),
- r'\Diamond' : ('psyr', 224),
- r'\Sigma' : ('psyr', 229),
- r'\sum' : ('psyr', 229),
- r'\forall' : ('psyr', 34),
- r'\exists' : ('psyr', 36),
- r'\lceil' : ('psyr', 233),
- r'\lbrace' : ('psyr', 123),
- r'\Psi' : ('psyr', 89),
- r'\bot' : ('psyr', 0o136),
- r'\Omega' : ('psyr', 0o127),
- r'\leftbracket' : ('psyr', 0o133),
- r'\rightbracket' : ('psyr', 0o135),
- r'\leftbrace' : ('psyr', 123),
- r'\leftparen' : ('psyr', 0o50),
- r'\prime' : ('psyr', 0o242),
- r'\sharp' : ('psyr', 0o43),
- r'\slash' : ('psyr', 0o57),
- r'\Lamda' : ('psyr', 0o114),
- r'\neg' : ('psyr', 0o330),
- r'\Upsilon' : ('psyr', 0o241),
- r'\rightbrace' : ('psyr', 0o175),
- r'\rfloor' : ('psyr', 0o373),
- r'\lambda' : ('psyr', 0o154),
- r'\to' : ('psyr', 0o256),
- r'\Xi' : ('psyr', 0o130),
- r'\emptyset' : ('psyr', 0o306),
- r'\lfloor' : ('psyr', 0o353),
- r'\rightparen' : ('psyr', 0o51),
- r'\rceil' : ('psyr', 0o371),
- r'\ni' : ('psyr', 0o47),
- r'\epsilon' : ('psyr', 0o145),
- r'\Theta' : ('psyr', 0o121),
- r'\langle' : ('psyr', 0o341),
- r'\leftangle' : ('psyr', 0o341),
- r'\rangle' : ('psyr', 0o361),
- r'\rightangle' : ('psyr', 0o361),
- r'\rbrace' : ('psyr', 0o175),
- r'\circ' : ('psyr', 0o260),
- r'\diamond' : ('psyr', 0o340),
- r'\mu' : ('psyr', 0o155),
- r'\mid' : ('psyr', 0o352),
- r'\imath' : ('pncri8a', 105),
- r'\%' : ('pncr8a', 37),
- r'\$' : ('pncr8a', 36),
- r'\{' : ('pncr8a', 123),
- r'\}' : ('pncr8a', 125),
- r'\backslash' : ('pncr8a', 92),
- r'\ast' : ('pncr8a', 42),
- r'\#' : ('pncr8a', 35),
-
- r'\circumflexaccent' : ('pncri8a', 124), # for \hat
- r'\combiningbreve' : ('pncri8a', 81), # for \breve
- r'\combininggraveaccent' : ('pncri8a', 114), # for \grave
- r'\combiningacuteaccent' : ('pncri8a', 63), # for \accute
- r'\combiningdiaeresis' : ('pncri8a', 91), # for \ddot
- r'\combiningtilde' : ('pncri8a', 75), # for \tilde
- r'\combiningrightarrowabove' : ('pncri8a', 110), # for \vec
- r'\combiningdotabove' : ('pncri8a', 26), # for \dot
-}
-
-# Automatically generated.
-
-type12uni = {
- 'uni24C8' : 9416,
- 'aring' : 229,
- 'uni22A0' : 8864,
- 'uni2292' : 8850,
- 'quotedblright' : 8221,
- 'uni03D2' : 978,
- 'uni2215' : 8725,
- 'uni03D0' : 976,
- 'V' : 86,
- 'dollar' : 36,
- 'uni301E' : 12318,
- 'uni03D5' : 981,
- 'four' : 52,
- 'uni25A0' : 9632,
- 'uni013C' : 316,
- 'uni013B' : 315,
- 'uni013E' : 318,
- 'Yacute' : 221,
- 'uni25DE' : 9694,
- 'uni013F' : 319,
- 'uni255A' : 9562,
- 'uni2606' : 9734,
- 'uni0180' : 384,
- 'uni22B7' : 8887,
- 'uni044F' : 1103,
- 'uni22B5' : 8885,
- 'uni22B4' : 8884,
- 'uni22AE' : 8878,
- 'uni22B2' : 8882,
- 'uni22B1' : 8881,
- 'uni22B0' : 8880,
- 'uni25CD' : 9677,
- 'uni03CE' : 974,
- 'uni03CD' : 973,
- 'uni03CC' : 972,
- 'uni03CB' : 971,
- 'uni03CA' : 970,
- 'uni22B8' : 8888,
- 'uni22C9' : 8905,
- 'uni0449' : 1097,
- 'uni20DD' : 8413,
- 'uni20DC' : 8412,
- 'uni20DB' : 8411,
- 'uni2231' : 8753,
- 'uni25CF' : 9679,
- 'uni306E' : 12398,
- 'uni03D1' : 977,
- 'uni01A1' : 417,
- 'uni20D7' : 8407,
- 'uni03D6' : 982,
- 'uni2233' : 8755,
- 'uni20D2' : 8402,
- 'uni20D1' : 8401,
- 'uni20D0' : 8400,
- 'P' : 80,
- 'uni22BE' : 8894,
- 'uni22BD' : 8893,
- 'uni22BC' : 8892,
- 'uni22BB' : 8891,
- 'underscore' : 95,
- 'uni03C8' : 968,
- 'uni03C7' : 967,
- 'uni0328' : 808,
- 'uni03C5' : 965,
- 'uni03C4' : 964,
- 'uni03C3' : 963,
- 'uni03C2' : 962,
- 'uni03C1' : 961,
- 'uni03C0' : 960,
- 'uni2010' : 8208,
- 'uni0130' : 304,
- 'uni0133' : 307,
- 'uni0132' : 306,
- 'uni0135' : 309,
- 'uni0134' : 308,
- 'uni0137' : 311,
- 'uni0136' : 310,
- 'uni0139' : 313,
- 'uni0138' : 312,
- 'uni2244' : 8772,
- 'uni229A' : 8858,
- 'uni2571' : 9585,
- 'uni0278' : 632,
- 'uni2239' : 8761,
- 'p' : 112,
- 'uni3019' : 12313,
- 'uni25CB' : 9675,
- 'uni03DB' : 987,
- 'uni03DC' : 988,
- 'uni03DA' : 986,
- 'uni03DF' : 991,
- 'uni03DD' : 989,
- 'uni013D' : 317,
- 'uni220A' : 8714,
- 'uni220C' : 8716,
- 'uni220B' : 8715,
- 'uni220E' : 8718,
- 'uni220D' : 8717,
- 'uni220F' : 8719,
- 'uni22CC' : 8908,
- 'Otilde' : 213,
- 'uni25E5' : 9701,
- 'uni2736' : 10038,
- 'perthousand' : 8240,
- 'zero' : 48,
- 'uni279B' : 10139,
- 'dotlessi' : 305,
- 'uni2279' : 8825,
- 'Scaron' : 352,
- 'zcaron' : 382,
- 'uni21D8' : 8664,
- 'egrave' : 232,
- 'uni0271' : 625,
- 'uni01AA' : 426,
- 'uni2332' : 9010,
- 'section' : 167,
- 'uni25E4' : 9700,
- 'Icircumflex' : 206,
- 'ntilde' : 241,
- 'uni041E' : 1054,
- 'ampersand' : 38,
- 'uni041C' : 1052,
- 'uni041A' : 1050,
- 'uni22AB' : 8875,
- 'uni21DB' : 8667,
- 'dotaccent' : 729,
- 'uni0416' : 1046,
- 'uni0417' : 1047,
- 'uni0414' : 1044,
- 'uni0415' : 1045,
- 'uni0412' : 1042,
- 'uni0413' : 1043,
- 'degree' : 176,
- 'uni0411' : 1041,
- 'K' : 75,
- 'uni25EB' : 9707,
- 'uni25EF' : 9711,
- 'uni0418' : 1048,
- 'uni0419' : 1049,
- 'uni2263' : 8803,
- 'uni226E' : 8814,
- 'uni2251' : 8785,
- 'uni02C8' : 712,
- 'uni2262' : 8802,
- 'acircumflex' : 226,
- 'uni22B3' : 8883,
- 'uni2261' : 8801,
- 'uni2394' : 9108,
- 'Aring' : 197,
- 'uni2260' : 8800,
- 'uni2254' : 8788,
- 'uni0436' : 1078,
- 'uni2267' : 8807,
- 'k' : 107,
- 'uni22C8' : 8904,
- 'uni226A' : 8810,
- 'uni231F' : 8991,
- 'smalltilde' : 732,
- 'uni2201' : 8705,
- 'uni2200' : 8704,
- 'uni2203' : 8707,
- 'uni02BD' : 701,
- 'uni2205' : 8709,
- 'uni2204' : 8708,
- 'Agrave' : 192,
- 'uni2206' : 8710,
- 'uni2209' : 8713,
- 'uni2208' : 8712,
- 'uni226D' : 8813,
- 'uni2264' : 8804,
- 'uni263D' : 9789,
- 'uni2258' : 8792,
- 'uni02D3' : 723,
- 'uni02D2' : 722,
- 'uni02D1' : 721,
- 'uni02D0' : 720,
- 'uni25E1' : 9697,
- 'divide' : 247,
- 'uni02D5' : 725,
- 'uni02D4' : 724,
- 'ocircumflex' : 244,
- 'uni2524' : 9508,
- 'uni043A' : 1082,
- 'uni24CC' : 9420,
- 'asciitilde' : 126,
- 'uni22B9' : 8889,
- 'uni24D2' : 9426,
- 'uni211E' : 8478,
- 'uni211D' : 8477,
- 'uni24DD' : 9437,
- 'uni211A' : 8474,
- 'uni211C' : 8476,
- 'uni211B' : 8475,
- 'uni25C6' : 9670,
- 'uni017F' : 383,
- 'uni017A' : 378,
- 'uni017C' : 380,
- 'uni017B' : 379,
- 'uni0346' : 838,
- 'uni22F1' : 8945,
- 'uni22F0' : 8944,
- 'two' : 50,
- 'uni2298' : 8856,
- 'uni24D1' : 9425,
- 'E' : 69,
- 'uni025D' : 605,
- 'scaron' : 353,
- 'uni2322' : 8994,
- 'uni25E3' : 9699,
- 'uni22BF' : 8895,
- 'F' : 70,
- 'uni0440' : 1088,
- 'uni255E' : 9566,
- 'uni22BA' : 8890,
- 'uni0175' : 373,
- 'uni0174' : 372,
- 'uni0177' : 375,
- 'uni0176' : 374,
- 'bracketleft' : 91,
- 'uni0170' : 368,
- 'uni0173' : 371,
- 'uni0172' : 370,
- 'asciicircum' : 94,
- 'uni0179' : 377,
- 'uni2590' : 9616,
- 'uni25E2' : 9698,
- 'uni2119' : 8473,
- 'uni2118' : 8472,
- 'uni25CC' : 9676,
- 'f' : 102,
- 'ordmasculine' : 186,
- 'uni229B' : 8859,
- 'uni22A1' : 8865,
- 'uni2111' : 8465,
- 'uni2110' : 8464,
- 'uni2113' : 8467,
- 'uni2112' : 8466,
- 'mu' : 181,
- 'uni2281' : 8833,
- 'paragraph' : 182,
- 'nine' : 57,
- 'uni25EC' : 9708,
- 'v' : 118,
- 'uni040C' : 1036,
- 'uni0113' : 275,
- 'uni22D0' : 8912,
- 'uni21CC' : 8652,
- 'uni21CB' : 8651,
- 'uni21CA' : 8650,
- 'uni22A5' : 8869,
- 'uni21CF' : 8655,
- 'uni21CE' : 8654,
- 'uni21CD' : 8653,
- 'guilsinglleft' : 8249,
- 'backslash' : 92,
- 'uni2284' : 8836,
- 'uni224E' : 8782,
- 'uni224D' : 8781,
- 'uni224F' : 8783,
- 'uni224A' : 8778,
- 'uni2287' : 8839,
- 'uni224C' : 8780,
- 'uni224B' : 8779,
- 'uni21BD' : 8637,
- 'uni2286' : 8838,
- 'uni030F' : 783,
- 'uni030D' : 781,
- 'uni030E' : 782,
- 'uni030B' : 779,
- 'uni030C' : 780,
- 'uni030A' : 778,
- 'uni026E' : 622,
- 'uni026D' : 621,
- 'six' : 54,
- 'uni026A' : 618,
- 'uni026C' : 620,
- 'uni25C1' : 9665,
- 'uni20D6' : 8406,
- 'uni045B' : 1115,
- 'uni045C' : 1116,
- 'uni256B' : 9579,
- 'uni045A' : 1114,
- 'uni045F' : 1119,
- 'uni045E' : 1118,
- 'A' : 65,
- 'uni2569' : 9577,
- 'uni0458' : 1112,
- 'uni0459' : 1113,
- 'uni0452' : 1106,
- 'uni0453' : 1107,
- 'uni2562' : 9570,
- 'uni0451' : 1105,
- 'uni0456' : 1110,
- 'uni0457' : 1111,
- 'uni0454' : 1108,
- 'uni0455' : 1109,
- 'icircumflex' : 238,
- 'uni0307' : 775,
- 'uni0304' : 772,
- 'uni0305' : 773,
- 'uni0269' : 617,
- 'uni0268' : 616,
- 'uni0300' : 768,
- 'uni0301' : 769,
- 'uni0265' : 613,
- 'uni0264' : 612,
- 'uni0267' : 615,
- 'uni0266' : 614,
- 'uni0261' : 609,
- 'uni0260' : 608,
- 'uni0263' : 611,
- 'uni0262' : 610,
- 'a' : 97,
- 'uni2207' : 8711,
- 'uni2247' : 8775,
- 'uni2246' : 8774,
- 'uni2241' : 8769,
- 'uni2240' : 8768,
- 'uni2243' : 8771,
- 'uni2242' : 8770,
- 'uni2312' : 8978,
- 'ogonek' : 731,
- 'uni2249' : 8777,
- 'uni2248' : 8776,
- 'uni3030' : 12336,
- 'q' : 113,
- 'uni21C2' : 8642,
- 'uni21C1' : 8641,
- 'uni21C0' : 8640,
- 'uni21C7' : 8647,
- 'uni21C6' : 8646,
- 'uni21C5' : 8645,
- 'uni21C4' : 8644,
- 'uni225F' : 8799,
- 'uni212C' : 8492,
- 'uni21C8' : 8648,
- 'uni2467' : 9319,
- 'oacute' : 243,
- 'uni028F' : 655,
- 'uni028E' : 654,
- 'uni026F' : 623,
- 'uni028C' : 652,
- 'uni028B' : 651,
- 'uni028A' : 650,
- 'uni2510' : 9488,
- 'ograve' : 242,
- 'edieresis' : 235,
- 'uni22CE' : 8910,
- 'uni22CF' : 8911,
- 'uni219F' : 8607,
- 'comma' : 44,
- 'uni22CA' : 8906,
- 'uni0429' : 1065,
- 'uni03C6' : 966,
- 'uni0427' : 1063,
- 'uni0426' : 1062,
- 'uni0425' : 1061,
- 'uni0424' : 1060,
- 'uni0423' : 1059,
- 'uni0422' : 1058,
- 'uni0421' : 1057,
- 'uni0420' : 1056,
- 'uni2465' : 9317,
- 'uni24D0' : 9424,
- 'uni2464' : 9316,
- 'uni0430' : 1072,
- 'otilde' : 245,
- 'uni2661' : 9825,
- 'uni24D6' : 9430,
- 'uni2466' : 9318,
- 'uni24D5' : 9429,
- 'uni219A' : 8602,
- 'uni2518' : 9496,
- 'uni22B6' : 8886,
- 'uni2461' : 9313,
- 'uni24D4' : 9428,
- 'uni2460' : 9312,
- 'uni24EA' : 9450,
- 'guillemotright' : 187,
- 'ecircumflex' : 234,
- 'greater' : 62,
- 'uni2011' : 8209,
- 'uacute' : 250,
- 'uni2462' : 9314,
- 'L' : 76,
- 'bullet' : 8226,
- 'uni02A4' : 676,
- 'uni02A7' : 679,
- 'cedilla' : 184,
- 'uni02A2' : 674,
- 'uni2015' : 8213,
- 'uni22C4' : 8900,
- 'uni22C5' : 8901,
- 'uni22AD' : 8877,
- 'uni22C7' : 8903,
- 'uni22C0' : 8896,
- 'uni2016' : 8214,
- 'uni22C2' : 8898,
- 'uni22C3' : 8899,
- 'uni24CF' : 9423,
- 'uni042F' : 1071,
- 'uni042E' : 1070,
- 'uni042D' : 1069,
- 'ydieresis' : 255,
- 'l' : 108,
- 'logicalnot' : 172,
- 'uni24CA' : 9418,
- 'uni0287' : 647,
- 'uni0286' : 646,
- 'uni0285' : 645,
- 'uni0284' : 644,
- 'uni0283' : 643,
- 'uni0282' : 642,
- 'uni0281' : 641,
- 'uni027C' : 636,
- 'uni2664' : 9828,
- 'exclamdown' : 161,
- 'uni25C4' : 9668,
- 'uni0289' : 649,
- 'uni0288' : 648,
- 'uni039A' : 922,
- 'endash' : 8211,
- 'uni2640' : 9792,
- 'uni20E4' : 8420,
- 'uni0473' : 1139,
- 'uni20E1' : 8417,
- 'uni2642' : 9794,
- 'uni03B8' : 952,
- 'uni03B9' : 953,
- 'agrave' : 224,
- 'uni03B4' : 948,
- 'uni03B5' : 949,
- 'uni03B6' : 950,
- 'uni03B7' : 951,
- 'uni03B0' : 944,
- 'uni03B1' : 945,
- 'uni03B2' : 946,
- 'uni03B3' : 947,
- 'uni2555' : 9557,
- 'Adieresis' : 196,
- 'germandbls' : 223,
- 'Odieresis' : 214,
- 'space' : 32,
- 'uni0126' : 294,
- 'uni0127' : 295,
- 'uni0124' : 292,
- 'uni0125' : 293,
- 'uni0122' : 290,
- 'uni0123' : 291,
- 'uni0120' : 288,
- 'uni0121' : 289,
- 'quoteright' : 8217,
- 'uni2560' : 9568,
- 'uni2556' : 9558,
- 'ucircumflex' : 251,
- 'uni2561' : 9569,
- 'uni2551' : 9553,
- 'uni25B2' : 9650,
- 'uni2550' : 9552,
- 'uni2563' : 9571,
- 'uni2553' : 9555,
- 'G' : 71,
- 'uni2564' : 9572,
- 'uni2552' : 9554,
- 'quoteleft' : 8216,
- 'uni2565' : 9573,
- 'uni2572' : 9586,
- 'uni2568' : 9576,
- 'uni2566' : 9574,
- 'W' : 87,
- 'uni214A' : 8522,
- 'uni012F' : 303,
- 'uni012D' : 301,
- 'uni012E' : 302,
- 'uni012B' : 299,
- 'uni012C' : 300,
- 'uni255C' : 9564,
- 'uni012A' : 298,
- 'uni2289' : 8841,
- 'Q' : 81,
- 'uni2320' : 8992,
- 'uni2321' : 8993,
- 'g' : 103,
- 'uni03BD' : 957,
- 'uni03BE' : 958,
- 'uni03BF' : 959,
- 'uni2282' : 8834,
- 'uni2285' : 8837,
- 'uni03BA' : 954,
- 'uni03BB' : 955,
- 'uni03BC' : 956,
- 'uni2128' : 8488,
- 'uni25B7' : 9655,
- 'w' : 119,
- 'uni0302' : 770,
- 'uni03DE' : 990,
- 'uni25DA' : 9690,
- 'uni0303' : 771,
- 'uni0463' : 1123,
- 'uni0462' : 1122,
- 'uni3018' : 12312,
- 'uni2514' : 9492,
- 'question' : 63,
- 'uni25B3' : 9651,
- 'uni24E1' : 9441,
- 'one' : 49,
- 'uni200A' : 8202,
- 'uni2278' : 8824,
- 'ring' : 730,
- 'uni0195' : 405,
- 'figuredash' : 8210,
- 'uni22EC' : 8940,
- 'uni0339' : 825,
- 'uni0338' : 824,
- 'uni0337' : 823,
- 'uni0336' : 822,
- 'uni0335' : 821,
- 'uni0333' : 819,
- 'uni0332' : 818,
- 'uni0331' : 817,
- 'uni0330' : 816,
- 'uni01C1' : 449,
- 'uni01C0' : 448,
- 'uni01C3' : 451,
- 'uni01C2' : 450,
- 'uni2353' : 9043,
- 'uni0308' : 776,
- 'uni2218' : 8728,
- 'uni2219' : 8729,
- 'uni2216' : 8726,
- 'uni2217' : 8727,
- 'uni2214' : 8724,
- 'uni0309' : 777,
- 'uni2609' : 9737,
- 'uni2213' : 8723,
- 'uni2210' : 8720,
- 'uni2211' : 8721,
- 'uni2245' : 8773,
- 'B' : 66,
- 'uni25D6' : 9686,
- 'iacute' : 237,
- 'uni02E6' : 742,
- 'uni02E7' : 743,
- 'uni02E8' : 744,
- 'uni02E9' : 745,
- 'uni221D' : 8733,
- 'uni221E' : 8734,
- 'Ydieresis' : 376,
- 'uni221C' : 8732,
- 'uni22D7' : 8919,
- 'uni221A' : 8730,
- 'R' : 82,
- 'uni24DC' : 9436,
- 'uni033F' : 831,
- 'uni033E' : 830,
- 'uni033C' : 828,
- 'uni033B' : 827,
- 'uni033A' : 826,
- 'b' : 98,
- 'uni228A' : 8842,
- 'uni22DB' : 8923,
- 'uni2554' : 9556,
- 'uni046B' : 1131,
- 'uni046A' : 1130,
- 'r' : 114,
- 'uni24DB' : 9435,
- 'Ccedilla' : 199,
- 'minus' : 8722,
- 'uni24DA' : 9434,
- 'uni03F0' : 1008,
- 'uni03F1' : 1009,
- 'uni20AC' : 8364,
- 'uni2276' : 8822,
- 'uni24C0' : 9408,
- 'uni0162' : 354,
- 'uni0163' : 355,
- 'uni011E' : 286,
- 'uni011D' : 285,
- 'uni011C' : 284,
- 'uni011B' : 283,
- 'uni0164' : 356,
- 'uni0165' : 357,
- 'Lslash' : 321,
- 'uni0168' : 360,
- 'uni0169' : 361,
- 'uni25C9' : 9673,
- 'uni02E5' : 741,
- 'uni21C3' : 8643,
- 'uni24C4' : 9412,
- 'uni24E2' : 9442,
- 'uni2277' : 8823,
- 'uni013A' : 314,
- 'uni2102' : 8450,
- 'Uacute' : 218,
- 'uni2317' : 8983,
- 'uni2107' : 8455,
- 'uni221F' : 8735,
- 'yacute' : 253,
- 'uni3012' : 12306,
- 'Ucircumflex' : 219,
- 'uni015D' : 349,
- 'quotedbl' : 34,
- 'uni25D9' : 9689,
- 'uni2280' : 8832,
- 'uni22AF' : 8879,
- 'onehalf' : 189,
- 'uni221B' : 8731,
- 'Thorn' : 222,
- 'uni2226' : 8742,
- 'M' : 77,
- 'uni25BA' : 9658,
- 'uni2463' : 9315,
- 'uni2336' : 9014,
- 'eight' : 56,
- 'uni2236' : 8758,
- 'multiply' : 215,
- 'uni210C' : 8460,
- 'uni210A' : 8458,
- 'uni21C9' : 8649,
- 'grave' : 96,
- 'uni210E' : 8462,
- 'uni0117' : 279,
- 'uni016C' : 364,
- 'uni0115' : 277,
- 'uni016A' : 362,
- 'uni016F' : 367,
- 'uni0112' : 274,
- 'uni016D' : 365,
- 'uni016E' : 366,
- 'Ocircumflex' : 212,
- 'uni2305' : 8965,
- 'm' : 109,
- 'uni24DF' : 9439,
- 'uni0119' : 281,
- 'uni0118' : 280,
- 'uni20A3' : 8355,
- 'uni20A4' : 8356,
- 'uni20A7' : 8359,
- 'uni2288' : 8840,
- 'uni24C3' : 9411,
- 'uni251C' : 9500,
- 'uni228D' : 8845,
- 'uni222F' : 8751,
- 'uni222E' : 8750,
- 'uni222D' : 8749,
- 'uni222C' : 8748,
- 'uni222B' : 8747,
- 'uni222A' : 8746,
- 'uni255B' : 9563,
- 'Ugrave' : 217,
- 'uni24DE' : 9438,
- 'guilsinglright' : 8250,
- 'uni250A' : 9482,
- 'Ntilde' : 209,
- 'uni0279' : 633,
- 'questiondown' : 191,
- 'uni256C' : 9580,
- 'Atilde' : 195,
- 'uni0272' : 626,
- 'uni0273' : 627,
- 'uni0270' : 624,
- 'ccedilla' : 231,
- 'uni0276' : 630,
- 'uni0277' : 631,
- 'uni0274' : 628,
- 'uni0275' : 629,
- 'uni2252' : 8786,
- 'uni041F' : 1055,
- 'uni2250' : 8784,
- 'Z' : 90,
- 'uni2256' : 8790,
- 'uni2257' : 8791,
- 'copyright' : 169,
- 'uni2255' : 8789,
- 'uni043D' : 1085,
- 'uni043E' : 1086,
- 'uni043F' : 1087,
- 'yen' : 165,
- 'uni041D' : 1053,
- 'uni043B' : 1083,
- 'uni043C' : 1084,
- 'uni21B0' : 8624,
- 'uni21B1' : 8625,
- 'uni21B2' : 8626,
- 'uni21B3' : 8627,
- 'uni21B4' : 8628,
- 'uni21B5' : 8629,
- 'uni21B6' : 8630,
- 'uni21B7' : 8631,
- 'uni21B8' : 8632,
- 'Eacute' : 201,
- 'uni2311' : 8977,
- 'uni2310' : 8976,
- 'uni228F' : 8847,
- 'uni25DB' : 9691,
- 'uni21BA' : 8634,
- 'uni21BB' : 8635,
- 'uni21BC' : 8636,
- 'uni2017' : 8215,
- 'uni21BE' : 8638,
- 'uni21BF' : 8639,
- 'uni231C' : 8988,
- 'H' : 72,
- 'uni0293' : 659,
- 'uni2202' : 8706,
- 'uni22A4' : 8868,
- 'uni231E' : 8990,
- 'uni2232' : 8754,
- 'uni225B' : 8795,
- 'uni225C' : 8796,
- 'uni24D9' : 9433,
- 'uni225A' : 8794,
- 'uni0438' : 1080,
- 'uni0439' : 1081,
- 'uni225D' : 8797,
- 'uni225E' : 8798,
- 'uni0434' : 1076,
- 'X' : 88,
- 'uni007F' : 127,
- 'uni0437' : 1079,
- 'Idieresis' : 207,
- 'uni0431' : 1073,
- 'uni0432' : 1074,
- 'uni0433' : 1075,
- 'uni22AC' : 8876,
- 'uni22CD' : 8909,
- 'uni25A3' : 9635,
- 'bar' : 124,
- 'uni24BB' : 9403,
- 'uni037E' : 894,
- 'uni027B' : 635,
- 'h' : 104,
- 'uni027A' : 634,
- 'uni027F' : 639,
- 'uni027D' : 637,
- 'uni027E' : 638,
- 'uni2227' : 8743,
- 'uni2004' : 8196,
- 'uni2225' : 8741,
- 'uni2224' : 8740,
- 'uni2223' : 8739,
- 'uni2222' : 8738,
- 'uni2221' : 8737,
- 'uni2220' : 8736,
- 'x' : 120,
- 'uni2323' : 8995,
- 'uni2559' : 9561,
- 'uni2558' : 9560,
- 'uni2229' : 8745,
- 'uni2228' : 8744,
- 'udieresis' : 252,
- 'uni029D' : 669,
- 'ordfeminine' : 170,
- 'uni22CB' : 8907,
- 'uni233D' : 9021,
- 'uni0428' : 1064,
- 'uni24C6' : 9414,
- 'uni22DD' : 8925,
- 'uni24C7' : 9415,
- 'uni015C' : 348,
- 'uni015B' : 347,
- 'uni015A' : 346,
- 'uni22AA' : 8874,
- 'uni015F' : 351,
- 'uni015E' : 350,
- 'braceleft' : 123,
- 'uni24C5' : 9413,
- 'uni0410' : 1040,
- 'uni03AA' : 938,
- 'uni24C2' : 9410,
- 'uni03AC' : 940,
- 'uni03AB' : 939,
- 'macron' : 175,
- 'uni03AD' : 941,
- 'uni03AF' : 943,
- 'uni0294' : 660,
- 'uni0295' : 661,
- 'uni0296' : 662,
- 'uni0297' : 663,
- 'uni0290' : 656,
- 'uni0291' : 657,
- 'uni0292' : 658,
- 'atilde' : 227,
- 'Acircumflex' : 194,
- 'uni2370' : 9072,
- 'uni24C1' : 9409,
- 'uni0298' : 664,
- 'uni0299' : 665,
- 'Oslash' : 216,
- 'uni029E' : 670,
- 'C' : 67,
- 'quotedblleft' : 8220,
- 'uni029B' : 667,
- 'uni029C' : 668,
- 'uni03A9' : 937,
- 'uni03A8' : 936,
- 'S' : 83,
- 'uni24C9' : 9417,
- 'uni03A1' : 929,
- 'uni03A0' : 928,
- 'exclam' : 33,
- 'uni03A5' : 933,
- 'uni03A4' : 932,
- 'uni03A7' : 935,
- 'Zcaron' : 381,
- 'uni2133' : 8499,
- 'uni2132' : 8498,
- 'uni0159' : 345,
- 'uni0158' : 344,
- 'uni2137' : 8503,
- 'uni2005' : 8197,
- 'uni2135' : 8501,
- 'uni2134' : 8500,
- 'uni02BA' : 698,
- 'uni2033' : 8243,
- 'uni0151' : 337,
- 'uni0150' : 336,
- 'uni0157' : 343,
- 'equal' : 61,
- 'uni0155' : 341,
- 'uni0154' : 340,
- 's' : 115,
- 'uni233F' : 9023,
- 'eth' : 240,
- 'uni24BE' : 9406,
- 'uni21E9' : 8681,
- 'uni2060' : 8288,
- 'Egrave' : 200,
- 'uni255D' : 9565,
- 'uni24CD' : 9421,
- 'uni21E1' : 8673,
- 'uni21B9' : 8633,
- 'hyphen' : 45,
- 'uni01BE' : 446,
- 'uni01BB' : 443,
- 'period' : 46,
- 'igrave' : 236,
- 'uni01BA' : 442,
- 'uni2296' : 8854,
- 'uni2297' : 8855,
- 'uni2294' : 8852,
- 'uni2295' : 8853,
- 'colon' : 58,
- 'uni2293' : 8851,
- 'uni2290' : 8848,
- 'uni2291' : 8849,
- 'uni032D' : 813,
- 'uni032E' : 814,
- 'uni032F' : 815,
- 'uni032A' : 810,
- 'uni032B' : 811,
- 'uni032C' : 812,
- 'uni231D' : 8989,
- 'Ecircumflex' : 202,
- 'uni24D7' : 9431,
- 'uni25DD' : 9693,
- 'trademark' : 8482,
- 'Aacute' : 193,
- 'cent' : 162,
- 'uni0445' : 1093,
- 'uni266E' : 9838,
- 'uni266D' : 9837,
- 'uni266B' : 9835,
- 'uni03C9' : 969,
- 'uni2003' : 8195,
- 'uni2047' : 8263,
- 'lslash' : 322,
- 'uni03A6' : 934,
- 'uni2043' : 8259,
- 'uni250C' : 9484,
- 'uni2040' : 8256,
- 'uni255F' : 9567,
- 'uni24CB' : 9419,
- 'uni0472' : 1138,
- 'uni0446' : 1094,
- 'uni0474' : 1140,
- 'uni0475' : 1141,
- 'uni2508' : 9480,
- 'uni2660' : 9824,
- 'uni2506' : 9478,
- 'uni2502' : 9474,
- 'c' : 99,
- 'uni2500' : 9472,
- 'N' : 78,
- 'uni22A6' : 8870,
- 'uni21E7' : 8679,
- 'uni2130' : 8496,
- 'uni2002' : 8194,
- 'breve' : 728,
- 'uni0442' : 1090,
- 'Oacute' : 211,
- 'uni229F' : 8863,
- 'uni25C7' : 9671,
- 'uni229D' : 8861,
- 'uni229E' : 8862,
- 'guillemotleft' : 171,
- 'uni0329' : 809,
- 'uni24E5' : 9445,
- 'uni011F' : 287,
- 'uni0324' : 804,
- 'uni0325' : 805,
- 'uni0326' : 806,
- 'uni0327' : 807,
- 'uni0321' : 801,
- 'uni0322' : 802,
- 'n' : 110,
- 'uni2032' : 8242,
- 'uni2269' : 8809,
- 'uni2268' : 8808,
- 'uni0306' : 774,
- 'uni226B' : 8811,
- 'uni21EA' : 8682,
- 'uni0166' : 358,
- 'uni203B' : 8251,
- 'uni01B5' : 437,
- 'idieresis' : 239,
- 'uni02BC' : 700,
- 'uni01B0' : 432,
- 'braceright' : 125,
- 'seven' : 55,
- 'uni02BB' : 699,
- 'uni011A' : 282,
- 'uni29FB' : 10747,
- 'brokenbar' : 166,
- 'uni2036' : 8246,
- 'uni25C0' : 9664,
- 'uni0156' : 342,
- 'uni22D5' : 8917,
- 'uni0258' : 600,
- 'ugrave' : 249,
- 'uni22D6' : 8918,
- 'uni22D1' : 8913,
- 'uni2034' : 8244,
- 'uni22D3' : 8915,
- 'uni22D2' : 8914,
- 'uni203C' : 8252,
- 'uni223E' : 8766,
- 'uni02BF' : 703,
- 'uni22D9' : 8921,
- 'uni22D8' : 8920,
- 'uni25BD' : 9661,
- 'uni25BE' : 9662,
- 'uni25BF' : 9663,
- 'uni041B' : 1051,
- 'periodcentered' : 183,
- 'uni25BC' : 9660,
- 'uni019E' : 414,
- 'uni019B' : 411,
- 'uni019A' : 410,
- 'uni2007' : 8199,
- 'uni0391' : 913,
- 'uni0390' : 912,
- 'uni0393' : 915,
- 'uni0392' : 914,
- 'uni0395' : 917,
- 'uni0394' : 916,
- 'uni0397' : 919,
- 'uni0396' : 918,
- 'uni0399' : 921,
- 'uni0398' : 920,
- 'uni25C8' : 9672,
- 'uni2468' : 9320,
- 'sterling' : 163,
- 'uni22EB' : 8939,
- 'uni039C' : 924,
- 'uni039B' : 923,
- 'uni039E' : 926,
- 'uni039D' : 925,
- 'uni039F' : 927,
- 'I' : 73,
- 'uni03E1' : 993,
- 'uni03E0' : 992,
- 'uni2319' : 8985,
- 'uni228B' : 8843,
- 'uni25B5' : 9653,
- 'uni25B6' : 9654,
- 'uni22EA' : 8938,
- 'uni24B9' : 9401,
- 'uni044E' : 1102,
- 'uni0199' : 409,
- 'uni2266' : 8806,
- 'Y' : 89,
- 'uni22A2' : 8866,
- 'Eth' : 208,
- 'uni266F' : 9839,
- 'emdash' : 8212,
- 'uni263B' : 9787,
- 'uni24BD' : 9405,
- 'uni22DE' : 8926,
- 'uni0360' : 864,
- 'uni2557' : 9559,
- 'uni22DF' : 8927,
- 'uni22DA' : 8922,
- 'uni22DC' : 8924,
- 'uni0361' : 865,
- 'i' : 105,
- 'uni24BF' : 9407,
- 'uni0362' : 866,
- 'uni263E' : 9790,
- 'uni028D' : 653,
- 'uni2259' : 8793,
- 'uni0323' : 803,
- 'uni2265' : 8805,
- 'daggerdbl' : 8225,
- 'y' : 121,
- 'uni010A' : 266,
- 'plusminus' : 177,
- 'less' : 60,
- 'uni21AE' : 8622,
- 'uni0315' : 789,
- 'uni230B' : 8971,
- 'uni21AF' : 8623,
- 'uni21AA' : 8618,
- 'uni21AC' : 8620,
- 'uni21AB' : 8619,
- 'uni01FB' : 507,
- 'uni01FC' : 508,
- 'uni223A' : 8762,
- 'uni01FA' : 506,
- 'uni01FF' : 511,
- 'uni01FD' : 509,
- 'uni01FE' : 510,
- 'uni2567' : 9575,
- 'uni25E0' : 9696,
- 'uni0104' : 260,
- 'uni0105' : 261,
- 'uni0106' : 262,
- 'uni0107' : 263,
- 'uni0100' : 256,
- 'uni0101' : 257,
- 'uni0102' : 258,
- 'uni0103' : 259,
- 'uni2038' : 8248,
- 'uni2009' : 8201,
- 'uni2008' : 8200,
- 'uni0108' : 264,
- 'uni0109' : 265,
- 'uni02A1' : 673,
- 'uni223B' : 8763,
- 'uni226C' : 8812,
- 'uni25AC' : 9644,
- 'uni24D3' : 9427,
- 'uni21E0' : 8672,
- 'uni21E3' : 8675,
- 'Udieresis' : 220,
- 'uni21E2' : 8674,
- 'D' : 68,
- 'uni21E5' : 8677,
- 'uni2621' : 9761,
- 'uni21D1' : 8657,
- 'uni203E' : 8254,
- 'uni22C6' : 8902,
- 'uni21E4' : 8676,
- 'uni010D' : 269,
- 'uni010E' : 270,
- 'uni010F' : 271,
- 'five' : 53,
- 'T' : 84,
- 'uni010B' : 267,
- 'uni010C' : 268,
- 'uni2605' : 9733,
- 'uni2663' : 9827,
- 'uni21E6' : 8678,
- 'uni24B6' : 9398,
- 'uni22C1' : 8897,
- 'oslash' : 248,
- 'acute' : 180,
- 'uni01F0' : 496,
- 'd' : 100,
- 'OE' : 338,
- 'uni22E3' : 8931,
- 'Igrave' : 204,
- 'uni2308' : 8968,
- 'uni2309' : 8969,
- 'uni21A9' : 8617,
- 't' : 116,
- 'uni2313' : 8979,
- 'uni03A3' : 931,
- 'uni21A4' : 8612,
- 'uni21A7' : 8615,
- 'uni21A6' : 8614,
- 'uni21A1' : 8609,
- 'uni21A0' : 8608,
- 'uni21A3' : 8611,
- 'uni21A2' : 8610,
- 'parenright' : 41,
- 'uni256A' : 9578,
- 'uni25DC' : 9692,
- 'uni24CE' : 9422,
- 'uni042C' : 1068,
- 'uni24E0' : 9440,
- 'uni042B' : 1067,
- 'uni0409' : 1033,
- 'uni0408' : 1032,
- 'uni24E7' : 9447,
- 'uni25B4' : 9652,
- 'uni042A' : 1066,
- 'uni228E' : 8846,
- 'uni0401' : 1025,
- 'adieresis' : 228,
- 'uni0403' : 1027,
- 'quotesingle' : 39,
- 'uni0405' : 1029,
- 'uni0404' : 1028,
- 'uni0407' : 1031,
- 'uni0406' : 1030,
- 'uni229C' : 8860,
- 'uni2306' : 8966,
- 'uni2253' : 8787,
- 'twodotenleader' : 8229,
- 'uni2131' : 8497,
- 'uni21DA' : 8666,
- 'uni2234' : 8756,
- 'uni2235' : 8757,
- 'uni01A5' : 421,
- 'uni2237' : 8759,
- 'uni2230' : 8752,
- 'uni02CC' : 716,
- 'slash' : 47,
- 'uni01A0' : 416,
- 'ellipsis' : 8230,
- 'uni2299' : 8857,
- 'uni2238' : 8760,
- 'numbersign' : 35,
- 'uni21A8' : 8616,
- 'uni223D' : 8765,
- 'uni01AF' : 431,
- 'uni223F' : 8767,
- 'uni01AD' : 429,
- 'uni01AB' : 427,
- 'odieresis' : 246,
- 'uni223C' : 8764,
- 'uni227D' : 8829,
- 'uni0280' : 640,
- 'O' : 79,
- 'uni227E' : 8830,
- 'uni21A5' : 8613,
- 'uni22D4' : 8916,
- 'uni25D4' : 9684,
- 'uni227F' : 8831,
- 'uni0435' : 1077,
- 'uni2302' : 8962,
- 'uni2669' : 9833,
- 'uni24E3' : 9443,
- 'uni2720' : 10016,
- 'uni22A8' : 8872,
- 'uni22A9' : 8873,
- 'uni040A' : 1034,
- 'uni22A7' : 8871,
- 'oe' : 339,
- 'uni040B' : 1035,
- 'uni040E' : 1038,
- 'uni22A3' : 8867,
- 'o' : 111,
- 'uni040F' : 1039,
- 'Edieresis' : 203,
- 'uni25D5' : 9685,
- 'plus' : 43,
- 'uni044D' : 1101,
- 'uni263C' : 9788,
- 'uni22E6' : 8934,
- 'uni2283' : 8835,
- 'uni258C' : 9612,
- 'uni219E' : 8606,
- 'uni24E4' : 9444,
- 'uni2136' : 8502,
- 'dagger' : 8224,
- 'uni24B7' : 9399,
- 'uni219B' : 8603,
- 'uni22E5' : 8933,
- 'three' : 51,
- 'uni210B' : 8459,
- 'uni2534' : 9524,
- 'uni24B8' : 9400,
- 'uni230A' : 8970,
- 'hungarumlaut' : 733,
- 'parenleft' : 40,
- 'uni0148' : 328,
- 'uni0149' : 329,
- 'uni2124' : 8484,
- 'uni2125' : 8485,
- 'uni2126' : 8486,
- 'uni2127' : 8487,
- 'uni0140' : 320,
- 'uni2129' : 8489,
- 'uni25C5' : 9669,
- 'uni0143' : 323,
- 'uni0144' : 324,
- 'uni0145' : 325,
- 'uni0146' : 326,
- 'uni0147' : 327,
- 'uni210D' : 8461,
- 'fraction' : 8260,
- 'uni2031' : 8241,
- 'uni2196' : 8598,
- 'uni2035' : 8245,
- 'uni24E6' : 9446,
- 'uni016B' : 363,
- 'uni24BA' : 9402,
- 'uni266A' : 9834,
- 'uni0116' : 278,
- 'uni2115' : 8469,
- 'registered' : 174,
- 'J' : 74,
- 'uni25DF' : 9695,
- 'uni25CE' : 9678,
- 'uni273D' : 10045,
- 'dieresis' : 168,
- 'uni212B' : 8491,
- 'uni0114' : 276,
- 'uni212D' : 8493,
- 'uni212E' : 8494,
- 'uni212F' : 8495,
- 'uni014A' : 330,
- 'uni014B' : 331,
- 'uni014C' : 332,
- 'uni014D' : 333,
- 'uni014E' : 334,
- 'uni014F' : 335,
- 'uni025E' : 606,
- 'uni24E8' : 9448,
- 'uni0111' : 273,
- 'uni24E9' : 9449,
- 'Ograve' : 210,
- 'j' : 106,
- 'uni2195' : 8597,
- 'uni2194' : 8596,
- 'uni2197' : 8599,
- 'uni2037' : 8247,
- 'uni2191' : 8593,
- 'uni2190' : 8592,
- 'uni2193' : 8595,
- 'uni2192' : 8594,
- 'uni29FA' : 10746,
- 'uni2713' : 10003,
- 'z' : 122,
- 'uni2199' : 8601,
- 'uni2198' : 8600,
- 'uni2667' : 9831,
- 'ae' : 230,
- 'uni0448' : 1096,
- 'semicolon' : 59,
- 'uni2666' : 9830,
- 'uni038F' : 911,
- 'uni0444' : 1092,
- 'uni0447' : 1095,
- 'uni038E' : 910,
- 'uni0441' : 1089,
- 'uni038C' : 908,
- 'uni0443' : 1091,
- 'uni038A' : 906,
- 'uni0250' : 592,
- 'uni0251' : 593,
- 'uni0252' : 594,
- 'uni0253' : 595,
- 'uni0254' : 596,
- 'at' : 64,
- 'uni0256' : 598,
- 'uni0257' : 599,
- 'uni0167' : 359,
- 'uni0259' : 601,
- 'uni228C' : 8844,
- 'uni2662' : 9826,
- 'uni0319' : 793,
- 'uni0318' : 792,
- 'uni24BC' : 9404,
- 'uni0402' : 1026,
- 'uni22EF' : 8943,
- 'Iacute' : 205,
- 'uni22ED' : 8941,
- 'uni22EE' : 8942,
- 'uni0311' : 785,
- 'uni0310' : 784,
- 'uni21E8' : 8680,
- 'uni0312' : 786,
- 'percent' : 37,
- 'uni0317' : 791,
- 'uni0316' : 790,
- 'uni21D6' : 8662,
- 'uni21D7' : 8663,
- 'uni21D4' : 8660,
- 'uni21D5' : 8661,
- 'uni21D2' : 8658,
- 'uni21D3' : 8659,
- 'uni21D0' : 8656,
- 'uni2138' : 8504,
- 'uni2270' : 8816,
- 'uni2271' : 8817,
- 'uni2272' : 8818,
- 'uni2273' : 8819,
- 'uni2274' : 8820,
- 'uni2275' : 8821,
- 'bracketright' : 93,
- 'uni21D9' : 8665,
- 'uni21DF' : 8671,
- 'uni21DD' : 8669,
- 'uni21DE' : 8670,
- 'AE' : 198,
- 'uni03AE' : 942,
- 'uni227A' : 8826,
- 'uni227B' : 8827,
- 'uni227C' : 8828,
- 'asterisk' : 42,
- 'aacute' : 225,
- 'uni226F' : 8815,
- 'uni22E2' : 8930,
- 'uni0386' : 902,
- 'uni22E0' : 8928,
- 'uni22E1' : 8929,
- 'U' : 85,
- 'uni22E7' : 8935,
- 'uni22E4' : 8932,
- 'uni0387' : 903,
- 'uni031A' : 794,
- 'eacute' : 233,
- 'uni22E8' : 8936,
- 'uni22E9' : 8937,
- 'uni24D8' : 9432,
- 'uni025A' : 602,
- 'uni025B' : 603,
- 'uni025C' : 604,
- 'e' : 101,
- 'uni0128' : 296,
- 'uni025F' : 607,
- 'uni2665' : 9829,
- 'thorn' : 254,
- 'uni0129' : 297,
- 'uni253C' : 9532,
- 'uni25D7' : 9687,
- 'u' : 117,
- 'uni0388' : 904,
- 'uni0389' : 905,
- 'uni0255' : 597,
- 'uni0171' : 369,
- 'uni0384' : 900,
- 'uni0385' : 901,
- 'uni044A' : 1098,
- 'uni252C' : 9516,
- 'uni044C' : 1100,
- 'uni044B' : 1099
-}
-
-uni2type1 = {v: k for k, v in type12uni.items()}
-
-tex2uni = {
- 'widehat' : 0x0302,
- 'widetilde' : 0x0303,
- 'widebar' : 0x0305,
- 'langle' : 0x27e8,
- 'rangle' : 0x27e9,
- 'perp' : 0x27c2,
- 'neq' : 0x2260,
- 'Join' : 0x2a1d,
- 'leqslant' : 0x2a7d,
- 'geqslant' : 0x2a7e,
- 'lessapprox' : 0x2a85,
- 'gtrapprox' : 0x2a86,
- 'lesseqqgtr' : 0x2a8b,
- 'gtreqqless' : 0x2a8c,
- 'triangleeq' : 0x225c,
- 'eqslantless' : 0x2a95,
- 'eqslantgtr' : 0x2a96,
- 'backepsilon' : 0x03f6,
- 'precapprox' : 0x2ab7,
- 'succapprox' : 0x2ab8,
- 'fallingdotseq' : 0x2252,
- 'subseteqq' : 0x2ac5,
- 'supseteqq' : 0x2ac6,
- 'varpropto' : 0x221d,
- 'precnapprox' : 0x2ab9,
- 'succnapprox' : 0x2aba,
- 'subsetneqq' : 0x2acb,
- 'supsetneqq' : 0x2acc,
- 'lnapprox' : 0x2ab9,
- 'gnapprox' : 0x2aba,
- 'longleftarrow' : 0x27f5,
- 'longrightarrow' : 0x27f6,
- 'longleftrightarrow' : 0x27f7,
- 'Longleftarrow' : 0x27f8,
- 'Longrightarrow' : 0x27f9,
- 'Longleftrightarrow' : 0x27fa,
- 'longmapsto' : 0x27fc,
- 'leadsto' : 0x21dd,
- 'dashleftarrow' : 0x290e,
- 'dashrightarrow' : 0x290f,
- 'circlearrowleft' : 0x21ba,
- 'circlearrowright' : 0x21bb,
- 'leftrightsquigarrow' : 0x21ad,
- 'leftsquigarrow' : 0x219c,
- 'rightsquigarrow' : 0x219d,
- 'Game' : 0x2141,
- 'hbar' : 0x0127,
- 'hslash' : 0x210f,
- 'ldots' : 0x2026,
- 'vdots' : 0x22ee,
- 'doteqdot' : 0x2251,
- 'doteq' : 8784,
- 'partial' : 8706,
- 'gg' : 8811,
- 'asymp' : 8781,
- 'blacktriangledown' : 9662,
- 'otimes' : 8855,
- 'nearrow' : 8599,
- 'varpi' : 982,
- 'vee' : 8744,
- 'vec' : 8407,
- 'smile' : 8995,
- 'succnsim' : 8937,
- 'gimel' : 8503,
- 'vert' : 124,
- '|' : 124,
- 'varrho' : 1009,
- 'P' : 182,
- 'approxident' : 8779,
- 'Swarrow' : 8665,
- 'textasciicircum' : 94,
- 'imageof' : 8887,
- 'ntriangleleft' : 8938,
- 'nleq' : 8816,
- 'div' : 247,
- 'nparallel' : 8742,
- 'Leftarrow' : 8656,
- 'lll' : 8920,
- 'oiint' : 8751,
- 'ngeq' : 8817,
- 'Theta' : 920,
- 'origof' : 8886,
- 'blacksquare' : 9632,
- 'solbar' : 9023,
- 'neg' : 172,
- 'sum' : 8721,
- 'Vdash' : 8873,
- 'coloneq' : 8788,
- 'degree' : 176,
- 'bowtie' : 8904,
- 'blacktriangleright' : 9654,
- 'varsigma' : 962,
- 'leq' : 8804,
- 'ggg' : 8921,
- 'lneqq' : 8808,
- 'scurel' : 8881,
- 'stareq' : 8795,
- 'BbbN' : 8469,
- 'nLeftarrow' : 8653,
- 'nLeftrightarrow' : 8654,
- 'k' : 808,
- 'bot' : 8869,
- 'BbbC' : 8450,
- 'Lsh' : 8624,
- 'leftleftarrows' : 8647,
- 'BbbZ' : 8484,
- 'digamma' : 989,
- 'BbbR' : 8477,
- 'BbbP' : 8473,
- 'BbbQ' : 8474,
- 'vartriangleright' : 8883,
- 'succsim' : 8831,
- 'wedge' : 8743,
- 'lessgtr' : 8822,
- 'veebar' : 8891,
- 'mapsdown' : 8615,
- 'Rsh' : 8625,
- 'chi' : 967,
- 'prec' : 8826,
- 'nsubseteq' : 8840,
- 'therefore' : 8756,
- 'eqcirc' : 8790,
- 'textexclamdown' : 161,
- 'nRightarrow' : 8655,
- 'flat' : 9837,
- 'notin' : 8713,
- 'llcorner' : 8990,
- 'varepsilon' : 949,
- 'bigtriangleup' : 9651,
- 'aleph' : 8501,
- 'dotminus' : 8760,
- 'upsilon' : 965,
- 'Lambda' : 923,
- 'cap' : 8745,
- 'barleftarrow' : 8676,
- 'mu' : 956,
- 'boxplus' : 8862,
- 'mp' : 8723,
- 'circledast' : 8859,
- 'tau' : 964,
- 'in' : 8712,
- 'backslash' : 92,
- 'varnothing' : 8709,
- 'sharp' : 9839,
- 'eqsim' : 8770,
- 'gnsim' : 8935,
- 'Searrow' : 8664,
- 'updownarrows' : 8645,
- 'heartsuit' : 9825,
- 'trianglelefteq' : 8884,
- 'ddag' : 8225,
- 'sqsubseteq' : 8849,
- 'mapsfrom' : 8612,
- 'boxbar' : 9707,
- 'sim' : 8764,
- 'Nwarrow' : 8662,
- 'nequiv' : 8802,
- 'succ' : 8827,
- 'vdash' : 8866,
- 'Leftrightarrow' : 8660,
- 'parallel' : 8741,
- 'invnot' : 8976,
- 'natural' : 9838,
- 'ss' : 223,
- 'uparrow' : 8593,
- 'nsim' : 8769,
- 'hookrightarrow' : 8618,
- 'Equiv' : 8803,
- 'approx' : 8776,
- 'Vvdash' : 8874,
- 'nsucc' : 8833,
- 'leftrightharpoons' : 8651,
- 'Re' : 8476,
- 'boxminus' : 8863,
- 'equiv' : 8801,
- 'Lleftarrow' : 8666,
- 'll' : 8810,
- 'Cup' : 8915,
- 'measeq' : 8798,
- 'upharpoonleft' : 8639,
- 'lq' : 8216,
- 'Upsilon' : 933,
- 'subsetneq' : 8842,
- 'greater' : 62,
- 'supsetneq' : 8843,
- 'Cap' : 8914,
- 'L' : 321,
- 'spadesuit' : 9824,
- 'lrcorner' : 8991,
- 'not' : 824,
- 'bar' : 772,
- 'rightharpoonaccent' : 8401,
- 'boxdot' : 8865,
- 'l' : 322,
- 'leftharpoondown' : 8637,
- 'bigcup' : 8899,
- 'iint' : 8748,
- 'bigwedge' : 8896,
- 'downharpoonleft' : 8643,
- 'textasciitilde' : 126,
- 'subset' : 8834,
- 'leqq' : 8806,
- 'mapsup' : 8613,
- 'nvDash' : 8877,
- 'looparrowleft' : 8619,
- 'nless' : 8814,
- 'rightarrowbar' : 8677,
- 'Vert' : 8214,
- 'downdownarrows' : 8650,
- 'uplus' : 8846,
- 'simeq' : 8771,
- 'napprox' : 8777,
- 'ast' : 8727,
- 'twoheaduparrow' : 8607,
- 'doublebarwedge' : 8966,
- 'Sigma' : 931,
- 'leftharpoonaccent' : 8400,
- 'ntrianglelefteq' : 8940,
- 'nexists' : 8708,
- 'times' : 215,
- 'measuredangle' : 8737,
- 'bumpeq' : 8783,
- 'carriagereturn' : 8629,
- 'adots' : 8944,
- 'checkmark' : 10003,
- 'lambda' : 955,
- 'xi' : 958,
- 'rbrace' : 125,
- 'rbrack' : 93,
- 'Nearrow' : 8663,
- 'maltese' : 10016,
- 'clubsuit' : 9827,
- 'top' : 8868,
- 'overarc' : 785,
- 'varphi' : 966,
- 'Delta' : 916,
- 'iota' : 953,
- 'nleftarrow' : 8602,
- 'candra' : 784,
- 'supset' : 8835,
- 'triangleleft' : 9665,
- 'gtreqless' : 8923,
- 'ntrianglerighteq' : 8941,
- 'quad' : 8195,
- 'Xi' : 926,
- 'gtrdot' : 8919,
- 'leftthreetimes' : 8907,
- 'minus' : 8722,
- 'preccurlyeq' : 8828,
- 'nleftrightarrow' : 8622,
- 'lambdabar' : 411,
- 'blacktriangle' : 9652,
- 'kernelcontraction' : 8763,
- 'Phi' : 934,
- 'angle' : 8736,
- 'spadesuitopen' : 9828,
- 'eqless' : 8924,
- 'mid' : 8739,
- 'varkappa' : 1008,
- 'Ldsh' : 8626,
- 'updownarrow' : 8597,
- 'beta' : 946,
- 'textquotedblleft' : 8220,
- 'rho' : 961,
- 'alpha' : 945,
- 'intercal' : 8890,
- 'beth' : 8502,
- 'grave' : 768,
- 'acwopencirclearrow' : 8634,
- 'nmid' : 8740,
- 'nsupset' : 8837,
- 'sigma' : 963,
- 'dot' : 775,
- 'Rightarrow' : 8658,
- 'turnednot' : 8985,
- 'backsimeq' : 8909,
- 'leftarrowtail' : 8610,
- 'approxeq' : 8778,
- 'curlyeqsucc' : 8927,
- 'rightarrowtail' : 8611,
- 'Psi' : 936,
- 'copyright' : 169,
- 'yen' : 165,
- 'vartriangleleft' : 8882,
- 'rasp' : 700,
- 'triangleright' : 9655,
- 'precsim' : 8830,
- 'infty' : 8734,
- 'geq' : 8805,
- 'updownarrowbar' : 8616,
- 'precnsim' : 8936,
- 'H' : 779,
- 'ulcorner' : 8988,
- 'looparrowright' : 8620,
- 'ncong' : 8775,
- 'downarrow' : 8595,
- 'circeq' : 8791,
- 'subseteq' : 8838,
- 'bigstar' : 9733,
- 'prime' : 8242,
- 'lceil' : 8968,
- 'Rrightarrow' : 8667,
- 'oiiint' : 8752,
- 'curlywedge' : 8911,
- 'vDash' : 8872,
- 'lfloor' : 8970,
- 'ddots' : 8945,
- 'exists' : 8707,
- 'underbar' : 817,
- 'Pi' : 928,
- 'leftrightarrows' : 8646,
- 'sphericalangle' : 8738,
- 'coprod' : 8720,
- 'circledcirc' : 8858,
- 'gtrsim' : 8819,
- 'gneqq' : 8809,
- 'between' : 8812,
- 'theta' : 952,
- 'complement' : 8705,
- 'arceq' : 8792,
- 'nVdash' : 8878,
- 'S' : 167,
- 'wr' : 8768,
- 'wp' : 8472,
- 'backcong' : 8780,
- 'lasp' : 701,
- 'c' : 807,
- 'nabla' : 8711,
- 'dotplus' : 8724,
- 'eta' : 951,
- 'forall' : 8704,
- 'eth' : 240,
- 'colon' : 58,
- 'sqcup' : 8852,
- 'rightrightarrows' : 8649,
- 'sqsupset' : 8848,
- 'mapsto' : 8614,
- 'bigtriangledown' : 9661,
- 'sqsupseteq' : 8850,
- 'propto' : 8733,
- 'pi' : 960,
- 'pm' : 177,
- 'dots' : 0x2026,
- 'nrightarrow' : 8603,
- 'textasciiacute' : 180,
- 'Doteq' : 8785,
- 'breve' : 774,
- 'sqcap' : 8851,
- 'twoheadrightarrow' : 8608,
- 'kappa' : 954,
- 'vartriangle' : 9653,
- 'diamondsuit' : 9826,
- 'pitchfork' : 8916,
- 'blacktriangleleft' : 9664,
- 'nprec' : 8832,
- 'curvearrowright' : 8631,
- 'barwedge' : 8892,
- 'multimap' : 8888,
- 'textquestiondown' : 191,
- 'cong' : 8773,
- 'rtimes' : 8906,
- 'rightzigzagarrow' : 8669,
- 'rightarrow' : 8594,
- 'leftarrow' : 8592,
- '__sqrt__' : 8730,
- 'twoheaddownarrow' : 8609,
- 'oint' : 8750,
- 'bigvee' : 8897,
- 'eqdef' : 8797,
- 'sterling' : 163,
- 'phi' : 981,
- 'Updownarrow' : 8661,
- 'backprime' : 8245,
- 'emdash' : 8212,
- 'Gamma' : 915,
- 'i' : 305,
- 'rceil' : 8969,
- 'leftharpoonup' : 8636,
- 'Im' : 8465,
- 'curvearrowleft' : 8630,
- 'wedgeq' : 8793,
- 'curlyeqprec' : 8926,
- 'questeq' : 8799,
- 'less' : 60,
- 'upuparrows' : 8648,
- 'tilde' : 771,
- 'textasciigrave' : 96,
- 'smallsetminus' : 8726,
- 'ell' : 8467,
- 'cup' : 8746,
- 'danger' : 9761,
- 'nVDash' : 8879,
- 'cdotp' : 183,
- 'cdots' : 8943,
- 'hat' : 770,
- 'eqgtr' : 8925,
- 'psi' : 968,
- 'frown' : 8994,
- 'acute' : 769,
- 'downzigzagarrow' : 8623,
- 'ntriangleright' : 8939,
- 'cupdot' : 8845,
- 'circleddash' : 8861,
- 'oslash' : 8856,
- 'mho' : 8487,
- 'd' : 803,
- 'sqsubset' : 8847,
- 'cdot' : 8901,
- 'Omega' : 937,
- 'OE' : 338,
- 'veeeq' : 8794,
- 'Finv' : 8498,
- 't' : 865,
- 'leftrightarrow' : 8596,
- 'swarrow' : 8601,
- 'rightthreetimes' : 8908,
- 'rightleftharpoons' : 8652,
- 'lesssim' : 8818,
- 'searrow' : 8600,
- 'because' : 8757,
- 'gtrless' : 8823,
- 'star' : 8902,
- 'nsubset' : 8836,
- 'zeta' : 950,
- 'dddot' : 8411,
- 'bigcirc' : 9675,
- 'Supset' : 8913,
- 'circ' : 8728,
- 'slash' : 8725,
- 'ocirc' : 778,
- 'prod' : 8719,
- 'twoheadleftarrow' : 8606,
- 'daleth' : 8504,
- 'upharpoonright' : 8638,
- 'odot' : 8857,
- 'Uparrow' : 8657,
- 'O' : 216,
- 'hookleftarrow' : 8617,
- 'trianglerighteq' : 8885,
- 'nsime' : 8772,
- 'oe' : 339,
- 'nwarrow' : 8598,
- 'o' : 248,
- 'ddddot' : 8412,
- 'downharpoonright' : 8642,
- 'succcurlyeq' : 8829,
- 'gamma' : 947,
- 'scrR' : 8475,
- 'dag' : 8224,
- 'thickspace' : 8197,
- 'frakZ' : 8488,
- 'lessdot' : 8918,
- 'triangledown' : 9663,
- 'ltimes' : 8905,
- 'scrB' : 8492,
- 'endash' : 8211,
- 'scrE' : 8496,
- 'scrF' : 8497,
- 'scrH' : 8459,
- 'scrI' : 8464,
- 'rightharpoondown' : 8641,
- 'scrL' : 8466,
- 'scrM' : 8499,
- 'frakC' : 8493,
- 'nsupseteq' : 8841,
- 'circledR' : 174,
- 'circledS' : 9416,
- 'ngtr' : 8815,
- 'bigcap' : 8898,
- 'scre' : 8495,
- 'Downarrow' : 8659,
- 'scrg' : 8458,
- 'overleftrightarrow' : 8417,
- 'scro' : 8500,
- 'lnsim' : 8934,
- 'eqcolon' : 8789,
- 'curlyvee' : 8910,
- 'urcorner' : 8989,
- 'lbrace' : 123,
- 'Bumpeq' : 8782,
- 'delta' : 948,
- 'boxtimes' : 8864,
- 'overleftarrow' : 8406,
- 'prurel' : 8880,
- 'clubsuitopen' : 9831,
- 'cwopencirclearrow' : 8635,
- 'geqq' : 8807,
- 'rightleftarrows' : 8644,
- 'ac' : 8766,
- 'ae' : 230,
- 'int' : 8747,
- 'rfloor' : 8971,
- 'risingdotseq' : 8787,
- 'nvdash' : 8876,
- 'diamond' : 8900,
- 'ddot' : 776,
- 'backsim' : 8765,
- 'oplus' : 8853,
- 'triangleq' : 8796,
- 'check' : 780,
- 'ni' : 8715,
- 'iiint' : 8749,
- 'ne' : 8800,
- 'lesseqgtr' : 8922,
- 'obar' : 9021,
- 'supseteq' : 8839,
- 'nu' : 957,
- 'AA' : 197,
- 'AE' : 198,
- 'models' : 8871,
- 'ominus' : 8854,
- 'dashv' : 8867,
- 'omega' : 969,
- 'rq' : 8217,
- 'Subset' : 8912,
- 'rightharpoonup' : 8640,
- 'Rdsh' : 8627,
- 'bullet' : 8729,
- 'divideontimes' : 8903,
- 'lbrack' : 91,
- 'textquotedblright' : 8221,
- 'Colon' : 8759,
- '%' : 37,
- '$' : 36,
- '{' : 123,
- '}' : 125,
- '_' : 95,
- '#' : 35,
- 'imath' : 0x131,
- 'circumflexaccent' : 770,
- 'combiningbreve' : 774,
- 'combiningoverline' : 772,
- 'combininggraveaccent' : 768,
- 'combiningacuteaccent' : 769,
- 'combiningdiaeresis' : 776,
- 'combiningtilde' : 771,
- 'combiningrightarrowabove' : 8407,
- 'combiningdotabove' : 775,
- 'to' : 8594,
- 'succeq' : 8829,
- 'emptyset' : 8709,
- 'leftparen' : 40,
- 'rightparen' : 41,
- 'bigoplus' : 10753,
- 'leftangle' : 10216,
- 'rightangle' : 10217,
- 'leftbrace' : 124,
- 'rightbrace' : 125,
- 'jmath' : 567,
- 'bigodot' : 10752,
- 'preceq' : 8828,
- 'biguplus' : 10756,
- 'epsilon' : 949,
- 'vartheta' : 977,
- 'bigotimes' : 10754,
- 'guillemotleft' : 171,
- 'ring' : 730,
- 'Thorn' : 222,
- 'guilsinglright' : 8250,
- 'perthousand' : 8240,
- 'macron' : 175,
- 'cent' : 162,
- 'guillemotright' : 187,
- 'equal' : 61,
- 'asterisk' : 42,
- 'guilsinglleft' : 8249,
- 'plus' : 43,
- 'thorn' : 254,
- 'dagger' : 8224
-}
-
-# Each element is a 4-tuple of the form:
-# src_start, src_end, dst_font, dst_start
-#
-stix_virtual_fonts = {
- 'bb':
- {
- 'rm':
- [
- (0x0030, 0x0039, 'rm', 0x1d7d8), # 0-9
- (0x0041, 0x0042, 'rm', 0x1d538), # A-B
- (0x0043, 0x0043, 'rm', 0x2102), # C
- (0x0044, 0x0047, 'rm', 0x1d53b), # D-G
- (0x0048, 0x0048, 'rm', 0x210d), # H
- (0x0049, 0x004d, 'rm', 0x1d540), # I-M
- (0x004e, 0x004e, 'rm', 0x2115), # N
- (0x004f, 0x004f, 'rm', 0x1d546), # O
- (0x0050, 0x0051, 'rm', 0x2119), # P-Q
- (0x0052, 0x0052, 'rm', 0x211d), # R
- (0x0053, 0x0059, 'rm', 0x1d54a), # S-Y
- (0x005a, 0x005a, 'rm', 0x2124), # Z
- (0x0061, 0x007a, 'rm', 0x1d552), # a-z
- (0x0393, 0x0393, 'rm', 0x213e), # \Gamma
- (0x03a0, 0x03a0, 'rm', 0x213f), # \Pi
- (0x03a3, 0x03a3, 'rm', 0x2140), # \Sigma
- (0x03b3, 0x03b3, 'rm', 0x213d), # \gamma
- (0x03c0, 0x03c0, 'rm', 0x213c), # \pi
- ],
- 'it':
- [
- (0x0030, 0x0039, 'rm', 0x1d7d8), # 0-9
- (0x0041, 0x0042, 'it', 0xe154), # A-B
- (0x0043, 0x0043, 'it', 0x2102), # C
- (0x0044, 0x0044, 'it', 0x2145), # D
- (0x0045, 0x0047, 'it', 0xe156), # E-G
- (0x0048, 0x0048, 'it', 0x210d), # H
- (0x0049, 0x004d, 'it', 0xe159), # I-M
- (0x004e, 0x004e, 'it', 0x2115), # N
- (0x004f, 0x004f, 'it', 0xe15e), # O
- (0x0050, 0x0051, 'it', 0x2119), # P-Q
- (0x0052, 0x0052, 'it', 0x211d), # R
- (0x0053, 0x0059, 'it', 0xe15f), # S-Y
- (0x005a, 0x005a, 'it', 0x2124), # Z
- (0x0061, 0x0063, 'it', 0xe166), # a-c
- (0x0064, 0x0065, 'it', 0x2146), # d-e
- (0x0066, 0x0068, 'it', 0xe169), # f-h
- (0x0069, 0x006a, 'it', 0x2148), # i-j
- (0x006b, 0x007a, 'it', 0xe16c), # k-z
- (0x0393, 0x0393, 'it', 0x213e), # \Gamma (not in beta STIX fonts)
- (0x03a0, 0x03a0, 'it', 0x213f), # \Pi
- (0x03a3, 0x03a3, 'it', 0x2140), # \Sigma (not in beta STIX fonts)
- (0x03b3, 0x03b3, 'it', 0x213d), # \gamma (not in beta STIX fonts)
- (0x03c0, 0x03c0, 'it', 0x213c), # \pi
- ],
- 'bf':
- [
- (0x0030, 0x0039, 'rm', 0x1d7d8), # 0-9
- (0x0041, 0x0042, 'bf', 0xe38a), # A-B
- (0x0043, 0x0043, 'bf', 0x2102), # C
- (0x0044, 0x0044, 'bf', 0x2145), # D
- (0x0045, 0x0047, 'bf', 0xe38d), # E-G
- (0x0048, 0x0048, 'bf', 0x210d), # H
- (0x0049, 0x004d, 'bf', 0xe390), # I-M
- (0x004e, 0x004e, 'bf', 0x2115), # N
- (0x004f, 0x004f, 'bf', 0xe395), # O
- (0x0050, 0x0051, 'bf', 0x2119), # P-Q
- (0x0052, 0x0052, 'bf', 0x211d), # R
- (0x0053, 0x0059, 'bf', 0xe396), # S-Y
- (0x005a, 0x005a, 'bf', 0x2124), # Z
- (0x0061, 0x0063, 'bf', 0xe39d), # a-c
- (0x0064, 0x0065, 'bf', 0x2146), # d-e
- (0x0066, 0x0068, 'bf', 0xe3a2), # f-h
- (0x0069, 0x006a, 'bf', 0x2148), # i-j
- (0x006b, 0x007a, 'bf', 0xe3a7), # k-z
- (0x0393, 0x0393, 'bf', 0x213e), # \Gamma
- (0x03a0, 0x03a0, 'bf', 0x213f), # \Pi
- (0x03a3, 0x03a3, 'bf', 0x2140), # \Sigma
- (0x03b3, 0x03b3, 'bf', 0x213d), # \gamma
- (0x03c0, 0x03c0, 'bf', 0x213c), # \pi
- ],
- },
- 'cal':
- [
- (0x0041, 0x005a, 'it', 0xe22d), # A-Z
- ],
- 'circled':
- {
- 'rm':
- [
- (0x0030, 0x0030, 'rm', 0x24ea), # 0
- (0x0031, 0x0039, 'rm', 0x2460), # 1-9
- (0x0041, 0x005a, 'rm', 0x24b6), # A-Z
- (0x0061, 0x007a, 'rm', 0x24d0) # a-z
- ],
- 'it':
- [
- (0x0030, 0x0030, 'rm', 0x24ea), # 0
- (0x0031, 0x0039, 'rm', 0x2460), # 1-9
- (0x0041, 0x005a, 'it', 0x24b6), # A-Z
- (0x0061, 0x007a, 'it', 0x24d0) # a-z
- ],
- 'bf':
- [
- (0x0030, 0x0030, 'bf', 0x24ea), # 0
- (0x0031, 0x0039, 'bf', 0x2460), # 1-9
- (0x0041, 0x005a, 'bf', 0x24b6), # A-Z
- (0x0061, 0x007a, 'bf', 0x24d0) # a-z
- ],
- },
- 'frak':
- {
- 'rm':
- [
- (0x0041, 0x0042, 'rm', 0x1d504), # A-B
- (0x0043, 0x0043, 'rm', 0x212d), # C
- (0x0044, 0x0047, 'rm', 0x1d507), # D-G
- (0x0048, 0x0048, 'rm', 0x210c), # H
- (0x0049, 0x0049, 'rm', 0x2111), # I
- (0x004a, 0x0051, 'rm', 0x1d50d), # J-Q
- (0x0052, 0x0052, 'rm', 0x211c), # R
- (0x0053, 0x0059, 'rm', 0x1d516), # S-Y
- (0x005a, 0x005a, 'rm', 0x2128), # Z
- (0x0061, 0x007a, 'rm', 0x1d51e), # a-z
- ],
- 'it':
- [
- (0x0041, 0x0042, 'rm', 0x1d504), # A-B
- (0x0043, 0x0043, 'rm', 0x212d), # C
- (0x0044, 0x0047, 'rm', 0x1d507), # D-G
- (0x0048, 0x0048, 'rm', 0x210c), # H
- (0x0049, 0x0049, 'rm', 0x2111), # I
- (0x004a, 0x0051, 'rm', 0x1d50d), # J-Q
- (0x0052, 0x0052, 'rm', 0x211c), # R
- (0x0053, 0x0059, 'rm', 0x1d516), # S-Y
- (0x005a, 0x005a, 'rm', 0x2128), # Z
- (0x0061, 0x007a, 'rm', 0x1d51e), # a-z
- ],
- 'bf':
- [
- (0x0041, 0x005a, 'bf', 0x1d56c), # A-Z
- (0x0061, 0x007a, 'bf', 0x1d586), # a-z
- ],
- },
- 'scr':
- [
- (0x0041, 0x0041, 'it', 0x1d49c), # A
- (0x0042, 0x0042, 'it', 0x212c), # B
- (0x0043, 0x0044, 'it', 0x1d49e), # C-D
- (0x0045, 0x0046, 'it', 0x2130), # E-F
- (0x0047, 0x0047, 'it', 0x1d4a2), # G
- (0x0048, 0x0048, 'it', 0x210b), # H
- (0x0049, 0x0049, 'it', 0x2110), # I
- (0x004a, 0x004b, 'it', 0x1d4a5), # J-K
- (0x004c, 0x004c, 'it', 0x2112), # L
- (0x004d, 0x004d, 'it', 0x2133), # M
- (0x004e, 0x0051, 'it', 0x1d4a9), # N-Q
- (0x0052, 0x0052, 'it', 0x211b), # R
- (0x0053, 0x005a, 'it', 0x1d4ae), # S-Z
- (0x0061, 0x0064, 'it', 0x1d4b6), # a-d
- (0x0065, 0x0065, 'it', 0x212f), # e
- (0x0066, 0x0066, 'it', 0x1d4bb), # f
- (0x0067, 0x0067, 'it', 0x210a), # g
- (0x0068, 0x006e, 'it', 0x1d4bd), # h-n
- (0x006f, 0x006f, 'it', 0x2134), # o
- (0x0070, 0x007a, 'it', 0x1d4c5), # p-z
- ],
- 'sf':
- {
- 'rm':
- [
- (0x0030, 0x0039, 'rm', 0x1d7e2), # 0-9
- (0x0041, 0x005a, 'rm', 0x1d5a0), # A-Z
- (0x0061, 0x007a, 'rm', 0x1d5ba), # a-z
- (0x0391, 0x03a9, 'rm', 0xe17d), # \Alpha-\Omega
- (0x03b1, 0x03c9, 'rm', 0xe196), # \alpha-\omega
- (0x03d1, 0x03d1, 'rm', 0xe1b0), # theta variant
- (0x03d5, 0x03d5, 'rm', 0xe1b1), # phi variant
- (0x03d6, 0x03d6, 'rm', 0xe1b3), # pi variant
- (0x03f1, 0x03f1, 'rm', 0xe1b2), # rho variant
- (0x03f5, 0x03f5, 'rm', 0xe1af), # lunate epsilon
- (0x2202, 0x2202, 'rm', 0xe17c), # partial differential
- ],
- 'it':
- [
- # These numerals are actually upright. We don't actually
- # want italic numerals ever.
- (0x0030, 0x0039, 'rm', 0x1d7e2), # 0-9
- (0x0041, 0x005a, 'it', 0x1d608), # A-Z
- (0x0061, 0x007a, 'it', 0x1d622), # a-z
- (0x0391, 0x03a9, 'rm', 0xe17d), # \Alpha-\Omega
- (0x03b1, 0x03c9, 'it', 0xe1d8), # \alpha-\omega
- (0x03d1, 0x03d1, 'it', 0xe1f2), # theta variant
- (0x03d5, 0x03d5, 'it', 0xe1f3), # phi variant
- (0x03d6, 0x03d6, 'it', 0xe1f5), # pi variant
- (0x03f1, 0x03f1, 'it', 0xe1f4), # rho variant
- (0x03f5, 0x03f5, 'it', 0xe1f1), # lunate epsilon
- ],
- 'bf':
- [
- (0x0030, 0x0039, 'bf', 0x1d7ec), # 0-9
- (0x0041, 0x005a, 'bf', 0x1d5d4), # A-Z
- (0x0061, 0x007a, 'bf', 0x1d5ee), # a-z
- (0x0391, 0x03a9, 'bf', 0x1d756), # \Alpha-\Omega
- (0x03b1, 0x03c9, 'bf', 0x1d770), # \alpha-\omega
- (0x03d1, 0x03d1, 'bf', 0x1d78b), # theta variant
- (0x03d5, 0x03d5, 'bf', 0x1d78d), # phi variant
- (0x03d6, 0x03d6, 'bf', 0x1d78f), # pi variant
- (0x03f0, 0x03f0, 'bf', 0x1d78c), # kappa variant
- (0x03f1, 0x03f1, 'bf', 0x1d78e), # rho variant
- (0x03f5, 0x03f5, 'bf', 0x1d78a), # lunate epsilon
- (0x2202, 0x2202, 'bf', 0x1d789), # partial differential
- (0x2207, 0x2207, 'bf', 0x1d76f), # \Nabla
- ],
- },
- 'tt':
- [
- (0x0030, 0x0039, 'rm', 0x1d7f6), # 0-9
- (0x0041, 0x005a, 'rm', 0x1d670), # A-Z
- (0x0061, 0x007a, 'rm', 0x1d68a) # a-z
- ],
- }
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_path.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_path.cpython-37m-darwin.so
deleted file mode 100644
index 51d13bb..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_path.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_png.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_png.cpython-37m-darwin.so
deleted file mode 100644
index 52f3678..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_png.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py b/server/venv/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py
deleted file mode 100644
index 45574b5..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py
+++ /dev/null
@@ -1,130 +0,0 @@
-"""
-Manage figures for pyplot interface.
-"""
-
-import atexit
-import gc
-
-
-class Gcf(object):
- """
- Singleton to manage a set of integer-numbered figures.
-
- This class is never instantiated; it consists of two class
- attributes (a list and a dictionary), and a set of static
- methods that operate on those attributes, accessing them
- directly as class attributes.
-
- Attributes:
-
- *figs*:
- dictionary of the form {*num*: *manager*, ...}
-
- *_activeQue*:
- list of *managers*, with active one at the end
-
- """
- _activeQue = []
- figs = {}
-
- @classmethod
- def get_fig_manager(cls, num):
- """
- If figure manager *num* exists, make it the active
- figure and return the manager; otherwise return *None*.
- """
- manager = cls.figs.get(num, None)
- if manager is not None:
- cls.set_active(manager)
- return manager
-
- @classmethod
- def destroy(cls, num):
- """
- Try to remove all traces of figure *num*.
-
- In the interactive backends, this is bound to the
- window "destroy" and "delete" events.
- """
- if not cls.has_fignum(num):
- return
- manager = cls.figs[num]
- manager.canvas.mpl_disconnect(manager._cidgcf)
- cls._activeQue.remove(manager)
- del cls.figs[num]
- manager.destroy()
- gc.collect(1)
-
- @classmethod
- def destroy_fig(cls, fig):
- "*fig* is a Figure instance"
- num = next((manager.num for manager in cls.figs.values()
- if manager.canvas.figure == fig), None)
- if num is not None:
- cls.destroy(num)
-
- @classmethod
- def destroy_all(cls):
- # this is need to ensure that gc is available in corner cases
- # where modules are being torn down after install with easy_install
- import gc # noqa
- for manager in list(cls.figs.values()):
- manager.canvas.mpl_disconnect(manager._cidgcf)
- manager.destroy()
-
- cls._activeQue = []
- cls.figs.clear()
- gc.collect(1)
-
- @classmethod
- def has_fignum(cls, num):
- """
- Return *True* if figure *num* exists.
- """
- return num in cls.figs
-
- @classmethod
- def get_all_fig_managers(cls):
- """
- Return a list of figure managers.
- """
- return list(cls.figs.values())
-
- @classmethod
- def get_num_fig_managers(cls):
- """
- Return the number of figures being managed.
- """
- return len(cls.figs)
-
- @classmethod
- def get_active(cls):
- """
- Return the manager of the active figure, or *None*.
- """
- if len(cls._activeQue) == 0:
- return None
- else:
- return cls._activeQue[-1]
-
- @classmethod
- def set_active(cls, manager):
- """
- Make the figure corresponding to *manager* the active one.
- """
- oldQue = cls._activeQue[:]
- cls._activeQue = [m for m in oldQue if m != manager]
- cls._activeQue.append(manager)
- cls.figs[manager.num] = manager
-
- @classmethod
- def draw_all(cls, force=False):
- """
- Redraw all figures registered with the pyplot
- state machine.
- """
- for f_mgr in cls.get_all_fig_managers():
- if force or f_mgr.canvas.figure.stale:
- f_mgr.canvas.draw_idle()
-
-atexit.register(Gcf.destroy_all)
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_qhull.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_qhull.cpython-37m-darwin.so
deleted file mode 100644
index d095fe9..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_qhull.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_tri.cpython-37m-darwin.so b/server/venv/lib/python3.7/site-packages/matplotlib/_tri.cpython-37m-darwin.so
deleted file mode 100644
index 0bf7d61..0000000
Binary files a/server/venv/lib/python3.7/site-packages/matplotlib/_tri.cpython-37m-darwin.so and /dev/null differ
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/_version.py b/server/venv/lib/python3.7/site-packages/matplotlib/_version.py
deleted file mode 100644
index 9858f0e..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/_version.py
+++ /dev/null
@@ -1,21 +0,0 @@
-
-# This file was generated by 'versioneer.py' (0.15) from
-# revision-control system data, or from the parent directory name of an
-# unpacked source archive. Distribution tarballs contain a pre-generated copy
-# of this file.
-
-import json
-import sys
-
-version_json = '''
-{
- "dirty": false,
- "error": null,
- "full-revisionid": "bed022902c04af827d24d86d161eaf401041dbe3",
- "version": "3.1.1"
-}
-''' # END VERSION_JSON
-
-
-def get_versions():
- return json.loads(version_json)
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/afm.py b/server/venv/lib/python3.7/site-packages/matplotlib/afm.py
deleted file mode 100644
index c2b0090..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/afm.py
+++ /dev/null
@@ -1,573 +0,0 @@
-"""
-This is a python interface to Adobe Font Metrics Files. Although a
-number of other python implementations exist, and may be more complete
-than this, it was decided not to go with them because they were
-either:
-
- 1) copyrighted or used a non-BSD compatible license
-
- 2) had too many dependencies and a free standing lib was needed
-
- 3) Did more than needed and it was easier to write afresh rather than
- figure out how to get just what was needed.
-
-It is pretty easy to use, and requires only built-in python libs:
-
- >>> from matplotlib import rcParams
- >>> import os.path
- >>> afm_fname = os.path.join(rcParams['datapath'],
- ... 'fonts', 'afm', 'ptmr8a.afm')
- >>>
- >>> from matplotlib.afm import AFM
- >>> with open(afm_fname, 'rb') as fh:
- ... afm = AFM(fh)
- >>> afm.string_width_height('What the heck?')
- (6220.0, 694)
- >>> afm.get_fontname()
- 'Times-Roman'
- >>> afm.get_kern_dist('A', 'f')
- 0
- >>> afm.get_kern_dist('A', 'y')
- -92.0
- >>> afm.get_bbox_char('!')
- [130, -9, 238, 676]
-
-As in the Adobe Font Metrics File Format Specification, all dimensions
-are given in units of 1/1000 of the scale factor (point size) of the font
-being used.
-"""
-
-from collections import namedtuple
-import logging
-import re
-
-
-from ._mathtext_data import uni2type1
-from matplotlib.cbook import deprecated
-
-
-_log = logging.getLogger(__name__)
-
-
-def _to_int(x):
- # Some AFM files have floats where we are expecting ints -- there is
- # probably a better way to handle this (support floats, round rather
- # than truncate). But I don't know what the best approach is now and
- # this change to _to_int should at least prevent mpl from crashing on
- # these JDH (2009-11-06)
- return int(float(x))
-
-
-def _to_float(x):
- # Some AFM files use "," instead of "." as decimal separator -- this
- # shouldn't be ambiguous (unless someone is wicked enough to use "," as
- # thousands separator...).
- if isinstance(x, bytes):
- # Encoding doesn't really matter -- if we have codepoints >127 the call
- # to float() will error anyways.
- x = x.decode('latin-1')
- return float(x.replace(',', '.'))
-
-
-def _to_str(x):
- return x.decode('utf8')
-
-
-def _to_list_of_ints(s):
- s = s.replace(b',', b' ')
- return [_to_int(val) for val in s.split()]
-
-
-def _to_list_of_floats(s):
- return [_to_float(val) for val in s.split()]
-
-
-def _to_bool(s):
- if s.lower().strip() in (b'false', b'0', b'no'):
- return False
- else:
- return True
-
-
-def _sanity_check(fh):
- """
- Check if the file looks like AFM; if it doesn't, raise `RuntimeError`.
- """
- # Remember the file position in case the caller wants to
- # do something else with the file.
- pos = fh.tell()
- try:
- line = next(fh)
- finally:
- fh.seek(pos, 0)
- # AFM spec, Section 4: The StartFontMetrics keyword [followed by a
- # version number] must be the first line in the file, and the
- # EndFontMetrics keyword must be the last non-empty line in the
- # file. We just check the first line.
- if not line.startswith(b'StartFontMetrics'):
- raise RuntimeError('Not an AFM file')
-
-
-def _parse_header(fh):
- """
- Reads the font metrics header (up to the char metrics) and returns
- a dictionary mapping *key* to *val*. *val* will be converted to the
- appropriate python type as necessary; e.g.:
-
- * 'False'->False
- * '0'->0
- * '-168 -218 1000 898'-> [-168, -218, 1000, 898]
-
- Dictionary keys are
-
- StartFontMetrics, FontName, FullName, FamilyName, Weight,
- ItalicAngle, IsFixedPitch, FontBBox, UnderlinePosition,
- UnderlineThickness, Version, Notice, EncodingScheme, CapHeight,
- XHeight, Ascender, Descender, StartCharMetrics
-
- """
- header_converters = {
- b'StartFontMetrics': _to_float,
- b'FontName': _to_str,
- b'FullName': _to_str,
- b'FamilyName': _to_str,
- b'Weight': _to_str,
- b'ItalicAngle': _to_float,
- b'IsFixedPitch': _to_bool,
- b'FontBBox': _to_list_of_ints,
- b'UnderlinePosition': _to_float,
- b'UnderlineThickness': _to_float,
- b'Version': _to_str,
- # Some AFM files have non-ASCII characters (which are not allowed by
- # the spec). Given that there is actually no public API to even access
- # this field, just return it as straight bytes.
- b'Notice': lambda x: x,
- b'EncodingScheme': _to_str,
- b'CapHeight': _to_float, # Is the second version a mistake, or
- b'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS
- b'XHeight': _to_float,
- b'Ascender': _to_float,
- b'Descender': _to_float,
- b'StdHW': _to_float,
- b'StdVW': _to_float,
- b'StartCharMetrics': _to_int,
- b'CharacterSet': _to_str,
- b'Characters': _to_int,
- }
-
- d = {}
- for line in fh:
- line = line.rstrip()
- if line.startswith(b'Comment'):
- continue
- lst = line.split(b' ', 1)
-
- key = lst[0]
- if len(lst) == 2:
- val = lst[1]
- else:
- val = b''
-
- try:
- converter = header_converters[key]
- except KeyError:
- _log.error('Found an unknown keyword in AFM header (was %r)' % key)
- continue
- try:
- d[key] = converter(val)
- except ValueError:
- _log.error('Value error parsing header in AFM: %s, %s', key, val)
- continue
- if key == b'StartCharMetrics':
- return d
- raise RuntimeError('Bad parse')
-
-
-CharMetrics = namedtuple('CharMetrics', 'width, name, bbox')
-CharMetrics.__doc__ = """
- Represents the character metrics of a single character.
-
- Notes
- -----
- The fields do currently only describe a subset of character metrics
- information defined in the AFM standard.
- """
-CharMetrics.width.__doc__ = """The character width (WX)."""
-CharMetrics.name.__doc__ = """The character name (N)."""
-CharMetrics.bbox.__doc__ = """
- The bbox of the character (B) as a tuple (*llx*, *lly*, *urx*, *ury*)."""
-
-
-def _parse_char_metrics(fh):
- """
- Parse the given filehandle for character metrics information and return
- the information as dicts.
-
- It is assumed that the file cursor is on the line behind
- 'StartCharMetrics'.
-
- Returns
- -------
- ascii_d : dict
- A mapping "ASCII num of the character" to `.CharMetrics`.
- name_d : dict
- A mapping "character name" to `.CharMetrics`.
-
- Notes
- -----
- This function is incomplete per the standard, but thus far parses
- all the sample afm files tried.
- """
- required_keys = {'C', 'WX', 'N', 'B'}
-
- ascii_d = {}
- name_d = {}
- for line in fh:
- # We are defensively letting values be utf8. The spec requires
- # ascii, but there are non-compliant fonts in circulation
- line = _to_str(line.rstrip()) # Convert from byte-literal
- if line.startswith('EndCharMetrics'):
- return ascii_d, name_d
- # Split the metric line into a dictionary, keyed by metric identifiers
- vals = dict(s.strip().split(' ', 1) for s in line.split(';') if s)
- # There may be other metrics present, but only these are needed
- if not required_keys.issubset(vals):
- raise RuntimeError('Bad char metrics line: %s' % line)
- num = _to_int(vals['C'])
- wx = _to_float(vals['WX'])
- name = vals['N']
- bbox = _to_list_of_floats(vals['B'])
- bbox = list(map(int, bbox))
- metrics = CharMetrics(wx, name, bbox)
- # Workaround: If the character name is 'Euro', give it the
- # corresponding character code, according to WinAnsiEncoding (see PDF
- # Reference).
- if name == 'Euro':
- num = 128
- if num != -1:
- ascii_d[num] = metrics
- name_d[name] = metrics
- raise RuntimeError('Bad parse')
-
-
-def _parse_kern_pairs(fh):
- """
- Return a kern pairs dictionary; keys are (*char1*, *char2*) tuples and
- values are the kern pair value. For example, a kern pairs line like
- ``KPX A y -50``
-
- will be represented as::
-
- d[ ('A', 'y') ] = -50
-
- """
-
- line = next(fh)
- if not line.startswith(b'StartKernPairs'):
- raise RuntimeError('Bad start of kern pairs data: %s' % line)
-
- d = {}
- for line in fh:
- line = line.rstrip()
- if not line:
- continue
- if line.startswith(b'EndKernPairs'):
- next(fh) # EndKernData
- return d
- vals = line.split()
- if len(vals) != 4 or vals[0] != b'KPX':
- raise RuntimeError('Bad kern pairs line: %s' % line)
- c1, c2, val = _to_str(vals[1]), _to_str(vals[2]), _to_float(vals[3])
- d[(c1, c2)] = val
- raise RuntimeError('Bad kern pairs parse')
-
-
-CompositePart = namedtuple('CompositePart', 'name, dx, dy')
-CompositePart.__doc__ = """
- Represents the information on a composite element of a composite char."""
-CompositePart.name.__doc__ = """Name of the part, e.g. 'acute'."""
-CompositePart.dx.__doc__ = """x-displacement of the part from the origin."""
-CompositePart.dy.__doc__ = """y-displacement of the part from the origin."""
-
-
-def _parse_composites(fh):
- """
- Parse the given filehandle for composites information return them as a
- dict.
-
- It is assumed that the file cursor is on the line behind 'StartComposites'.
-
- Returns
- -------
- composites : dict
- A dict mapping composite character names to a parts list. The parts
- list is a list of `.CompositePart` entries describing the parts of
- the composite.
-
- Example
- -------
- A composite definition line::
-
- CC Aacute 2 ; PCC A 0 0 ; PCC acute 160 170 ;
-
- will be represented as::
-
- composites['Aacute'] = [CompositePart(name='A', dx=0, dy=0),
- CompositePart(name='acute', dx=160, dy=170)]
-
- """
- composites = {}
- for line in fh:
- line = line.rstrip()
- if not line:
- continue
- if line.startswith(b'EndComposites'):
- return composites
- vals = line.split(b';')
- cc = vals[0].split()
- name, numParts = cc[1], _to_int(cc[2])
- pccParts = []
- for s in vals[1:-1]:
- pcc = s.split()
- part = CompositePart(pcc[1], _to_float(pcc[2]), _to_float(pcc[3]))
- pccParts.append(part)
- composites[name] = pccParts
-
- raise RuntimeError('Bad composites parse')
-
-
-def _parse_optional(fh):
- """
- Parse the optional fields for kern pair data and composites.
-
- Returns
- -------
- kern_data : dict
- A dict containing kerning information. May be empty.
- See `._parse_kern_pairs`.
- composites : dict
- A dict containing composite information. May be empty.
- See `._parse_composites`.
- """
- optional = {
- b'StartKernData': _parse_kern_pairs,
- b'StartComposites': _parse_composites,
- }
-
- d = {b'StartKernData': {},
- b'StartComposites': {}}
- for line in fh:
- line = line.rstrip()
- if not line:
- continue
- key = line.split()[0]
-
- if key in optional:
- d[key] = optional[key](fh)
-
- return d[b'StartKernData'], d[b'StartComposites']
-
-
-@deprecated("3.0", alternative="the AFM class")
-def parse_afm(fh):
- return _parse_afm(fh)
-
-
-def _parse_afm(fh):
- """
- Parse the Adobe Font Metrics file in file handle *fh*.
-
- Returns
- -------
- header : dict
- A header dict. See :func:`_parse_header`.
- cmetrics_by_ascii : dict
- From :func:`_parse_char_metrics`.
- cmetrics_by_name : dict
- From :func:`_parse_char_metrics`.
- kernpairs : dict
- From :func:`_parse_kern_pairs`.
- composites : dict
- From :func:`_parse_composites`
-
- """
- _sanity_check(fh)
- header = _parse_header(fh)
- cmetrics_by_ascii, cmetrics_by_name = _parse_char_metrics(fh)
- kernpairs, composites = _parse_optional(fh)
- return header, cmetrics_by_ascii, cmetrics_by_name, kernpairs, composites
-
-
-class AFM(object):
-
- def __init__(self, fh):
- """Parse the AFM file in file object *fh*."""
- (self._header,
- self._metrics,
- self._metrics_by_name,
- self._kern,
- self._composite) = _parse_afm(fh)
-
- def get_bbox_char(self, c, isord=False):
- if not isord:
- c = ord(c)
- return self._metrics[c].bbox
-
- def string_width_height(self, s):
- """
- Return the string width (including kerning) and string height
- as a (*w*, *h*) tuple.
- """
- if not len(s):
- return 0, 0
- total_width = 0
- namelast = None
- miny = 1e9
- maxy = 0
- for c in s:
- if c == '\n':
- continue
- wx, name, bbox = self._metrics[ord(c)]
-
- total_width += wx + self._kern.get((namelast, name), 0)
- l, b, w, h = bbox
- miny = min(miny, b)
- maxy = max(maxy, b + h)
-
- namelast = name
-
- return total_width, maxy - miny
-
- def get_str_bbox_and_descent(self, s):
- """Return the string bounding box and the maximal descent."""
- if not len(s):
- return 0, 0, 0, 0, 0
- total_width = 0
- namelast = None
- miny = 1e9
- maxy = 0
- left = 0
- if not isinstance(s, str):
- s = _to_str(s)
- for c in s:
- if c == '\n':
- continue
- name = uni2type1.get(ord(c), 'question')
- try:
- wx, _, bbox = self._metrics_by_name[name]
- except KeyError:
- name = 'question'
- wx, _, bbox = self._metrics_by_name[name]
- total_width += wx + self._kern.get((namelast, name), 0)
- l, b, w, h = bbox
- left = min(left, l)
- miny = min(miny, b)
- maxy = max(maxy, b + h)
-
- namelast = name
-
- return left, miny, total_width, maxy - miny, -miny
-
- def get_str_bbox(self, s):
- """Return the string bounding box."""
- return self.get_str_bbox_and_descent(s)[:4]
-
- def get_name_char(self, c, isord=False):
- """Get the name of the character, i.e., ';' is 'semicolon'."""
- if not isord:
- c = ord(c)
- return self._metrics[c].name
-
- def get_width_char(self, c, isord=False):
- """
- Get the width of the character from the character metric WX field.
- """
- if not isord:
- c = ord(c)
- return self._metrics[c].width
-
- def get_width_from_char_name(self, name):
- """Get the width of the character from a type1 character name."""
- return self._metrics_by_name[name].width
-
- def get_height_char(self, c, isord=False):
- """Get the bounding box (ink) height of character *c* (space is 0)."""
- if not isord:
- c = ord(c)
- return self._metrics[c].bbox[-1]
-
- def get_kern_dist(self, c1, c2):
- """
- Return the kerning pair distance (possibly 0) for chars *c1* and *c2*.
- """
- name1, name2 = self.get_name_char(c1), self.get_name_char(c2)
- return self.get_kern_dist_from_name(name1, name2)
-
- def get_kern_dist_from_name(self, name1, name2):
- """
- Return the kerning pair distance (possibly 0) for chars
- *name1* and *name2*.
- """
- return self._kern.get((name1, name2), 0)
-
- def get_fontname(self):
- """Return the font name, e.g., 'Times-Roman'."""
- return self._header[b'FontName']
-
- def get_fullname(self):
- """Return the font full name, e.g., 'Times-Roman'."""
- name = self._header.get(b'FullName')
- if name is None: # use FontName as a substitute
- name = self._header[b'FontName']
- return name
-
- def get_familyname(self):
- """Return the font family name, e.g., 'Times'."""
- name = self._header.get(b'FamilyName')
- if name is not None:
- return name
-
- # FamilyName not specified so we'll make a guess
- name = self.get_fullname()
- extras = (r'(?i)([ -](regular|plain|italic|oblique|bold|semibold|'
- r'light|ultralight|extra|condensed))+$')
- return re.sub(extras, '', name)
-
- @property
- def family_name(self):
- """The font family name, e.g., 'Times'."""
- return self.get_familyname()
-
- def get_weight(self):
- """Return the font weight, e.g., 'Bold' or 'Roman'."""
- return self._header[b'Weight']
-
- def get_angle(self):
- """Return the fontangle as float."""
- return self._header[b'ItalicAngle']
-
- def get_capheight(self):
- """Return the cap height as float."""
- return self._header[b'CapHeight']
-
- def get_xheight(self):
- """Return the xheight as float."""
- return self._header[b'XHeight']
-
- def get_underline_thickness(self):
- """Return the underline thickness as float."""
- return self._header[b'UnderlineThickness']
-
- def get_horizontal_stem_width(self):
- """
- Return the standard horizontal stem width as float, or *None* if
- not specified in AFM file.
- """
- return self._header.get(b'StdHW', None)
-
- def get_vertical_stem_width(self):
- """
- Return the standard vertical stem width as float, or *None* if
- not specified in AFM file.
- """
- return self._header.get(b'StdVW', None)
diff --git a/server/venv/lib/python3.7/site-packages/matplotlib/animation.py b/server/venv/lib/python3.7/site-packages/matplotlib/animation.py
deleted file mode 100644
index 8346a4e..0000000
--- a/server/venv/lib/python3.7/site-packages/matplotlib/animation.py
+++ /dev/null
@@ -1,1764 +0,0 @@
-# TODO:
-# * Documentation -- this will need a new section of the User's Guide.
-# Both for Animations and just timers.
-# - Also need to update http://www.scipy.org/Cookbook/Matplotlib/Animations
-# * Blit
-# * Currently broken with Qt4 for widgets that don't start on screen
-# * Still a few edge cases that aren't working correctly
-# * Can this integrate better with existing matplotlib animation artist flag?
-# - If animated removes from default draw(), perhaps we could use this to
-# simplify initial draw.
-# * Example
-# * Frameless animation - pure procedural with no loop
-# * Need example that uses something like inotify or subprocess
-# * Complex syncing examples
-# * Movies
-# * Can blit be enabled for movies?
-# * Need to consider event sources to allow clicking through multiple figures
-
-import abc
-import base64
-import contextlib
-from io import BytesIO, TextIOWrapper
-import itertools
-import logging
-import os
-from pathlib import Path
-import platform
-import shutil
-import subprocess
-import sys
-from tempfile import TemporaryDirectory
-import uuid
-
-import numpy as np
-
-import matplotlib as mpl
-from matplotlib._animation_data import (
- DISPLAY_TEMPLATE, INCLUDED_FRAMES, JS_INCLUDE, STYLE_INCLUDE)
-from matplotlib import cbook, rcParams, rcParamsDefault, rc_context
-
-
-_log = logging.getLogger(__name__)
-
-# Process creation flag for subprocess to prevent it raising a terminal
-# window. See for example:
-# https://stackoverflow.com/questions/24130623/using-python-subprocess-popen-cant-prevent-exe-stopped-working-prompt
-if platform.system() == 'Windows':
- subprocess_creation_flags = CREATE_NO_WINDOW = 0x08000000
-else:
- # Apparently None won't work here
- subprocess_creation_flags = 0
-
-# Other potential writing methods:
-# * http://pymedia.org/
-# * libming (produces swf) python wrappers: https://github.com/libming/libming
-# * Wrap x264 API:
-
-# (http://stackoverflow.com/questions/2940671/
-# how-to-encode-series-of-images-into-h264-using-x264-api-c-c )
-
-
-def adjusted_figsize(w, h, dpi, n):
- '''Compute figure size so that pixels are a multiple of n
-
- Parameters
- ----------
- w, h : float
- Size in inches
-
- dpi : float
- The dpi
-
- n : int
- The target multiple
-
- Returns
- -------
- wnew, hnew : float
- The new figure size in inches.
- '''
-
- # this maybe simplified if / when we adopt consistent rounding for
- # pixel size across the whole library
- def correct_roundoff(x, dpi, n):
- if int(x*dpi) % n != 0:
- if int(np.nextafter(x, np.inf)*dpi) % n == 0:
- x = np.nextafter(x, np.inf)
- elif int(np.nextafter(x, -np.inf)*dpi) % n == 0:
- x = np.nextafter(x, -np.inf)
- return x
-
- wnew = int(w * dpi / n) * n / dpi
- hnew = int(h * dpi / n) * n / dpi
- return (correct_roundoff(wnew, dpi, n), correct_roundoff(hnew, dpi, n))
-
-
-# A registry for available MovieWriter classes
-class MovieWriterRegistry(object):
- '''Registry of available writer classes by human readable name.'''
- def __init__(self):
- self.avail = dict()
- self._registered = dict()
- self._dirty = False
-
- def set_dirty(self):
- """Sets a flag to re-setup the writers."""
- self._dirty = True
-
- def register(self, name):
- """Decorator for registering a class under a name.
-
- Example use::
-
- @registry.register(name)
- class Foo:
- pass
- """
- def wrapper(writerClass):
- self._registered[name] = writerClass
- if writerClass.isAvailable():
- self.avail[name] = writerClass
- return writerClass
- return wrapper
-
- def ensure_not_dirty(self):
- """If dirty, reasks the writers if they are available"""
- if self._dirty:
- self.reset_available_writers()
-
- def reset_available_writers(self):
- """Reset the available state of all registered writers"""
- self.avail = {name: writerClass
- for name, writerClass in self._registered.items()
- if writerClass.isAvailable()}
- self._dirty = False
-
- def list(self):
- '''Get a list of available MovieWriters.'''
- self.ensure_not_dirty()
- return list(self.avail)
-
- def is_available(self, name):
- '''Check if given writer is available by name.
-
- Parameters
- ----------
- name : str
-
- Returns
- -------
- available : bool
- '''
- self.ensure_not_dirty()
- return name in self.avail
-
- def __getitem__(self, name):
- self.ensure_not_dirty()
- if not self.avail:
- raise RuntimeError("No MovieWriters available!")
- try:
- return self.avail[name]
- except KeyError:
- raise RuntimeError(
- 'Requested MovieWriter ({}) not available'.format(name))
-
-
-writers = MovieWriterRegistry()
-
-
-class AbstractMovieWriter(abc.ABC):
- '''
- Abstract base class for writing movies. Fundamentally, what a MovieWriter
- does is provide is a way to grab frames by calling grab_frame().
-
- setup() is called to start the process and finish() is called afterwards.
-
- This class is set up to provide for writing movie frame data to a pipe.
- saving() is provided as a context manager to facilitate this process as::
-
- with moviewriter.saving(fig, outfile='myfile.mp4', dpi=100):
- # Iterate over frames
- moviewriter.grab_frame(**savefig_kwargs)
-
- The use of the context manager ensures that setup() and finish() are
- performed as necessary.
-
- An instance of a concrete subclass of this class can be given as the
- ``writer`` argument of `Animation.save()`.
- '''
-
- @abc.abstractmethod
- def setup(self, fig, outfile, dpi=None):
- '''
- Perform setup for writing the movie file.
-
- Parameters
- ----------
- fig : `matplotlib.figure.Figure` instance
- The figure object that contains the information for frames
- outfile : string
- The filename of the resulting movie file
- dpi : int, optional
- The DPI (or resolution) for the file. This controls the size
- in pixels of the resulting movie file. Default is ``fig.dpi``.
- '''
-
- @abc.abstractmethod
- def grab_frame(self, **savefig_kwargs):
- '''
- Grab the image information from the figure and save as a movie frame.
-
- All keyword arguments in savefig_kwargs are passed on to the `savefig`
- command that saves the figure.
- '''
-
- @abc.abstractmethod
- def finish(self):
- '''Finish any processing for writing the movie.'''
-
- @contextlib.contextmanager
- def saving(self, fig, outfile, dpi, *args, **kwargs):
- '''
- Context manager to facilitate writing the movie file.
-
- ``*args, **kw`` are any parameters that should be passed to `setup`.
- '''
- # This particular sequence is what contextlib.contextmanager wants
- self.setup(fig, outfile, dpi, *args, **kwargs)
- try:
- yield self
- finally:
- self.finish()
-
-
-class MovieWriter(AbstractMovieWriter):
- '''Base class for writing movies.
-
- This is a base class for MovieWriter subclasses that write a movie frame
- data to a pipe. You cannot instantiate this class directly.
- See examples for how to use its subclasses.
-
- Attributes
- ----------
- frame_format : str
- The format used in writing frame data, defaults to 'rgba'
- fig : `~matplotlib.figure.Figure`
- The figure to capture data from.
- This must be provided by the sub-classes.
-
- '''
-
- def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
- metadata=None):
- '''MovieWriter
-
- Parameters
- ----------
- fps : int
- Framerate for movie.
- codec : string or None, optional
- The codec to use. If ``None`` (the default) the ``animation.codec``
- rcParam is used.
- bitrate : int or None, optional
- The bitrate for the saved movie file, which is one way to control
- the output file size and quality. The default value is ``None``,
- which uses the ``animation.bitrate`` rcParam. A value of -1
- implies that the bitrate should be determined automatically by the
- underlying utility.
- extra_args : list of strings or None, optional
- A list of extra string arguments to be passed to the underlying
- movie utility. The default is ``None``, which passes the additional
- arguments in the ``animation.extra_args`` rcParam.
- metadata : Dict[str, str] or None
- A dictionary of keys and values for metadata to include in the
- output file. Some keys that may be of use include:
- title, artist, genre, subject, copyright, srcform, comment.
- '''
- if self.__class__ is MovieWriter:
- # TODO MovieWriter is still an abstract class and needs to be
- # extended with a mixin. This should be clearer in naming
- # and description. For now, just give a reasonable error
- # message to users.
- raise TypeError(
- 'MovieWriter cannot be instantiated directly. Please use one '
- 'of its subclasses.')
-
- self.fps = fps
- self.frame_format = 'rgba'
-
- if codec is None:
- self.codec = rcParams['animation.codec']
- else:
- self.codec = codec
-
- if bitrate is None:
- self.bitrate = rcParams['animation.bitrate']
- else:
- self.bitrate = bitrate
-
- if extra_args is None:
- self.extra_args = list(rcParams[self.args_key])
- else:
- self.extra_args = extra_args
-
- if metadata is None:
- self.metadata = dict()
- else:
- self.metadata = metadata
-
- @property
- def frame_size(self):
- '''A tuple ``(width, height)`` in pixels of a movie frame.'''
- w, h = self.fig.get_size_inches()
- return int(w * self.dpi), int(h * self.dpi)
-
- def _adjust_frame_size(self):
- if self.codec == 'h264':
- wo, ho = self.fig.get_size_inches()
- w, h = adjusted_figsize(wo, ho, self.dpi, 2)
- if not (wo, ho) == (w, h):
- self.fig.set_size_inches(w, h, forward=True)
- _log.info('figure size (inches) has been adjusted '
- 'from %s x %s to %s x %s', wo, ho, w, h)
- else:
- w, h = self.fig.get_size_inches()
- _log.debug('frame size in pixels is %s x %s', *self.frame_size)
- return w, h
-
- def setup(self, fig, outfile, dpi=None):
- '''
- Perform setup for writing the movie file.
-
- Parameters
- ----------
- fig : matplotlib.figure.Figure
- The figure object that contains the information for frames
- outfile : string
- The filename of the resulting movie file
- dpi : int, optional
- The DPI (or resolution) for the file. This controls the size
- in pixels of the resulting movie file. Default is fig.dpi.
- '''
- self.outfile = outfile
- self.fig = fig
- if dpi is None:
- dpi = self.fig.dpi
- self.dpi = dpi
- self._w, self._h = self._adjust_frame_size()
-
- # Run here so that grab_frame() can write the data to a pipe. This
- # eliminates the need for temp files.
- self._run()
-
- def _run(self):
- # Uses subprocess to call the program for assembling frames into a
- # movie file. *args* returns the sequence of command line arguments
- # from a few configuration options.
- command = self._args()
- _log.info('MovieWriter.run: running command: %s', command)
- PIPE = subprocess.PIPE
- self._proc = subprocess.Popen(
- command, stdin=PIPE, stdout=PIPE, stderr=PIPE,
- creationflags=subprocess_creation_flags)
-
- def finish(self):
- '''Finish any processing for writing the movie.'''
- self.cleanup()
-
- def grab_frame(self, **savefig_kwargs):
- '''
- Grab the image information from the figure and save as a movie frame.
-
- All keyword arguments in savefig_kwargs are passed on to the `savefig`
- command that saves the figure.
- '''
- _log.debug('MovieWriter.grab_frame: Grabbing frame.')
- # re-adjust the figure size in case it has been changed by the
- # user. We must ensure that every frame is the same size or
- # the movie will not save correctly.
- self.fig.set_size_inches(self._w, self._h)
- # Tell the figure to save its data to the sink, using the
- # frame format and dpi.
- self.fig.savefig(self._frame_sink(), format=self.frame_format,
- dpi=self.dpi, **savefig_kwargs)
-
- def _frame_sink(self):
- '''Return the place to which frames should be written.'''
- return self._proc.stdin
-
- def _args(self):
- '''Assemble list of utility-specific command-line arguments.'''
- return NotImplementedError("args needs to be implemented by subclass.")
-
- def cleanup(self):
- '''Clean-up and collect the process used to write the movie file.'''
- out, err = self._proc.communicate()
- self._frame_sink().close()
- # Use the encoding/errors that universal_newlines would use.
- out = TextIOWrapper(BytesIO(out)).read()
- err = TextIOWrapper(BytesIO(err)).read()
- if out:
- _log.log(
- logging.WARNING if self._proc.returncode else logging.DEBUG,
- "MovieWriter stdout:\n%s", out)
- if err:
- _log.log(
- logging.WARNING if self._proc.returncode else logging.DEBUG,
- "MovieWriter stderr:\n%s", err)
- if self._proc.returncode:
- raise subprocess.CalledProcessError(
- self._proc.returncode, self._proc.args, out, err)
-
- @classmethod
- def bin_path(cls):
- '''
- Return the binary path to the commandline tool used by a specific
- subclass. This is a class method so that the tool can be looked for
- before making a particular MovieWriter subclass available.
- '''
- return str(rcParams[cls.exec_key])
-
- @classmethod
- def isAvailable(cls):
- '''
- Check to see if a MovieWriter subclass is actually available.
- '''
- return shutil.which(cls.bin_path()) is not None
-
-
-class FileMovieWriter(MovieWriter):
- '''`MovieWriter` for writing to individual files and stitching at the end.
-
- This must be sub-classed to be useful.
- '''
- def __init__(self, *args, **kwargs):
- MovieWriter.__init__(self, *args, **kwargs)
- self.frame_format = rcParams['animation.frame_format']
-
- def setup(self, fig, outfile, dpi=None, frame_prefix='_tmp',
- clear_temp=True):
- '''Perform setup for writing the movie file.
-
- Parameters
- ----------
- fig : matplotlib.figure.Figure
- The figure to grab the rendered frames from.
- outfile : str
- The filename of the resulting movie file.
- dpi : number, optional
- The dpi of the output file. This, with the figure size,
- controls the size in pixels of the resulting movie file.
- Default is fig.dpi.
- frame_prefix : str, optional
- The filename prefix to use for temporary files. Defaults to
- ``'_tmp'``.
- clear_temp : bool, optional
- If the temporary files should be deleted after stitching
- the final result. Setting this to ``False`` can be useful for
- debugging. Defaults to ``True``.
-
- '''
- self.fig = fig
- self.outfile = outfile
- if dpi is None:
- dpi = self.fig.dpi
- self.dpi = dpi
- self._adjust_frame_size()
-
- self.clear_temp = clear_temp
- self.temp_prefix = frame_prefix
- self._frame_counter = 0 # used for generating sequential file names
- self._temp_names = list()
- self.fname_format_str = '%s%%07d.%s'
-
- @property
- def frame_format(self):
- '''
- Format (png, jpeg, etc.) to use for saving the frames, which can be
- decided by the individual subclasses.
- '''
- return self._frame_format
-
- @frame_format.setter
- def frame_format(self, frame_format):
- if frame_format in self.supported_formats:
- self._frame_format = frame_format
- else:
- self._frame_format = self.supported_formats[0]
-
- def _base_temp_name(self):
- # Generates a template name (without number) given the frame format
- # for extension and the prefix.
- return self.fname_format_str % (self.temp_prefix, self.frame_format)
-
- def _frame_sink(self):
- # Creates a filename for saving using the basename and the current
- # counter.
- fname = self._base_temp_name() % self._frame_counter
-
- # Save the filename so we can delete it later if necessary
- self._temp_names.append(fname)
- _log.debug('FileMovieWriter.frame_sink: saving frame %d to fname=%s',
- self._frame_counter, fname)
- self._frame_counter += 1 # Ensures each created name is 'unique'
-
- # This file returned here will be closed once it's used by savefig()
- # because it will no longer be referenced and will be gc-ed.
- return open(fname, 'wb')
-
- def grab_frame(self, **savefig_kwargs):
- '''
- Grab the image information from the figure and save as a movie frame.
- All keyword arguments in savefig_kwargs are passed on to the `savefig`
- command that saves the figure.
- '''
- # Overloaded to explicitly close temp file.
- _log.debug('MovieWriter.grab_frame: Grabbing frame.')
- # Tell the figure to save its data to the sink, using the
- # frame format and dpi.
- with self._frame_sink() as myframesink:
- self.fig.savefig(myframesink, format=self.frame_format,
- dpi=self.dpi, **savefig_kwargs)
-
- def finish(self):
- # Call run here now that all frame grabbing is done. All temp files
- # are available to be assembled.
- self._run()
- MovieWriter.finish(self) # Will call clean-up
-
- def cleanup(self):
- MovieWriter.cleanup(self)
-
- # Delete temporary files
- if self.clear_temp:
- _log.debug('MovieWriter: clearing temporary fnames=%s',
- self._temp_names)
- for fname in self._temp_names:
- os.remove(fname)
-
-
-@writers.register('pillow')
-class PillowWriter(MovieWriter):
- @classmethod
- def isAvailable(cls):
- try:
- import PIL
- except ImportError:
- return False
- return True
-
- def __init__(self, *args, **kwargs):
- if kwargs.get("extra_args") is None:
- kwargs["extra_args"] = ()
- super().__init__(*args, **kwargs)
-
- def setup(self, fig, outfile, dpi=None):
- self._frames = []
- self._outfile = outfile
- self._dpi = dpi
- self._fig = fig
-
- def grab_frame(self, **savefig_kwargs):
- from PIL import Image
- buf = BytesIO()
- self._fig.savefig(buf, **dict(savefig_kwargs, format="rgba"))
- renderer = self._fig.canvas.get_renderer()
- # Using frombuffer / getbuffer may be slightly more efficient, but
- # Py3-only.
- self._frames.append(Image.frombytes(
- "RGBA",
- (int(renderer.width), int(renderer.height)),
- buf.getvalue()))
-
- def finish(self):
- self._frames[0].save(
- self._outfile, save_all=True, append_images=self._frames[1:],
- duration=int(1000 / self.fps), loop=0)
-
-
-# Base class of ffmpeg information. Has the config keys and the common set
-# of arguments that controls the *output* side of things.
-class FFMpegBase(object):
- '''Mixin class for FFMpeg output.
-
- To be useful this must be multiply-inherited from with a
- `MovieWriterBase` sub-class.
- '''
-
- exec_key = 'animation.ffmpeg_path'
- args_key = 'animation.ffmpeg_args'
-
- @property
- def output_args(self):
- args = ['-vcodec', self.codec]
- # For h264, the default format is yuv444p, which is not compatible
- # with quicktime (and others). Specifying yuv420p fixes playback on
- # iOS,as well as HTML5 video in firefox and safari (on both Win and
- # OSX). Also fixes internet explorer. This is as of 2015/10/29.
- if self.codec == 'h264' and '-pix_fmt' not in self.extra_args:
- args.extend(['-pix_fmt', 'yuv420p'])
- # The %dk adds 'k' as a suffix so that ffmpeg treats our bitrate as in
- # kbps
- if self.bitrate > 0:
- args.extend(['-b', '%dk' % self.bitrate])
- if self.extra_args:
- args.extend(self.extra_args)
- for k, v in self.metadata.items():
- args.extend(['-metadata', '%s=%s' % (k, v)])
-
- return args + ['-y', self.outfile]
-
- @classmethod
- def isAvailable(cls):
- return (
- super().isAvailable()
- # Ubuntu 12.04 ships a broken ffmpeg binary which we shouldn't use.
- # NOTE: when removed, remove the same method in AVConvBase.
- and b'LibAv' not in subprocess.run(
- [cls.bin_path()], creationflags=subprocess_creation_flags,
- stdout=subprocess.DEVNULL, stderr=subprocess.PIPE).stderr)
-
-
-# Combine FFMpeg options with pipe-based writing
-@writers.register('ffmpeg')
-class FFMpegWriter(FFMpegBase, MovieWriter):
- '''Pipe-based ffmpeg writer.
-
- Frames are streamed directly to ffmpeg via a pipe and written in a single
- pass.
- '''
- def _args(self):
- # Returns the command line parameters for subprocess to use
- # ffmpeg to create a movie using a pipe.
- args = [self.bin_path(), '-f', 'rawvideo', '-vcodec', 'rawvideo',
- '-s', '%dx%d' % self.frame_size, '-pix_fmt', self.frame_format,
- '-r', str(self.fps)]
- # Logging is quieted because subprocess.PIPE has limited buffer size.
- # If you have a lot of frames in your animation and set logging to
- # DEBUG, you will have a buffer overrun.
- if _log.getEffectiveLevel() > logging.DEBUG:
- args += ['-loglevel', 'error']
- args += ['-i', 'pipe:'] + self.output_args
- return args
-
-
-# Combine FFMpeg options with temp file-based writing
-@writers.register('ffmpeg_file')
-class FFMpegFileWriter(FFMpegBase, FileMovieWriter):
- '''File-based ffmpeg writer.
-
- Frames are written to temporary files on disk and then stitched
- together at the end.
-
- '''
- supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp',
- 'pbm', 'raw', 'rgba']
-
- def _args(self):
- # Returns the command line parameters for subprocess to use
- # ffmpeg to create a movie using a collection of temp images
- return [self.bin_path(), '-r', str(self.fps),
- '-i', self._base_temp_name(),
- '-vframes', str(self._frame_counter)] + self.output_args
-
-
-# Base class of avconv information. AVConv has identical arguments to FFMpeg.
-class AVConvBase(FFMpegBase):
- '''Mixin class for avconv output.
-
- To be useful this must be multiply-inherited from with a
- `MovieWriterBase` sub-class.
- '''
-
- exec_key = 'animation.avconv_path'
- args_key = 'animation.avconv_args'
-
- # NOTE : should be removed when the same method is removed in FFMpegBase.
- isAvailable = classmethod(MovieWriter.isAvailable.__func__)
-
-
-# Combine AVConv options with pipe-based writing
-@writers.register('avconv')
-class AVConvWriter(AVConvBase, FFMpegWriter):
- '''Pipe-based avconv writer.
-
- Frames are streamed directly to avconv via a pipe and written in a single
- pass.
- '''
-
-
-# Combine AVConv options with file-based writing
-@writers.register('avconv_file')
-class AVConvFileWriter(AVConvBase, FFMpegFileWriter):
- '''File-based avconv writer.
-
- Frames are written to temporary files on disk and then stitched
- together at the end.
- '''
-
-
-# Base class for animated GIFs with ImageMagick
-class ImageMagickBase(object):
- '''Mixin class for ImageMagick output.
-
- To be useful this must be multiply-inherited from with a
- `MovieWriterBase` sub-class.
- '''
-
- exec_key = 'animation.convert_path'
- args_key = 'animation.convert_args'
-
- @property
- def delay(self):
- return 100. / self.fps
-
- @property
- def output_args(self):
- return [self.outfile]
-
- @classmethod
- def bin_path(cls):
- binpath = super().bin_path()
- if binpath == 'convert':
- binpath = mpl._get_executable_info('magick').executable
- return binpath
-
- @classmethod
- def isAvailable(cls):
- try:
- return super().isAvailable()
- except FileNotFoundError: # May be raised by get_executable_info.
- return False
-
-
-# Combine ImageMagick options with pipe-based writing
-@writers.register('imagemagick')
-class ImageMagickWriter(ImageMagickBase, MovieWriter):
- '''Pipe-based animated gif.
-
- Frames are streamed directly to ImageMagick via a pipe and written
- in a single pass.
-
- '''
- def _args(self):
- return ([self.bin_path(),
- '-size', '%ix%i' % self.frame_size, '-depth', '8',
- '-delay', str(self.delay), '-loop', '0',
- '%s:-' % self.frame_format]
- + self.output_args)
-
-
-# Combine ImageMagick options with temp file-based writing
-@writers.register('imagemagick_file')
-class ImageMagickFileWriter(ImageMagickBase, FileMovieWriter):
- '''File-based animated gif writer.
-
- Frames are written to temporary files on disk and then stitched
- together at the end.
-
- '''
-
- supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp',
- 'pbm', 'raw', 'rgba']
-
- def _args(self):
- return ([self.bin_path(), '-delay', str(self.delay), '-loop', '0',
- '%s*.%s' % (self.temp_prefix, self.frame_format)]
- + self.output_args)
-
-
-# Taken directly from jakevdp's JSAnimation package at
-# http://github.com/jakevdp/JSAnimation
-def _included_frames(frame_list, frame_format):
- """frame_list should be a list of filenames"""
- return INCLUDED_FRAMES.format(Nframes=len(frame_list),
- frame_dir=os.path.dirname(frame_list[0]),
- frame_format=frame_format)
-
-
-def _embedded_frames(frame_list, frame_format):
- """frame_list should be a list of base64-encoded png files"""
- template = ' frames[{0}] = "data:image/{1};base64,{2}"\n'
- return "\n" + "".join(
- template.format(i, frame_format, frame_data.replace('\n', '\\\n'))
- for i, frame_data in enumerate(frame_list))
-
-
-@writers.register('html')
-class HTMLWriter(FileMovieWriter):
- supported_formats = ['png', 'jpeg', 'tiff', 'svg']
- args_key = 'animation.html_args'
-
- @classmethod
- def isAvailable(cls):
- return True
-
- def __init__(self, fps=30, codec=None, bitrate=None, extra_args=None,
- metadata=None, embed_frames=False, default_mode='loop',
- embed_limit=None):
- self.embed_frames = embed_frames
- self.default_mode = default_mode.lower()
-
- # Save embed limit, which is given in MB
- if embed_limit is None:
- self._bytes_limit = rcParams['animation.embed_limit']
- else:
- self._bytes_limit = embed_limit
-
- # Convert from MB to bytes
- self._bytes_limit *= 1024 * 1024
-
- if self.default_mode not in ['loop', 'once', 'reflect']:
- raise ValueError(
- "unrecognized default_mode {!r}".format(self.default_mode))
-
- super().__init__(fps, codec, bitrate, extra_args, metadata)
-
- def setup(self, fig, outfile, dpi, frame_dir=None):
- root, ext = os.path.splitext(outfile)
- if ext not in ['.html', '.htm']:
- raise ValueError("outfile must be *.htm or *.html")
-
- self._saved_frames = []
- self._total_bytes = 0
- self._hit_limit = False
-
- if not self.embed_frames:
- if frame_dir is None:
- frame_dir = root + '_frames'
- if not os.path.exists(frame_dir):
- os.makedirs(frame_dir)
- frame_prefix = os.path.join(frame_dir, 'frame')
- else:
- frame_prefix = None
-
- super().setup(fig, outfile, dpi, frame_prefix, clear_temp=False)
-
- def grab_frame(self, **savefig_kwargs):
- if self.embed_frames:
- # Just stop processing if we hit the limit
- if self._hit_limit:
- return
- f = BytesIO()
- self.fig.savefig(f, format=self.frame_format,
- dpi=self.dpi, **savefig_kwargs)
- imgdata64 = base64.encodebytes(f.getvalue()).decode('ascii')
- self._total_bytes += len(imgdata64)
- if self._total_bytes >= self._bytes_limit:
- _log.warning(
- "Animation size has reached %s bytes, exceeding the limit "
- "of %s. If you're sure you want a larger animation "
- "embedded, set the animation.embed_limit rc parameter to "
- "a larger value (in MB). This and further frames will be "
- "dropped.", self._total_bytes, self._bytes_limit)
- self._hit_limit = True
- else:
- self._saved_frames.append(imgdata64)
- else:
- return super().grab_frame(**savefig_kwargs)
-
- def finish(self):
- # save the frames to an html file
- if self.embed_frames:
- fill_frames = _embedded_frames(self._saved_frames,
- self.frame_format)
- Nframes = len(self._saved_frames)
- else:
- # temp names is filled by FileMovieWriter
- fill_frames = _included_frames(self._temp_names,
- self.frame_format)
- Nframes = len(self._temp_names)
- mode_dict = dict(once_checked='',
- loop_checked='',
- reflect_checked='')
- mode_dict[self.default_mode + '_checked'] = 'checked'
-
- interval = 1000 // self.fps
-
- with open(self.outfile, 'w') as of:
- of.write(JS_INCLUDE + STYLE_INCLUDE)
- of.write(DISPLAY_TEMPLATE.format(id=uuid.uuid4().hex,
- Nframes=Nframes,
- fill_frames=fill_frames,
- interval=interval,
- **mode_dict))
-
-
-class Animation(object):
- '''This class wraps the creation of an animation using matplotlib.
-
- It is only a base class which should be subclassed to provide
- needed behavior.
-
- This class is not typically used directly.
-
- Parameters
- ----------
- fig : matplotlib.figure.Figure
- The figure object that is used to get draw, resize, and any
- other needed events.
-
- event_source : object, optional
- A class that can run a callback when desired events
- are generated, as well as be stopped and started.
-
- Examples include timers (see :class:`TimedAnimation`) and file
- system notifications.
-
- blit : bool, optional
- controls whether blitting is used to optimize drawing. Defaults
- to ``False``.
-
- See Also
- --------
- FuncAnimation, ArtistAnimation
-
- '''
- def __init__(self, fig, event_source=None, blit=False):
- self._fig = fig
- # Disables blitting for backends that don't support it. This
- # allows users to request it if available, but still have a
- # fallback that works if it is not.
- self._blit = blit and fig.canvas.supports_blit
-
- # These are the basics of the animation. The frame sequence represents
- # information for each frame of the animation and depends on how the
- # drawing is handled by the subclasses. The event source fires events
- # that cause the frame sequence to be iterated.
- self.frame_seq = self.new_frame_seq()
- self.event_source = event_source
-
- # Instead of starting the event source now, we connect to the figure's
- # draw_event, so that we only start once the figure has been drawn.
- self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start)
-
- # Connect to the figure's close_event so that we don't continue to
- # fire events and try to draw to a deleted figure.
- self._close_id = self._fig.canvas.mpl_connect('close_event',
- self._stop)
- if self._blit:
- self._setup_blit()
-
- def _start(self, *args):
- '''
- Starts interactive animation. Adds the draw frame command to the GUI
- handler, calls show to start the event loop.
- '''
- # First disconnect our draw event handler
- self._fig.canvas.mpl_disconnect(self._first_draw_id)
- self._first_draw_id = None # So we can check on save
-
- # Now do any initial draw
- self._init_draw()
-
- # Add our callback for stepping the animation and
- # actually start the event_source.
- self.event_source.add_callback(self._step)
- self.event_source.start()
-
- def _stop(self, *args):
- # On stop we disconnect all of our events.
- if self._blit:
- self._fig.canvas.mpl_disconnect(self._resize_id)
- self._fig.canvas.mpl_disconnect(self._close_id)
- self.event_source.remove_callback(self._step)
- self.event_source = None
-
- def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
- bitrate=None, extra_args=None, metadata=None, extra_anim=None,
- savefig_kwargs=None, *, progress_callback=None):
- """
- Save the animation as a movie file by drawing every frame.
-
- Parameters
- ----------
-
- filename : str
- The output filename, e.g., :file:`mymovie.mp4`.
-
- writer : :class:`MovieWriter` or str, optional
- A `MovieWriter` instance to use or a key that identifies a
- class to use, such as 'ffmpeg'. If ``None``, defaults to
- :rc:`animation.writer` = 'ffmpeg'.
-
- fps : number, optional
- Frames per second in the movie. Defaults to ``None``, which will use
- the animation's specified interval to set the frames per second.
-
- dpi : number, optional
- Controls the dots per inch for the movie frames. This combined with
- the figure's size in inches controls the size of the movie. If
- ``None``, defaults to :rc:`savefig.dpi`.
-
- codec : str, optional
- The video codec to be used. Not all codecs are supported
- by a given :class:`MovieWriter`. If ``None``, default to
- :rc:`animation.codec` = 'h264'.
-
- bitrate : number, optional
- Specifies the number of bits used per second in the compressed
- movie, in kilobits per second. A higher number means a higher
- quality movie, but at the cost of increased file size. If ``None``,
- defaults to :rc:`animation.bitrate` = -1.
-
- extra_args : list, optional
- List of extra string arguments to be passed to the underlying movie
- utility. If ``None``, defaults to :rc:`animation.extra_args`.
-
- metadata : Dict[str, str], optional
- Dictionary of keys and values for metadata to include in
- the output file. Some keys that may be of use include:
- title, artist, genre, subject, copyright, srcform, comment.
-
- extra_anim : list, optional
- Additional `Animation` objects that should be included
- in the saved movie file. These need to be from the same
- `matplotlib.figure.Figure` instance. Also, animation frames will
- just be simply combined, so there should be a 1:1 correspondence
- between the frames from the different animations.
-
- savefig_kwargs : dict, optional
- Is a dictionary containing keyword arguments to be passed
- on to the `savefig` command which is called repeatedly to
- save the individual frames.
-
- progress_callback : function, optional
- A callback function that will be called for every frame to notify
- the saving progress. It must have the signature ::
-
- def func(current_frame: int, total_frames: int) -> Any
-
- where *current_frame* is the current frame number and
- *total_frames* is the total number of frames to be saved.
- *total_frames* is set to None, if the total number of frames can
- not be determined. Return values may exist but are ignored.
-
- Example code to write the progress to stdout::
-
- progress_callback =\
- lambda i, n: print(f'Saving frame {i} of {n}')
-
- Notes
- -----
- *fps*, *codec*, *bitrate*, *extra_args* and *metadata* are used to
- construct a `.MovieWriter` instance and can only be passed if
- *writer* is a string. If they are passed as non-*None* and *writer*
- is a `.MovieWriter`, a `RuntimeError` will be raised.
-
- """
- # If the writer is None, use the rc param to find the name of the one
- # to use
- if writer is None:
- writer = rcParams['animation.writer']
- elif (not isinstance(writer, str) and
- any(arg is not None
- for arg in (fps, codec, bitrate, extra_args, metadata))):
- raise RuntimeError('Passing in values for arguments '
- 'fps, codec, bitrate, extra_args, or metadata '
- 'is not supported when writer is an existing '
- 'MovieWriter instance. These should instead be '
- 'passed as arguments when creating the '
- 'MovieWriter instance.')
-
- if savefig_kwargs is None:
- savefig_kwargs = {}
-
- # Need to disconnect the first draw callback, since we'll be doing
- # draws. Otherwise, we'll end up starting the animation.
- if self._first_draw_id is not None:
- self._fig.canvas.mpl_disconnect(self._first_draw_id)
- reconnect_first_draw = True
- else:
- reconnect_first_draw = False
-
- if fps is None and hasattr(self, '_interval'):
- # Convert interval in ms to frames per second
- fps = 1000. / self._interval
-
- # Re-use the savefig DPI for ours if none is given
- if dpi is None:
- dpi = rcParams['savefig.dpi']
- if dpi == 'figure':
- dpi = self._fig.dpi
-
- if codec is None:
- codec = rcParams['animation.codec']
-
- if bitrate is None:
- bitrate = rcParams['animation.bitrate']
-
- all_anim = [self]
- if extra_anim is not None:
- all_anim.extend(anim
- for anim
- in extra_anim if anim._fig is self._fig)
-
- # If we have the name of a writer, instantiate an instance of the
- # registered class.
- if isinstance(writer, str):
- if writer in writers.avail:
- writer = writers[writer](fps, codec, bitrate,
- extra_args=extra_args,
- metadata=metadata)
- else:
- if writers.list():
- alt_writer = writers[writers.list()[0]]
- _log.warning("MovieWriter %s unavailable; trying to use "
- "%s instead.", writer, alt_writer)
- writer = alt_writer(
- fps, codec, bitrate,
- extra_args=extra_args, metadata=metadata)
- else:
- raise ValueError("Cannot save animation: no writers are "
- "available. Please install ffmpeg to "
- "save animations.")
- _log.info('Animation.save using %s', type(writer))
-
- if 'bbox_inches' in savefig_kwargs:
- _log.warning("Warning: discarding the 'bbox_inches' argument in "
- "'savefig_kwargs' as it may cause frame size "
- "to vary, which is inappropriate for animation.")
- savefig_kwargs.pop('bbox_inches')
-
- # Create a new sequence of frames for saved data. This is different
- # from new_frame_seq() to give the ability to save 'live' generated
- # frame information to be saved later.
- # TODO: Right now, after closing the figure, saving a movie won't work
- # since GUI widgets are gone. Either need to remove extra code to
- # allow for this non-existent use case or find a way to make it work.
- with rc_context():
- if rcParams['savefig.bbox'] == 'tight':
- _log.info("Disabling savefig.bbox = 'tight', as it may cause "
- "frame size to vary, which is inappropriate for "
- "animation.")
- rcParams['savefig.bbox'] = None
- with writer.saving(self._fig, filename, dpi):
- for anim in all_anim:
- # Clear the initial frame
- anim._init_draw()
- frame_number = 0
- # TODO: Currently only FuncAnimation has a save_count
- # attribute. Can we generalize this to all Animations?
- save_count_list = [getattr(a, 'save_count', None)
- for a in all_anim]
- if None in save_count_list:
- total_frames = None
- else:
- total_frames = sum(save_count_list)
- for data in zip(*[a.new_saved_frame_seq() for a in all_anim]):
- for anim, d in zip(all_anim, data):
- # TODO: See if turning off blit is really necessary
- anim._draw_next_frame(d, blit=False)
- if progress_callback is not None:
- progress_callback(frame_number, total_frames)
- frame_number += 1
- writer.grab_frame(**savefig_kwargs)
-
- # Reconnect signal for first draw if necessary
- if reconnect_first_draw:
- self._first_draw_id = self._fig.canvas.mpl_connect('draw_event',
- self._start)
-
- def _step(self, *args):
- '''
- Handler for getting events. By default, gets the next frame in the
- sequence and hands the data off to be drawn.
- '''
- # Returns True to indicate that the event source should continue to
- # call _step, until the frame sequence reaches the end of iteration,
- # at which point False will be returned.
- try:
- framedata = next(self.frame_seq)
- self._draw_next_frame(framedata, self._blit)
- return True
- except StopIteration:
- return False
-
- def new_frame_seq(self):
- """Return a new sequence of frame information."""
- # Default implementation is just an iterator over self._framedata
- return iter(self._framedata)
-
- def new_saved_frame_seq(self):
- """Return a new sequence of saved/cached frame information."""
- # Default is the same as the regular frame sequence
- return self.new_frame_seq()
-
- def _draw_next_frame(self, framedata, blit):
- # Breaks down the drawing of the next frame into steps of pre- and
- # post- draw, as well as the drawing of the frame itself.
- self._pre_draw(framedata, blit)
- self._draw_frame(framedata)
- self._post_draw(framedata, blit)
-
- def _init_draw(self):
- # Initial draw to clear the frame. Also used by the blitting code
- # when a clean base is required.
- pass
-
- def _pre_draw(self, framedata, blit):
- # Perform any cleaning or whatnot before the drawing of the frame.
- # This default implementation allows blit to clear the frame.
- if blit:
- self._blit_clear(self._drawn_artists, self._blit_cache)
-
- def _draw_frame(self, framedata):
- # Performs actual drawing of the frame.
- raise NotImplementedError('Needs to be implemented by subclasses to'
- ' actually make an animation.')
-
- def _post_draw(self, framedata, blit):
- # After the frame is rendered, this handles the actual flushing of
- # the draw, which can be a direct draw_idle() or make use of the
- # blitting.
- if blit and self._drawn_artists:
- self._blit_draw(self._drawn_artists, self._blit_cache)
- else:
- self._fig.canvas.draw_idle()
-
- # The rest of the code in this class is to facilitate easy blitting
- def _blit_draw(self, artists, bg_cache):
- # Handles blitted drawing, which renders only the artists given instead
- # of the entire figure.
- updated_ax = []
- for a in artists:
- # If we haven't cached the background for this axes object, do
- # so now. This might not always be reliable, but it's an attempt
- # to automate the process.
- if a.axes not in bg_cache:
- bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox)
- a.axes.draw_artist(a)
- updated_ax.append(a.axes)
-
- # After rendering all the needed artists, blit each axes individually.
- for ax in set(updated_ax):
- ax.figure.canvas.blit(ax.bbox)
-
- def _blit_clear(self, artists, bg_cache):
- # Get a list of the axes that need clearing from the artists that
- # have been drawn. Grab the appropriate saved background from the
- # cache and restore.
- axes = {a.axes for a in artists}
- for a in axes:
- if a in bg_cache:
- a.figure.canvas.restore_region(bg_cache[a])
-
- def _setup_blit(self):
- # Setting up the blit requires: a cache of the background for the
- # axes
- self._blit_cache = dict()
- self._drawn_artists = []
- for ax in self._fig.axes:
- ax.callbacks.connect('xlim_changed',
- lambda ax: self._blit_cache.pop(ax, None))
- ax.callbacks.connect('ylim_changed',
- lambda ax: self._blit_cache.pop(ax, None))
- self._resize_id = self._fig.canvas.mpl_connect('resize_event',
- self._handle_resize)
- self._post_draw(None, self._blit)
-
- def _handle_resize(self, *args):
- # On resize, we need to disable the resize event handling so we don't
- # get too many events. Also stop the animation events, so that
- # we're paused. Reset the cache and re-init. Set up an event handler
- # to catch once the draw has actually taken place.
- self._fig.canvas.mpl_disconnect(self._resize_id)
- self.event_source.stop()
- self._blit_cache.clear()
- self._init_draw()
- self._resize_id = self._fig.canvas.mpl_connect('draw_event',
- self._end_redraw)
-
- def _end_redraw(self, evt):
- # Now that the redraw has happened, do the post draw flushing and
- # blit handling. Then re-enable all of the original events.
- self._post_draw(None, False)
- self.event_source.start()
- self._fig.canvas.mpl_disconnect(self._resize_id)
- self._resize_id = self._fig.canvas.mpl_connect('resize_event',
- self._handle_resize)
-
- def to_html5_video(self, embed_limit=None):
- """
- Convert the animation to an HTML5 ``