def load_pathlib_path(self, dct, class_name=pathlib_path_class_name):

return Path(dct["<STR_LIT:$>" + class_name])<EOL>

``pathlib.Path`` or ``pathlib2.Path`` loader.


def dump_pathlib_mate_path(self, obj, class_name=pathlib_mate_path_class_name):

return {"<STR_LIT:$>" + class_name: str(obj)}<EOL>


def load_pathlib_mate_path(self, dct, class_name=pathlib_mate_path_class_name):

return PathCls(dct["<STR_LIT:$>" + class_name])<EOL>


parts = line.split(start)<EOL>counts = [len(findall(r'<STR_LIT>', part))<EOL>for part in parts]<EOL>total = <NUM_LIT:0><EOL>for nr, count in enumerate(counts):<EOL><INDENT>total += count<EOL>if total % <NUM_LIT:2> == <NUM_LIT:0>:<EOL><INDENT>return start.join(parts[:nr + <NUM_LIT:1>]).rstrip()<EOL><DEDENT><DEDENT>else:  <EOL><INDENT>return line.rstrip()<EOL><DEDENT>


def strip_comments(string, comment_symbols=frozenset(('<STR_LIT:#>', '<STR_LIT>'))):

lines = string.splitlines()<EOL>for k in range(len(lines)):<EOL><INDENT>for symbol in comment_symbols:<EOL><INDENT>lines[k] = strip_comment_line_with_symbol(lines[k], start=symbol)<EOL><DEDENT><DEDENT>return '<STR_LIT:\n>'.join(lines)<EOL>

Strip comments from json string.

    :param string: A string containing json with comments started by comment_symbols.
    :param comment_symbols: Iterable of symbols that start a line comment (default # or //).
    :return: The string with the comments removed.


return obj.__class__.__module__ + "<STR_LIT:.>" + obj.__class__.__name__<EOL>

Get class name in dot separete notation

        >>> from datetime import datetime
        >>> obj = datetime.datetime(2000, 1, 1)
        >>> get_class_name(obj) -> "datetime.datetime"

        >>> from collections import deque
        >>> obj = deque([1, 2, 3])
        >>> get_class_name(obj) -> "collections.deque"


func.__doc__ = doc<EOL>


__import__(name)<EOL>return sys.modules[name]<EOL>

Import module, returning the module after the last dot.


setattr(_MovedItems, move.name, move)<EOL>


try:<EOL><INDENT>delattr(_MovedItems, name)<EOL><DEDENT>except AttributeError:<EOL><INDENT>try:<EOL><INDENT>del moves.__dict__[name]<EOL><DEDENT>except KeyError:<EOL><INDENT>raise AttributeError("<STR_LIT>" % (name,))<EOL><DEDENT><DEDENT>


<EOL>class metaclass(meta):<EOL><INDENT>def __new__(cls, name, this_bases, d):<EOL><INDENT>return meta(name, bases, d)<EOL><DEDENT><DEDENT>return type.__new__(metaclass, '<STR_LIT>', (), {})<EOL>


def wrapper(cls):<EOL><INDENT>orig_vars = cls.__dict__.copy()<EOL>slots = orig_vars.get('<STR_LIT>')<EOL>if slots is not None:<EOL><INDENT>if isinstance(slots, str):<EOL><INDENT>slots = [slots]<EOL><DEDENT>for slots_var in slots:<EOL><INDENT>orig_vars.pop(slots_var)<EOL><DEDENT><DEDENT>orig_vars.pop('<STR_LIT>', None)<EOL>orig_vars.pop('<STR_LIT>', None)<EOL>return metaclass(cls.__name__, cls.__bases__, orig_vars)<EOL><DEDENT>return wrapper<EOL>

Class decorator for creating a class with a metaclass.


if PY2:<EOL><INDENT>if '<STR_LIT>' not in klass.__dict__:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>" %<EOL>klass.__name__)<EOL><DEDENT>klass.__unicode__ = klass.__str__<EOL>klass.__str__ = lambda self: self.__unicode__().encode('<STR_LIT:utf-8>')<EOL><DEDENT>return klass<EOL>

A decorator that defines __unicode__ and __str__ methods under Python 2.
Under Python 3 it does nothing.

To support Python 2 and 3 with a single code base, define a __str__ method
returning text and apply this decorator to the class.


return hasattr(self.__get_module(fullname), "<STR_LIT>")<EOL>

Return true, if the named module is a package.

We need this method to get correct spec objects with
Python 3.4 (see PEP451)


self.__get_module(fullname)  <EOL>return None<EOL>

Return None

        Required, if is_package is implemented


return _replace_atomic(src, dst)<EOL>

Move ``src`` to ``dst``. If ``dst`` exists, it will be silently
overwritten.

Both paths must reside on the same filesystem for the operation to be
atomic.


return _move_atomic(src, dst)<EOL>

Move ``src`` to ``dst``. There might a timewindow where both filesystem
entries exist. If ``dst`` already exists, :py:exc:`FileExistsError` will be
raised.

Both paths must reside on the same filesystem for the operation to be
atomic.


def atomic_write(path, writer_cls=AtomicWriter, **cls_kwargs):

return writer_cls(path, **cls_kwargs).open()<EOL>

Simple atomic writes. This wraps :py:class:`AtomicWriter`::

    with atomic_write(path) as f:
        f.write(...)

:param path: The target path to write to.
:param writer_cls: The writer class to use. This parameter is useful if you
    subclassed :py:class:`AtomicWriter` to change some behavior and want to
    use that new subclass.

Additional keyword arguments are passed to the writer class. See
:py:class:`AtomicWriter`.


return self._open(self.get_fileobject)<EOL>


def get_fileobject(self, dir=None, **kwargs):

if dir is None:<EOL><INDENT>dir = os.path.normpath(os.path.dirname(self._path))<EOL><DEDENT>descriptor, name = tempfile.mkstemp(dir=dir)<EOL>os.close(descriptor)<EOL>kwargs['<STR_LIT>'] = self._mode<EOL>kwargs['<STR_LIT:file>'] = name<EOL>return io.open(**kwargs)<EOL>


f.flush()<EOL>_proper_fsync(f.fileno())<EOL>

responsible for clearing as many file caches as possible before
        commit


if self._overwrite:<EOL><INDENT>replace_atomic(f.name, self._path)<EOL><DEDENT>else:<EOL><INDENT>move_atomic(f.name, self._path)<EOL><DEDENT>

Move the temporary file to the target location.


os.unlink(f.name)<EOL>


return zlib.compress(pickle.dumps(obj, protocol=<NUM_LIT:2>), level)<EOL>


return zlib.compress(s.encode("<STR_LIT:utf-8>"), level)<EOL>


return zlib.compress(b, level)<EOL>


def compress(obj, level=<NUM_LIT:6>, return_type="<STR_LIT>"):

if isinstance(obj, binary_type):<EOL><INDENT>b = zlib.compress(obj, level)<EOL><DEDENT>elif isinstance(obj, string_types):<EOL><INDENT>b = zlib.compress(obj.encode("<STR_LIT:utf-8>"), level)<EOL><DEDENT>else:<EOL><INDENT>b = zlib.compress(pickle.dumps(obj, protocol=<NUM_LIT:2>), level)<EOL><DEDENT>if return_type == "<STR_LIT>":<EOL><INDENT>return b<EOL><DEDENT>elif return_type == "<STR_LIT:str>":<EOL><INDENT>return base64.b64encode(b).decode("<STR_LIT:utf-8>")<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>

Compress anything to bytes or string.

    :params obj:
    :params level:
    :params return_type: if bytes, then return bytes; if str, then return
      base64.b64encode bytes in utf-8 string.


if isinstance(obj, binary_type):<EOL><INDENT>b = zlib.decompress(obj)<EOL><DEDENT>elif isinstance(obj, string_types):<EOL><INDENT>b = zlib.decompress(base64.b64decode(obj.encode("<STR_LIT:utf-8>")))<EOL><DEDENT>else:<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>if return_type == "<STR_LIT>":<EOL><INDENT>return b<EOL><DEDENT>elif return_type == "<STR_LIT:str>":<EOL><INDENT>return b.decode("<STR_LIT:utf-8>")<EOL><DEDENT>elif return_type == "<STR_LIT>":<EOL><INDENT>return pickle.loads(b)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError(<EOL>"<STR_LIT>")<EOL><DEDENT>

De-compress it to it's original.

    :params obj: Compressed object, could be bytes or str.
    :params return_type: if bytes, then return bytes; if str, then use
      base64.b64decode; if obj, then use pickle.loads return an object.


def inner_func(self, *args, **kwargs):<EOL><INDENT>rv = f(self, *args, **kwargs)<EOL>self._invalidate_cache()<EOL>return rv<EOL><DEDENT>return inner_func<EOL>

Decorator for rruleset methods which may invalidate the
cached length.


if self._len is None:<EOL><INDENT>for x in self:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>return self._len<EOL>

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._cache_complete:<EOL><INDENT>gen = self._cache<EOL><DEDENT>else:<EOL><INDENT>gen = self<EOL><DEDENT>last = None<EOL>if inc:<EOL><INDENT>for i in gen:<EOL><INDENT>if i > dt:<EOL><INDENT>break<EOL><DEDENT>last = i<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for i in gen:<EOL><INDENT>if i >= dt:<EOL><INDENT>break<EOL><DEDENT>last = i<EOL><DEDENT><DEDENT>return last<EOL>

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:<EOL><INDENT>gen = self._cache<EOL><DEDENT>else:<EOL><INDENT>gen = self<EOL><DEDENT>if inc:<EOL><INDENT>for i in gen:<EOL><INDENT>if i >= dt:<EOL><INDENT>return i<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for i in gen:<EOL><INDENT>if i > dt:<EOL><INDENT>return i<EOL><DEDENT><DEDENT><DEDENT>return None<EOL>

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.


def xafter(self, dt, count=None, inc=False):

if self._cache_complete:<EOL><INDENT>gen = self._cache<EOL><DEDENT>else:<EOL><INDENT>gen = self<EOL><DEDENT>if inc:<EOL><INDENT>def comp(dc, dtc): return dc >= dtc<EOL><DEDENT>else:<EOL><INDENT>def comp(dc, dtc): return dc > dtc<EOL><DEDENT>n = <NUM_LIT:0><EOL>for d in gen:<EOL><INDENT>if comp(d, dt):<EOL><INDENT>if count is not None:<EOL><INDENT>n += <NUM_LIT:1><EOL>if n > count:<EOL><INDENT>break<EOL><DEDENT><DEDENT>yield d<EOL><DEDENT><DEDENT>

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.


def between(self, after, before, inc=False, count=<NUM_LIT:1>):

if self._cache_complete:<EOL><INDENT>gen = self._cache<EOL><DEDENT>else:<EOL><INDENT>gen = self<EOL><DEDENT>started = False<EOL>l = []<EOL>if inc:<EOL><INDENT>for i in gen:<EOL><INDENT>if i > before:<EOL><INDENT>break<EOL><DEDENT>elif not started:<EOL><INDENT>if i >= after:<EOL><INDENT>started = True<EOL>l.append(i)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>l.append(i)<EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>for i in gen:<EOL><INDENT>if i >= before:<EOL><INDENT>break<EOL><DEDENT>elif not started:<EOL><INDENT>if i > after:<EOL><INDENT>started = True<EOL>l.append(i)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>l.append(i)<EOL><DEDENT><DEDENT><DEDENT>return l<EOL>

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.


output = []<EOL>h, m, s = [None] * <NUM_LIT:3><EOL>if self._dtstart:<EOL><INDENT>output.append(self._dtstart.strftime('<STR_LIT>'))<EOL>h, m, s = self._dtstart.timetuple()[<NUM_LIT:3>:<NUM_LIT:6>]<EOL><DEDENT>parts = ['<STR_LIT>' + FREQNAMES[self._freq]]<EOL>if self._interval != <NUM_LIT:1>:<EOL><INDENT>parts.append('<STR_LIT>' + str(self._interval))<EOL><DEDENT>if self._wkst:<EOL><INDENT>parts.append('<STR_LIT>' + repr(weekday(self._wkst))[<NUM_LIT:0>:<NUM_LIT:2>])<EOL><DEDENT>if self._count is not None:<EOL><INDENT>parts.append('<STR_LIT>' + str(self._count))<EOL><DEDENT>if self._until:<EOL><INDENT>parts.append(self._until.strftime('<STR_LIT>'))<EOL><DEDENT>if self._original_rule.get('<STR_LIT>') is not None:<EOL><INDENT>original_rule = dict(self._original_rule)<EOL>wday_strings = []<EOL>for wday in original_rule['<STR_LIT>']:<EOL><INDENT>if wday.n:<EOL><INDENT>wday_strings.append('<STR_LIT>'.format(<EOL>n=wday.n,<EOL>wday=repr(wday)[<NUM_LIT:0>:<NUM_LIT:2>]))<EOL><DEDENT>else:<EOL><INDENT>wday_strings.append(repr(wday))<EOL><DEDENT><DEDENT>original_rule['<STR_LIT>'] = wday_strings<EOL><DEDENT>else:<EOL><INDENT>original_rule = self._original_rule<EOL><DEDENT>partfmt = '<STR_LIT>'<EOL>for name, key in [('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>'),<EOL>('<STR_LIT>', '<STR_LIT>')]:<EOL><INDENT>value = original_rule.get(key)<EOL>if value:<EOL><INDENT>parts.append(partfmt.format(name=name, vals=('<STR_LIT:U+002C>'.join(str(v)<EOL>for v in value))))<EOL><DEDENT><DEDENT>output.append('<STR_LIT:;>'.join(parts))<EOL>return '<STR_LIT:\n>'.join(output)<EOL>

Output a string that would generate this RRULE if passed to rrulestr.
This is mostly compatible with RFC2445, except for the
dateutil-specific extension BYEASTER.


new_kwargs = {"<STR_LIT>": self._interval,<EOL>"<STR_LIT:count>": self._count,<EOL>"<STR_LIT>": self._dtstart,<EOL>"<STR_LIT>": self._freq,<EOL>"<STR_LIT>": self._until,<EOL>"<STR_LIT>": self._wkst,<EOL>"<STR_LIT>": False if self._cache is None else True}<EOL>new_kwargs.update(self._original_rule)<EOL>new_kwargs.update(kwargs)<EOL>return rrule(**new_kwargs)<EOL>

Return new rrule with same attributes except for those attributes given new
           values by whichever keyword arguments are specified.


def __construct_byset(self, start, byxxx, base):

cset = set()<EOL>if isinstance(byxxx, integer_types):<EOL><INDENT>byxxx = (byxxx, )<EOL><DEDENT>for num in byxxx:<EOL><INDENT>i_gcd = gcd(self._interval, base)<EOL>if i_gcd == <NUM_LIT:1> or divmod(num - start, i_gcd)[<NUM_LIT:1>] == <NUM_LIT:0>:<EOL><INDENT>cset.add(num)<EOL><DEDENT><DEDENT>if len(cset) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>return cset<EOL>

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.


def __mod_distance(self, value, byxxx, base):

accumulator = <NUM_LIT:0><EOL>for ii in range(<NUM_LIT:1>, base + <NUM_LIT:1>):<EOL><INDENT>div, value = divmod(value + self._interval, base)<EOL>accumulator += div<EOL>if value in byxxx:<EOL><INDENT>return (accumulator, value)<EOL><DEDENT><DEDENT>

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.


Include the given :py:class:`rrule` instance in the recurrence set
            generation.


Include the given :py:class:`datetime` instance in the recurrence
            set generation.


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.


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.


def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwargs):

l = []<EOL>for wday in value.split('<STR_LIT:U+002C>'):<EOL><INDENT>if '<STR_LIT:(>' in wday:<EOL><INDENT>splt = wday.split('<STR_LIT:(>')<EOL>w = splt[<NUM_LIT:0>]<EOL>n = int(splt[<NUM_LIT:1>][:-<NUM_LIT:1>])<EOL><DEDENT>elif len(wday):<EOL><INDENT>for i in range(len(wday)):<EOL><INDENT>if wday[i] not in '<STR_LIT>':<EOL><INDENT>break<EOL><DEDENT><DEDENT>n = wday[:i] or None<EOL>w = wday[i:]<EOL>if n:<EOL><INDENT>n = int(n)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>l.append(weekdays[self._weekday_map[w]](n))<EOL><DEDENT>rrkwargs["<STR_LIT>"] = l<EOL>

Two ways to specify this: +1MO or MO(+1)


def parse(timestr, parserinfo=None, **kwargs):

if parserinfo:<EOL><INDENT>return parser(parserinfo).parse(timestr, **kwargs)<EOL><DEDENT>else:<EOL><INDENT>return DEFAULTPARSER.parse(timestr, **kwargs)<EOL><DEDENT>

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 minutes or a :class:`tzinfo` object.

        .. doctest::
           :options: +NORMALIZE_WHITESPACE

            >>> from dateutil.parser import parse
            >>> from dateutil.tz import gettz
            >>> tzinfos = {"BRST": -10800, "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', -10800))
            >>> 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 "<STR_LIT:.>" not in value:<EOL><INDENT>return int(value), <NUM_LIT:0><EOL><DEDENT>else:<EOL><INDENT>i, f = value.split("<STR_LIT:.>")<EOL>return int(i), int(f.ljust(<NUM_LIT:6>, "<STR_LIT:0>")[:<NUM_LIT:6>])<EOL><DEDENT>

Parse a I[.F] seconds value into (seconds, microseconds).


if self.tokenstack:<EOL><INDENT>return self.tokenstack.pop(<NUM_LIT:0>)<EOL><DEDENT>seenletters = False<EOL>token = None<EOL>state = None<EOL>while not self.eof:<EOL><INDENT>if self.charstack:<EOL><INDENT>nextchar = self.charstack.pop(<NUM_LIT:0>)<EOL><DEDENT>else:<EOL><INDENT>nextchar = self.instream.read(<NUM_LIT:1>)<EOL>while nextchar == '<STR_LIT:\x00>':<EOL><INDENT>nextchar = self.instream.read(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>if not nextchar:<EOL><INDENT>self.eof = True<EOL>break<EOL><DEDENT>elif not state:<EOL><INDENT>token = nextchar<EOL>if self.isword(nextchar):<EOL><INDENT>state = '<STR_LIT:a>'<EOL><DEDENT>elif self.isnum(nextchar):<EOL><INDENT>state = '<STR_LIT:0>'<EOL><DEDENT>elif self.isspace(nextchar):<EOL><INDENT>token = '<STR_LIT:U+0020>'<EOL>break  <EOL><DEDENT>else:<EOL><INDENT>break  <EOL><DEDENT><DEDENT>elif state == '<STR_LIT:a>':<EOL><INDENT>seenletters = True<EOL>if self.isword(nextchar):<EOL><INDENT>token += nextchar<EOL><DEDENT>elif nextchar == '<STR_LIT:.>':<EOL><INDENT>token += nextchar<EOL>state = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>self.charstack.append(nextchar)<EOL>break  <EOL><DEDENT><DEDENT>elif state == '<STR_LIT:0>':<EOL><INDENT>if self.isnum(nextchar):<EOL><INDENT>token += nextchar<EOL><DEDENT>elif nextchar == '<STR_LIT:.>' or (nextchar == '<STR_LIT:U+002C>' and len(token) >= <NUM_LIT:2>):<EOL><INDENT>token += nextchar<EOL>state = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>self.charstack.append(nextchar)<EOL>break  <EOL><DEDENT><DEDENT>elif state == '<STR_LIT>':<EOL><INDENT>seenletters = True<EOL>if nextchar == '<STR_LIT:.>' or self.isword(nextchar):<EOL><INDENT>token += nextchar<EOL><DEDENT>elif self.isnum(nextchar) and token[-<NUM_LIT:1>] == '<STR_LIT:.>':<EOL><INDENT>token += nextchar<EOL>state = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>self.charstack.append(nextchar)<EOL>break  <EOL><DEDENT><DEDENT>elif state == '<STR_LIT>':<EOL><INDENT>if nextchar == '<STR_LIT:.>' or self.isnum(nextchar):<EOL><INDENT>token += nextchar<EOL><DEDENT>elif self.isword(nextchar) and token[-<NUM_LIT:1>] == '<STR_LIT:.>':<EOL><INDENT>token += nextchar<EOL>state = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>self.charstack.append(nextchar)<EOL>break  <EOL><DEDENT><DEDENT><DEDENT>if (state in ('<STR_LIT>', '<STR_LIT>') and (seenletters or token.count('<STR_LIT:.>') > <NUM_LIT:1> or<EOL>token[-<NUM_LIT:1>] in '<STR_LIT>')):<EOL><INDENT>l = self._split_decimal.split(token)<EOL>token = l[<NUM_LIT:0>]<EOL>for tok in l[<NUM_LIT:1>:]:<EOL><INDENT>if tok:<EOL><INDENT>self.tokenstack.append(tok)<EOL><DEDENT><DEDENT><DEDENT>if state == '<STR_LIT>' and token.count('<STR_LIT:.>') == <NUM_LIT:0>:<EOL><INDENT>token = token.replace('<STR_LIT:U+002C>', '<STR_LIT:.>')<EOL><DEDENT>return token<EOL>

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.


return nextchar.isalpha()<EOL>

Whether or not the next character is part of a word


return nextchar.isdigit()<EOL>

Whether the next character is part of a number


return nextchar.isspace()<EOL>

Whether the next character is whitespace


for index, token in enumerate(self):<EOL><INDENT>potential_year_tokens = _ymd.find_potential_year_tokens(<EOL>token, tokens)<EOL>if len(potential_year_tokens) == <NUM_LIT:1> and len(potential_year_tokens[<NUM_LIT:0>]) > <NUM_LIT:2>:<EOL><INDENT>return index<EOL><DEDENT><DEDENT>

attempt to deduce if a pre 100 year was lost
 due to padded zeros being taken off


def parse(self, timestr, default=None, ignoretz=False, tzinfos=None, **kwargs):

if default is None:<EOL><INDENT>default = datetime.datetime.now().replace(hour=<NUM_LIT:0>, minute=<NUM_LIT:0>,<EOL>second=<NUM_LIT:0>, microsecond=<NUM_LIT:0>)<EOL><DEDENT>res, skipped_tokens = self._parse(timestr, **kwargs)<EOL>if res is None:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>if len(res) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>repl = {}<EOL>for attr in ("<STR_LIT>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>",<EOL>"<STR_LIT>", "<STR_LIT>", "<STR_LIT>"):<EOL><INDENT>value = getattr(res, attr)<EOL>if value is not None:<EOL><INDENT>repl[attr] = value<EOL><DEDENT><DEDENT>if '<STR_LIT>' not in repl:<EOL><INDENT>cyear = default.year if res.year is None else res.year<EOL>cmonth = default.month if res.month is None else res.month<EOL>cday = default.day if res.day is None else res.day<EOL>if cday > monthrange(cyear, cmonth)[<NUM_LIT:1>]:<EOL><INDENT>repl['<STR_LIT>'] = monthrange(cyear, cmonth)[<NUM_LIT:1>]<EOL><DEDENT><DEDENT>ret = default.replace(**repl)<EOL>if res.weekday is not None and not res.day:<EOL><INDENT>ret = ret + relativedelta.relativedelta(weekday=res.weekday)<EOL><DEDENT>if not ignoretz:<EOL><INDENT>if (isinstance(tzinfos, collections.Callable) or<EOL>tzinfos and res.tzname in tzinfos):<EOL><INDENT>if isinstance(tzinfos, collections.Callable):<EOL><INDENT>tzdata = tzinfos(res.tzname, res.tzoffset)<EOL><DEDENT>else:<EOL><INDENT>tzdata = tzinfos.get(res.tzname)<EOL><DEDENT>if isinstance(tzdata, datetime.tzinfo):<EOL><INDENT>tzinfo = tzdata<EOL><DEDENT>elif isinstance(tzdata, text_type):<EOL><INDENT>tzinfo = tz.tzstr(tzdata)<EOL><DEDENT>elif isinstance(tzdata, integer_types):<EOL><INDENT>tzinfo = tz.tzoffset(res.tzname, tzdata)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>ret = ret.replace(tzinfo=tzinfo)<EOL><DEDENT>elif res.tzname and res.tzname in time.tzname:<EOL><INDENT>ret = ret.replace(tzinfo=tz.tzlocal())<EOL><DEDENT>elif res.tzoffset == <NUM_LIT:0>:<EOL><INDENT>ret = ret.replace(tzinfo=tz.tzutc())<EOL><DEDENT>elif res.tzoffset:<EOL><INDENT>ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))<EOL><DEDENT><DEDENT>if kwargs.get('<STR_LIT>', False):<EOL><INDENT>return ret, skipped_tokens<EOL><DEDENT>else:<EOL><INDENT>return ret<EOL><DEDENT>

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 minutes or a :class:`tzinfo` object.

    .. doctest::
       :options: +NORMALIZE_WHITESPACE

        >>> from dateutil.parser import parse
        >>> from dateutil.tz import gettz
        >>> tzinfos = {"BRST": -10800, "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', -10800))
        >>> 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.


def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,<EOL>fuzzy_with_tokens=False):

if fuzzy_with_tokens:<EOL><INDENT>fuzzy = True<EOL><DEDENT>info = self.info<EOL>if dayfirst is None:<EOL><INDENT>dayfirst = info.dayfirst<EOL><DEDENT>if yearfirst is None:<EOL><INDENT>yearfirst = info.yearfirst<EOL><DEDENT>res = self._result()<EOL>l = _timelex.split(timestr)         <EOL>last_skipped_token_i = -<NUM_LIT:2><EOL>skipped_tokens = list()<EOL>try:<EOL><INDENT>ymd = _ymd(timestr)<EOL>mstridx = -<NUM_LIT:1><EOL>len_l = len(l)<EOL>i = <NUM_LIT:0><EOL>while i < len_l:<EOL><INDENT>try:<EOL><INDENT>value_repr = l[i]<EOL>value = float(value_repr)<EOL><DEDENT>except ValueError:<EOL><INDENT>value = None<EOL><DEDENT>if value is not None:<EOL><INDENT>len_li = len(l[i])<EOL>i += <NUM_LIT:1><EOL>if (len(ymd) == <NUM_LIT:3> and len_li in (<NUM_LIT:2>, <NUM_LIT:4>)<EOL>and res.hour is None and (i >= len_l or (l[i] != '<STR_LIT::>' and<EOL>info.hms(l[i]) is None))):<EOL><INDENT>s = l[i - <NUM_LIT:1>]<EOL>res.hour = int(s[:<NUM_LIT:2>])<EOL>if len_li == <NUM_LIT:4>:<EOL><INDENT>res.minute = int(s[<NUM_LIT:2>:])<EOL><DEDENT><DEDENT>elif len_li == <NUM_LIT:6> or (len_li > <NUM_LIT:6> and l[i - <NUM_LIT:1>].find('<STR_LIT:.>') == <NUM_LIT:6>):<EOL><INDENT>s = l[i - <NUM_LIT:1>]<EOL>if not ymd and l[i - <NUM_LIT:1>].find('<STR_LIT:.>') == -<NUM_LIT:1>:<EOL><INDENT>ymd.append(s[:<NUM_LIT:2>])<EOL>ymd.append(s[<NUM_LIT:2>:<NUM_LIT:4>])<EOL>ymd.append(s[<NUM_LIT:4>:])<EOL><DEDENT>else:<EOL><INDENT>res.hour = int(s[:<NUM_LIT:2>])<EOL>res.minute = int(s[<NUM_LIT:2>:<NUM_LIT:4>])<EOL>res.second, res.microsecond = _parsems(s[<NUM_LIT:4>:])<EOL><DEDENT><DEDENT>elif len_li in (<NUM_LIT:8>, <NUM_LIT:12>, <NUM_LIT>):<EOL><INDENT>s = l[i - <NUM_LIT:1>]<EOL>ymd.append(s[:<NUM_LIT:4>])<EOL>ymd.append(s[<NUM_LIT:4>:<NUM_LIT:6>])<EOL>ymd.append(s[<NUM_LIT:6>:<NUM_LIT:8>])<EOL>if len_li > <NUM_LIT:8>:<EOL><INDENT>res.hour = int(s[<NUM_LIT:8>:<NUM_LIT:10>])<EOL>res.minute = int(s[<NUM_LIT:10>:<NUM_LIT:12>])<EOL>if len_li > <NUM_LIT:12>:<EOL><INDENT>res.second = int(s[<NUM_LIT:12>:])<EOL><DEDENT><DEDENT><DEDENT>elif ((i < len_l and info.hms(l[i]) is not None) or<EOL>(i + <NUM_LIT:1> < len_l and l[i] == '<STR_LIT:U+0020>' and<EOL>info.hms(l[i + <NUM_LIT:1>]) is not None)):<EOL><INDENT>if l[i] == '<STR_LIT:U+0020>':<EOL><INDENT>i += <NUM_LIT:1><EOL><DEDENT>idx = info.hms(l[i])<EOL>while True:<EOL><INDENT>if idx == <NUM_LIT:0>:<EOL><INDENT>res.hour = int(value)<EOL>if value % <NUM_LIT:1>:<EOL><INDENT>res.minute = int(<NUM_LIT> * (value % <NUM_LIT:1>))<EOL><DEDENT><DEDENT>elif idx == <NUM_LIT:1>:<EOL><INDENT>res.minute = int(value)<EOL>if value % <NUM_LIT:1>:<EOL><INDENT>res.second = int(<NUM_LIT> * (value % <NUM_LIT:1>))<EOL><DEDENT><DEDENT>elif idx == <NUM_LIT:2>:<EOL><INDENT>res.second, res.microsecond =_parsems(value_repr)<EOL><DEDENT>i += <NUM_LIT:1><EOL>if i >= len_l or idx == <NUM_LIT:2>:<EOL><INDENT>break<EOL><DEDENT>try:<EOL><INDENT>value_repr = l[i]<EOL>value = float(value_repr)<EOL><DEDENT>except ValueError:<EOL><INDENT>break<EOL><DEDENT>else:<EOL><INDENT>i += <NUM_LIT:1><EOL>idx += <NUM_LIT:1><EOL>if i < len_l:<EOL><INDENT>newidx = info.hms(l[i])<EOL>if newidx is not None:<EOL><INDENT>idx = newidx<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>elif (i == len_l and l[i - <NUM_LIT:2>] == '<STR_LIT:U+0020>' and<EOL>info.hms(l[i - <NUM_LIT:3>]) is not None):<EOL><INDENT>idx = info.hms(l[i - <NUM_LIT:3>])<EOL>if idx == <NUM_LIT:0>:               <EOL><INDENT>res.minute = int(value)<EOL>sec_remainder = value % <NUM_LIT:1><EOL>if sec_remainder:<EOL><INDENT>res.second = int(<NUM_LIT> * sec_remainder)<EOL><DEDENT><DEDENT>elif idx == <NUM_LIT:1>:             <EOL><INDENT>res.second, res.microsecond =_parsems(value_repr)<EOL><DEDENT><DEDENT>elif i + <NUM_LIT:1> < len_l and l[i] == '<STR_LIT::>':<EOL><INDENT>res.hour = int(value)<EOL>i += <NUM_LIT:1><EOL>value = float(l[i])<EOL>res.minute = int(value)<EOL>if value % <NUM_LIT:1>:<EOL><INDENT>res.second = int(<NUM_LIT> * (value % <NUM_LIT:1>))<EOL><DEDENT>i += <NUM_LIT:1><EOL>if i < len_l and l[i] == '<STR_LIT::>':<EOL><INDENT>res.second, res.microsecond = _parsems(l[i + <NUM_LIT:1>])<EOL>i += <NUM_LIT:2><EOL><DEDENT><DEDENT>elif i < len_l and l[i] in ('<STR_LIT:->', '<STR_LIT:/>', '<STR_LIT:.>'):<EOL><INDENT>sep = l[i]<EOL>ymd.append(value_repr)<EOL>i += <NUM_LIT:1><EOL>if i < len_l and not info.jump(l[i]):<EOL><INDENT>try:<EOL><INDENT>ymd.append(l[i])<EOL><DEDENT>except ValueError:<EOL><INDENT>value = info.month(l[i])<EOL>if value is not None:<EOL><INDENT>ymd.append(value)<EOL>assert mstridx == -<NUM_LIT:1><EOL>mstridx = len(ymd) - <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>return None, None<EOL><DEDENT><DEDENT>i += <NUM_LIT:1><EOL>if i < len_l and l[i] == sep:<EOL><INDENT>i += <NUM_LIT:1><EOL>value = info.month(l[i])<EOL>if value is not None:<EOL><INDENT>ymd.append(value)<EOL>mstridx = len(ymd) - <NUM_LIT:1><EOL>assert mstridx == -<NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>ymd.append(l[i])<EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT><DEDENT><DEDENT>elif i >= len_l or info.jump(l[i]):<EOL><INDENT>if i + <NUM_LIT:1> < len_l and info.ampm(l[i + <NUM_LIT:1>]) is not None:<EOL><INDENT>res.hour = int(value)<EOL>if res.hour < <NUM_LIT:12> and info.ampm(l[i + <NUM_LIT:1>]) == <NUM_LIT:1>:<EOL><INDENT>res.hour += <NUM_LIT:12><EOL><DEDENT>elif res.hour == <NUM_LIT:12> and info.ampm(l[i + <NUM_LIT:1>]) == <NUM_LIT:0>:<EOL><INDENT>res.hour = <NUM_LIT:0><EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>ymd.append(value)<EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT>elif info.ampm(l[i]) is not None:<EOL><INDENT>res.hour = int(value)<EOL>if res.hour < <NUM_LIT:12> and info.ampm(l[i]) == <NUM_LIT:1>:<EOL><INDENT>res.hour += <NUM_LIT:12><EOL><DEDENT>elif res.hour == <NUM_LIT:12> and info.ampm(l[i]) == <NUM_LIT:0>:<EOL><INDENT>res.hour = <NUM_LIT:0><EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT>elif not fuzzy:<EOL><INDENT>return None, None<EOL><DEDENT>else:<EOL><INDENT>i += <NUM_LIT:1><EOL><DEDENT>continue<EOL><DEDENT>value = info.weekday(l[i])<EOL>if value is not None:<EOL><INDENT>res.weekday = value<EOL>i += <NUM_LIT:1><EOL>continue<EOL><DEDENT>value = info.month(l[i])<EOL>if value is not None:<EOL><INDENT>ymd.append(value)<EOL>assert mstridx == -<NUM_LIT:1><EOL>mstridx = len(ymd) - <NUM_LIT:1><EOL>i += <NUM_LIT:1><EOL>if i < len_l:<EOL><INDENT>if l[i] in ('<STR_LIT:->', '<STR_LIT:/>'):<EOL><INDENT>sep = l[i]<EOL>i += <NUM_LIT:1><EOL>ymd.append(l[i])<EOL>i += <NUM_LIT:1><EOL>if i < len_l and l[i] == sep:<EOL><INDENT>i += <NUM_LIT:1><EOL>ymd.append(l[i])<EOL>i += <NUM_LIT:1><EOL><DEDENT><DEDENT>elif (i + <NUM_LIT:3> < len_l and l[i] == l[i + <NUM_LIT:2>] == '<STR_LIT:U+0020>'<EOL>and info.pertain(l[i + <NUM_LIT:1>])):<EOL><INDENT>try:<EOL><INDENT>value = int(l[i + <NUM_LIT:3>])<EOL><DEDENT>except ValueError:<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>ymd.append(str(info.convertyear(value)))<EOL><DEDENT>i += <NUM_LIT:4><EOL><DEDENT><DEDENT>continue<EOL><DEDENT>value = info.ampm(l[i])<EOL>if value is not None:<EOL><INDENT>val_is_ampm = True<EOL>if fuzzy and res.ampm is not None:<EOL><INDENT>val_is_ampm = False<EOL><DEDENT>if res.hour is None:<EOL><INDENT>if fuzzy:<EOL><INDENT>val_is_ampm = False<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>elif not <NUM_LIT:0> <= res.hour <= <NUM_LIT:12>:<EOL><INDENT>if fuzzy:<EOL><INDENT>val_is_ampm = False<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL><DEDENT><DEDENT>if val_is_ampm:<EOL><INDENT>if value == <NUM_LIT:1> and res.hour < <NUM_LIT:12>:<EOL><INDENT>res.hour += <NUM_LIT:12><EOL><DEDENT>elif value == <NUM_LIT:0> and res.hour == <NUM_LIT:12>:<EOL><INDENT>res.hour = <NUM_LIT:0><EOL><DEDENT>res.ampm = value<EOL><DEDENT>elif fuzzy:<EOL><INDENT>last_skipped_token_i = self._skip_token(skipped_tokens,<EOL>last_skipped_token_i, i, l)<EOL><DEDENT>i += <NUM_LIT:1><EOL>continue<EOL><DEDENT>if (res.hour is not None and len(l[i]) <= <NUM_LIT:5> and<EOL>res.tzname is None and res.tzoffset is None and<EOL>not [x for x in l[i] if x not in<EOL>string.ascii_uppercase]):<EOL><INDENT>res.tzname = l[i]<EOL>res.tzoffset = info.tzoffset(res.tzname)<EOL>i += <NUM_LIT:1><EOL>if i < len_l and l[i] in ('<STR_LIT:+>', '<STR_LIT:->'):<EOL><INDENT>l[i] = ('<STR_LIT:+>', '<STR_LIT:->')[l[i] == '<STR_LIT:+>']<EOL>res.tzoffset = None<EOL>if info.utczone(res.tzname):<EOL><INDENT>res.tzname = None<EOL><DEDENT><DEDENT>continue<EOL><DEDENT>if res.hour is not None and l[i] in ('<STR_LIT:+>', '<STR_LIT:->'):<EOL><INDENT>signal = (-<NUM_LIT:1>, <NUM_LIT:1>)[l[i] == '<STR_LIT:+>']<EOL>i += <NUM_LIT:1><EOL>len_li = len(l[i])<EOL>if len_li == <NUM_LIT:4>:<EOL><INDENT>res.tzoffset = int(l[i][:<NUM_LIT:2>]) *<NUM_LIT> + int(l[i][<NUM_LIT:2>:]) * <NUM_LIT><EOL><DEDENT>elif i + <NUM_LIT:1> < len_l and l[i + <NUM_LIT:1>] == '<STR_LIT::>':<EOL><INDENT>res.tzoffset = int(l[i]) * <NUM_LIT> + int(l[i + <NUM_LIT:2>]) * <NUM_LIT><EOL>i += <NUM_LIT:2><EOL><DEDENT>elif len_li <= <NUM_LIT:2>:<EOL><INDENT>res.tzoffset = int(l[i][:<NUM_LIT:2>]) * <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>return None, None<EOL><DEDENT>i += <NUM_LIT:1><EOL>res.tzoffset *= signal<EOL>if (i + <NUM_LIT:3> < len_l and<EOL>info.jump(l[i]) and l[i + <NUM_LIT:1>] == '<STR_LIT:(>' and l[i + <NUM_LIT:3>] == '<STR_LIT:)>' and<EOL><NUM_LIT:3> <= len(l[i + <NUM_LIT:2>]) <= <NUM_LIT:5> and<EOL>not [x for x in l[i + <NUM_LIT:2>]<EOL>if x not in string.ascii_uppercase]):<EOL><INDENT>res.tzname = l[i + <NUM_LIT:2>]<EOL>i += <NUM_LIT:4><EOL><DEDENT>continue<EOL><DEDENT>if not (info.jump(l[i]) or fuzzy):<EOL><INDENT>return None, None<EOL><DEDENT>last_skipped_token_i = self._skip_token(skipped_tokens,<EOL>last_skipped_token_i, i, l)<EOL>i += <NUM_LIT:1><EOL><DEDENT>year, month, day = ymd.resolve_ymd(mstridx, yearfirst, dayfirst)<EOL>if year is not None:<EOL><INDENT>res.year = year<EOL>res.century_specified = ymd.century_specified<EOL><DEDENT>if month is not None:<EOL><INDENT>res.month = month<EOL><DEDENT>if day is not None:<EOL><INDENT>res.day = day<EOL><DEDENT><DEDENT>except (IndexError, ValueError, AssertionError):<EOL><INDENT>return None, None<EOL><DEDENT>if not info.validate(res):<EOL><INDENT>return None, None<EOL><DEDENT>if fuzzy_with_tokens:<EOL><INDENT>return res, tuple(skipped_tokens)<EOL><DEDENT>else:<EOL><INDENT>return res, None<EOL><DEDENT>

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 '))


def adjust_encoding(*args, **kwargs):<EOL><INDENT>name = namefunc(*args, **kwargs)<EOL>if name is not None and not PY3:<EOL><INDENT>name = name.encode()<EOL><DEDENT>return name<EOL><DEDENT>return adjust_encoding<EOL>

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


@wraps(f)<EOL>def fromutc(self, dt):<EOL><INDENT>if not isinstance(dt, datetime):<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>if dt.tzinfo is not self:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>return f(self, dt)<EOL><DEDENT>return fromutc<EOL>

The CPython version of ``fromutc`` checks that the input is a ``datetime``
object and that ``self`` is attached as its ``tzinfo``.


dt = dt.replace(tzinfo=self)<EOL>wall_0 = enfold(dt, fold=<NUM_LIT:0>)<EOL>wall_1 = enfold(dt, fold=<NUM_LIT:1>)<EOL>same_offset = wall_0.utcoffset() == wall_1.utcoffset()<EOL>same_dt = wall_0.replace(tzinfo=None) == wall_1.replace(tzinfo=None)<EOL>return same_dt and not same_offset<EOL>

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


def _fold_status(self, dt_utc, dt_wall):

if self.is_ambiguous(dt_wall):<EOL><INDENT>delta_wall = dt_wall - dt_utc<EOL>_fold = int(delta_wall == (dt_utc.utcoffset() - dt_utc.dst()))<EOL><DEDENT>else:<EOL><INDENT>_fold = <NUM_LIT:0><EOL><DEDENT>return _fold<EOL>

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.


<EOL>dtoff = dt.utcoffset()<EOL>if dtoff is None:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT:result>")<EOL><DEDENT>dtdst = dt.dst()<EOL>if dtdst is None:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>delta = dtoff - dtdst<EOL>dt += delta<EOL>dtdst = enfold(dt, fold=<NUM_LIT:1>).dst()<EOL>if dtdst is None:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>return dt + dtdst<EOL>

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.


dt_wall = self._fromutc(dt)<EOL>_fold = self._fold_status(dt, dt_wall)<EOL>return enfold(dt_wall, fold=_fold)<EOL>

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.


if not isinstance(dt, datetime):<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>if dt.tzinfo is not self:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>transitions = self.transitions(dt.year)<EOL>if transitions is None:<EOL><INDENT>return dt + self.utcoffset(dt)<EOL><DEDENT>dston, dstoff = transitions<EOL>dston -= self._std_offset<EOL>dstoff -= self._std_offset<EOL>utc_transitions = (dston, dstoff)<EOL>dt_utc = dt.replace(tzinfo=None)<EOL>isdst = self._naive_isdst(dt_utc, utc_transitions)<EOL>if isdst:<EOL><INDENT>dt_wall = dt + self._dst_offset<EOL><DEDENT>else:<EOL><INDENT>dt_wall = dt + self._std_offset<EOL><DEDENT>_fold = int(not isdst and self.is_ambiguous(dt_wall))<EOL>return enfold(dt_wall, fold=_fold)<EOL>

Given a datetime in UTC, return local time


if not self.hasdst:<EOL><INDENT>return False<EOL><DEDENT>start, end = self.transitions(dt.year)<EOL>dt = dt.replace(tzinfo=None)<EOL>return (end <= dt < end + self._dst_base_offset)<EOL>


def picknthweekday(year, month, dayofweek, hour, minute, whichweek):

first = datetime.datetime(year, month, <NUM_LIT:1>, hour, minute)<EOL>weekdayone = first.replace(day=((dayofweek - first.isoweekday()) % <NUM_LIT:7>) + <NUM_LIT:1>)<EOL>wd = weekdayone + ((whichweek - <NUM_LIT:1>) * ONEWEEK)<EOL>if (wd.month != month):<EOL><INDENT>wd -= ONEWEEK<EOL><DEDENT>return wd<EOL>

dayofweek == 0 means Sunday, whichweek 5 means last instance


dout = {}<EOL>size = winreg.QueryInfoKey(key)[<NUM_LIT:1>]<EOL>tz_res = None<EOL>for i in range(size):<EOL><INDENT>key_name, value, dtype = winreg.EnumValue(key, i)<EOL>if dtype == winreg.REG_DWORD or dtype == winreg.REG_DWORD_LITTLE_ENDIAN:<EOL><INDENT>if value & (<NUM_LIT:1> << <NUM_LIT>):<EOL><INDENT>value = value - (<NUM_LIT:1> << <NUM_LIT:32>)<EOL><DEDENT><DEDENT>elif dtype == winreg.REG_SZ:<EOL><INDENT>if value.startswith('<STR_LIT>'):<EOL><INDENT>tz_res = tz_res or tzres()<EOL>value = tz_res.name_from_string(value)<EOL><DEDENT>value = value.rstrip('<STR_LIT:\x00>')    <EOL><DEDENT>dout[key_name] = value<EOL><DEDENT>return dout<EOL>

Convert a registry key's values to a dictionary.


resource = self.p_wchar()<EOL>lpBuffer = ctypes.cast(ctypes.byref(resource), wintypes.LPWSTR)<EOL>nchar = self.LoadStringW(self._tzres._handle, offset, lpBuffer, <NUM_LIT:0>)<EOL>return resource[:nchar]<EOL>

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 if 114, not -114.


if not tzname_str.startswith('<STR_LIT:@>'):<EOL><INDENT>return tzname_str<EOL><DEDENT>name_splt = tzname_str.split('<STR_LIT>')<EOL>try:<EOL><INDENT>offset = int(name_splt[<NUM_LIT:1>])<EOL><DEDENT>except:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>return self.load_name(offset)<EOL>

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.


with winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) as handle:<EOL><INDENT>with winreg.OpenKey(handle, TZKEYNAME) as tzkey:<EOL><INDENT>result = [winreg.EnumKey(tzkey, i)<EOL>for i in range(winreg.QueryInfoKey(tzkey)[<NUM_LIT:0>])]<EOL><DEDENT><DEDENT>return result<EOL>

Return a list of all time zones known to the system.


if not self.hasdst:<EOL><INDENT>return None<EOL><DEDENT>dston = picknthweekday(year, self._dstmonth, self._dstdayofweek,<EOL>self._dsthour, self._dstminute,<EOL>self._dstweeknumber)<EOL>dstoff = picknthweekday(year, self._stdmonth, self._stddayofweek,<EOL>self._stdhour, self._stdminute,<EOL>self._stdweeknumber)<EOL>dstoff -= self._dst_base_offset<EOL>return dston, dstoff<EOL>

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 tz is None:<EOL><INDENT>if dt.tzinfo is None:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>tz = dt.tzinfo<EOL><DEDENT>dt = dt.replace(tzinfo=None)<EOL>dt_rt = dt.replace(tzinfo=tz).astimezone(tzutc()).astimezone(tz)<EOL>dt_rt = dt_rt.replace(tzinfo=None)<EOL>return dt == dt_rt<EOL>

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``.


if tz is None:<EOL><INDENT>if dt.tzinfo is None:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>tz = dt.tzinfo<EOL><DEDENT>is_ambiguous_fn = getattr(tz, '<STR_LIT>', None)<EOL>if is_ambiguous_fn is not None:<EOL><INDENT>try:<EOL><INDENT>return tz.is_ambiguous(dt)<EOL><DEDENT>except:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>dt = dt.replace(tzinfo=tz)<EOL>wall_0 = enfold(dt, fold=<NUM_LIT:0>)<EOL>wall_1 = enfold(dt, fold=<NUM_LIT:1>)<EOL>same_offset = wall_0.utcoffset() == wall_1.utcoffset()<EOL>same_dst = wall_0.dst() == wall_1.dst()<EOL>return not (same_offset and same_dst)<EOL>

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


return _total_seconds((dt.replace(tzinfo=None) - EPOCH))<EOL>

Convert a :class:`datetime.datetime` object to an epoch timestamp in seconds
since January 1, 1970, ignoring the time zone.


return False<EOL>


return dt<EOL>

Fast track version of fromutc() returns the original ``dt`` object for
any valid :py:class:`datetime.datetime` object.


naive_dst = self._naive_is_dst(dt)<EOL>return (not naive_dst and<EOL>(naive_dst != self._naive_is_dst(dt - self._dst_saved)))<EOL>


<EOL>for attr in _tzfile.attrs:<EOL><INDENT>setattr(self, '<STR_LIT:_>' + attr, getattr(tzobj, attr))<EOL><DEDENT>

Set the time zone data of this object from a _tzfile object


<EOL>if not isinstance(dt, datetime.datetime):<EOL><INDENT>raise TypeError("<STR_LIT>")<EOL><DEDENT>if dt.tzinfo is not self:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>idx = self._find_last_transition(dt, in_utc=True)<EOL>tti = self._get_ttinfo(idx)<EOL>dt_out = dt + datetime.timedelta(seconds=tti.offset)<EOL>fold = self.is_ambiguous(dt_out, idx=idx)<EOL>return enfold(dt_out, fold=int(fold))<EOL>

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.


if idx is None:<EOL><INDENT>idx = self._find_last_transition(dt)<EOL><DEDENT>timestamp = _datetime_to_timestamp(dt)<EOL>tti = self._get_ttinfo(idx)<EOL>if idx is None or idx <= <NUM_LIT:0>:<EOL><INDENT>return False<EOL><DEDENT>od = self._get_ttinfo(idx - <NUM_LIT:1>).offset - tti.offset<EOL>tt = self._trans_list[idx]          <EOL>return timestamp < tt + od<EOL>

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:<EOL><INDENT>return None<EOL><DEDENT>base_year = datetime.datetime(year, <NUM_LIT:1>, <NUM_LIT:1>)<EOL>start = base_year + self._start_delta<EOL>end = base_year + self._end_delta<EOL>return (start, end)<EOL>


return list(self._vtz.keys())<EOL>

Retrieves the available time zones as a list.


if tzid is None:<EOL><INDENT>if len(self._vtz) == <NUM_LIT:0>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>elif len(self._vtz) > <NUM_LIT:1>:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>tzid = next(iter(self._vtz))<EOL><DEDENT>return self._vtz.get(tzid)<EOL>

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.


<EOL>days = int(self.days)<EOL>hours_f = round(self.hours + <NUM_LIT> * (self.days - days), <NUM_LIT:11>)<EOL>hours = int(hours_f)<EOL>minutes_f = round(self.minutes + <NUM_LIT> * (hours_f - hours), <NUM_LIT:10>)<EOL>minutes = int(minutes_f)<EOL>seconds_f = round(self.seconds + <NUM_LIT> * (minutes_f - minutes), <NUM_LIT:8>)<EOL>seconds = int(seconds_f)<EOL>microseconds = round(self.microseconds + <NUM_LIT> * (seconds_f - seconds))<EOL>return self.__class__(years=self.years, months=self.months,<EOL>days=days, hours=hours, minutes=minutes,<EOL>seconds=seconds, microseconds=microseconds,<EOL>leapdays=self.leapdays, year=self.year,<EOL>month=self.month, day=self.day,<EOL>weekday=self.weekday, hour=self.hour,<EOL>minute=self.minute, second=self.second,<EOL>microsecond=self.microsecond)<EOL>

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.


if new_instance:<EOL><INDENT>zif = None<EOL><DEDENT>else:<EOL><INDENT>zif = getattr(get_zonefile_instance, '<STR_LIT>', None)<EOL><DEDENT>if zif is None:<EOL><INDENT>zif = ZoneInfoFile(getzoneinfofile_stream())<EOL>get_zonefile_instance._cached_instance = zif<EOL><DEDENT>return zif<EOL>

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


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.


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``.


return self.zones.get(name, default)<EOL>

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


def rebuild(filename, tag=None, format="<STR_LIT>", zonegroups=[], metadata=None):

tmpdir = tempfile.mkdtemp()<EOL>zonedir = os.path.join(tmpdir, "<STR_LIT>")<EOL>moduledir = os.path.dirname(__file__)<EOL>try:<EOL><INDENT>with tar_open(filename) as tf:<EOL><INDENT>for name in zonegroups:<EOL><INDENT>tf.extract(name, tmpdir)<EOL><DEDENT>filepaths = [os.path.join(tmpdir, n) for n in zonegroups]<EOL>try:<EOL><INDENT>check_call(["<STR_LIT>", "<STR_LIT>", zonedir] + filepaths)<EOL><DEDENT>except OSError as e:<EOL><INDENT>_print_on_nosuchfile(e)<EOL>raise<EOL><DEDENT><DEDENT>with open(os.path.join(zonedir, METADATA_FN), '<STR_LIT:w>') as f:<EOL><INDENT>json.dump(metadata, f, indent=<NUM_LIT:4>, sort_keys=True)<EOL><DEDENT>target = os.path.join(moduledir, ZONEFILENAME)<EOL>with tar_open(target, "<STR_LIT>" % format) as tf:<EOL><INDENT>for entry in os.listdir(zonedir):<EOL><INDENT>entrypath = os.path.join(zonedir, entry)<EOL>tf.add(entrypath, entry)<EOL><DEDENT><DEDENT><DEDENT>finally:<EOL><INDENT>shutil.rmtree(tmpdir)<EOL><DEDENT>

Rebuild the internal timezone info in dateutil/zoneinfo/zoneinfo*tar*

    filename is the timezone tarball from ftp.iana.org/tz.


if e.errno == <NUM_LIT:2>:<EOL><INDENT>logging.error(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>

Print helpful troubleshooting message

    e is an exception raised by subprocess.check_call()


if not (<NUM_LIT:1> <= method <= <NUM_LIT:3>):<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>y = year<EOL>g = y % <NUM_LIT><EOL>e = <NUM_LIT:0><EOL>if method < <NUM_LIT:3>:<EOL><INDENT>i = (<NUM_LIT> * g + <NUM_LIT:15>) % <NUM_LIT:30><EOL>j = (y + y // <NUM_LIT:4> + i) % <NUM_LIT:7><EOL>if method == <NUM_LIT:2>:<EOL><INDENT>e = <NUM_LIT:10><EOL>if y > <NUM_LIT>:<EOL><INDENT>e = e + y // <NUM_LIT:100> - <NUM_LIT:16> - (y // <NUM_LIT:100> - <NUM_LIT:16>) // <NUM_LIT:4><EOL><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>c = y // <NUM_LIT:100><EOL>h = (c - c // <NUM_LIT:4> - (<NUM_LIT:8> * c + <NUM_LIT>) // <NUM_LIT> + <NUM_LIT> * g + <NUM_LIT:15>) % <NUM_LIT:30><EOL>i = h - (h // <NUM_LIT>) * (<NUM_LIT:1> - (h // <NUM_LIT>) *<EOL>(<NUM_LIT> // (h + <NUM_LIT:1>)) * ((<NUM_LIT> - g) // <NUM_LIT:11>))<EOL>j = (y + y // <NUM_LIT:4> + i + <NUM_LIT:2> - c + c // <NUM_LIT:4>) % <NUM_LIT:7><EOL><DEDENT>p = i - j + e<EOL>d = <NUM_LIT:1> + (p + <NUM_LIT> + (p + <NUM_LIT:6>) // <NUM_LIT>) % <NUM_LIT><EOL>m = <NUM_LIT:3> + (p + <NUM_LIT>) // <NUM_LIT:30><EOL>return datetime.date(int(y), int(m), int(d))<EOL>

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:

http://users.chariot.net.au/~gmarts/eastalg.htm

and

http://www.tondering.dk/claus/calendar.html


if verbose:<EOL><INDENT>logger.info(message)<EOL><DEDENT>

Print message to console, if ``verbose`` is True.


element_type = element.__class__.__name__.lower()<EOL>args_list = [arg.strip() for arg in args.split('<STR_LIT:U+002C>')]<EOL>layout = (len(args_list) and args_list[<NUM_LIT:0>]) or "<STR_LIT:default>"<EOL>size = (len(args_list) > <NUM_LIT:1> and args_list[<NUM_LIT:1>]) or "<STR_LIT>"<EOL>label_cols = (len(args_list) > <NUM_LIT:2> and args_list[<NUM_LIT:2>]) or "<STR_LIT:2>"<EOL>input_cols = (len(args_list) > <NUM_LIT:3> and args_list[<NUM_LIT:3>]) or str(<NUM_LIT:12> - int(label_cols))<EOL>lbl_size_class = "<STR_LIT>" % (size, label_cols)<EOL>lbl_size_offset_class = "<STR_LIT>" % (size, label_cols)<EOL>ipt_size_class = "<STR_LIT>" % (size, input_cols)<EOL>if layout not in ["<STR_LIT:default>", "<STR_LIT>", "<STR_LIT>", "<STR_LIT>"]:<EOL><INDENT>layout = "<STR_LIT:default>"<EOL><DEDENT>if element_type == '<STR_LIT>':<EOL><INDENT>pass<EOL><DEDENT>else:<EOL><INDENT>if layout == "<STR_LIT:default>":<EOL><INDENT>field_template_file = "<STR_LIT>"<EOL><DEDENT>else:<EOL><INDENT>field_template_file = "<STR_LIT>" % layout<EOL><DEDENT>template = get_template("<STR_LIT>")<EOL>context = {<EOL>'<STR_LIT>': element,<EOL>'<STR_LIT>': layout,<EOL>'<STR_LIT>': lbl_size_class,<EOL>'<STR_LIT>': lbl_size_offset_class,<EOL>'<STR_LIT>': ipt_size_class,<EOL>'<STR_LIT>': settings.BOOTSTRAP_REQUIRED_SUFFIX,<EOL>'<STR_LIT>': "<STR_LIT>" % field_template_file}<EOL><DEDENT>return template.render(context)<EOL>

valid layouts are:
- default
- search
- inline
- horizontal

{{ form|twitter_bootstrap:"default" }}
{{ form|twitter_bootstrap:"horizontal" }}
{{ form|twitter_bootstrap:"horizontal,[xs,sm,md,lg],[1-12],[1-12]" }}


return dict(<EOL>(key, os.path.expandvars(value))<EOL>for key, value in settings.iteritems()<EOL>)<EOL>

Expands all environment variables in a settings dictionary.


<EOL>try:<EOL><INDENT>import sentry_sdk<EOL>from sentry_sdk.integrations.pyramid import PyramidIntegration<EOL>from sentry_sdk.integrations.celery import CeleryIntegration<EOL><DEDENT>except ImportError:<EOL><INDENT>warnings.warn(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>",<EOL>UserWarning,<EOL>)<EOL>return  <EOL><DEDENT>try:<EOL><INDENT>dsn = os.environ['<STR_LIT>']<EOL><DEDENT>except KeyError:<EOL><INDENT>warnings.warn(<EOL>"<STR_LIT>"<EOL>"<STR_LIT>",<EOL>UserWarning,<EOL>)<EOL><DEDENT>else:<EOL><INDENT>sentry_sdk.init(<EOL>dsn=dsn,<EOL>integrations=[PyramidIntegration(), CeleryIntegration()],<EOL>)<EOL><DEDENT>

\
    Used to optionally initialize the Sentry service with this app.
    See https://docs.sentry.io/platforms/python/pyramid/


global cache_manager<EOL>settings = config.registry.settings<EOL>cache_manager = CacheManager(**parse_cache_config_options(settings))<EOL>


def _make_one(self, payload, channel=None, pid=None):

if channel is None:<EOL><INDENT>channel = '<STR_LIT>'<EOL><DEDENT>if pid is None:<EOL><INDENT>pid = <NUM_LIT><EOL><DEDENT>from psycopg2.extensions import Notify<EOL>notif = Notify(pid=pid, channel=channel, payload=payload)<EOL>return notif<EOL>

Make a `psycopg2.extensions.Notify` object


<EOL>model.set_uri('<STR_LIT>', model.ident_hash)<EOL>

Set the model's cnx-archive-uri to the model's ident_hash.


cursor.execute("""<STR_LIT>""",<EOL>(uuid_,))<EOL>return cursor.fetchone()[<NUM_LIT:0>]<EOL>

Inserts a UUID value into the ``document_controls`` table.


uuid_ = model.id<EOL>permission = '<STR_LIT>'<EOL>for person_struct in model.metadata['<STR_LIT>']:<EOL><INDENT>user_id = person_struct['<STR_LIT:id>']<EOL>cursor.execute("""<STR_LIT>""", (uuid_, user_id, permission,))<EOL><DEDENT>

Insert the access control list for the given model.


user_ids = set([])<EOL>for role_attr in cnxepub.ATTRIBUTED_ROLE_KEYS:<EOL><INDENT>for role in model.metadata.get(role_attr, []):<EOL><INDENT>user_ids.add(role['<STR_LIT:id>'])<EOL><DEDENT><DEDENT>cursor.execute("<STR_LIT>",<EOL>(list(user_ids),))<EOL>try:<EOL><INDENT>existing_user_ids = [x[<NUM_LIT:0>] for x in cursor.fetchall()]<EOL><DEDENT>except TypeError:<EOL><INDENT>existing_user_ids = []<EOL><DEDENT>new_user_ids = [u for u in user_ids if u not in existing_user_ids]<EOL>for user_id in new_user_ids:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (user_id,))<EOL><DEDENT>


def _insert_file(file_bytes, media_type, cursor):

cursor.execute('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>',<EOL>(Binary(file_bytes), media_type))<EOL>return cursor.fetchone()[<NUM_LIT:0>]<EOL>

Insert a file, with media_type, into the files table. Returns fileid


config_uri = os.environ.get('<STR_LIT>', None)<EOL>if config_uri is None:<EOL><INDENT>config_uri = os.path.join(here, '<STR_LIT>')<EOL><DEDENT>return config_uri<EOL>

Return the file path of the testing config uri


@functools.wraps(method)<EOL>def wrapped(self, *args, **kwargs):<EOL><INDENT>connect = db_connection_factory()<EOL>with connect() as db_connection:<EOL><INDENT>with db_connection.cursor() as cursor:<EOL><INDENT>return method(self, cursor, *args, **kwargs)<EOL><DEDENT><DEDENT><DEDENT>return wrapped<EOL>

Decorator for methods that need to use the database

    Example:
    @db_connect
    def setUp(self, cursor):
        cursor.execute(some_sql)
        # some other code


def make_publication(self, publisher='<STR_LIT>', message="<STR_LIT>",<EOL>epub=None):

if epub is None:<EOL><INDENT>epub = b'<STR_LIT>'<EOL><DEDENT>epub = psycopg2.Binary(epub)<EOL>args = (publisher, message, epub,)<EOL>with psycopg2.connect(self.db_conn_str) as db_conn:<EOL><INDENT>with db_conn.cursor() as cursor:<EOL><INDENT>cursor.execute("""<STR_LIT>""", args)<EOL>publication_id = cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>return publication_id<EOL>

Make a publication entry in the database.


@db_connect<EOL><INDENT>def make_one(self, cursor, channel, payload):<DEDENT>

pl = json.dumps(payload)<EOL>cursor.execute("<STR_LIT>", (channel, pl,))<EOL>cursor.connection.commit()<EOL>time.sleep(<NUM_LIT:1>)<EOL>


setup_mapping = {<EOL>use_cases.BOOK: use_cases.setup_BOOK_in_archive,<EOL>}<EOL>try:<EOL><INDENT>setup = setup_mapping[use_case]<EOL><DEDENT>except:  <EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>with self.db_connect() as db_conn:<EOL><INDENT>with db_conn.cursor() as cursor:<EOL><INDENT>setup(self, cursor)<EOL><DEDENT><DEDENT>

Used to setup a content set in the archive.
        This is most useful when publishing revisions.


def app_get_license_acceptance(self, publication_id, uid, headers=[]):

path = '<STR_LIT>'.format(publication_id, uid)<EOL>return self.app.get(path, headers=headers)<EOL>

User at ``uid`` lookups up the HTML page for license acceptance.


def app_post_json_license_acceptance(self, publication_id, uid,<EOL>data, headers=[]):

path = '<STR_LIT>'.format(publication_id, uid)<EOL>self.app.post_json(path, data, headers=headers)<EOL>

User at ``uid`` accepts the license for publication at
        ``publication_id either for or against as ``accept``.
        The ``data`` value is expected to be a python type that
        this method will marshal to JSON.


def app_get_role_acceptance(self, publication_id, uid, headers=[]):

User at ``uid`` lookups up the HTML page for role acceptance.


def app_post_json_role_acceptance(self, publication_id, uid,<EOL>data, headers=[]):

User at ``uid`` accepts the attributed role for publication at
        ``publication_id either for or against as ``accept``.
        The ``data`` value is expected to be a python type that
        this method will marshal to JSON.


def app_post_acl(self, uuid_, data, headers=[]):

path = '<STR_LIT>'.format(uuid_)<EOL>self.app.post_json(path, data, headers=headers)<EOL>

Submission of ACL information for content at ``uuid``.
        The ``data`` value is expected to be a python type that this method
        will marshal to JSON.


path = '<STR_LIT>'<EOL>resp = self.app.get(path, headers=headers)<EOL>return resp<EOL>

Gets a list of the publication that are currently being moderated.


def app_post_moderation(self, publication_id, data, headers=[]):

path = '<STR_LIT>'.format(publication_id)<EOL>resp = self.app.post_json(path, data, headers=headers)<EOL>return resp<EOL>

Moderate the publication by sending an accept/reject state.


def app_login(self, username, password):

path = '<STR_LIT>'<EOL>data = {<EOL>'<STR_LIT:username>': username,<EOL>'<STR_LIT:password>': password,<EOL>}<EOL>resp = self.app.post(path, data)<EOL>return resp<EOL>

Logins in to the app using (a stub) accounts.


path = '<STR_LIT>'<EOL>resp = self.app.get(path)<EOL>return resp<EOL>


cookie = resp.headers['<STR_LIT>']<EOL>return [('<STR_LIT>', cookie,)]<EOL>

Extracts the cookie header from a login response.


<EOL>metadata = [x.metadata.copy()<EOL>for x in cnxepub.flatten_to_documents(binder)][<NUM_LIT:0>]<EOL>del metadata['<STR_LIT>']<EOL>del metadata['<STR_LIT:version>']<EOL>metadata['<STR_LIT:title>'] = "<STR_LIT>"<EOL>publisher = [p['<STR_LIT:id>'] for p in metadata['<STR_LIT>']][<NUM_LIT:0>]<EOL>message = "<STR_LIT>"<EOL>composite_doc = cnxepub.CompositeDocument(None, content, metadata)<EOL>return publisher, message, composite_doc<EOL>

Given a binder and content, make a composite document for that
        binder. Returns publisher, message and CompositeDocument instance.


def make_epub(self, binder, publisher, message):

zip_fd, zip_filepath = tempfile.mkstemp('<STR_LIT>', dir=self.tmpdir)<EOL>cnxepub.make_publication_epub(binder, publisher, message,<EOL>zip_filepath)<EOL>return zip_filepath<EOL>

Given a cnx-epub model, create an EPUB.
        This returns a temporary file location where the EPUB can be found.


zip_fd, zip_filepath = tempfile.mkstemp('<STR_LIT>', dir=self.tmpdir)<EOL>with zipfile.ZipFile(zip_filepath, '<STR_LIT:w>') as zippy:<EOL><INDENT>base_path = os.path.abspath(directory)<EOL>for root, dirs, filenames in os.walk(directory):<EOL><INDENT>archive_path = os.path.abspath(root)[len(base_path):]<EOL>for filename in filenames:<EOL><INDENT>filepath = os.path.join(root, filename)<EOL>archival_filepath = os.path.join(archive_path, filename)<EOL>zippy.write(filepath, archival_filepath)<EOL><DEDENT><DEDENT><DEDENT>return zip_filepath<EOL>

Given an directory containing epub contents,
        pack it up and make return filepath.
        Packed file is remove on test exit.


def copy(self, src, dst_name='<STR_LIT>'):

dst = os.path.join(self.tmpdir, dst_name)<EOL>shutil.copytree(src, dst)<EOL>return dst<EOL>

Convenient method for copying test data directories.


attr_name = '<STR_LIT>'<EOL>api_keys = getattr(self, attr_name, None)<EOL>def get_info():<EOL><INDENT>from cnxpublishing.authnz import lookup_api_key_info<EOL>with self.db_connect() as db_conn:<EOL><INDENT>with db_conn.cursor():<EOL><INDENT>return lookup_api_key_info()<EOL><DEDENT><DEDENT><DEDENT>if api_keys is None:<EOL><INDENT>self.addCleanup(delattr, self, attr_name)<EOL>api_keys = {}<EOL>for key, value in get_info().items():<EOL><INDENT>api_keys[value['<STR_LIT:name>']] = key<EOL><DEDENT>setattr(self, attr_name, api_keys)<EOL><DEDENT>return api_keys<EOL>


api_key = self.api_keys_by_name[name]<EOL>api_key_header = [('<STR_LIT>', api_key,)]<EOL>return api_key_header<EOL>

Generate authentication headers for the given user.


module_ident, ident_hash = event.module_ident, event.ident_hash<EOL>celery_app = get_current_registry().celery_app<EOL>cursor.execute('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>', (module_ident,))<EOL>for result in cursor.fetchall():<EOL><INDENT>state = celery_app.AsyncResult(result[<NUM_LIT:0>]).state<EOL>if state in ('<STR_LIT>', '<STR_LIT>', '<STR_LIT>'):<EOL><INDENT>logger.debug('<STR_LIT>'.format(<EOL>module_ident, ident_hash))<EOL>return<EOL><DEDENT><DEDENT>logger.debug('<STR_LIT>'.format(<EOL>module_ident, ident_hash))<EOL>recipe_ids = _get_recipe_ids(module_ident, cursor)<EOL>update_module_state(cursor, module_ident, '<STR_LIT>', recipe_ids[<NUM_LIT:0>])<EOL>cursor.connection.commit()<EOL>task_name = '<STR_LIT>'<EOL>baking_processor = celery_app.tasks[task_name]<EOL>result = baking_processor.delay(module_ident, ident_hash)<EOL>baking_processor.backend.store_result(result.id, None, '<STR_LIT>')<EOL>track_baking_proc_state(result, module_ident, cursor)<EOL>

Process post-publication events coming out of the database.


cursor.execute("""<STR_LIT>""", (module_ident,))<EOL>return cursor.fetchone()<EOL>

Returns a tuple of length 2 of primary and fallback recipe ids.

    The primary will be based on the print_style of the book. It is the first
    of:
        1. default recipe currently associated with the print_style of the book
           being baked (defined by module_ident)
        2. A CSS file associated with this book that is named the same as the
           print_style
        3. A CSS file associated with this book that is named 'ruleset.css'

        The fallback is the recipe used for last successful bake of this book,
        if different than the primary. Either value or both values may be
        None


here = os.path.abspath(os.path.dirname(__file__))<EOL>return os.path.join(here, '<STR_LIT>')<EOL>

Finds and returns the location of the database migrations directory.
    This function is used from a setuptools entry-point for db-migrator.


from .config import configure<EOL>return configure(settings).make_wsgi_app()<EOL>


if connection_string is None:<EOL><INDENT>connection_string = get_current_registry().settings[CONNECTION_STRING]<EOL><DEDENT>db_conn = psycopg2.connect(connection_string, **kwargs)<EOL>try:<EOL><INDENT>with db_conn:<EOL><INDENT>yield db_conn<EOL><DEDENT><DEDENT>finally:<EOL><INDENT>db_conn.close()<EOL><DEDENT>

Function to supply a database connection object.


@functools.wraps(func)<EOL>def wrapped(*args, **kwargs):<EOL><INDENT>if '<STR_LIT>' in kwargs or func.__code__.co_argcount == len(args):<EOL><INDENT>return func(*args, **kwargs)<EOL><DEDENT>with db_connect() as db_connection:<EOL><INDENT>with db_connection.cursor() as cursor:<EOL><INDENT>kwargs['<STR_LIT>'] = cursor<EOL>return func(*args, **kwargs)<EOL><DEDENT><DEDENT><DEDENT>return wrapped<EOL>

Decorator that supplies a cursor to the function.
    This passes in a psycopg2 Cursor as the argument 'cursor'.
    It also accepts a cursor if one is given.


cursor.execute("""<STR_LIT>""")<EOL>return cursor.fetchall()<EOL>

Acquire a list of term and identifier values.
    Returns a list of tuples containing the term and the subject identifier.


with db_connect() as db_conn:<EOL><INDENT>with db_conn.cursor() as cursor:<EOL><INDENT>cursor.execute("""<STR_LIT>""")<EOL>db_types = cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>return dict(list(zip(cnxepub.ATTRIBUTED_ROLE_KEYS, db_types)))[type_]<EOL>

Translates a role type (a value found in
    ``cnxepub.ATTRIBUTED_ROLE_KEYS``) to a database compatible
    value for ``role_types``.


for role_key in cnxepub.ATTRIBUTED_ROLE_KEYS:<EOL><INDENT>for user in metadata.get(role_key, []):<EOL><INDENT>if user['<STR_LIT:type>'] != '<STR_LIT>':<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>uid = parse_user_uri(user['<STR_LIT:id>'])<EOL>yield uid, role_key<EOL><DEDENT><DEDENT>raise StopIteration()<EOL>

Given a model's ``metadata``, iterate over the roles.
    Return values are the role identifier and role type as a tuple.


cursor.execute("""<STR_LIT>""", (document_id,))<EOL>uuid_, metadata = cursor.fetchone()<EOL>acceptors = set([uid for uid, type_ in _dissect_roles(metadata)])<EOL>cursor.execute("""<STR_LIT>""", (uuid_,))<EOL>existing_acceptors_mapping = dict(cursor.fetchall())<EOL>existing_acceptors = set(existing_acceptors_mapping.keys())<EOL>new_acceptors = acceptors.difference(existing_acceptors)<EOL>for acceptor in new_acceptors:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (uuid_, acceptor,))<EOL><DEDENT>cursor.execute("""<STR_LIT>""", (uuid_,))<EOL>defectors = set(cursor.fetchall())<EOL>if not defectors:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (document_id,))<EOL><DEDENT>

Update or insert records for pending license acceptors.


cursor.execute("""<STR_LIT>""", (document_id,))<EOL>uuid_, metadata = cursor.fetchone()<EOL>acceptors = set([(uid, _role_type_to_db_type(type_),)<EOL>for uid, type_ in _dissect_roles(metadata)])<EOL>upsert_users(cursor, [x[<NUM_LIT:0>] for x in acceptors])<EOL>cursor.execute("""<STR_LIT>""", (uuid_,))<EOL>existing_roles = set([(r, t,) for r, t in cursor.fetchall()])<EOL>existing_acceptors = existing_roles<EOL>new_acceptors = acceptors.difference(existing_acceptors)<EOL>for acceptor, type_ in new_acceptors:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (uuid_, acceptor, type_))<EOL><DEDENT>cursor.execute("""<STR_LIT>""", (uuid_,))<EOL>defectors = set(cursor.fetchall())<EOL>if not defectors:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (document_id,))<EOL><DEDENT>

Update or insert records for pending document role acceptance.


if isinstance(model, cnxepub.Binder):<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>return '<STR_LIT>'<EOL><DEDENT>

Returns a type name of 'Document' or 'Binder' based model's type.


with db_connect() as db_conn:<EOL><INDENT>with db_conn.cursor() as cursor:<EOL><INDENT>cursor.execute("""<STR_LIT>""")<EOL>licenses = {r[<NUM_LIT:0>]: r[<NUM_LIT:1>] for r in cursor.fetchall()}<EOL><DEDENT><DEDENT>return licenses<EOL>

Obtain the licenses in a dictionary form, keyed by url.


license_mapping = obtain_licenses()<EOL>try:<EOL><INDENT>license_url = model.metadata['<STR_LIT>']<EOL><DEDENT>except KeyError:<EOL><INDENT>raise exceptions.MissingRequiredMetadata('<STR_LIT>')<EOL><DEDENT>try:<EOL><INDENT>license = license_mapping[license_url]<EOL><DEDENT>except KeyError:<EOL><INDENT>raise exceptions.InvalidLicense(license_url)<EOL><DEDENT>if not license['<STR_LIT>']:<EOL><INDENT>raise exceptions.InvalidLicense(license_url)<EOL><DEDENT>

Given the model, check the license is one valid for publication.


required_roles = (ATTRIBUTED_ROLE_KEYS[<NUM_LIT:0>], ATTRIBUTED_ROLE_KEYS[<NUM_LIT:4>],)<EOL>for role_key in ATTRIBUTED_ROLE_KEYS:<EOL><INDENT>try:<EOL><INDENT>roles = model.metadata[role_key]<EOL><DEDENT>except KeyError:<EOL><INDENT>if role_key in required_roles:<EOL><INDENT>raise exceptions.MissingRequiredMetadata(role_key)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if role_key in required_roles and len(roles) == <NUM_LIT:0>:<EOL><INDENT>raise exceptions.MissingRequiredMetadata(role_key)<EOL><DEDENT><DEDENT>for role in roles:<EOL><INDENT>if role.get('<STR_LIT:type>') != '<STR_LIT>':<EOL><INDENT>raise exceptions.InvalidRole(role_key, role)<EOL><DEDENT><DEDENT><DEDENT>

Given the model, check that all the metadata role values
    have valid information in them and any required metadata fields
    contain values.


derived_from_uri = model.metadata.get('<STR_LIT>')<EOL>if derived_from_uri is None:<EOL><INDENT>return  <EOL><DEDENT>try:<EOL><INDENT>ident_hash = parse_archive_uri(derived_from_uri)<EOL>uuid_, version = split_ident_hash(ident_hash, split_version=True)<EOL><DEDENT>except (ValueError, IdentHashSyntaxError, IdentHashShortId) as exc:<EOL><INDENT>raise exceptions.InvalidMetadata('<STR_LIT>', derived_from_uri,<EOL>original_exception=exc)<EOL><DEDENT>args = [uuid_]<EOL>table = '<STR_LIT>'<EOL>version_condition = '<STR_LIT>'<EOL>if version != (None, None,):<EOL><INDENT>args.extend(version)<EOL>table = '<STR_LIT>'<EOL>version_condition = "<STR_LIT>""<STR_LIT>".format(version[<NUM_LIT:1>] is None and '<STR_LIT>' or '<STR_LIT:=>')<EOL><DEDENT>cursor.execute("""<STR_LIT>"""<EOL>.format(table, version_condition), args)<EOL>try:<EOL><INDENT>_exists = cursor.fetchone()[<NUM_LIT:0>]  <EOL><DEDENT>except TypeError:  <EOL><INDENT>raise exceptions.InvalidMetadata('<STR_LIT>', derived_from_uri)<EOL><DEDENT>model.metadata['<STR_LIT>'] = ident_hash<EOL>

Given a database cursor and model, check the derived-from
    value accurately points to content in the archive.
    The value can be nothing or must point to existing content.


subject_vocab = [term[<NUM_LIT:0>] for term in acquire_subject_vocabulary(cursor)]<EOL>subjects = model.metadata.get('<STR_LIT>', [])<EOL>invalid_subjects = [s for s in subjects if s not in subject_vocab]<EOL>if invalid_subjects:<EOL><INDENT>raise exceptions.InvalidMetadata('<STR_LIT>', invalid_subjects)<EOL><DEDENT>

Give a database cursor and model, check the subjects against
    the subject vocabulary.


<EOL>_validate_license(model)<EOL>_validate_roles(model)<EOL>required_metadata = ('<STR_LIT:title>', '<STR_LIT>',)<EOL>for metadata_key in required_metadata:<EOL><INDENT>if model.metadata.get(metadata_key) in [None, '<STR_LIT>', []]:<EOL><INDENT>raise exceptions.MissingRequiredMetadata(metadata_key)<EOL><DEDENT><DEDENT>_validate_derived_from(cursor, model)<EOL>_validate_subjects(cursor, model)<EOL>

Validates the model using a series of checks on bits of the data.


def is_publication_permissible(cursor, publication_id, uuid_):

<EOL>cursor.execute("""<STR_LIT>""", (publication_id, uuid_,))<EOL>try:<EOL><INDENT>is_allowed = cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT>except TypeError:<EOL><INDENT>is_allowed = False<EOL><DEDENT>return is_allowed<EOL>

Check the given publisher of this publication given
    by ``publication_id`` is allowed to publish the content given
    by ``uuid``.


def add_pending_model(cursor, publication_id, model):

<EOL>assert isinstance(model, (cnxepub.Document, cnxepub.Binder)), type(model)<EOL>uri = model.get_uri('<STR_LIT>')<EOL>if uri is not None:<EOL><INDENT>ident_hash = parse_archive_uri(uri)<EOL>id, version = split_ident_hash(ident_hash, split_version=True)<EOL>cursor.execute("""<STR_LIT>"""<EOL>rol_insert AS (<EOL>SERT INTO document_controls (uuid) VALUES (DEFAULT) RETURNING uuid),<EOL>insert AS (<EOL>SERT INTO document_acl (uuid, user_id, permission)<EOL>LUES ((SELECT uuid FROM control_insert),<EOL>(SELECT publisher FROM publications WHERE id = %s),<EOL>'<STR_LIT>'::permission_type))<EOL>CT uuid FROM control_insert"""<STR_LIT>"""RT INTO "<STR_LIT>"<EOL>publication_id"<STR_LIT:U+002CU+0020>"uuid"<STR_LIT:U+002CU+0020>"major_version"<STR_LIT:U+002CU+0020>"minor_version"<STR_LIT:U+002CU+0020>"type",<EOL>"<STR_LIT>", "<STR_LIT>", "<STR_LIT>")<EOL><DEDENT>ES (%s, %s, %s, %s, %s, '<STR_LIT:f>', '<STR_LIT:f>', %s)<EOL>RNING "<STR_LIT:id>", "<STR_LIT>", module_version("<STR_LIT>", "<STR_LIT>")<EOL><INDENT>args)<EOL>pending_id, uuid_, version = cursor.fetchone()<EOL>pending_ident_hash = join_ident_hash(uuid_, version)<EOL>request = get_current_request()<EOL>path = request.route_path('<STR_LIT>', ident_hash=pending_ident_hash)<EOL>model.set_uri('<STR_LIT>', path)<EOL>if not is_publication_permissible(cursor, publication_id, id):<EOL>exc = exceptions.NotAllowed(id)<EOL>exc.publication_id = publication_id<EOL>exc.pending_document_id = pending_id<EOL>exc.pending_ident_hash = pending_ident_hash<EOL>set_publication_failure(cursor, exc)<EOL>try:<EOL>validate_model(cursor, model)<EOL>except exceptions.PublicationException as exc:<EOL>exc_info = sys.exc_info()<EOL>exc.publication_id = publication_id<EOL>exc.pending_document_id = pending_id<EOL>exc.pending_ident_hash = pending_ident_hash<EOL>try:<EOL>set_publication_failure(cursor, exc)<EOL>except BaseException:<EOL>import traceback<EOL>print("<STR_LIT>"<EOL><INDENT>"<STR_LIT>"<EOL>.format(publication_id),<EOL>file=sys.stderr)<EOL>traceback.print_exc()<EOL>raise exc_info[<NUM_LIT:0>](exc_info[<NUM_LIT:1>]).with_traceback(exc_info[<NUM_LIT:2>])<EOL>else:<EOL>upsert_pending_licensors(cursor, pending_id)<EOL>upsert_pending_roles(cursor, pending_id)<EOL>notify_users(cursor, pending_id)<EOL>return pending_ident_hash<EOL>

Adds a model (binder or document) that is awaiting publication
    to the database.


id, version = split_ident_hash(ident_hash, split_version=True)<EOL>stmt = "<STR_LIT>"<EOL>args = [id]<EOL>if version and version[<NUM_LIT:0>] is not None:<EOL><INDENT>operator = version[<NUM_LIT:1>] is None and '<STR_LIT>' or '<STR_LIT:=>'<EOL>stmt += "<STR_LIT>".format(operator)<EOL>args.extend(version)<EOL><DEDENT>cursor.execute(stmt, args)<EOL>try:<EOL><INDENT>title = cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT>except TypeError:<EOL><INDENT>raise DocumentLookupError()<EOL><DEDENT>else:<EOL><INDENT>metadata = {'<STR_LIT:title>': title}<EOL><DEDENT>return cnxepub.DocumentPointer(ident_hash, metadata)<EOL>


def add_pending_model_content(cursor, publication_id, model):

cursor.execute("""<STR_LIT>""",<EOL>(publication_id, model.id,))<EOL>document_info = cursor.fetchone()<EOL>def attach_info_to_exception(exc):<EOL><INDENT>"""<STR_LIT>"""<EOL>exc.publication_id = publication_id<EOL>exc.pending_document_id, exc.pending_ident_hash = document_info<EOL><DEDENT>def mark_invalid_reference(reference):<EOL><INDENT>"""<STR_LIT>"""<EOL>exc = exceptions.InvalidReference(reference)<EOL>attach_info_to_exception(exc)<EOL>set_publication_failure(cursor, exc)<EOL><DEDENT>for resource in getattr(model, '<STR_LIT>', []):<EOL><INDENT>add_pending_resource(cursor, resource, document=model)<EOL><DEDENT>if isinstance(model, cnxepub.Document):<EOL><INDENT>for reference in model.references:<EOL><INDENT>if reference.is_bound:<EOL><INDENT>reference.bind(reference.bound_model, '<STR_LIT>')<EOL><DEDENT>elif reference.remote_type == cnxepub.INTERNAL_REFERENCE_TYPE:<EOL><INDENT>if reference.uri.startswith('<STR_LIT:#>'):<EOL><INDENT>pass<EOL><DEDENT>elif reference.uri.startswith('<STR_LIT>'):<EOL><INDENT>ident_hash = parse_archive_uri(reference.uri)<EOL>try:<EOL><INDENT>doc_pointer = lookup_document_pointer(<EOL>ident_hash, cursor)<EOL><DEDENT>except DocumentLookupError:<EOL><INDENT>mark_invalid_reference(reference)<EOL><DEDENT>else:<EOL><INDENT>reference.bind(doc_pointer, "<STR_LIT>")<EOL><DEDENT><DEDENT>else:<EOL><INDENT>mark_invalid_reference(reference)<EOL><DEDENT><DEDENT><DEDENT>args = (psycopg2.Binary(model.content.encode('<STR_LIT:utf-8>')),<EOL>publication_id, model.id,)<EOL>stmt = """<STR_LIT>"""<EOL><DEDENT>else:<EOL><INDENT>metadata = model.metadata.copy()<EOL>document_pointers = [m for m in cnxepub.flatten_model(model)<EOL>if isinstance(m, cnxepub.DocumentPointer)]<EOL>document_pointer_ident_hashes = [<EOL>(split_ident_hash(dp.ident_hash)[<NUM_LIT:0>],<EOL>split_ident_hash(dp.ident_hash, split_version=True)[<NUM_LIT:1>][<NUM_LIT:0>],<EOL>split_ident_hash(dp.ident_hash, split_version=True)[<NUM_LIT:1>][<NUM_LIT:1>],)<EOL>for dp in document_pointers]<EOL>document_pointer_ident_hashes = list(zip(*document_pointer_ident_hashes))<EOL>if document_pointers:<EOL><INDENT>uuids, major_vers, minor_vers = document_pointer_ident_hashes<EOL>cursor.execute("""<STR_LIT>""",<EOL>(list(uuids), list(major_vers), list(minor_vers),))<EOL>valid_pointer_results = cursor.fetchall()<EOL>for result_row in valid_pointer_results:<EOL><INDENT>uuid, version, exists, is_document = result_row<EOL>if not (exists and is_document):<EOL><INDENT>dp = [dp for dp in document_pointers<EOL>if dp.ident_hash == join_ident_hash(uuid, version)<EOL>][<NUM_LIT:0>]<EOL>exc = exceptions.InvalidDocumentPointer(<EOL>dp, exists=exists, is_document=is_document)<EOL>attach_info_to_exception(exc)<EOL>set_publication_failure(cursor, exc)<EOL><DEDENT><DEDENT><DEDENT>metadata['<STR_LIT>'] = cnxepub.model_to_tree(model)<EOL>args = (json.dumps(metadata),<EOL>None,  <EOL>publication_id, model.id,)<EOL>stmt = """<STR_LIT>"""<EOL><DEDENT>cursor.execute(stmt, args)<EOL>

Updates the pending model's content.
    This is a secondary step not in ``add_pending_model, because
    content reference resolution requires the identifiers as they
    will appear in the end publication.


publication_id = exc.publication_id<EOL>if publication_id is None:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>cursor.execute("""<STR_LIT>""", (publication_id,))<EOL>state_messages = cursor.fetchone()[<NUM_LIT:0>]<EOL>if state_messages is None:<EOL><INDENT>state_messages = []<EOL><DEDENT>entry = exc.__dict__<EOL>entry['<STR_LIT:message>'] = exc.message<EOL>state_messages.append(entry)<EOL>state_messages = json.dumps(state_messages)<EOL>cursor.execute("""<STR_LIT>""", ('<STR_LIT>', state_messages, publication_id,))<EOL>

Given a publication exception, set the publication as failed and
    append the failure message to the publication record.


def add_publication(cursor, epub, epub_file, is_pre_publication=False):

publisher = epub[<NUM_LIT:0>].metadata['<STR_LIT>']<EOL>publish_message = epub[<NUM_LIT:0>].metadata['<STR_LIT>']<EOL>epub_binary = psycopg2.Binary(epub_file.read())<EOL>args = (publisher, publish_message, epub_binary, is_pre_publication,)<EOL>cursor.execute(

Adds a publication entry and makes each item
    a pending document.


cursor.execute("""<STR_LIT>""",<EOL>(document_id,))<EOL>try:<EOL><INDENT>is_accepted = cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT>except TypeError:<EOL><INDENT>is_accepted = True<EOL><DEDENT>return is_accepted<EOL>

Check the aggregate state on the pending document.


def _update_pending_document_state(cursor, document_id, is_license_accepted,<EOL>are_roles_accepted):

args = (bool(is_license_accepted), bool(are_roles_accepted),<EOL>document_id,)<EOL>cursor.execute("""<STR_LIT>""",<EOL>args)<EOL>

Update the state of the document's state values.


cursor.execute("""<STR_LIT>""", (publication_id,))<EOL>try:<EOL><INDENT>cursor.fetchone()[<NUM_LIT:0>]<EOL><DEDENT>except TypeError:  <EOL><INDENT>has_revision_models = False<EOL><DEDENT>else:<EOL><INDENT>has_revision_models = True<EOL><DEDENT>return has_revision_models<EOL>

Checks to see if the publication contains any revised models.
    Revised in this context means that it is a new version of an
    existing piece of content.


cursor.execute("""<STR_LIT>""", (publication_id,))<EOL>row = cursor.fetchone()<EOL>current_state, messages, is_pre_publication, publisher = row<EOL>if current_state in END_N_INTERIM_STATES:<EOL><INDENT>return current_state, messages<EOL><DEDENT>cursor.execute("""<STR_LIT>"""CT is_moderated<EOL>users AS u LEFT JOIN publications AS p ON (u.username = p.publisher)<EOL>E p.id = %s"""<STR_LIT>"""TE publications<EOL>state = %s<EOL>E id = %s<EOL>RNING state, state_messages"""<STR_LIT>"""TE publications<EOL>state = %s<EOL>E id = %s<EOL>RNING state, state_messages

Invoked to poke at the publication to update and acquire its current
    state. This is used to persist the publication to archive.


with db_connect() as db_conn:<EOL><INDENT>with db_conn.cursor() as cursor:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (publication_id,))<EOL>publication_state, publication_messages = cursor.fetchone()<EOL><DEDENT><DEDENT>return publication_state, publication_messages<EOL>


def _node_to_model(tree_or_item, metadata=None, parent=None,<EOL>lucent_id=cnxepub.TRANSLUCENT_BINDER_ID):

if '<STR_LIT>' in tree_or_item:<EOL><INDENT>tree = tree_or_item<EOL>binder = cnxepub.TranslucentBinder(metadata=tree)<EOL>for item in tree['<STR_LIT>']:<EOL><INDENT>node = _node_to_model(item, parent=binder,<EOL>lucent_id=lucent_id)<EOL>if node.metadata['<STR_LIT:title>'] != item['<STR_LIT:title>']:<EOL><INDENT>binder.set_title_for_node(node, item['<STR_LIT:title>'])<EOL><DEDENT><DEDENT>result = binder<EOL><DEDENT>else:<EOL><INDENT>item = tree_or_item<EOL>result = cnxepub.DocumentPointer(item['<STR_LIT:id>'], metadata=item)<EOL><DEDENT>if parent is not None:<EOL><INDENT>parent.append(result)<EOL><DEDENT>return result<EOL>


def _reassemble_binder(id, tree, metadata):

binder = cnxepub.Binder(id, metadata=metadata)<EOL>for item in tree['<STR_LIT>']:<EOL><INDENT>node = _node_to_model(item, parent=binder)<EOL>if node.metadata['<STR_LIT:title>'] != item['<STR_LIT:title>']:<EOL><INDENT>binder.set_title_for_node(node, item['<STR_LIT:title>'])<EOL><DEDENT><DEDENT>return binder<EOL>

Reassemble a Binder object coming out of the database.


cursor.execute("""<STR_LIT>""",<EOL>(publication_id, publication_id,))<EOL>publisher, message = cursor.fetchone()<EOL>cursor.connection.commit()<EOL>all_models = []<EOL>from .publish import publish_model<EOL>type_ = cnxepub.Document.__name__<EOL>cursor.execute("""<STR_LIT>""", (type_, publication_id,))<EOL>for row in cursor.fetchall():<EOL><INDENT>id, major_version, minor_version = row[<NUM_LIT:1>:<NUM_LIT:4>]<EOL>id = str(id)<EOL>version = '<STR_LIT:.>'.join([str(x)<EOL>for x in (major_version, minor_version,)<EOL>if x is not None])<EOL>metadata, content = row[-<NUM_LIT:2>:]<EOL>content = content[:]<EOL>metadata['<STR_LIT:version>'] = version<EOL>document = cnxepub.Document(id, content, metadata)<EOL>for ref in document.references:<EOL><INDENT>if ref.uri.startswith('<STR_LIT>'):<EOL><INDENT>hash = ref.uri[len('<STR_LIT>'):]<EOL>cursor.execute("""<STR_LIT>""", (hash,))<EOL>data, media_type = cursor.fetchone()<EOL>document.resources.append(cnxepub.Resource(<EOL>hash, io.BytesIO(data[:]), media_type, filename=hash))<EOL><DEDENT><DEDENT>_ident_hash = publish_model(cursor, document, publisher, message)  <EOL>all_models.append(document)<EOL><DEDENT>type_ = cnxepub.Binder.__name__<EOL>cursor.execute("""<STR_LIT>""", (type_, publication_id,))<EOL>for row in cursor.fetchall():<EOL><INDENT>id, major_version, minor_version, metadata = row[<NUM_LIT:1>:<NUM_LIT:5>]<EOL>tree = metadata['<STR_LIT>']<EOL>binder = _reassemble_binder(str(id), tree, metadata)<EOL>cursor.execute("""<STR_LIT>""",<EOL>(binder.ident_hash,))<EOL>binder.resources = [<EOL>cnxepub.Resource(r_hash,<EOL>io.BytesIO(r_data[:]),<EOL>r_media_type,<EOL>filename=r_filename)<EOL>for (r_hash, r_data, r_media_type, r_filename)<EOL>in cursor.fetchall()]<EOL>_ident_hash = publish_model(cursor, binder, publisher, message)  <EOL>all_models.append(binder)<EOL><DEDENT>from .publish import republish_binders<EOL>_republished_ident_hashes = republish_binders(cursor, all_models)  <EOL>cursor.execute("""<STR_LIT>""", (publication_id,))<EOL>state = cursor.fetchone()[<NUM_LIT:0>]<EOL>return state<EOL>

Given a publication id as ``publication_id``,
    write the documents to the *Connexions Archive*.


def accept_publication_license(cursor, publication_id, user_id,<EOL>document_ids, is_accepted=False):

cursor.execute("""<STR_LIT>""",<EOL>(is_accepted, publication_id, user_id, document_ids,))<EOL>

Accept or deny  the document license for the publication
    (``publication_id``) and user (at ``user_id``)
    for the documents (listed by id as ``document_ids``).


def accept_publication_role(cursor, publication_id, user_id,<EOL>document_ids, is_accepted=False):

Accept or deny  the document role attribution for the publication
    (``publication_id``) and user (at ``user_id``)
    for the documents (listed by id as ``document_ids``).


def upsert_license_requests(cursor, uuid_, roles):

if not isinstance(roles, (list, set, tuple)):<EOL><INDENT>raise TypeError("<STR_LIT>".format(type(roles)))<EOL><DEDENT>acceptors = set([x['<STR_LIT>'] for x in roles])<EOL>cursor.execute("""<STR_LIT>""",<EOL>(uuid_,))<EOL>existing_acceptors = cursor.fetchall()<EOL>new_acceptors = acceptors.difference([x[<NUM_LIT:0>] for x in existing_acceptors])<EOL>if new_acceptors:<EOL><INDENT>args = []<EOL>values_fmt = []<EOL>for uid in new_acceptors:<EOL><INDENT>has_accepted = [x.get('<STR_LIT>', None)<EOL>for x in roles<EOL>if uid == x['<STR_LIT>']][<NUM_LIT:0>]<EOL>args.extend([uuid_, uid, has_accepted])<EOL>values_fmt.append("<STR_LIT>")<EOL><DEDENT>values_fmt = '<STR_LIT:U+002CU+0020>'.join(values_fmt)<EOL>cursor.execute("""<STR_LIT>""".format(values_fmt), args)<EOL><DEDENT>acceptors = set([<EOL>(x['<STR_LIT>'], x.get('<STR_LIT>', None),)<EOL>for x in roles<EOL>if (x['<STR_LIT>'], x.get('<STR_LIT>', None),) not in new_acceptors<EOL>])<EOL>existing_acceptors = set([<EOL>x for x in existing_acceptors<EOL>if x[<NUM_LIT:0>] not in new_acceptors<EOL>])<EOL>tobe_updated_acceptors = acceptors.difference(existing_acceptors)<EOL>for uid, has_accepted in tobe_updated_acceptors:<EOL><INDENT>cursor.execute("""<STR_LIT>""", (has_accepted, uuid_, uid,))<EOL><DEDENT>

Given a ``uuid`` and list of ``roles`` (user identifiers)
    create a license acceptance entry. If ``has_accepted`` is supplied,
    it will be used to assign an acceptance value to all listed ``uids``.


def remove_license_requests(cursor, uuid_, uids):

if not isinstance(uids, (list, set, tuple)):<EOL><INDENT>raise TypeError("<STR_LIT>".format(type(uids)))<EOL><DEDENT>acceptors = list(set(uids))<EOL>cursor.execute("""<STR_LIT>""", (uuid_, acceptors,))<EOL>

Given a ``uuid`` and list of ``uids`` (user identifiers)
    remove the identified users' license acceptance entries.