From 6aa7b291cb9c587aaf6d13f74bf29b2d4d33823f Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 8 Oct 2012 19:57:03 -0400 Subject: [PATCH 01/24] First pass at making setup more sane. --- MANIFEST.in | 14 +- distribute_setup.py | 515 +++++++ lib/matplotlib/__init__.py | 10 +- lib/matplotlib/artist.py | 2 +- lib/matplotlib/ticker.py | 6 +- setup.cfg.template | 10 + setup.py | 472 +++---- setupext.py | 2733 +++++++++++++++++++----------------- src/_backend_agg.cpp | 1 + 9 files changed, 2196 insertions(+), 1567 deletions(-) create mode 100755 distribute_setup.py diff --git a/MANIFEST.in b/MANIFEST.in index 9838df35c44b..0ee8e71c2677 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,20 +1,16 @@ -include CHANGELOG KNOWN_BUGS INSTALL +include CHANGELOG INSTALL include INTERACTIVE TODO CONTRIBUTING.md -include Makefile make.osx MANIFEST.in MANIFEST +include Makefile MANIFEST.in MANIFEST include matplotlibrc.template setup.cfg.template -include __init__.py setupext.py setup.py setupegg.py -include examples/data/* -include lib/mpl_toolkits -include lib/matplotlib/mpl-data/matplotlib.conf -include lib/matplotlib/mpl-data/matplotlib.conf.template +include setupext.py setup.py setupegg.py include lib/matplotlib/mpl-data/lineprops.glade include lib/matplotlib/mpl-data/matplotlibrc include lib/matplotlib/mpl-data/images/* include lib/matplotlib/mpl-data/fonts/ttf/* include lib/matplotlib/mpl-data/fonts/pdfcorefonts/* include lib/matplotlib/mpl-data/fonts/afm/* -recursive-include lib/matplotlib/mpl-data/sample_data/* -recursive-include license LICENSE* +recursive-include lib/matplotlib/mpl-data/sample_data/ * +recursive-include LICENSE * recursive-include examples * recursive-include doc * recursive-include src *.cpp *.c *.h *.m diff --git a/distribute_setup.py b/distribute_setup.py new file mode 100755 index 000000000000..8f5b0637bf39 --- /dev/null +++ b/distribute_setup.py @@ -0,0 +1,515 @@ +#!python +"""Bootstrap distribute installation + +If you want to use setuptools in your package's setup.py, just include this +file in the same directory with it, and add this to the top of your setup.py:: + + from distribute_setup import use_setuptools + use_setuptools() + +If you want to require a specific version of setuptools, set a download +mirror, or use an alternate download directory, you can do so by supplying +the appropriate options to ``use_setuptools()``. + +This file can also be run as a script to install or upgrade setuptools. +""" +import os +import sys +import time +import fnmatch +import tempfile +import tarfile +from distutils import log + +try: + from site import USER_SITE +except ImportError: + USER_SITE = None + +try: + import subprocess + + def _python_cmd(*args): + args = (sys.executable,) + args + return subprocess.call(args) == 0 + +except ImportError: + # will be used for python 2.3 + def _python_cmd(*args): + args = (sys.executable,) + args + # quoting arguments if windows + if sys.platform == 'win32': + def quote(arg): + if ' ' in arg: + return '"%s"' % arg + return arg + args = [quote(arg) for arg in args] + return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 + +DEFAULT_VERSION = "0.6.28" +DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" +SETUPTOOLS_FAKED_VERSION = "0.6c11" + +SETUPTOOLS_PKG_INFO = """\ +Metadata-Version: 1.0 +Name: setuptools +Version: %s +Summary: xxxx +Home-page: xxx +Author: xxx +Author-email: xxx +License: xxx +Description: xxx +""" % SETUPTOOLS_FAKED_VERSION + + +def _install(tarball, install_args=()): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # installing + log.warn('Installing Distribute') + if not _python_cmd('setup.py', 'install', *install_args): + log.warn('Something went wrong during the installation.') + log.warn('See the error message above.') + finally: + os.chdir(old_wd) + + +def _build_egg(egg, tarball, to_dir): + # extracting the tarball + tmpdir = tempfile.mkdtemp() + log.warn('Extracting in %s', tmpdir) + old_wd = os.getcwd() + try: + os.chdir(tmpdir) + tar = tarfile.open(tarball) + _extractall(tar) + tar.close() + + # going in the directory + subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) + os.chdir(subdir) + log.warn('Now working in %s', subdir) + + # building an egg + log.warn('Building a Distribute egg in %s', to_dir) + _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) + + finally: + os.chdir(old_wd) + # returning the result + log.warn(egg) + if not os.path.exists(egg): + raise IOError('Could not build the egg.') + + +def _do_download(version, download_base, to_dir, download_delay): + egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' + % (version, sys.version_info[0], sys.version_info[1])) + if not os.path.exists(egg): + tarball = download_setuptools(version, download_base, + to_dir, download_delay) + _build_egg(egg, tarball, to_dir) + sys.path.insert(0, egg) + import setuptools + setuptools.bootstrap_install_from = egg + + +def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, download_delay=15, no_fake=True): + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + was_imported = 'pkg_resources' in sys.modules or \ + 'setuptools' in sys.modules + try: + try: + import pkg_resources + if not hasattr(pkg_resources, '_distribute'): + if not no_fake: + _fake_setuptools() + raise ImportError + except ImportError: + return _do_download(version, download_base, to_dir, download_delay) + try: + pkg_resources.require("distribute>=" + version) + return + except pkg_resources.VersionConflict: + e = sys.exc_info()[1] + if was_imported: + sys.stderr.write( + "The required version of distribute (>=%s) is not available,\n" + "and can't be installed while this script is running. Please\n" + "install a more recent version first, using\n" + "'easy_install -U distribute'." + "\n\n(Currently using %r)\n" % (version, e.args[0])) + sys.exit(2) + else: + del pkg_resources, sys.modules['pkg_resources'] # reload ok + return _do_download(version, download_base, to_dir, + download_delay) + except pkg_resources.DistributionNotFound: + return _do_download(version, download_base, to_dir, + download_delay) + finally: + if not no_fake: + _create_fake_setuptools_pkg_info(to_dir) + + +def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, + to_dir=os.curdir, delay=15): + """Download distribute from a specified location and return its filename + + `version` should be a valid distribute version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download + attempt. + """ + # making sure we use the absolute path + to_dir = os.path.abspath(to_dir) + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + tgz_name = "distribute-%s.tar.gz" % version + url = download_base + tgz_name + saveto = os.path.join(to_dir, tgz_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + log.warn("Downloading %s", url) + src = urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = src.read() + dst = open(saveto, "wb") + dst.write(data) + finally: + if src: + src.close() + if dst: + dst.close() + return os.path.realpath(saveto) + + +def _no_sandbox(function): + def __no_sandbox(*args, **kw): + try: + from setuptools.sandbox import DirectorySandbox + if not hasattr(DirectorySandbox, '_old'): + def violation(*args): + pass + DirectorySandbox._old = DirectorySandbox._violation + DirectorySandbox._violation = violation + patched = True + else: + patched = False + except ImportError: + patched = False + + try: + return function(*args, **kw) + finally: + if patched: + DirectorySandbox._violation = DirectorySandbox._old + del DirectorySandbox._old + + return __no_sandbox + + +def _patch_file(path, content): + """Will backup the file then patch it""" + existing_content = open(path).read() + if existing_content == content: + # already patched + log.warn('Already patched.') + return False + log.warn('Patching...') + _rename_path(path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + return True + +_patch_file = _no_sandbox(_patch_file) + + +def _same_content(path, content): + return open(path).read() == content + + +def _rename_path(path): + new_name = path + '.OLD.%s' % time.time() + log.warn('Renaming %s into %s', path, new_name) + os.rename(path, new_name) + return new_name + + +def _remove_flat_installation(placeholder): + if not os.path.isdir(placeholder): + log.warn('Unkown installation at %s', placeholder) + return False + found = False + for file in os.listdir(placeholder): + if fnmatch.fnmatch(file, 'setuptools*.egg-info'): + found = True + break + if not found: + log.warn('Could not locate setuptools*.egg-info') + return + + log.warn('Removing elements out of the way...') + pkg_info = os.path.join(placeholder, file) + if os.path.isdir(pkg_info): + patched = _patch_egg_dir(pkg_info) + else: + patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) + + if not patched: + log.warn('%s already patched.', pkg_info) + return False + # now let's move the files out of the way + for element in ('setuptools', 'pkg_resources.py', 'site.py'): + element = os.path.join(placeholder, element) + if os.path.exists(element): + _rename_path(element) + else: + log.warn('Could not find the %s element of the ' + 'Setuptools distribution', element) + return True + +_remove_flat_installation = _no_sandbox(_remove_flat_installation) + + +def _after_install(dist): + log.warn('After install bootstrap.') + placeholder = dist.get_command_obj('install').install_purelib + _create_fake_setuptools_pkg_info(placeholder) + + +def _create_fake_setuptools_pkg_info(placeholder): + if not placeholder or not os.path.exists(placeholder): + log.warn('Could not find the install location') + return + pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) + setuptools_file = 'setuptools-%s-py%s.egg-info' % \ + (SETUPTOOLS_FAKED_VERSION, pyver) + pkg_info = os.path.join(placeholder, setuptools_file) + if os.path.exists(pkg_info): + log.warn('%s already exists', pkg_info) + return + + if not os.access(pkg_info, os.W_OK): + log.warn("Don't have permissions to write %s, skipping", pkg_info) + + log.warn('Creating %s', pkg_info) + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + + pth_file = os.path.join(placeholder, 'setuptools.pth') + log.warn('Creating %s', pth_file) + f = open(pth_file, 'w') + try: + f.write(os.path.join(os.curdir, setuptools_file)) + finally: + f.close() + +_create_fake_setuptools_pkg_info = _no_sandbox( + _create_fake_setuptools_pkg_info +) + + +def _patch_egg_dir(path): + # let's check if it's already patched + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + if os.path.exists(pkg_info): + if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): + log.warn('%s already patched.', pkg_info) + return False + _rename_path(path) + os.mkdir(path) + os.mkdir(os.path.join(path, 'EGG-INFO')) + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + f = open(pkg_info, 'w') + try: + f.write(SETUPTOOLS_PKG_INFO) + finally: + f.close() + return True + +_patch_egg_dir = _no_sandbox(_patch_egg_dir) + + +def _before_install(): + log.warn('Before install bootstrap.') + _fake_setuptools() + + +def _under_prefix(location): + if 'install' not in sys.argv: + return True + args = sys.argv[sys.argv.index('install') + 1:] + for index, arg in enumerate(args): + for option in ('--root', '--prefix'): + if arg.startswith('%s=' % option): + top_dir = arg.split('root=')[-1] + return location.startswith(top_dir) + elif arg == option: + if len(args) > index: + top_dir = args[index + 1] + return location.startswith(top_dir) + if arg == '--user' and USER_SITE is not None: + return location.startswith(USER_SITE) + return True + + +def _fake_setuptools(): + log.warn('Scanning installed packages') + try: + import pkg_resources + except ImportError: + # we're cool + log.warn('Setuptools or Distribute does not seem to be installed.') + return + ws = pkg_resources.working_set + try: + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools', replacement=False) + ) + except TypeError: + # old distribute API + setuptools_dist = ws.find( + pkg_resources.Requirement.parse('setuptools') + ) + + if setuptools_dist is None: + log.warn('No setuptools distribution found') + return + # detecting if it was already faked + setuptools_location = setuptools_dist.location + log.warn('Setuptools installation detected at %s', setuptools_location) + + # if --root or --preix was provided, and if + # setuptools is not located in them, we don't patch it + if not _under_prefix(setuptools_location): + log.warn('Not patching, --root or --prefix is installing Distribute' + ' in another location') + return + + # let's see if its an egg + if not setuptools_location.endswith('.egg'): + log.warn('Non-egg installation') + res = _remove_flat_installation(setuptools_location) + if not res: + return + else: + log.warn('Egg installation') + pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') + if (os.path.exists(pkg_info) and + _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): + log.warn('Already patched.') + return + log.warn('Patching...') + # let's create a fake egg replacing setuptools one + res = _patch_egg_dir(setuptools_location) + if not res: + return + log.warn('Patched done.') + _relaunch() + + +def _relaunch(): + log.warn('Relaunching...') + # we have to relaunch the process + # pip marker to avoid a relaunch bug + _cmd = ['-c', 'install', '--single-version-externally-managed'] + if sys.argv[:3] == _cmd: + sys.argv[0] = 'setup.py' + args = [sys.executable] + sys.argv + sys.exit(subprocess.call(args)) + + +def _extractall(self, path=".", members=None): + """Extract all members from the archive to the current working + directory and set owner, modification time and permissions on + directories afterwards. `path' specifies a different directory + to extract to. `members' is optional and must be a subset of the + list returned by getmembers(). + """ + import copy + import operator + from tarfile import ExtractError + directories = [] + + if members is None: + members = self + + for tarinfo in members: + if tarinfo.isdir(): + # Extract directories with a safe mode. + directories.append(tarinfo) + tarinfo = copy.copy(tarinfo) + tarinfo.mode = 448 # decimal for oct 0700 + self.extract(tarinfo, path) + + # Reverse sort directories. + if sys.version_info < (2, 4): + def sorter(dir1, dir2): + return cmp(dir1.name, dir2.name) + directories.sort(sorter) + directories.reverse() + else: + directories.sort(key=operator.attrgetter('name'), reverse=True) + + # Set correct owner, mtime and filemode on directories. + for tarinfo in directories: + dirpath = os.path.join(path, tarinfo.name) + try: + self.chown(tarinfo, dirpath) + self.utime(tarinfo, dirpath) + self.chmod(tarinfo, dirpath) + except ExtractError: + e = sys.exc_info()[1] + if self.errorlevel > 1: + raise + else: + self._dbg(1, "tarfile: %s" % e) + + +def _build_install_args(argv): + install_args = [] + user_install = '--user' in argv + if user_install and sys.version_info < (2, 6): + log.warn("--user requires Python 2.6 or later") + raise SystemExit(1) + if user_install: + install_args.append('--user') + return install_args + + +def main(argv, version=DEFAULT_VERSION): + """Install or upgrade setuptools and EasyInstall""" + tarball = download_setuptools() + _install(tarball, _build_install_args(argv)) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 03bdd3f0b12d..3f91b6194a67 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -944,10 +944,10 @@ class rc_context(object): This allows one to do:: >>> with mpl.rc_context(fname='screen.rc'): - >>> plt.plot(x, a) - >>> with mpl.rc_context(fname='print.rc'): - >>> plt.plot(x, b) - >>> plt.plot(x, c) + ... plt.plot(x, a) + ... with mpl.rc_context(fname='print.rc'): + ... plt.plot(x, b) + ... plt.plot(x, c) The 'a' vs 'x' and 'c' vs 'x' plots would have settings from 'screen.rc', while the 'b' vs 'x' plot would have settings from @@ -956,7 +956,7 @@ class rc_context(object): A dictionary can also be passed to the context manager:: >>> with mpl.rc_context(rc={'text.usetex': True}, fname='screen.rc'): - >>> plt.plot(x, a) + ... plt.plot(x, a) The 'rc' dictionary takes precedence over the settings loaded from 'fname'. Passing a dictionary only is also valid. diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 2ad7e4cbd570..39ef1f7fc5c8 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -1197,7 +1197,7 @@ def setp(obj, *args, **kwargs): with python kwargs. For example, the following are equivalent:: >>> setp(lines, 'linewidth', 2, 'color', r') # MATLAB style - + ... >>> setp(lines, linewidth=2, color='r') # python style """ diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 267e5c485651..646e917d45d4 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -808,13 +808,13 @@ def format_eng(self, num): """ Formats a number in engineering notation, appending a letter representing the power of 1000 of the original number. Some examples: - >>> format_eng(0) for self.places = 0 + >>> format_eng(0) # for self.places = 0 '0' - >>> format_eng(1000000) for self.places = 1 + >>> format_eng(1000000) # for self.places = 1 '1.0 M' - >>> format_eng("-1e-6") for self.places = 2 + >>> format_eng("-1e-6") # for self.places = 2 u'-1.00 \u03bc' @param num: the value to represent diff --git a/setup.cfg.template b/setup.cfg.template index 2cf7e53c6ad9..9de2b6980965 100644 --- a/setup.cfg.template +++ b/setup.cfg.template @@ -16,6 +16,15 @@ # Uncomment to insert lots of diagnostic prints in extension code #verbose = True +[packages] +# There are a number of subpackages of matplotlib that are considered +# optional. They are all installed by default, but they may be turned +# off here. +# +#tests = False +#sample_data = False +#toolkits = False + [provide_packages] # By default, matplotlib checks for a few dependencies and # installs them if missing. This feature can be turned off @@ -59,6 +68,7 @@ #gtkagg = False #tkagg = False #macosx = False +#windowing = False [rc_options] # User-configurable options diff --git a/setup.py b/setup.py index e37eb485bbc3..ac07dcb96369 100644 --- a/setup.py +++ b/setup.py @@ -1,12 +1,15 @@ """ -You will need to have freetype, libpng and zlib installed to compile -matplotlib, inlcuding the *-devel versions of these libraries if you -are using a package manager like RPM or debian. - The matplotlib build options can be modified with a setup.cfg file. See setup.cfg.template for more information. """ -from __future__ import print_function + +from __future__ import print_function, absolute_import + +# This needs to be the very first thing to use distribute +from distribute_setup import use_setuptools +use_setuptools() + +import sys # distutils is breaking our sdists for files in symlinked dirs. # distutils will copy if os.link is not available, so this is a hack @@ -17,327 +20,202 @@ except AttributeError: pass -# This dict will be updated as we try to select the best option during -# the build process. However, values in setup.cfg will be used, if -# defined. -rc = {'backend':'Agg'} - -# BEFORE importing disutils, remove MANIFEST. distutils doesn't properly +# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly # update it when the contents of directories change. -import os -if os.path.exists('MANIFEST'): os.remove('MANIFEST') - -import sys -major, minor1, minor2, s, tmp = sys.version_info - -if major==2 and minor1<6 or major<2: - raise SystemExit("""matplotlib requires Python 2.6 or later.""") +if os.path.exists('MANIFEST'): + os.remove('MANIFEST') -import glob -from distutils.core import setup try: - from distutils.command.build_py import build_py_2to3 as build_py + from setuptools.core import setup except ImportError: - from distutils.command.build_py import build_py -from setupext import build_agg, build_gtkagg, build_tkagg,\ - build_macosx, build_ft2font, build_image, build_windowing, build_path, \ - build_contour, build_delaunay, build_gdk, \ - build_ttconv, print_line, print_status, print_message, \ - print_raw, check_for_freetype, check_for_libpng, check_for_gtk, \ - check_for_tk, check_for_macosx, check_for_numpy, \ - check_for_qt, check_for_qt4, check_for_pyside, check_for_cairo, \ - check_provide_pytz, check_provide_dateutil,\ - check_for_dvipng, check_for_ghostscript, check_for_latex, \ - check_for_pdftops, options, build_png, build_tri, check_provide_six, \ - check_for_tornado - - -packages = [ - 'matplotlib', - 'matplotlib.backends', - 'matplotlib.backends.qt4_editor', - 'matplotlib.projections', - 'matplotlib.testing', - 'matplotlib.testing.jpl_units', - 'matplotlib.tests', - 'mpl_toolkits', - 'mpl_toolkits.mplot3d', - 'mpl_toolkits.axes_grid', - 'mpl_toolkits.axes_grid1', - 'mpl_toolkits.axisartist', - 'matplotlib.sphinxext', - 'matplotlib.tri', - + from distutils.core import setup + + +import setupext +from setupext import print_line, print_raw, print_message, print_status + +# Get the version from the source code +__version__ = setupext.Matplotlib().check() + + +# These are the packages in the order we want to build them. This +# list may contain strings to create section headers for the display. +mpl_packages = [ + 'Building Matplotlib', + setupext.Matplotlib(), + setupext.Python(), + setupext.Platform(), + 'Required dependencies and extensions', + setupext.Numpy(), + setupext.CXX(), + setupext.LibAgg(), + setupext.FreeType(), + setupext.FT2Font(), + setupext.Png(), + setupext.Image(), + setupext.TTConv(), + setupext.Path(), + setupext.Contour(), + setupext.Delaunay(), + setupext.Tri(), + 'Optional subpackages', + setupext.SampleData(), + setupext.Toolkits(), + setupext.Tests(), + 'Optional backend extensions', + # These backends are listed in order of preference, the first + # being the most preferred. The first one that looks like it will + # work will be selected as the default backend. + setupext.BackendMacOSX(), + setupext.BackendQt4(), + setupext.BackendGtk3Agg(), + setupext.BackendGtk3Cairo(), + setupext.BackendGtkAgg(), + setupext.BackendTkAgg(), + setupext.BackendWxAgg(), + setupext.BackendGtk(), + setupext.BackendQt(), + setupext.BackendAgg(), + setupext.BackendCairo(), + 'Optional LaTeX dependencies', + setupext.DviPng(), + setupext.Ghostscript(), + setupext.LaTeX(), + setupext.PdfToPs() ] -py_modules = ['pylab'] +# These are distutils.setup parameters that the various packages add +# things to. +packages = [] +py_modules = [] ext_modules = [] - -classifiers = [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: Python Software Foundation License', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 3', - 'Topic :: Scientific/Engineering :: Visualization', - ] - -for line in open('lib/matplotlib/__init__.py').readlines(): - if (line.startswith('__version__')): - exec(line.strip()) - -print_line() -print_raw("BUILDING MATPLOTLIB") -print_status('matplotlib', __version__) -print_status('python', sys.version) -print_status('platform', sys.platform) -if sys.platform == 'win32': - print_status('Windows version', sys.getwindowsversion()) -print_raw("") -print_raw("REQUIRED DEPENDENCIES") - -# Specify all the required mpl data -package_data = {'matplotlib':['mpl-data/fonts/afm/*.afm', - 'mpl-data/fonts/pdfcorefonts/*.afm', - 'mpl-data/fonts/pdfcorefonts/*.txt', - 'mpl-data/fonts/ttf/*.ttf', - 'mpl-data/fonts/ttf/LICENSE_STIX', - 'mpl-data/fonts/ttf/COPYRIGHT.TXT', - 'mpl-data/fonts/ttf/README.TXT', - 'mpl-data/fonts/ttf/RELEASENOTES.TXT', - 'mpl-data/images/*.xpm', - 'mpl-data/images/*.svg', - 'mpl-data/images/*.gif', - 'mpl-data/images/*.png', - 'mpl-data/images/*.ppm', - 'mpl-data/example/*.npy', - 'mpl-data/matplotlibrc', - 'mpl-data/*.glade', - 'mpl-data/sample_data/*.*', - 'mpl-data/sample_data/axes_grid/*.*', - 'backends/Matplotlib.nib/*', - 'backends/web_backend/*.*', - 'backends/web_backend/jquery/js/*', - 'backends/web_backend/jquery/css/themes/base/*.*', - 'backends/web_backend/jquery/css/themes/base/images/*', - 'backends/web_backend/css/*.*', - - ]} - +package_data = {} package_dir = {'': 'lib'} +default_backend = None -if 1: - # TODO: exclude these when making release? - baseline_images = glob.glob(os.path.join('lib','matplotlib','tests', - 'baseline_images','*','*')) - def chop_package(fname): - badstr = os.path.join('lib','matplotlib','') - assert fname.startswith(badstr) - result = fname[ len(badstr): ] - return result - baseline_images = [chop_package(f) for f in baseline_images] - package_data['matplotlib'].extend(baseline_images) - package_data['matplotlib'].append('tests/mpltest.ttf') - package_data['matplotlib'].append('tests/test_rcparams.rc') - -if not check_for_numpy(__version__numpy__): - sys.exit(1) - -if not check_for_freetype(): - sys.exit(1) - -build_ft2font(ext_modules, packages) -build_ttconv(ext_modules, packages) -build_contour(ext_modules, packages) -build_delaunay(ext_modules, packages) -build_path(ext_modules, packages) -build_tri(ext_modules, packages) - -print_raw("") -print_raw("OPTIONAL BACKEND DEPENDENCIES") -has_libpng = check_for_libpng() - -if has_libpng and options['build_agg']: - build_agg(ext_modules, packages) - rc['backend'] = 'Agg' -else: - rc['backend'] = 'SVG' - -if has_libpng and options['build_image']: - build_image(ext_modules, packages) - -if has_libpng and options['build_agg'] or options['build_image']: - build_png(ext_modules, packages) - -if options['build_windowing'] and sys.platform=='win32': - build_windowing(ext_modules, packages) -# the options can be True, False, or 'auto'. If True, try to build -# regardless of the lack of dependencies. If auto, silently skip -# when dependencies are missing. -if options['build_tkagg']: - if check_for_tk() or (options['build_tkagg'] is True): - options['build_agg'] = 1 - build_tkagg(ext_modules, packages) - rc['backend'] = 'TkAgg' - -hasgtk = check_for_gtk() -if options['build_gtk']: - if hasgtk or (options['build_gtk'] is True): - build_gdk(ext_modules, packages) -if options['build_gtkagg']: - if hasgtk or (options['build_gtkagg'] is True): - options['build_agg'] = 1 - build_gtkagg(ext_modules, packages) - rc['backend'] = 'GTKAgg' - -if options['build_macosx']: - if check_for_macosx() or (options['build_macosx'] is True): - build_macosx(ext_modules, packages) - rc['backend'] = 'MacOSX' - -# These are informational only. We don't build any extensions for them. -check_for_qt() -check_for_qt4() -check_for_pyside() -check_for_cairo() -check_for_tornado() - -print_raw("") -print_raw("OPTIONAL DATE/TIMEZONE DEPENDENCIES") - -provide_dateutil = check_provide_dateutil() -provide_pytz = check_provide_pytz() -provide_six = check_provide_six() - -def add_pytz(): - packages.append('pytz') - - resources = ['zone.tab', 'locales/pytz.pot'] - for dirpath, dirnames, filenames in os.walk( - os.path.join('lib', 'pytz', 'zoneinfo') - ): +# Go through all of the packages and figure out which ones we are +# going to build/install. +print_line() +print_raw("Edit setup.cfg to change the build options") - # remove the 'pytz' part of the path - basepath = os.path.join(*dirpath.split(os.path.sep)[2:]) - #print dirpath, basepath - resources.extend([os.path.join(basepath, filename) - for filename in filenames]) - package_data['pytz'] = resources - #print resources - assert len(resources) > 10, 'zoneinfo files not found!' -def add_dateutil(): - packages.append('dateutil') - packages.append('dateutil.zoneinfo') - package_data['dateutil'] = ['zoneinfo/*.tar.gz'] - if sys.version_info[0] >= 3: - package_dir['dateutil'] = 'lib/dateutil_py3' +required_failed = [] +good_packages = [] +for package in mpl_packages: + if isinstance(package, str): + print_raw('') + print_raw(package.upper()) else: - package_dir['dateutil'] = 'lib/dateutil_py2' - -def add_six(): - py_modules.append('six') - -if sys.platform=='win32': - # always add these to the win32 installer - add_pytz() - add_dateutil() - add_six() -else: - # only add them if we need them - if provide_pytz: - add_pytz() - if provide_dateutil: - add_dateutil() - if provide_six: - add_six() + try: + result = package.check() + if result is not None: + message = 'yes [%s]' % result + print_status(package.name, message) + except setupext.CheckFailed as e: + print_status(package.name, 'no [%s]' % str(e)) + if not package.optional: + required_failed.append(package) + else: + good_packages.append(package) + if isinstance(package, setupext.OptionalBackendPackage): + if default_backend is None: + default_backend = package.name +print_raw('') + + +# Abort if any of the required packages can not be built. +if required_failed: + print_line() + print_message( + "The following required packages can not " + "be built: %s" % + ', '.join(x.name for x in required_failed)) + sys.exit(1) -print_raw("") -print_raw("OPTIONAL USETEX DEPENDENCIES") -check_for_dvipng() -check_for_ghostscript() -check_for_latex() -check_for_pdftops() -print_raw("") -print_raw("[Edit setup.cfg to suppress the above messages]") -print_line() +# Now collect all of the information we need to build all of the +# packages. +for package in good_packages: + if isinstance(package, str): + continue + packages.extend(package.get_packages()) + py_modules.extend(package.get_py_modules()) + ext = package.get_extension() + if ext is not None: + ext_modules.append(ext) + data = package.get_package_data() + for key, val in data.items(): + package_data.setdefault(key, []) + package_data[key].extend(val) # Write the default matplotlibrc file -if options['backend']: rc['backend'] = options['backend'] -template = open('matplotlibrc.template').read() -open('lib/matplotlib/mpl-data/matplotlibrc', 'w').write(template%rc) - -try: additional_params # has setupegg.py provided -except NameError: additional_params = {} - -for mod in ext_modules: - if options['verbose']: +if default_backend is None: + default_backend = 'svg' +if setupext.options['backend']: + default_backend = setupext.options['backend'] +with open('matplotlibrc.template') as fd: + template = fd.read() +with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd: + fd.write(template % {'backend': default_backend}) + + +# Build in verbose mode if requested +if setupext.options['verbose']: + for mod in ext_modules: mod.extra_compile_args.append('-DVERBOSE') -if sys.version_info[0] >= 3: - def should_2to3(file, root): - file = os.path.abspath(file)[len(os.path.abspath(root))+1:] - if ('py3' in file or - file.startswith('pytz') or - file.startswith('dateutil') or - file.startswith('six')): - return False - return True - import multiprocessing - def refactor(x): - from lib2to3.refactor import RefactoringTool, get_fixers_from_package - class DistutilsRefactoringTool(RefactoringTool): - def ignore(self, msg, *args, **kw): - pass - log_error = log_message = log_debug = ignore - fixer_names = get_fixers_from_package('lib2to3.fixes') - r = DistutilsRefactoringTool(fixer_names, options=None) - r.refactor([x], write=True) +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: Python Software Foundation License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 3', + 'Topic :: Scientific/Engineering :: Visualization', + ] - original_build_py = build_py - class build_py(original_build_py): - def run_2to3(self, files): - # We need to skip certain files that have already been - # converted to Python 3.x - filtered = [x for x in files if should_2to3(x, self.build_lib)] - if sys.platform.startswith('win') or 'TRAVIS' in os.environ: - # doing this in parallel on windows may crash your computer - [refactor(f) for f in filtered] - else: - p = multiprocessing.Pool() - for i, x in enumerate(p.imap_unordered(refactor, filtered)): - print("Running 2to3... %.02f%%" % - (float(i) / len(filtered) * 100.0), end='\r') - print() -print_raw("pymods %s" % py_modules) -print_raw("packages %s" % packages) +# Finally, pass this all along to distutils to do the heavy lifting. distrib = setup(name="matplotlib", - version= __version__, - description = "Python plotting package", - author = "John D. Hunter, Michael Droettboom", + version=__version__, + description="Python plotting package", + author="John D. Hunter, Michael Droettboom", author_email="mdroe@stsci.edu", - url = "http://matplotlib.org", - long_description = """ + url="http://matplotlib.org", + long_description=""" matplotlib strives to produce publication quality 2D graphics for interactive graphing, scientific publishing, user interface development and web application servers targeting multiple user interfaces and hardcopy output formats. There is a 'pylab' mode - which emulates matlab graphics + which emulates matlab graphics. """, download_url="https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-{0}/matplotlib-{0}.tar.gz".format(__version__), - packages = packages, + install_requires=['dateutils', 'tornado'], + license="BSD", + packages=packages, platforms='any', - py_modules = py_modules, - ext_modules = ext_modules, - package_dir = package_dir, - package_data = package_data, - classifiers = classifiers, - cmdclass = {'build_py': build_py}, - **additional_params - ) + py_modules=py_modules, + ext_modules=ext_modules, + package_dir=package_dir, + package_data=package_data, + classifiers=classifiers, + + # Automatically 2to3 source on Python 3.x + use_2to3=True, + + # matplotlib has C/C++ extensions, so it's not zip safe. + # Telling setuptools this prevents it from doing an automatic + # check for zip safety. + zip_safe=False, + + # This option is important -- it reverts to the standard + # distutils installation method. Otherwise, the behavior is to + # build an egg and install that, which unfortunately, makes + # building and importing much slower. + options={ + 'install': {'old_and_unmanageable': 'True'} + } + ) diff --git a/setupext.py b/setupext.py index 4a3ec79e9c0d..8414d6f2c0a1 100644 --- a/setupext.py +++ b/setupext.py @@ -1,183 +1,147 @@ -""" -Some helper functions for building the C extensions +from __future__ import print_function, absolute_import -You may need to use the "basedirlist" option in setup.cfg to point -to the location of your required libs, eg, png, z, freetype, -overriding the settings hard-coded in the "basedir" directory -below. +from distutils import sysconfig +from distutils import version +from distutils.core import Extension +import glob +import multiprocessing +import os +import re +import subprocess +import sys +from textwrap import fill -DARWIN - I have installed all of the backends on OSX. +if sys.platform != 'win32': + if sys.version_info[0] < 3: + from commands import getstatusoutput + else: + from subprocess import getstatusoutput - Tk: If you want to install TkAgg, I recommend the "batteries included" - binary build of Tcl/Tk at - http://www.apple.com/downloads/macosx/unix_open_source/tcltkaqua.html +if sys.version_info[0] < 3: + import ConfigParser as configparser +else: + import configparser - GTK: I installed GTK from src as described at - http://www.macgimp.org/index.php?topic=gtk. There are several - packages, but all configure/make/make install w/o problem. In - addition to the packages listed there, You will also need libpng, - libjpeg, and libtiff if you want output to these formats from GTK. -WIN32 - MINGW +def get_win32_compiler(): + # Used to determine mingw32 or msvc + # This is pretty bad logic, someone know a better way? + for v in sys.argv: + if 'mingw32' in v: + return 'mingw32' + return 'msvc' +win32_compiler = get_win32_compiler() - If you are sufficiently masochistic that you want to build this - yourself, download the win32_static dir from - http://matplotlib.sourceforge.net/win32_static.tar.gz and - see the README file in that dir - > python setup.py build --compiler=mingw32 bdist_wininst > build23.out +def extract_versions(): + """ + Extracts version values from the main matplotlib __init__.py and + returns them as a dictionary. + """ + with open('lib/matplotlib/__init__.py') as fd: + for line in fd.readlines(): + if (line.startswith('__version__')): + exec(line.strip()) + return locals() - NOTE, if you are building on python24 on win32, see - http://mail.python.org/pipermail/python-list/2004-December/254826.html -WIN32 - VISUAL STUDIO 7.1 (2003) +def has_include_file(include_dirs, filename): + """ + Returns `True` if `filename` can be found in one of the + directories in `include_dirs`. + """ + for dir in include_dirs: + if os.path.exists(os.path.join(dir, filename)): + return True + return False - This build is similar to the mingw. Download the visual studio static - dependencies from - http://matplotlib.sourceforge.net/win32_static_vs.tar.gz and - see the README in that dir - > python setup.py build --compiler=msvc bdist_wininst +def check_include_file(include_dirs, filename, package): + """ + Raises an exception if the given include file can not be found. + """ + if not has_include_file(include_dirs, filename): + raise CheckFailed( + "The C/C++ header for %s (%s) could not be found. You " + "may need to install the development package." % + (package, filename)) -""" -import os -import re -import subprocess -from distutils import sysconfig, version -from collections import defaultdict - -# basedir is a dictionary keyed by sys.platform, and on most platforms it is -# set to ['/usr/local', '/usr']. Giving this defaultdict a factory that -# returns this default removes the need to update this code every time a new -# version of freebsd comes out, for example, provided that the default basedir -# remains sufficient on that platform -basedir = defaultdict(lambda: ['/usr/local', '/usr'], { - # execptions to the ['/usr/local', '/usr'] defaults - 'win32' : ['win32_static',], - 'darwin' : ['/usr/local/', '/usr', '/usr/X11', '/opt/local'], - 'sunos5' : [os.getenv('MPLIB_BASE') or '/usr/local',], - 'gnu0' : ['/usr'], - 'aix5' : ['/usr/local'], - }) +def get_base_dirs(): + """ + Returns a list of standard base directories on this platform. + """ + if options['basedirlist']: + return options['basedirlist'] -import sys + basedir_map = { + 'win32': ['win32_static',], + 'darwin': ['/usr/local/', '/usr', '/usr/X11', '/opt/local'], + 'sunos5': [os.getenv('MPLIB_BASE') or '/usr/local',], + 'gnu0': ['/usr'], + 'aix5': ['/usr/local'], + } + return basedir_map.get(sys.platform, ['/usr/local', '/usr']) -from textwrap import fill -from distutils.core import Extension -import glob -if sys.version_info[0] < 3: - import ConfigParser as configparser - from cStringIO import StringIO - if sys.platform != 'win32': - from commands import getstatusoutput -else: - import configparser - from io import StringIO - if sys.platform != 'win32': - from subprocess import getstatusoutput +def run_child_process(cmd): + """ + Run a subprocess as a sanity check. + """ + p = subprocess.Popen(cmd, shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + close_fds=(sys.platform != 'win32')) + return p.stdin, p.stdout + + +def is_min_version(found, minversion): + """ + Returns `True` if `found` is at least as high a version as + `minversion`. + """ + expected_version = version.LooseVersion(minversion) + found_version = version.LooseVersion(found) + return found_version >= expected_version -BUILT_PNG = False -BUILT_AGG = False -BUILT_FT2FONT = False -BUILT_TTCONV = False -BUILT_GTKAGG = False -BUILT_IMAGE = False -BUILT_MACOSX = False -BUILT_TKAGG = False -BUILT_WINDOWING = False -BUILT_CONTOUR = False -BUILT_DELAUNAY = False -BUILT_CONTOUR = False -BUILT_GDK = False -BUILT_PATH = False -BUILT_TRI = False - -AGG_VERSION = 'agg24' -TCL_TK_CACHE = None - -# for nonstandard installation/build with --prefix variable -numpy_inc_dirs = [] # matplotlib build options, which can be altered using setup.cfg -options = {'display_status': True, - 'verbose': False, - 'provide_pytz': 'auto', - 'provide_dateutil': 'auto', - 'provide_six': 'auto', - 'build_agg': True, - 'build_gtk': 'auto', - 'build_gtkagg': 'auto', - 'build_tkagg': 'auto', - 'build_macosx': 'auto', - 'build_image': True, - 'build_windowing': True, - 'backend': None, - 'basedirlist': None} - -defines = [ - ('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API'), - ('PYCXX_ISO_CPP_LIB', '1')] - -if sys.version_info[0] >= 3: - defines.append(('PYCXX_PYTHON_2TO3', '1')) +options = { + 'display_status': True, + 'verbose': False, + 'backend': None, + 'basedirlist': None + } setup_cfg = os.environ.get('MPLSETUPCFG', 'setup.cfg') -# Based on the contents of setup.cfg, determine the build options if os.path.exists(setup_cfg): config = configparser.SafeConfigParser() config.read(setup_cfg) - try: options['display_status'] = not config.getboolean("status", "suppress") - except: pass - - try: options['verbose'] = not config.getboolean("status", "verbose") - except: pass - - try: options['provide_pytz'] = config.getboolean("provide_packages", "pytz") - except: options['provide_pytz'] = 'auto' - - try: options['provide_dateutil'] = config.getboolean("provide_packages", - "dateutil") - except: options['provide_dateutil'] = 'auto' - - try: options['provide_six'] = config.getboolean("provide_packages", - "six") - except: options['provide_six'] = 'auto' - - try: options['build_gtk'] = config.getboolean("gui_support", "gtk") - except: options['build_gtk'] = 'auto' - - try: options['build_gtkagg'] = config.getboolean("gui_support", "gtkagg") - except: options['build_gtkagg'] = 'auto' - - try: options['build_tkagg'] = config.getboolean("gui_support", "tkagg") - except: options['build_tkagg'] = 'auto' - - try: options['build_macosx'] = config.getboolean("gui_support", "macosx") - except: options['build_macosx'] = 'auto' + try: + options['display_status'] = not config.getboolean("status", "suppress") + except: + pass - try: options['backend'] = config.get("rc_options", "backend") - except: pass + try: + options['verbose'] = not config.getboolean("status", "verbose") + except: + pass - try: options['basedirlist'] = config.get("directories", "basedirlist") - except: pass + try: + options['backend'] = config.get("rc_options", "backend") + except: + pass -# For get_base_flags: -if options['basedirlist']: - basedirlist = options['basedirlist'].split() + try: + options['basedirlist'] = config.get("directories", "basedirlist") + except: + pass else: - basedirlist = basedir[sys.platform] -print("basedirlist is: %s" % basedirlist) + config = None -def make_extension(*args, **kwargs): - ext = Extension(*args, **kwargs) - for dir in basedirlist: - ext.include_dirs.append(os.path.join(dir, 'include')) - return ext if options['display_status']: def print_line(char='='): @@ -203,6 +167,7 @@ def print_line(*args, **kwargs): pass print_status = print_message = print_raw = print_line + # Remove the -Wstrict-prototypesoption, is it's not valid for C++ customize_compiler = sysconfig.customize_compiler def my_customize_compiler(compiler): @@ -216,1181 +181,1445 @@ def my_customize_compiler(compiler): sysconfig.customize_compiler = my_customize_compiler +def make_extension(name, files, *args, **kwargs): + """ + Make a new extension. Automatically sets include_dirs and + library_dirs to the base directories appropriate for this + platform. -def run_child_process(cmd): - p = subprocess.Popen(cmd, shell=True, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - close_fds=(sys.platform != 'win32')) - return p.stdin, p.stdout + `name` is the name of the extension. -class CleanUpFile: - """CleanUpFile deletes the specified filename when self is destroyed.""" - def __init__(self, name): - self.name = name - def __del__(self): - os.remove(self.name) - -def temp_copy(_from, _to): - """temp_copy copies a named file into a named temporary file. - The temporary will be deleted when the setupext module is destructed. - """ - # Copy the file data from _from to _to - s = open(_from).read() - open(_to,"w+").write(s) - # Suppress object rebuild by preserving time stamps. - stats = os.stat(_from) - os.utime(_to, (stats.st_atime, stats.st_mtime)) - # Make an object to eliminate the temporary file at exit time. - globals()["_cleanup_"+_to] = CleanUpFile(_to) + `files` is a list of source files -def get_win32_compiler(): - # Used to determine mingw32 or msvc - # This is pretty bad logic, someone know a better way? - for v in sys.argv: - if 'mingw32' in v: - return 'mingw32' - return 'msvc' -win32_compiler = get_win32_compiler() -if sys.platform == 'win32' and win32_compiler == 'msvc': - std_libs = [] -else: - std_libs = ['stdc++', 'm'] + Any additional arguments are passed to the + `distutils.core.Extension` constructor. + """ + ext = Extension(name, files, *args, **kwargs) + for dir in get_base_dirs(): + include_dir = os.path.join(dir, 'include') + if os.path.exists(include_dir): + ext.include_dirs.append(include_dir) + for lib in ('lib', 'lib64'): + lib_dir = os.path.join(dir, lib) + if os.path.exists(lib_dir): + ext.library_dirs.append(lib_dir) + ext.include_dirs.append('.') -def set_pkgconfig_path(): - pkgconfig_path = sysconfig.get_config_var('LIBDIR') - if pkgconfig_path is None: - return + return ext - pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') - if not os.path.isdir(pkgconfig_path): - return - try: - os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path - except KeyError: - os.environ['PKG_CONFIG_PATH'] = pkgconfig_path - -def has_pkgconfig(): - if has_pkgconfig.cache is not None: - return has_pkgconfig.cache - if sys.platform == 'win32': - has_pkgconfig.cache = False - else: - #print 'environ', os.environ['PKG_CONFIG_PATH'] - status, output = getstatusoutput("pkg-config --help") - has_pkgconfig.cache = (status == 0) - - # Set the PKG_CONFIG_PATH environment variable - if has_pkgconfig.cache: - set_pkgconfig_path() - return has_pkgconfig.cache -has_pkgconfig.cache = None - -def get_pkgconfig(module, - packages, - flags="--libs --cflags", - pkg_config_exec='pkg-config', - report_error=False): - """Loosely based on an article in the Python Cookbook: - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/502261""" - if not has_pkgconfig(): - return False +class PkgConfig(object): + """ + This is a class for communicating with pkg-config. + """ + def __init__(self): + if sys.platform == 'win32': + self.has_pkgconfig = False + else: + self.set_pkgconfig_path() + status, output = getstatusoutput("pkg-config --help") + self.has_pkgconfig = (status == 0) - _flags = {'-I': 'include_dirs', - '-L': 'library_dirs', - '-l': 'libraries', - '-D': 'define_macros', - '-U': 'undef_macros'} - - cmd = "%s %s %s" % (pkg_config_exec, flags, packages) - status, output = getstatusoutput(cmd) - if status == 0: - for token in output.split(): - attr = _flags.get(token[:2], None) - if attr is not None: - if token[:2] == '-D': - value = tuple(token[2:].split('=')) - if len(value) == 1: - value = (value[0], None) - else: - value = token[2:] - set = getattr(module, attr) - if value not in set: - set.append(value) + def set_pkgconfig_path(self): + pkgconfig_path = sysconfig.get_config_var('LIBDIR') + if pkgconfig_path is None: + return + + pkgconfig_path = os.path.join(pkgconfig_path, 'pkgconfig') + if not os.path.isdir(pkgconfig_path): + return + + try: + os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path + except KeyError: + os.environ['PKG_CONFIG_PATH'] = pkgconfig_path + + def setup_extension(self, ext, package, default_include_dirs=[], + default_library_dirs=[], default_libraries=[]): + flag_map = { + '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} + command = "pkg-config --libs --cflags {0}".format(package) + + use_defaults = True + if self.has_pkgconfig: + try: + output = subprocess.check_output(command, shell=True) + except subprocess.CalledProcessError: + pass else: - if token not in module.extra_link_args: - module.extra_link_args.append(token) - return True - if report_error: - print_status("pkg-config", "looking for %s" % packages) - print_message(output) - return False + output = output.decode(sys.getfilesystemencoding()) + use_defaults = False + for token in output.split(): + attr = flag_map.get(token[:2]) + if attr is not None: + getattr(ext, attr).append(token[2:]) + + if use_defaults: + basedirs = get_base_dirs() + for base in basedirs: + for include in default_include_dirs: + dir = os.path.join(base, include) + if os.path.exists(dir): + ext.include_dirs.append(dir) + for lib in default_library_dirs: + dir = os.path.join(base, lib) + if os.path.exists(dir): + ext.library_dirs.append(dir) + ext.libraries = default_libraries + return True -def get_pkgconfig_version(package): - default = "found, but unknown version (no pkg-config)" - if not has_pkgconfig(): - return default + return False - status, output = getstatusoutput( - "pkg-config %s --modversion" % (package)) - if status == 0: - return output - return default + def get_version(self, package): + if not self.has_pkgconfig: + return None -def try_pkgconfig(module, package, fallback): - if not get_pkgconfig(module, package): - module.libraries.append(fallback) + status, output = getstatusoutput( + "pkg-config %s --modversion" % (package)) + if status == 0: + return output + return None -def find_include_file(include_dirs, filename): - for d in include_dirs: - if os.path.exists(os.path.join(d, filename)): - return True - return False +# The PkgConfig class should be used through this singleton +pkg_config = PkgConfig() + + +class CheckFailed(Exception): + """ + Exception thrown when a `SetupPackage.check` method fails. + """ + pass + + +class SetupPackage(object): + optional = False + + def check(self): + """ + Checks whether the dependencies are met. Should raise a + `CheckFailed` exception if the dependency could not be met, + otherwise return a string indicating a version number or some + other message indicating what was found. + """ + pass + + def get_packages(self): + """ + Get a list of package names to add to the configuration. + These are added to the `packages` list passed to + `distutils.setup`. + """ + return [] + + def get_py_modules(self): + """ + Get a list of top-level modules to add to the configuration. + These are added to the `py_modules` list passed to + `distutils.setup`. + """ + return [] + + def get_package_data(self): + """ + Get a package data dictionary to add to the configuration. + These are merged into to the `package_data` list passed to + `distutils.setup`. + """ + return {} + + def get_extension(self): + """ + Get a list of C extensions (`distutils.core.Extension` + objects) to add to the configuration. These are added to the + `extensions` list passed to `distutils.setup`. + """ + return None + + def _check_for_pkg_config(self, package, include_file, min_version=None, + version=None): + """ + A convenience function for writing checks for a + pkg_config-defined dependency. + + `package` is the pkg_config package name. + + `include_file` is a top-level include file we expect to find. + + `min_version` is the minimum version required. + + `version` will override the found version if this package + requires an alternate method for that. + """ + if version is None: + version = pkg_config.get_version(package) + + if min_version == 'PATCH': + raise CheckFailed( + "Requires patches that have not been merged upstream.") + + if min_version: + if (version is not None and + not is_min_version(version, min_version)): + raise CheckFailed( + "Requires %s %s or later. Found %s." % + (package, min_version, version)) + + ext = self.get_extension() + if ext is None: + ext = make_extension('test', []) + pkg_config.setup_extension(ext, package) + + check_include_file(ext.include_dirs, include_file, package) + + return 'version %s' % version + + +class OptionalPackage(SetupPackage): + optional = True + + def get_config(self): + install = True + if config is not None: + try: + install = config.getboolean( + 'packages', self.name) + except: + pass + return install + + def check(self): + self.install = self.get_config() + if not self.install: + raise CheckFailed("skipping due to configuration") + return "installing" + + +class OptionalBackendPackage(SetupPackage): + optional = True + + def get_config(self): + install = 'auto' + if config is not None: + try: + install = config.getboolean( + 'gui_support', self.name) + except: + install = 'auto' + if install is True: + self.optional = False + return install + + +class Platform(SetupPackage): + name = "platform" + + def check(self): + return sys.platform + + +class Python(SetupPackage): + name = "python" + + def check(self): + major, minor1, minor2, s, tmp = sys.version_info + + if major < 2: + raise CheckFailed( + "Requires Python 2.6 or later") + elif major == 2 and minor1 < 6: + raise CheckFailed( + "Requires Python 2.6 or later (in the 2.x series)") + elif major == 3 and minor1 < 1: + raise CheckFailed( + "Requires Python 3.1 or later (in the 3.x series)") + + return sys.version + + +class Matplotlib(SetupPackage): + """ + This package handles the base requirements of matplotlib. + """ + name = "matplotlib" + + def check(self): + return extract_versions()['__version__'] + + def get_packages(self): + return [ + 'matplotlib', + 'matplotlib.backends', + 'matplotlib.backends.qt4_editor', + 'matplotlib.projections', + 'matplotlib.sphinxext', + 'matplotlib.testing', + 'matplotlib.testing.jpl_units', + 'matplotlib.tri', + ] + + def get_py_packages(self): + return ['pylab'] + + def get_package_data(self): + return { + 'matplotlib': + [ + 'mpl-data/fonts/afm/*.afm', + 'mpl-data/fonts/pdfcorefonts/*.afm', + 'mpl-data/fonts/pdfcorefonts/*.txt', + 'mpl-data/fonts/ttf/*.ttf', + 'mpl-data/fonts/ttf/LICENSE_STIX', + 'mpl-data/fonts/ttf/COPYRIGHT.TXT', + 'mpl-data/fonts/ttf/README.TXT', + 'mpl-data/fonts/ttf/RELEASENOTES.TXT', + 'mpl-data/images/*.xpm', # TODO: Only with GUIs + 'mpl-data/images/*.svg', + 'mpl-data/images/*.gif', + 'mpl-data/images/*.png', + 'mpl-data/images/*.ppm', + 'mpl-data/example/*.npy', + 'mpl-data/matplotlibrc', + 'mpl-data/*.glade', # TODO: Only with gtk backend + 'backends/Matplotlib.nib/*', # TODO: Only with macosx backend + 'backends/web_backend/*.*', + 'backends/web_backend/jquery/js/*', + 'backends/web_backend/jquery/css/themes/base/*.*', + 'backends/web_backend/jquery/css/themes/base/images/*', + 'backends/web_backend/css/*.*', + ]} + + +class SampleData(OptionalPackage): + """ + This handles the sample data that ships with matplotlib. It is + technically optional, though most often will be desired. + """ + name = "sample_data" + + def get_package_data(self): + return { + 'matplotlib': + [ + 'mpl-data/sample_data/*.*', + 'mpl-data/sample_data/axes_grid/*.*', + ]} + + +class Toolkits(OptionalPackage): + """ + This package handles the optional toolkits that ship with + matplotlib. + """ + name = "toolkits" + + def get_packages(self): + return [ + 'mpl_toolkits', + 'mpl_toolkits.mplot3d', + 'mpl_toolkits.axes_grid', + 'mpl_toolkits.axes_grid1', + 'mpl_toolkits.axisartist', + ] + + +class Tests(OptionalPackage): + """ + This package contains the regression tests and data. + """ + name = "tests" + + def check(self): + super(Tests, self).check() -def check_for_freetype(): - module = make_extension('test', []) - add_base_flags(module) - if not get_pkgconfig(module, 'freetype2'): - basedirs = module.include_dirs[:] # copy the list to avoid inf loop! - for d in basedirs: - module.include_dirs.append(os.path.join(d, 'freetype2')) - - print_status("freetype2", get_pkgconfig_version('freetype2')) - if not find_include_file(module.include_dirs, 'ft2build.h'): - print_message( - "WARNING: Could not find 'freetype2' headers in any of %s." % - ", ".join(["'%s'" % x for x in module.include_dirs])) - - return True - -def check_for_libpng(): - module = make_extension("test", []) - get_pkgconfig(module, 'libpng') - add_base_flags(module) - - print_status("libpng", get_pkgconfig_version('libpng')) - if not find_include_file(module.include_dirs, 'png.h'): - print_message( - "Could not find 'libpng' headers in any of %s" % - ", ".join(["'%s'" % x for x in module.include_dirs])) - - return True - -def add_base_flags(module): - incdirs = filter(os.path.exists, - [os.path.join(p, 'include') for p in basedirlist ]) - libdirs = filter(os.path.exists, - [os.path.join(p, 'lib') for p in basedirlist ]+ - [os.path.join(p, 'lib64') for p in basedirlist ] ) - - module.include_dirs.extend(incdirs) - module.include_dirs.append('.') - module.library_dirs.extend(libdirs) - -def getoutput(s): - 'get the output of a system command' - - ret = os.popen(s).read().strip() - return ret - -def convert_qt_version(version): - version = '%x'%version - temp = [] - while len(version) > 0: - version, chunk = version[:-2], version[-2:] - temp.insert(0, str(int(chunk, 16))) - return '.'.join(temp) - -def check_for_qt(): - try: - import pyqtconfig - except ImportError: - print_status("Qt", "no") - return False - else: try: - qt_version = pyqtconfig.Configuration().qt_version - qt_version = convert_qt_version(qt_version) - except AttributeError: - qt_version = "" - print_status("Qt", "Qt: %s, PyQt: %s" % - (qt_version, - pyqtconfig.Configuration().pyqt_version_str)) - return True + import nose + except ImportError: + return ( + "nose 0.11.1 or later is required to run the " + "matplotlib test suite") + + if nose.__versioninfo__ < (0, 11, 1): + return ( + "nose 0.11.1 or later is required to run the " + "matplotlib test suite") + + return 'using nose version %s' % nose.__version__ + + def get_packages(self): + return [ + 'matplotlib.tests', + ] -def check_for_qt4(): - try: - from PyQt4 import pyqtconfig - except ImportError: - print_status("Qt4", "no") - return False - else: - print_status("Qt4", "Qt: %s, PyQt4: %s" % - (convert_qt_version(pyqtconfig.Configuration().qt_version), - pyqtconfig.Configuration().pyqt_version_str)) - return True + def get_package_data(self): + baseline_images = [ + 'tests/baseline_images/%s/*' % x + for x in os.listdir('lib/matplotlib/tests/baseline_images')] -def check_for_pyside(): - try: - from PySide import __version__ - from PySide import QtCore - except ImportError: - print_status("PySide", "no") - return False - else: - print_status("PySide", "Qt: %s, PySide: %s" % - (QtCore.__version__, __version__)) - return True + return { + 'matplotlib': + baseline_images + + [ + 'tests/mpltest.ttf', + 'tests/test_rcparams.rc' + ]} -def check_for_cairo(): - try: - import cairo - except ImportError: - print_status("Cairo", "no") - return False - else: - print_status("Cairo", cairo.version) - return True -def check_for_tornado(): - try: - import tornado - except ImportError: - print_status("Tornado (webagg)", "no") - return False - else: - print_status("Tornado (webagg)", tornado.version) - return True +class Numpy(SetupPackage): + """ + Checks for the existence of Numpy. + """ -def check_provide_pytz(): - if options['provide_pytz'] is True: - print_status("pytz", "matplotlib will provide") - return True - try: - import pytz - except ImportError: - if options['provide_pytz']: - print_status("pytz", "matplotlib will provide") - return True + name = "numpy" + + def check(self): + min_version = extract_versions()['__version__numpy__'] + try: + import numpy + except ImportError: + raise CheckFailed( + "Requires numpy %s or later. (Numpy not found)" % + min_version) + + if not is_min_version(numpy.__version__, min_version): + raise CheckFailed( + "Requires numpy %s or later. (Found %s)" % + (min_version, numpy.__version__)) + + ext = make_extension('test', []) + ext.include_dirs.append(numpy.get_include()) + if not has_include_file( + ext.include_dirs, os.path.join("numpy", "arrayobject.h")): + raise CheckFailed( + "The C headers for numpy could not be found. You" + "may need to install the development package.") + + return 'version %s' % numpy.__version__ + + def add_flags(self, ext): + import numpy + + ext.include_dirs.append(numpy.get_include()) + ext.define_macros.append(('PY_ARRAY_UNIQUE_SYMBOL', 'MPL_ARRAY_API')) + + +class CXX(SetupPackage): + """ + This package handles PyCXX. + """ + name = 'pycxx' + + # TODO: Investigate what patches need to be added to PyCXX to get + # a minimum version + + def check(self): + try: + return self._check_for_pkg_config( + 'PyCXX', 'CXX/Extensions.hxx', min_version='PATCH') + except CheckFailed as e: + self.__class__.found_external = False + return str(e) + ' Using local copy.' + finally: + self.__class__.found_external = True + + def add_flags(self, ext): + if self.found_external: + pkg_config.setup_extension(ext, 'PyCXX') else: - print_status("pytz", "no") - return False - else: - if pytz.__version__.endswith('mpl'): - print_status("pytz", "matplotlib will provide") - return True + ext.sources.extend(glob.glob('CXX/*.cxx')) + ext.sources.extend(glob.glob('CXX/*.c')) + ext.define_macros.append(('PYCXX_ISO_CPP_LIB', '1')) + if sys.version_info[0] >= 3: + ext.define_macros.append(('PYCXX_PYTHON_2TO3', '1')) + if not (sys.platform == 'win32' and win32_compiler == 'msvc'): + ext.libraries.append('stdc++') + ext.libraries.append('m') + + +class LibAgg(SetupPackage): + name = 'libagg' + + def check(self): + try: + return self._check_for_pkg_config( + 'libagg', 'agg2/agg_basics.h', min_version='PATCH') + except CheckFailed as e: + self.__class__.found_external = False + return str(e) + ' Using local copy.' + finally: + self.__class__.found_external = True + + def add_flags(self, ext): + ext.include_dirs.append('agg24/include') + agg_sources = [ + 'agg_bezier_arc.cpp', + 'agg_curves.cpp', + 'agg_image_filters.cpp', + 'agg_trans_affine.cpp', + 'agg_vcgen_contour.cpp', + 'agg_vcgen_dash.cpp', + 'agg_vcgen_stroke.cpp', + ] + ext.sources.extend( + os.path.join('agg24', 'src', x) for x in agg_sources) + + +class FreeType(SetupPackage): + """ + Handles the Freetype dependency. + """ + name = "freetype" + + def check(self): + status, output = getstatusoutput("freetype-config --version") + if status == 0: + version = output else: - print_status("pytz", pytz.__version__) - return False + version = None -def check_provide_dateutil(): - if options['provide_dateutil'] is True: - print_status("dateutil", "matplotlib will provide") - return True - try: - import dateutil - except ImportError: - if options['provide_dateutil']: - print_status("dateutil", "matplotlib will provide") - return True + return self._check_for_pkg_config( + 'freetype2', 'ft2build.h', + min_version='2.4', version=version) + + def add_flags(self, ext): + pkg_config.setup_extension( + ext, 'freetype2', + default_include_dirs=[ + 'freetype2', 'lib/freetype2/include', + 'lib/freetype2/include/freetype2'], + default_library_dirs=[ + 'freetype2/lib'], + default_libraries=['freetype', 'z']) + + +class FT2Font(SetupPackage): + """ + Handles the ft2font extension. + """ + name = 'ft2font' + + def get_extension(self): + sources = [ + 'src/ft2font.cpp', + 'src/mplutils.cpp' + ] + ext = make_extension('matplotlib.ft2font', sources) + FreeType().add_flags(ext) + Numpy().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class Png(SetupPackage): + """ + Handles the png extension. + """ + name = "png" + + def check(self): + return self._check_for_pkg_config( + 'libpng', 'png.h', + # TODO: Determine minimum version + min_version='1.4') + + def get_extension(self): + sources = [ + 'src/_png.cpp' + ] + ext = make_extension('matplotlib._png', sources) + pkg_config.setup_extension( + ext, 'libpng', default_libraries=['png', 'z']) + Numpy().add_flags(ext) + CXX().add_flags(ext) + + +class TTConv(SetupPackage): + """ + Builds the ttconv extension. + """ + name = "ttconv" + + def get_extension(self): + sources = [ + 'src/_ttconv.cpp', + 'ttconv/pprdrv_tt.cpp', + 'ttconv/pprdrv_tt2.cpp', + 'ttconv/ttutil.cpp' + ] + ext = make_extension('matplotlib.ttconv', sources) + Numpy().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class Path(SetupPackage): + """ + Builds the Path extension. + """ + name = "path" + + def get_extension(self): + sources = [ + 'src/_path.cpp', + 'src/path_cleanup.cpp', + 'src/agg_py_transforms.cpp' + ] + + ext = make_extension('matplotlib._path', sources) + Numpy().add_flags(ext) + LibAgg().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class Image(SetupPackage): + """ + Builds the Image extension. + """ + name = "image" + + def get_extension(self): + sources = [ + 'src/_image.cpp', 'src/mplutils.cpp' + ] + ext = make_extension('matplotlib._image', sources) + Numpy().add_flags(ext) + LibAgg().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class Contour(SetupPackage): + """ + Builds the contour extension. + """ + name = "contour" + + def get_extension(self): + sources = [ + "src/cntr.c" + ] + ext = make_extension('matplotlib._cntr', sources) + Numpy().add_flags(ext) + return ext + + +class Delaunay(SetupPackage): + """ + Builds the delaunay extension. + """ + name = "delaunay" + + def get_packages(self): + return ['matplotlib.delaunay'] + + def get_extension(self): + sources = ["_delaunay.cpp", "VoronoiDiagramGenerator.cpp", + "delaunay_utils.cpp", "natneighbors.cpp"] + sources = [os.path.join('lib/matplotlib/delaunay', s) for s in sources] + ext = make_extension('matplotlib._delaunay', sources) + Numpy().add_flags(ext) + return ext + + +class Tri(SetupPackage): + """ + Builds the tri extension. + """ + name = "tri" + + def get_extension(self): + sources = [ + "lib/matplotlib/tri/_tri.cpp", + "src/mplutils.cpp" + ] + ext = make_extension('matplotlib._tri', sources) + Numpy().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class BackendAgg(OptionalBackendPackage): + """ + Builds the Agg backend. + """ + name = "agg" + force = False + + def check(self): + # The Agg backend extension needs to be built even + # for certain GUI backends, such as TkAgg + config = self.get_config() + if config is False and self.force is False: + raise CheckFailed("skipping due to configuration") else: - print_status("dateutil", "no") - return False - else: + return "installing" + + def get_extension(self): + sources = [ + "src/mplutils.cpp", + "src/agg_py_transforms.cpp", + "src/_backend_agg.cpp" + ] + ext = make_extension('matplotlib.backends._backend_agg', sources) + Numpy().add_flags(ext) + LibAgg().add_flags(ext) + FreeType().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class BackendTkAgg(OptionalBackendPackage): + name = "tkagg" + + def __init__(self): + self.tcl_tk_cache = None + + def check(self): + if self.get_config() is False: + raise CheckFailed("skipping due to configuration") + try: - if dateutil.__version__.endswith('mpl'): - print_status("dateutil", "matplotlib will provide") - return True + if sys.version_info[0] < 3: + import Tkinter else: - print_status("dateutil", dateutil.__version__) - return False - except AttributeError: - print_status("dateutil", "present, version unknown") - return False + import tkinter as Tkinter + except ImportError: + raise CheckFailed('TKAgg requires Tkinter.') + except RuntimeError: + raise CheckFailed('Tkinter present but import failed.') + else: + if Tkinter.TkVersion < 8.3: + raise CheckFailed("Tcl/Tk v8.3 or later required.") -def check_provide_six(): - # We don't need six on Python 2.x - if sys.version_info[0] < 3: - return + ext = self.get_extension() + check_include_file(ext.include_dirs, "tk.h", "Tk") - if options['provide_six'] is True: - print_status("six", "matplotlib will provide") - return True - try: - import six - except ImportError: - if options['provide_six']: - print_status("six", "matplotlib will provide") - return True + try: + tk_v = Tkinter.__version__.split()[-2] + except (AttributeError, IndexError): + # Tkinter.__version__ has been removed in python 3 + tk_v = 'version not identified' + + BackendAgg.force = True + + return "version %s" % tk_v + + def get_extension(self): + sources = [ + 'src/agg_py_transforms.cpp', + 'src/_tkagg.cpp' + ] + + ext = make_extension('matplotlib.backends._tkagg', sources) + self.add_flags(ext) + LibAgg().add_flags(ext) + CXX().add_flags(ext) + return ext + + def query_tcltk(self): + """ + Tries to open a Tk window in order to query the Tk object + about its library paths. This should never be called more + than once by the same process, as Tk intricacies may cause the + Python interpreter to hang. The function also has a workaround + if no X server is running (useful for autobuild systems). + """ + # Use cached values if they exist, which ensures this function + # only executes once + if self.tcl_tk_cache is not None: + return self.tcl_tk_cache + + # By this point, we already know that Tkinter imports correctly + if sys.version_info[0] < 3: + import Tkinter else: - print_status("six", "no") - return False - else: + import tkinter as Tkinter + tcl_lib_dir = '' + tk_lib_dir = '' + # First try to open a Tk window (requires a running X server) try: - if six.__version__.endswith('mpl'): - print_status("six", "matplotlib will provide") - return True + tk = Tkinter.Tk() + except Tkinter.TclError: + # Next, start Tcl interpreter without opening a Tk window + # (no need for X server) This feature is available in + # python version 2.4 and up + try: + tcl = Tkinter.Tcl() + except AttributeError: # Python version not high enough + pass + except Tkinter.TclError: # Something went wrong while opening Tcl + pass else: - print_status("six", six.__version__) - return False - except AttributeError: - print_status("six", "present, version unknown") - return False + tcl_lib_dir = str(tcl.getvar('tcl_library')) + # Guess Tk location based on Tcl location + (head, tail) = os.path.split(tcl_lib_dir) + tail = tail.replace('Tcl', 'Tk').replace('tcl', 'tk') + tk_lib_dir = os.path.join(head, tail) + if not os.path.exists(tk_lib_dir): + tk_lib_dir = tcl_lib_dir.replace( + 'Tcl', 'Tk').replace('tcl', 'tk') + else: + # Obtain Tcl and Tk locations from Tk widget + tk.withdraw() + tcl_lib_dir = str(tk.getvar('tcl_library')) + tk_lib_dir = str(tk.getvar('tk_library')) + tk.destroy() + # Save directories and version string to cache + self.tcl_tk_cache = tcl_lib_dir, tk_lib_dir, str(Tkinter.TkVersion)[:3] + return self.tcl_tk_cache -def check_for_dvipng(): - try: - stdin, stdout = run_child_process('dvipng -version') - print_status("dvipng", stdout.readlines()[1].decode().split()[-1]) - return True - except (IndexError, ValueError): - print_status("dvipng", "no") - return False + def parse_tcl_config(self, tcl_lib_dir, tk_lib_dir): + try: + if sys.version_info[0] < 3: + import Tkinter + else: + import tkinter as Tkinter + except ImportError: + return None + + tcl_poss = [tcl_lib_dir, + os.path.normpath(os.path.join(tcl_lib_dir, '..')), + "/usr/lib/tcl" + str(Tkinter.TclVersion), + "/usr/lib"] + tk_poss = [tk_lib_dir, + os.path.normpath(os.path.join(tk_lib_dir, '..')), + "/usr/lib/tk" + str(Tkinter.TkVersion), + "/usr/lib"] + for ptcl, ptk in zip(tcl_poss, tk_poss): + tcl_config = os.path.join(ptcl, "tclConfig.sh") + tk_config = os.path.join(ptk, "tkConfig.sh") + if (os.path.exists(tcl_config) and os.path.exists(tk_config)): + break + if not (os.path.exists(tcl_config) and os.path.exists(tk_config)): + return None + + def get_var(file, varname): + p = subprocess.Popen( + '. %s ; eval echo ${%s}' % (file, varname), + shell=True, + executable="/bin/sh", + stdout=subprocess.PIPE) + result = p.communicate()[0] + return result.decode('ascii') + + tcl_lib_dir = get_var( + tcl_config, 'TCL_LIB_SPEC').split()[0][2:].strip() + tcl_inc_dir = get_var( + tcl_config, 'TCL_INCLUDE_SPEC')[2:].strip() + tcl_lib = get_var(tcl_config, 'TCL_LIB_FLAG')[2:].strip() + + tk_lib_dir = get_var(tk_config, 'TK_LIB_SPEC').split()[0][2:].strip() + tk_inc_dir = get_var(tk_config, 'TK_INCLUDE_SPEC').strip() + if tk_inc_dir == '': + tk_inc_dir = tcl_inc_dir + else: + tk_inc_dir = tk_inc_dir[2:] + tk_lib = get_var(tk_config, 'TK_LIB_FLAG')[2:].strip() + + if not os.path.exists(os.path.join(tk_inc_dir, 'tk.h')): + return None + + return (tcl_lib_dir, tcl_inc_dir, tcl_lib, + tk_lib_dir, tk_inc_dir, tk_lib) + + def guess_tcl_config(self, tcl_lib_dir, tk_lib_dir, tk_ver): + if not (os.path.exists(tcl_lib_dir) and os.path.exists(tk_lib_dir)): + return None + + tcl_lib = os.path.normpath(os.path.join(tcl_lib_dir, '../')) + tk_lib = os.path.normpath(os.path.join(tk_lib_dir, '../')) + + tcl_inc = os.path.normpath( + os.path.join(tcl_lib_dir, + '../../include/tcl' + tk_ver)) + if not os.path.exists(tcl_inc): + tcl_inc = os.path.normpath( + os.path.join(tcl_lib_dir, + '../../include')) + + tk_inc = os.path.normpath(os.path.join( + tk_lib_dir, + '../../include/tk' + tk_ver)) + if not os.path.exists(tk_inc): + tk_inc = os.path.normpath(os.path.join( + tk_lib_dir, + '../../include')) + + if not os.path.exists(os.path.join(tk_inc, 'tk.h')): + tk_inc = tcl_inc + + if not os.path.exists(tcl_inc): + # this is a hack for suse linux, which is broken + if (sys.platform.startswith('linux') and + os.path.exists('/usr/include/tcl.h') and + os.path.exists('/usr/include/tk.h')): + tcl_inc = '/usr/include' + tk_inc = '/usr/include' + + if not os.path.exists(os.path.join(tk_inc, 'tk.h')): + return None + + return tcl_lib, tcl_inc, 'tcl' + tk_ver, tk_lib, tk_inc, 'tk' + tk_ver + + def hardcoded_tcl_config(self): + tcl_inc = "/usr/local/include" + tk_inc = "/usr/local/include" + tcl_lib = "/usr/local/lib" + tk_lib = "/usr/local/lib" + return tcl_lib, tcl_inc, 'tcl', tk_lib, tk_inc, 'tk' + + def add_flags(self, ext): + if sys.platform == 'win32': + major, minor1, minor2, s, tmp = sys.version_info + ext.include_dirs.extend(['win32_static/include/tcl85']) + ext.libraries.extend(['tk85', 'tcl85']) + ext.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) + + elif sys.platform == 'darwin': + # this config section lifted directly from Imaging - thanks to + # the effbot! + + # First test for a MacOSX/darwin framework install + from os.path import join, exists + framework_dirs = [ + join(os.getenv('HOME'), '/Library/Frameworks'), + '/Library/Frameworks', + '/System/Library/Frameworks/', + ] -def check_for_ghostscript(): - try: + # Find the directory that contains the Tcl.framework and + # Tk.framework bundles. + tk_framework_found = 0 + for F in framework_dirs: + # both Tcl.framework and Tk.framework should be present + for fw in 'Tcl', 'Tk': + if not exists(join(F, fw + '.framework')): + break + else: + # ok, F is now directory with both frameworks. Continure + # building + tk_framework_found = 1 + break + if tk_framework_found: + # For 8.4a2, we must add -I options that point inside + # the Tcl and Tk frameworks. In later release we + # should hopefully be able to pass the -F option to + # gcc, which specifies a framework lookup path. + + tk_include_dirs = [ + join(F, fw + '.framework', H) + for fw in ('Tcl', 'Tk') + for H in ('Headers', 'Versions/Current/PrivateHeaders') + ] + + # For 8.4a2, the X11 headers are not included. Rather + # than include a complicated search, this is a + # hard-coded path. It could bail out if X11 libs are + # not found... + + # tk_include_dirs.append('/usr/X11R6/include') + frameworks = ['-framework', 'Tcl', '-framework', 'Tk'] + ext.include_dirs.extend(tk_include_dirs) + ext.extra_link_args.extend(frameworks) + ext.extra_compile_args.extend(frameworks) + + # you're still here? ok we'll try it this way... + else: + # There are 3 methods to try, in decreasing order of "smartness" + # + # 1. Parse the tclConfig.sh and tkConfig.sh files that have + # all the information we need + # + # 2. Guess the include and lib dirs based on the location of + # Tkinter's 'tcl_library' and 'tk_library' variables. + # + # 3. Use some hardcoded locations that seem to work on a lot + # of distros. + + # Query Tcl/Tk system for library paths and version string + try: + tcl_lib_dir, tk_lib_dir, tk_ver = self.query_tcltk() + except: + tk_ver = '' + result = self.hardcoded_tcl_config() + else: + result = self.parse_tcl_config(tcl_lib_dir, tk_lib_dir) + if result is None: + result = self.guess_tcl_config( + tcl_lib_dir, tk_lib_dir, tk_ver) + if result is None: + result = self.hardcoded_tcl_config() + + # Add final versions of directories and libraries to ext lists + (tcl_lib_dir, tcl_inc_dir, tcl_lib, + tk_lib_dir, tk_inc_dir, tk_lib) = result + ext.include_dirs.extend([tcl_inc_dir, tk_inc_dir]) + ext.library_dirs.extend([tcl_lib_dir, tk_lib_dir]) + ext.libraries.extend([tcl_lib, tk_lib]) + + +class BackendGtk(OptionalBackendPackage): + """ + Handles the Gtk (regular Gdk) backend. + """ + name = "gtk" + + def check(self): + if self.get_config() is False: + raise CheckFailed("skipping due to configuration") + + try: + import gtk + except ImportError: + raise CheckFailed("Requires pygtk") + except RuntimeError: + raise CheckFailed('pygtk present, but import failed.') + else: + version = (2, 2, 0) + if gtk.pygtk_version < version: + raise CheckFailed( + "Requires pygtk %d.%d.%d or later. " + "Found %d.%d.%d" % (version + gtk.pygtk_version)) + + ext = self.get_extension() + self.add_flags(ext) + check_include_file(ext.include_dirs, + os.path.join("gtk", "gtk.h"), + 'gtk') + check_include_file(ext.include_dirs, + os.path.join("pygtk", "pygtk.h"), + 'pygtk') + + return 'Gtk: %s pygtk: %s' % ( + ".".join(str(x) for x in gtk.gtk_version), + ".".join(str(x) for x in gtk.pygtk_version)) + + def get_extension(self): + sources = [ + 'src/_backend_gdk.c' + ] + ext = make_extension('matplotlib.backends._backend_gdk', sources) + self.add_flags(ext) + Numpy().add_flags(ext) + return ext + + def add_flags(self, ext): if sys.platform == 'win32': - command = 'gswin32c --version' + # popen broken on my win32 plaform so I can't use pkgconfig + ext.library_dirs.extend( + ['C:/GTK/bin', 'C:/GTK/lib']) + + ext.include_dirs.extend( + ['win32_static/include/pygtk-2.0', + 'C:/GTK/include', + 'C:/GTK/include/gobject', + 'C:/GTK/include/gext', + 'C:/GTK/include/glib', + 'C:/GTK/include/pango', + 'C:/GTK/include/atk', + 'C:/GTK/include/X11', + 'C:/GTK/include/cairo', + 'C:/GTK/include/gdk', + 'C:/GTK/include/gdk-pixbuf', + 'C:/GTK/include/gtk', + ]) + + def getoutput(s): + ret = os.popen(s).read().strip() + return ret + + if 'PKG_CONFIG_PATH' not in os.environ: + # If Gtk+ is installed, pkg-config is required to be installed + os.environ['PKG_CONFIG_PATH'] = 'C:\GTK\lib\pkgconfig' + + pygtkIncludes = getoutput( + 'pkg-config --cflags-only-I pygtk-2.0').split() + gtkIncludes = getoutput( + 'pkg-config --cflags-only-I gtk+-2.0').split() + includes = pygtkIncludes + gtkIncludes + ext.include_dirs.extend([include[2:] for include in includes]) + + pygtkLinker = getoutput('pkg-config --libs pygtk-2.0').split() + gtkLinker = getoutput('pkg-config --libs gtk+-2.0').split() + linkerFlags = pygtkLinker + gtkLinker + + ext.libraries.extend( + [flag[2:] for flag in linkerFlags if flag.startswith('-l')]) + + ext.library_dirs.extend( + [flag[2:] for flag in linkerFlags if flag.startswith('-L')]) + + ext.extra_link_args.extend( + [flag for flag in linkerFlags if not + (flag.startswith('-l') or flag.startswith('-L'))]) + + # visual studio doesn't need the math library + if (sys.platform == 'win32' and + win32_compiler == 'msvc' and + 'm' in ext.libraries): + ext.libraries.remove('m') + + elif sys.platform != 'win32': + pkg_config.setup_extension(ext, 'pygtk-2.0') + pkg_config.setup_extension(ext, 'gtk+-2.0') + + +class BackendGtkAgg(BackendGtk): + """ + Builds the GtkAgg extension. + """ + name = "gtkagg" + + def check(self): + try: + return super(BackendGtkAgg, self).check() + except: + raise else: - command = 'gs --version' - stdin, stdout = run_child_process(command) - print_status("ghostscript", stdout.read().decode()[:-1]) - return True - except (IndexError, ValueError): - print_status("ghostscript", "no") - return False + BackendAgg.force = True -def check_for_latex(): - try: - stdin, stdout = run_child_process('latex -version') - line = stdout.readlines()[0].decode() - pattern = '(3\.1\d+)|(MiKTeX \d+.\d+)' - match = re.search(pattern, line) - print_status("latex", match.group(0)) - return True - except (IndexError, ValueError, AttributeError): - print_status("latex", "no") - return False + def get_extension(self): + sources = [ + 'src/agg_py_transforms.cpp', + 'src/_gtkagg.cpp', + 'src/mplutils.cpp' + ] + ext = make_extension('matplotlib.backends._gtkagg', sources) + self.add_flags(ext) + LibAgg().add_flags(ext) + return ext -def check_for_pdftops(): - try: - stdin, stdout = run_child_process('pdftops -v') - for line in stdout.readlines(): - line = line.decode() - if 'version' in line: - print_status("pdftops", line.split()[-1]) - return True - except (IndexError, ValueError): - print_status("pdftops", "no") - return False -def check_for_numpy(min_version): +def backend_gtk3agg_internal_check(x): try: - import numpy + from gi.repository import Gtk, Gdk, GObject except ImportError: - print_status("numpy", "no") - print_message("You must install numpy %s or later to build matplotlib." % - min_version) - return False + return (False, "Requires pygobject to be installed.") - expected_version = version.LooseVersion(min_version) - found_version = version.LooseVersion(numpy.__version__) - if not found_version >= expected_version: - print_message( - 'numpy %s or later is required; you have %s' % - (min_version, numpy.__version__)) - return False - module = Extension('test', []) - add_numpy_flags(module) - add_base_flags(module) + if sys.version_info[0] >= 3: + return (False, "gtk3agg does not work on Python 3") - print_status("numpy", numpy.__version__) - if not find_include_file(module.include_dirs, os.path.join("numpy", "arrayobject.h")): - print_message("Could not find the headers for numpy. You may need to install the development package.") - return False - return True - -def add_numpy_flags(module): - "Add the modules flags to build extensions which use numpy" - import numpy - module.include_dirs.append(numpy.get_include()) - -def add_png_flags(module): - try_pkgconfig(module, 'libpng', 'png') - add_base_flags(module) - add_numpy_flags(module) - module.libraries.append('z') - module.include_dirs.extend(['.']) - module.libraries.extend(std_libs) - -def add_agg_flags(module): - 'Add the module flags to build extensions which use agg' - - # before adding the freetype flags since -z comes later - add_base_flags(module) - add_numpy_flags(module) - module.include_dirs.extend(['src', '%s/include'%AGG_VERSION, '.']) - - # put these later for correct link order - module.libraries.extend(std_libs) - -def add_ft2font_flags(module): - 'Add the module flags to ft2font extension' - add_numpy_flags(module) - if not get_pkgconfig(module, 'freetype2'): - module.libraries.extend(['freetype', 'z']) - add_base_flags(module) - - basedirs = module.include_dirs[:] # copy the list to avoid inf loop! - for d in basedirs: - module.include_dirs.append(os.path.join(d, 'freetype2')) - p = os.path.join(d, 'lib/freetype2/include') - if os.path.exists(p): module.include_dirs.append(p) - p = os.path.join(d, 'lib/freetype2/include/freetype2') - if os.path.exists(p): module.include_dirs.append(p) - - basedirs = module.library_dirs[:] # copy the list to avoid inf loop! - for d in basedirs: - p = os.path.join(d, 'freetype2/lib') - if os.path.exists(p): module.library_dirs.append(p) - else: - add_base_flags(module) - module.libraries.append('z') + return (True, "version %s.%s.%s" % ( + Gtk.get_major_version(), + Gtk.get_micro_version(), + Gtk.get_minor_version())) - # put this last for library link order - module.libraries.extend(std_libs) -def check_for_gtk(): - 'check for the presence of pygtk' - gotit = False - explanation = None - try: - import gtk - except ImportError: - explanation = 'Building for Gtk+ requires pygtk; you must be able to "import gtk" in your build/install environment' - except RuntimeError: - explanation = 'pygtk present but import failed' - else: - version = (2,2,0) - if gtk.pygtk_version < version: - explanation = "Error: GTK backend requires PyGTK %d.%d.%d (or later), " \ - "%d.%d.%d was detected." % ( - version + gtk.pygtk_version) - else: - gotit = True - - if gotit: - module = make_extension('test', []) - add_pygtk_flags(module) - if not find_include_file(module.include_dirs, os.path.join("gtk", "gtk.h")): - explanation = ( - "Could not find Gtk+ headers in any of %s" % - ", ".join(["'%s'" % x for x in module.include_dirs])) - gotit = False - - def ver2str(tup): - return ".".join([str(x) for x in tup]) - - if gotit: - import gobject - if hasattr(gobject, 'pygobject_version'): - pygobject_version = ver2str(gobject.pygobject_version) +class BackendGtk3Agg(OptionalBackendPackage): + """ + Builds the Gtk3Agg extension. + """ + name = "gtk3agg" + + def check(self): + # This check needs to be performed out-of-process, because + # importing gi and then importing regular old pygtk afterward + # segfaults the interpreter. + p = multiprocessing.Pool() + success, msg = p.map(backend_gtk3agg_internal_check, [0])[0] + p.close() + p.join() + if success: + BackendAgg.force = True + + return msg else: - pygobject_version = '[pre-pygobject]' - print_status("Gtk+", "gtk+: %s, glib: %s, pygtk: %s, pygobject: %s" % - (ver2str(gtk.gtk_version), ver2str(gobject.glib_version), - ver2str(gtk.pygtk_version), pygobject_version)) - else: - print_status("Gtk+", "no") + raise CheckFailed(msg) - if explanation is not None: - print_message(explanation) - # Switch off the event loop for PyGTK >= 2.15.0 - if gotit: - try: - gtk.set_interactive(False) - except AttributeError: # PyGTK < 2.15.0 - pass +def backend_gtk3cairo_internal_check(x): + try: + import cairo + except ImportError: + return (False, "Requires cairo to be installed.") - return gotit - -def add_pygtk_flags(module): - 'Add the module flags to build extensions which use gtk' - - if sys.platform=='win32': - # popen broken on my win32 plaform so I can't use pkgconfig - module.library_dirs.extend( - ['C:/GTK/bin', 'C:/GTK/lib']) - - module.include_dirs.extend( - ['win32_static/include/pygtk-2.0', - 'C:/GTK/include', - 'C:/GTK/include/gobject', - 'C:/GTK/include/gmodule', - 'C:/GTK/include/glib', - 'C:/GTK/include/pango', - 'C:/GTK/include/atk', - 'C:/GTK/include/X11', - 'C:/GTK/include/cairo', - 'C:/GTK/include/gdk', - 'C:/GTK/include/gdk-pixbuf', - 'C:/GTK/include/gtk', - ]) - - add_base_flags(module) - - if 'PKG_CONFIG_PATH' not in os.environ: - # If Gtk+ is installed, pkg-config is required to be installed - os.environ['PKG_CONFIG_PATH'] = 'C:\GTK\lib\pkgconfig' - - pygtkIncludes = getoutput('pkg-config --cflags-only-I pygtk-2.0').split() - gtkIncludes = getoutput('pkg-config --cflags-only-I gtk+-2.0').split() - includes = pygtkIncludes + gtkIncludes - module.include_dirs.extend([include[2:] for include in includes]) - - pygtkLinker = getoutput('pkg-config --libs pygtk-2.0').split() - gtkLinker = getoutput('pkg-config --libs gtk+-2.0').split() - linkerFlags = pygtkLinker + gtkLinker - - module.libraries.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-l')]) - - module.library_dirs.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-L')]) - - module.extra_link_args.extend( - [flag for flag in linkerFlags if not - (flag.startswith('-l') or flag.startswith('-L'))]) - - # visual studio doesn't need the math library - if sys.platform == 'win32' and win32_compiler == 'msvc' and 'm' in module.libraries: - module.libraries.remove('m') - - if sys.platform != 'win32': - # If Gtk+ is installed, pkg-config is required to be installed - add_base_flags(module) - ok = get_pkgconfig(module, 'pygtk-2.0 gtk+-2.0', report_error=True) - if not ok: - print_message( - "You may need to install 'dev' package(s) to provide header files.") - # visual studio doesn't need the math library - if sys.platform == 'win32' and win32_compiler == 'msvc' and 'm' in module.libraries: - module.libraries.remove('m') - -# Make sure you use the Tk version given by Tkinter.TkVersion -# or else you'll build for a wrong version of the Tcl -# interpreter (leading to nasty segfaults). -def check_for_tk(): - gotit = False - explanation = None try: - if sys.version_info[0] < 3: - import Tkinter - else: - import tkinter as Tkinter + from gi.repository import Gtk, Gdk, GObject except ImportError: - explanation = 'TKAgg requires Tkinter' - except RuntimeError: - explanation = 'Tkinter present but import failed' - else: - if Tkinter.TkVersion < 8.3: - explanation = "Tcl/Tk v8.3 or later required" + return (False, "Requires pygobject to be installed.") + + return (True, "version %s.%s.%s" % ( + Gtk.get_major_version(), + Gtk.get_micro_version(), + Gtk.get_minor_version())) + + +class BackendGtk3Cairo(OptionalBackendPackage): + """ + Builds the Gtk3Cairo extension. + """ + name = "gtk3cairo" + + def check(self): + # This check needs to be performed out-of-process, because + # importing gi and then importing regular old pygtk afterward + # segfaults the interpreter. + p = multiprocessing.Pool() + success, msg = p.map(backend_gtk3cairo_internal_check, [0])[0] + p.close() + p.join() + if success: + BackendAgg.force = True + + return msg else: - gotit = True + raise CheckFailed(msg) + - if gotit: - module = make_extension('test', []) +class BackendWxAgg(OptionalBackendPackage): + """ + Builds the WxAgg extension. + """ + name = "wxagg" + + def check(self): try: - explanation = add_tk_flags(module) - # except RuntimeError: - # # This deals with the change in exception handling syntax in - # # python 3. If we only need to support >= 2.6, we can just use the - # # commented out lines below. - # exc_type,exc,tb = sys.exc_info() - # explanation = str(exc) - # gotit = False - except RuntimeError as e: - explanation = str(e) - else: - if not find_include_file(module.include_dirs, "tk.h"): - message = 'Tkinter present, but header files are not found. ' + \ - 'You may need to install development packages.' - if explanation is not None: - explanation += '\n' + message - else: - explanation = message - gotit = False + import wxversion + except ImportError: + raise CheckFailed("requires wxPython") - if gotit: try: - tk_v = Tkinter.__version__.split()[-2] - except (AttributeError, IndexError): - # Tkinter.__version__ has been removed in python 3 - tk_v = 'version not identified' - print_status("Tkinter", "Tkinter: %s, Tk: %s, Tcl: %s" % - (tk_v, Tkinter.TkVersion, Tkinter.TclVersion)) - else: - print_status("Tkinter", "no") - if explanation is not None: - print_message(explanation) - return gotit - -def check_for_macosx(): - gotit = False - import sys - if sys.platform=='darwin': - gotit = True - if gotit: - print_status("Mac OS X native", "yes") - else: - print_status("Mac OS X native", "no") - return gotit - -def query_tcltk(): - """Tries to open a Tk window in order to query the Tk object about its library paths. - This should never be called more than once by the same process, as Tk intricacies - may cause the Python interpreter to hang. The function also has a workaround if - no X server is running (useful for autobuild systems).""" - global TCL_TK_CACHE - # Use cached values if they exist, which ensures this function only executes once - if TCL_TK_CACHE is not None: - return TCL_TK_CACHE - - # By this point, we already know that Tkinter imports correctly - if sys.version_info[0] < 3: - import Tkinter - else: - import tkinter as Tkinter - tcl_lib_dir = '' - tk_lib_dir = '' - # First try to open a Tk window (requires a running X server) - try: - tk = Tkinter.Tk() - except Tkinter.TclError: - # Next, start Tcl interpreter without opening a Tk window (no need for X server) - # This feature is available in python version 2.4 and up + _wx_ensure_failed = wxversion.AlreadyImportedError + except AttributeError: + _wx_ensure_failed = wxversion.VersionError + try: - tcl = Tkinter.Tcl() - except AttributeError: # Python version not high enough - pass - except Tkinter.TclError: # Something went wrong while opening Tcl + wxversion.ensureMinimal('2.8') + except _wx_ensure_failed: pass + + try: + import wx + backend_version = wx.VERSION_STRING + except ImportError: + raise CheckFailed("requires wxPython") + + # Extra version check in case wxversion lacks AlreadyImportedError; + # then VersionError might have been raised and ignored when + # there really *is* a problem with the version. + major, minor = [int(n) for n in backend_version.split('.')[:2]] + if major < 2 or (major < 3 and minor < 8): + raise CheckFailed( + "Requires wxPython 2.8, found %s" % backend_version) + + BackendAgg.force = True + + return "version %s" % backend_version + + +class BackendMacOSX(OptionalBackendPackage): + """ + Builds the OSX backend + """ + name = 'macosx' + + def check(self): + if self.get_config() is False: + raise CheckFailed("skipping due to configuration") + + if sys.platform != 'darwin': + raise CheckFailed("Mac OS-X only") + + def get_extension(self): + sources = [ + 'src/_macosx.m', + 'src/agg_py_transforms.cpp', + 'src/path_cleanup.cpp' + ] + + ext = make_extension('matplotlib.backends._macosx', sources) + Numpy().add_flags(ext) + LibAgg().add_flags(ext) + CXX().add_flags(ext) + return ext + + +class Windowing(OptionalBackendPackage): + """ + Builds the windowing extension. + """ + name = "windowing" + + def check(self): + if sys.platform != 'win32': + raise CheckFailed("Microsoft Windows only") + config = self.get_config() + if config is False: + raise CheckFailed("skipping due to configuration") + return "installing" + + def get_extension(self): + sources = [ + "src/_windowing.cpp" + ] + ext = make_extension('matplotlib._windowing', sources) + ext.include_dirs.extend(['C:/include']) + ext.libraries.extend(['user32']) + ext.library_dirs.extend(['C:/lib']) + ext.extra_link_args.append("-mwindows") + return ext + + +class BackendQt(OptionalBackendPackage): + """ + Provides information about the installed PyQt. + """ + name = "qtagg" + + def convert_qt_version(self, version): + version = '%x' % version + temp = [] + while len(version) > 0: + version, chunk = version[:-2], version[-2:] + temp.insert(0, str(int(chunk, 16))) + return '.'.join(temp) + + def check(self): + try: + import pyqtconfig + except ImportError: + raise CheckFailed("not found") else: - tcl_lib_dir = str(tcl.getvar('tcl_library')) - # Guess Tk location based on Tcl location - (head, tail) = os.path.split(tcl_lib_dir) - tail = tail.replace('Tcl', 'Tk').replace('tcl', 'tk') - tk_lib_dir = os.path.join(head, tail) - if not os.path.exists(tk_lib_dir): - tk_lib_dir = tcl_lib_dir.replace('Tcl', 'Tk').replace('tcl', 'tk') - else: - # Obtain Tcl and Tk locations from Tk widget - tk.withdraw() - tcl_lib_dir = str(tk.getvar('tcl_library')) - tk_lib_dir = str(tk.getvar('tk_library')) - tk.destroy() + try: + qt_version = pyqtconfig.Configuration().qt_version + qt_version = self.convert_qt_version(qt_version) + except AttributeError: + qt_version = "" - # Save directories and version string to cache - TCL_TK_CACHE = tcl_lib_dir, tk_lib_dir, str(Tkinter.TkVersion)[:3] - return TCL_TK_CACHE + BackendAgg.force = True -def parse_tcl_config(tcl_lib_dir, tk_lib_dir): - try: - if sys.version_info[0] < 3: - import Tkinter + return ("Qt: %s, PyQt: %s" % + (qt_version, + pyqtconfig.Configuration().pyqt_version_str)) + + +class BackendQt4(OptionalBackendPackage): + """ + Provides information about the installed PyQt4. + """ + name = "qt4agg" + + def convert_qt_version(self, version): + version = '%x' % version + temp = [] + while len(version) > 0: + version, chunk = version[:-2], version[-2:] + temp.insert(0, str(int(chunk, 16))) + return '.'.join(temp) + + def check(self): + try: + from PyQt4 import pyqtconfig + except ImportError: + raise CheckFailed("not found") else: - import tkinter as Tkinter - except ImportError: - return None - tcl_poss = [tcl_lib_dir, - os.path.normpath(os.path.join(tcl_lib_dir, '..')), - "/usr/lib/tcl"+str(Tkinter.TclVersion), - "/usr/lib"] - tk_poss = [tk_lib_dir, - os.path.normpath(os.path.join(tk_lib_dir, '..')), - "/usr/lib/tk"+str(Tkinter.TkVersion), - "/usr/lib"] - for ptcl, ptk in zip(tcl_poss, tk_poss): - tcl_config = os.path.join(ptcl, "tclConfig.sh") - tk_config = os.path.join(ptk, "tkConfig.sh") - if (os.path.exists(tcl_config) and os.path.exists(tk_config)): - break - if not (os.path.exists(tcl_config) and os.path.exists(tk_config)): - return None + BackendAgg.force = True - def get_var(file, varname): - p = subprocess.Popen( - '. %s ; eval echo ${%s}' % (file, varname), - shell=True, - executable="/bin/sh", - stdout=subprocess.PIPE) - result = p.communicate()[0] - return result.decode('ascii') - - tcl_lib_dir = get_var(tcl_config, 'TCL_LIB_SPEC').split()[0][2:].strip() - tcl_inc_dir = get_var(tcl_config, 'TCL_INCLUDE_SPEC')[2:].strip() - tcl_lib = get_var(tcl_config, 'TCL_LIB_FLAG')[2:].strip() - - tk_lib_dir = get_var(tk_config, 'TK_LIB_SPEC').split()[0][2:].strip() - tk_inc_dir = get_var(tk_config, 'TK_INCLUDE_SPEC').strip() - if tk_inc_dir == '': - tk_inc_dir = tcl_inc_dir - else: - tk_inc_dir = tk_inc_dir[2:] - tk_lib = get_var(tk_config, 'TK_LIB_FLAG')[2:].strip() + return ("Qt: %s, PyQt4: %s" % + (self.convert_qt_version( + pyqtconfig.Configuration().qt_version), + pyqtconfig.Configuration().pyqt_version_str)) - if not os.path.exists(os.path.join(tk_inc_dir, 'tk.h')): - return None - return tcl_lib_dir, tcl_inc_dir, tcl_lib, tk_lib_dir, tk_inc_dir, tk_lib +class BackendPySide(OptionalBackendPackage): + """ + Provides information about the installed PySide. + """ + name = "pyside" -def guess_tcl_config(tcl_lib_dir, tk_lib_dir, tk_ver): - if not (os.path.exists(tcl_lib_dir) and os.path.exists(tk_lib_dir)): - return None + def check(self): + try: + from PySide import __version__ + from PySide import QtCore + except ImportError: + raise CheckFailed("not found") + else: + BackendAgg.force = True - tcl_lib = os.path.normpath(os.path.join(tcl_lib_dir, '../')) - tk_lib = os.path.normpath(os.path.join(tk_lib_dir, '../')) - - tcl_inc = os.path.normpath(os.path.join(tcl_lib_dir, - '../../include/tcl' + tk_ver)) - if not os.path.exists(tcl_inc): - tcl_inc = os.path.normpath(os.path.join(tcl_lib_dir, - '../../include')) - - tk_inc = os.path.normpath(os.path.join(tk_lib_dir, - '../../include/tk' + tk_ver)) - if not os.path.exists(tk_inc): - tk_inc = os.path.normpath(os.path.join(tk_lib_dir, - '../../include')) - - if not os.path.exists(os.path.join(tk_inc, 'tk.h')): - tk_inc = tcl_inc - - if not os.path.exists(tcl_inc): - # this is a hack for suse linux, which is broken - if (sys.platform.startswith('linux') and - os.path.exists('/usr/include/tcl.h') and - os.path.exists('/usr/include/tk.h')): - tcl_inc = '/usr/include' - tk_inc = '/usr/include' - - if not os.path.exists(os.path.join(tk_inc, 'tk.h')): - return None + return ("Qt: %s, PySide: %s" % + (QtCore.__version__, __version__)) - return tcl_lib, tcl_inc, 'tcl' + tk_ver, tk_lib, tk_inc, 'tk' + tk_ver -def hardcoded_tcl_config(): - tcl_inc = "/usr/local/include" - tk_inc = "/usr/local/include" - tcl_lib = "/usr/local/lib" - tk_lib = "/usr/local/lib" - return tcl_lib, tcl_inc, 'tcl', tk_lib, tk_inc, 'tk' +class BackendCairo(OptionalBackendPackage): + """ + Provides information about the installed pycairo. + """ + name = "cairo" -def add_tk_flags(module): - 'Add the module flags to build extensions which use tk' - message = None - if sys.platform == 'win32': - major, minor1, minor2, s, tmp = sys.version_info - if (2, 6) <= (major, minor1) <= (3, 3): - module.include_dirs.extend(['win32_static/include/tcl85']) - module.libraries.extend(['tk85', 'tcl85']) - elif major == 2 and minor1 in [3, 4, 5]: - module.include_dirs.extend(['win32_static/include/tcl84']) - module.libraries.extend(['tk84', 'tcl84']) - elif major == 2 and minor1 == 2: - module.include_dirs.extend(['win32_static/include/tcl83']) - module.libraries.extend(['tk83', 'tcl83']) + def check(self): + try: + import cairo + except ImportError: + raise CheckFailed("not found") else: - raise RuntimeError('No tk/win32 support for this python version yet') - module.library_dirs.extend([os.path.join(sys.prefix, 'dlls')]) - - elif sys.platform == 'darwin': - # this config section lifted directly from Imaging - thanks to - # the effbot! - - # First test for a MacOSX/darwin framework install - from os.path import join, exists - framework_dirs = [ - join(os.getenv('HOME'), '/Library/Frameworks'), - '/Library/Frameworks', - '/System/Library/Frameworks/', - ] - - # Find the directory that contains the Tcl.framework and Tk.framework - # bundles. - # XXX distutils should support -F! - tk_framework_found = 0 - for F in framework_dirs: - # both Tcl.framework and Tk.framework should be present - for fw in 'Tcl', 'Tk': - if not exists(join(F, fw + '.framework')): - break + return "version %s" % cairo.version + + +class DviPng(SetupPackage): + """ + A simple check for the presence of dvipng. + """ + name = "dvipng" + + def check(self): + try: + stdin, stdout = run_child_process('dvipng -version') + return "version %s" % stdout.readlines()[1].decode().split()[-1] + except (IndexError, ValueError): + raise CheckFailed() + + +class Ghostscript(SetupPackage): + """ + A simple check for the presence of Ghostscript. + """ + name = "ghostscript" + + def check(self): + try: + if sys.platform == 'win32': + command = 'gswin32c --version' else: - # ok, F is now directory with both frameworks. Continue - # building - tk_framework_found = 1 - break - if tk_framework_found: - # For 8.4a2, we must add -I options that point inside the Tcl and Tk - # frameworks. In later release we should hopefully be able to pass - # the -F option to gcc, which specifies a framework lookup path. - # - tk_include_dirs = [ - join(F, fw + '.framework', H) - for fw in ('Tcl', 'Tk') - for H in ('Headers', 'Versions/Current/PrivateHeaders') - ] + command = 'gs --version' + stdin, stdout = run_child_process(command) + return "version %s" % stdout.read().decode()[:-1] + except (IndexError, ValueError): + raise CheckFailed() - # For 8.4a2, the X11 headers are not included. Rather than include a - # complicated search, this is a hard-coded path. It could bail out - # if X11 libs are not found... - # tk_include_dirs.append('/usr/X11R6/include') - frameworks = ['-framework', 'Tcl', '-framework', 'Tk'] - module.include_dirs.extend(tk_include_dirs) - module.extra_link_args.extend(frameworks) - module.extra_compile_args.extend(frameworks) - # you're still here? ok we'll try it this way... - else: - success = False - # There are 3 methods to try, in decreasing order of "smartness" - # - # 1. Parse the tclConfig.sh and tkConfig.sh files that have - # all the information we need - # - # 2. Guess the include and lib dirs based on the location of - # Tkinter's 'tcl_library' and 'tk_library' variables. - # - # 3. Use some hardcoded locations that seem to work on a lot - # of distros. - - # Query Tcl/Tk system for library paths and version string +class LaTeX(SetupPackage): + """ + A simple check for the presence of LaTeX. + """ + name = "latex" + + def check(self): try: - tcl_lib_dir, tk_lib_dir, tk_ver = query_tcltk() - except: - tk_ver = '' - result = hardcoded_tcl_config() - else: - result = parse_tcl_config(tcl_lib_dir, tk_lib_dir) - if result is None: - message = """\ -Guessing the library and include directories for Tcl and Tk because the -tclConfig.sh and tkConfig.sh could not be found and/or parsed.""" - result = guess_tcl_config(tcl_lib_dir, tk_lib_dir, tk_ver) - if result is None: - message = """\ -Using default library and include directories for Tcl and Tk because a -Tk window failed to open. You may need to define DISPLAY for Tk to work -so that setup can determine where your libraries are located.""" - result = hardcoded_tcl_config() - - # Add final versions of directories and libraries to module lists - tcl_lib_dir, tcl_inc_dir, tcl_lib, tk_lib_dir, tk_inc_dir, tk_lib = result - module.include_dirs.extend([tcl_inc_dir, tk_inc_dir]) - module.library_dirs.extend([tcl_lib_dir, tk_lib_dir]) - module.libraries.extend([tcl_lib, tk_lib]) - - return message - -def add_windowing_flags(module): - 'Add the module flags to build extensions using windowing api' - module.include_dirs.extend(['C:/include']) - module.libraries.extend(['user32']) - module.library_dirs.extend(['C:/lib']) - module.extra_link_args.append("-mwindows") - -def build_windowing(ext_modules, packages): - """windowing is optional and provides functions for managing - windows better, .e.g. maintaining focus on win32""" - global BUILT_WINDOWING - if BUILT_WINDOWING: return # only build it if you you haven't already - module = make_extension('matplotlib._windowing', - ['src/_windowing.cpp'], - ) - add_windowing_flags(module) - ext_modules.append(module) - BUILT_WINDOWING = True - -def build_ft2font(ext_modules, packages): - global BUILT_FT2FONT - if BUILT_FT2FONT: return # only build it if you you haven't already - deps = ['src/ft2font.cpp', 'src/mplutils.cpp'] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension('matplotlib.ft2font', deps, - define_macros=defines) - add_ft2font_flags(module) - ext_modules.append(module) - BUILT_FT2FONT = True - -def build_ttconv(ext_modules, packages): - global BUILT_TTCONV - if BUILT_TTCONV: return # only build it if you you haven't already - deps = ['src/_ttconv.cpp', - 'ttconv/pprdrv_tt.cpp', - 'ttconv/pprdrv_tt2.cpp', - 'ttconv/ttutil.cpp'] - - module = make_extension('matplotlib.ttconv', deps, - define_macros=defines) - add_base_flags(module) - ext_modules.append(module) - BUILT_TTCONV = True - -def build_gtkagg(ext_modules, packages): - global BUILT_GTKAGG - if BUILT_GTKAGG: return # only build it if you you haven't already - deps = ['src/agg_py_transforms.cpp', 'src/_gtkagg.cpp', 'src/mplutils.cpp'] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension('matplotlib.backends._gtkagg', - deps, - define_macros=defines - ) - - # add agg flags before pygtk because agg only supports freetype1 - # and pygtk includes freetype2. This is a bit fragile. - - add_agg_flags(module) - add_ft2font_flags(module) - add_pygtk_flags(module) - add_numpy_flags(module) - - ext_modules.append(module) - BUILT_GTKAGG = True - -def build_tkagg(ext_modules, packages): - global BUILT_TKAGG - if BUILT_TKAGG: return # only build it if you you haven't already - deps = ['src/agg_py_transforms.cpp', 'src/_tkagg.cpp'] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension('matplotlib.backends._tkagg', - deps, - define_macros=defines - ) - - add_tk_flags(module) # do this first - add_agg_flags(module) - add_ft2font_flags(module) - - ext_modules.append(module) - BUILT_TKAGG = True - - -def build_macosx(ext_modules, packages): - global BUILT_MACOSX - if BUILT_MACOSX: return # only build it if you you haven't already - deps = ['src/_macosx.m', - 'CXX/cxx_extensions.cxx', - 'CXX/cxxextensions.c', - 'CXX/cxxsupport.cxx', - 'CXX/IndirectPythonInterface.cxx', - 'src/agg_py_transforms.cpp', - 'src/path_cleanup.cpp'] - module = make_extension('matplotlib.backends._macosx', - deps, - extra_link_args = ['-framework','Cocoa'], - define_macros=defines - ) - add_numpy_flags(module) - add_agg_flags(module) - ext_modules.append(module) - BUILT_MACOSX = True - -def build_png(ext_modules, packages): - global BUILT_PNG - if BUILT_PNG: return # only build it if you you haven't already - - deps = ['src/_png.cpp', 'src/mplutils.cpp'] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension( - 'matplotlib._png', - deps, - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - - add_png_flags(module) - ext_modules.append(module) - - BUILT_PNG = True - - -def build_agg(ext_modules, packages): - global BUILT_AGG - if BUILT_AGG: return # only build it if you you haven't already - - agg = ( - 'agg_trans_affine.cpp', - 'agg_bezier_arc.cpp', - 'agg_curves.cpp', - 'agg_vcgen_dash.cpp', - 'agg_vcgen_stroke.cpp', - 'agg_image_filters.cpp', - ) - - deps = ['%s/src/%s'%(AGG_VERSION, name) for name in agg] - deps.extend(['src/mplutils.cpp', 'src/agg_py_transforms.cpp']) - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - temp_copy('src/_backend_agg.cpp', 'src/backend_agg.cpp') - deps.append('src/backend_agg.cpp') - module = make_extension( - 'matplotlib.backends._backend_agg', - deps, - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - - add_numpy_flags(module) - add_agg_flags(module) - add_ft2font_flags(module) - ext_modules.append(module) - - BUILT_AGG = True - -def build_path(ext_modules, packages): - global BUILT_PATH - if BUILT_PATH: return # only build it if you you haven't already - - agg = ( - 'agg_vcgen_contour.cpp', - 'agg_curves.cpp', - 'agg_bezier_arc.cpp', - 'agg_trans_affine.cpp', - 'agg_vcgen_stroke.cpp', - ) - - deps = ['%s/src/%s'%(AGG_VERSION, name) for name in agg] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - temp_copy('src/_path.cpp', 'src/path.cpp') - deps.extend(['src/agg_py_transforms.cpp', - 'src/path_cleanup.cpp', - 'src/path.cpp']) - module = make_extension( - 'matplotlib._path', - deps, - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - - add_numpy_flags(module) - - add_agg_flags(module) - ext_modules.append(module) - - BUILT_PATH = True - -def build_image(ext_modules, packages): - global BUILT_IMAGE - if BUILT_IMAGE: return # only build it if you you haven't already - - agg = ('agg_trans_affine.cpp', - 'agg_image_filters.cpp', - 'agg_bezier_arc.cpp', - ) - - temp_copy('src/_image.cpp', 'src/image.cpp') - deps = ['src/image.cpp', 'src/mplutils.cpp'] - deps.extend(['%s/src/%s'%(AGG_VERSION,name) for name in agg]) - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension( - 'matplotlib._image', - deps, - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - - add_numpy_flags(module) - add_agg_flags(module) - ext_modules.append(module) - - BUILT_IMAGE = True - - - -def build_delaunay(ext_modules, packages): - global BUILT_DELAUNAY - if BUILT_DELAUNAY: - return # only build it if you you haven't already - - sourcefiles=["_delaunay.cpp", "VoronoiDiagramGenerator.cpp", - "delaunay_utils.cpp", "natneighbors.cpp"] - sourcefiles = [os.path.join('lib/matplotlib/delaunay',s) for s in sourcefiles] - delaunay = make_extension('matplotlib._delaunay',sourcefiles, - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - add_numpy_flags(delaunay) - add_base_flags(delaunay) - ext_modules.append(delaunay) - packages.extend(['matplotlib.delaunay']) - BUILT_DELAUNAY = True - - -def build_contour(ext_modules, packages): - global BUILT_CONTOUR - if BUILT_CONTOUR: return # only build it if you you haven't already - - module = make_extension( - 'matplotlib._cntr', - [ 'src/cntr.c'], - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - add_numpy_flags(module) - add_base_flags(module) - ext_modules.append(module) - - BUILT_CONTOUR = True - - -def build_gdk(ext_modules, packages): - global BUILT_GDK - if BUILT_GDK: return # only build it if you you haven't already - - temp_copy('src/_backend_gdk.c', 'src/backend_gdk.c') - module = make_extension( - 'matplotlib.backends._backend_gdk', - ['src/backend_gdk.c'], - libraries = [], - include_dirs=numpy_inc_dirs, - define_macros=defines - ) - - add_numpy_flags(module) - add_base_flags(module) - add_pygtk_flags(module) - ext_modules.append(module) - - BUILT_GDK = True - - -def build_tri(ext_modules, packages): - global BUILT_TRI - if BUILT_TRI: return # only build it if you you haven't already - - deps = ['lib/matplotlib/tri/_tri.cpp', 'src/mplutils.cpp'] - deps.extend(glob.glob('CXX/*.cxx')) - deps.extend(glob.glob('CXX/*.c')) - - module = make_extension('matplotlib._tri', deps, - define_macros=defines) - add_numpy_flags(module) - add_base_flags(module) - ext_modules.append(module) - BUILT_TRI = True + stdin, stdout = run_child_process('latex -version') + line = stdout.readlines()[0].decode() + pattern = '(3\.1\d+)|(MiKTeX \d+.\d+)' + match = re.search(pattern, line) + return "version %s" % match.group(0) + except (IndexError, ValueError, AttributeError): + raise CheckFailed() + + +class PdfToPs(SetupPackage): + """ + A simple check for the presence of pdftops. + """ + name = "pdftops" + + def check(self): + try: + stdin, stdout = run_child_process('pdftops -v') + for line in stdout.readlines(): + line = line.decode() + if 'version' in line: + return "version %s" % line.split()[2] + except (IndexError, ValueError): + pass + + raise CheckFailed() diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 42089f9d5be4..69ce4417d56c 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -6,6 +6,7 @@ /* Python API mandates Python.h is included *first* */ #include "Python.h" +/* TODO: Remove this dependency */ #include "ft2font.h" #include "_image.h" #include "_backend_agg.h" From 4ae2fd2c3b96745f5a9474d644ab0585d5a22273 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 9 Oct 2012 14:15:20 -0400 Subject: [PATCH 02/24] Removing dateutils, pytz and six (external Python dependencies) --- lib/dateutil_py2/LICENSE | 259 --- lib/dateutil_py2/NEWS | 143 -- lib/dateutil_py2/README | 1970 ----------------- lib/dateutil_py2/__init__.py | 9 - lib/dateutil_py2/easter.py | 92 - lib/dateutil_py2/parser.py | 886 -------- lib/dateutil_py2/relativedelta.py | 432 ---- lib/dateutil_py2/rrule.py | 1097 --------- lib/dateutil_py2/tz.py | 951 -------- lib/dateutil_py2/tzwin.py | 180 -- lib/dateutil_py2/zoneinfo/__init__.py | 87 - .../zoneinfo/zoneinfo-2010g.tar.gz | Bin 171995 -> 0 bytes lib/dateutil_py3/LICENSE | 30 - lib/dateutil_py3/NEWS | 164 -- lib/dateutil_py3/README | 1970 ----------------- lib/dateutil_py3/__init__.py | 10 - lib/dateutil_py3/easter.py | 91 - lib/dateutil_py3/parser.py | 909 -------- lib/dateutil_py3/relativedelta.py | 436 ---- lib/dateutil_py3/rrule.py | 1112 ---------- lib/dateutil_py3/tz.py | 960 -------- lib/dateutil_py3/tzwin.py | 179 -- lib/dateutil_py3/zoneinfo/__init__.py | 90 - .../zoneinfo/zoneinfo--latest.tar.gz | Bin 86784 -> 0 bytes .../zoneinfo/zoneinfo-2011d.tar.gz | Bin 197294 -> 0 bytes lib/pytz/CHANGES.txt | 54 - lib/pytz/LICENSE.txt | 19 - lib/pytz/README.txt | 552 ----- lib/pytz/__init__.py | 1537 ------------- lib/pytz/exceptions.py | 48 - lib/pytz/reference.py | 127 -- lib/pytz/tests/test_docs.py | 36 - lib/pytz/tests/test_tzinfo.py | 813 ------- lib/pytz/tzfile.py | 137 -- lib/pytz/tzinfo.py | 563 ----- lib/pytz/zoneinfo/Africa/Abidjan | Bin 156 -> 0 bytes lib/pytz/zoneinfo/Africa/Accra | Bin 378 -> 0 bytes lib/pytz/zoneinfo/Africa/Addis_Ababa | Bin 180 -> 0 bytes lib/pytz/zoneinfo/Africa/Algiers | Bin 734 -> 0 bytes lib/pytz/zoneinfo/Africa/Asmara | Bin 201 -> 0 bytes lib/pytz/zoneinfo/Africa/Asmera | Bin 201 -> 0 bytes lib/pytz/zoneinfo/Africa/Bamako | Bin 224 -> 0 bytes lib/pytz/zoneinfo/Africa/Bangui | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Banjul | Bin 232 -> 0 bytes lib/pytz/zoneinfo/Africa/Bissau | Bin 194 -> 0 bytes lib/pytz/zoneinfo/Africa/Blantyre | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Brazzaville | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Bujumbura | Bin 140 -> 0 bytes lib/pytz/zoneinfo/Africa/Cairo | Bin 1901 -> 0 bytes lib/pytz/zoneinfo/Africa/Casablanca | Bin 1362 -> 0 bytes lib/pytz/zoneinfo/Africa/Ceuta | Bin 2049 -> 0 bytes lib/pytz/zoneinfo/Africa/Conakry | Bin 224 -> 0 bytes lib/pytz/zoneinfo/Africa/Dakar | Bin 194 -> 0 bytes lib/pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 229 -> 0 bytes lib/pytz/zoneinfo/Africa/Djibouti | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Douala | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/El_Aaiun | Bin 194 -> 0 bytes lib/pytz/zoneinfo/Africa/Freetown | Bin 665 -> 0 bytes lib/pytz/zoneinfo/Africa/Gaborone | Bin 194 -> 0 bytes lib/pytz/zoneinfo/Africa/Harare | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Johannesburg | Bin 245 -> 0 bytes lib/pytz/zoneinfo/Africa/Juba | Bin 669 -> 0 bytes lib/pytz/zoneinfo/Africa/Kampala | Bin 269 -> 0 bytes lib/pytz/zoneinfo/Africa/Khartoum | Bin 669 -> 0 bytes lib/pytz/zoneinfo/Africa/Kigali | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Kinshasa | Bin 140 -> 0 bytes lib/pytz/zoneinfo/Africa/Lagos | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Libreville | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Lome | Bin 139 -> 0 bytes lib/pytz/zoneinfo/Africa/Luanda | Bin 178 -> 0 bytes lib/pytz/zoneinfo/Africa/Lubumbashi | Bin 140 -> 0 bytes lib/pytz/zoneinfo/Africa/Lusaka | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Malabo | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Africa/Maputo | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Africa/Maseru | Bin 204 -> 0 bytes lib/pytz/zoneinfo/Africa/Mbabane | Bin 160 -> 0 bytes lib/pytz/zoneinfo/Africa/Mogadishu | Bin 210 -> 0 bytes lib/pytz/zoneinfo/Africa/Monrovia | Bin 215 -> 0 bytes lib/pytz/zoneinfo/Africa/Nairobi | Bin 269 -> 0 bytes lib/pytz/zoneinfo/Africa/Ndjamena | Bin 211 -> 0 bytes lib/pytz/zoneinfo/Africa/Niamey | Bin 225 -> 0 bytes lib/pytz/zoneinfo/Africa/Nouakchott | Bin 224 -> 0 bytes lib/pytz/zoneinfo/Africa/Ouagadougou | Bin 156 -> 0 bytes lib/pytz/zoneinfo/Africa/Porto-Novo | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Africa/Sao_Tome | Bin 173 -> 0 bytes lib/pytz/zoneinfo/Africa/Timbuktu | Bin 224 -> 0 bytes lib/pytz/zoneinfo/Africa/Tripoli | Bin 599 -> 0 bytes lib/pytz/zoneinfo/Africa/Tunis | Bin 684 -> 0 bytes lib/pytz/zoneinfo/Africa/Windhoek | Bin 1556 -> 0 bytes lib/pytz/zoneinfo/America/Adak | Bin 2353 -> 0 bytes lib/pytz/zoneinfo/America/Anchorage | Bin 2358 -> 0 bytes lib/pytz/zoneinfo/America/Anguilla | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Antigua | Bin 194 -> 0 bytes lib/pytz/zoneinfo/America/Araguaina | Bin 854 -> 0 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 1061 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Catamarca | Bin 1103 -> 0 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Cordoba | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Jujuy | Bin 1119 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/La_Rioja | Bin 1117 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Mendoza | Bin 1147 -> 0 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Salta | Bin 1075 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/San_Juan | Bin 1117 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/San_Luis | Bin 1125 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Tucuman | Bin 1131 -> 0 bytes lib/pytz/zoneinfo/America/Argentina/Ushuaia | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Aruba | Bin 194 -> 0 bytes lib/pytz/zoneinfo/America/Asuncion | Bin 2036 -> 0 bytes lib/pytz/zoneinfo/America/Atikokan | Bin 319 -> 0 bytes lib/pytz/zoneinfo/America/Atka | Bin 2353 -> 0 bytes lib/pytz/zoneinfo/America/Bahia | Bin 1777 -> 0 bytes lib/pytz/zoneinfo/America/Bahia_Banderas | Bin 1574 -> 0 bytes lib/pytz/zoneinfo/America/Barbados | Bin 330 -> 0 bytes lib/pytz/zoneinfo/America/Belem | Bin 574 -> 0 bytes lib/pytz/zoneinfo/America/Belize | Bin 962 -> 0 bytes lib/pytz/zoneinfo/America/Blanc-Sablon | Bin 281 -> 0 bytes lib/pytz/zoneinfo/America/Boa_Vista | Bin 630 -> 0 bytes lib/pytz/zoneinfo/America/Bogota | Bin 231 -> 0 bytes lib/pytz/zoneinfo/America/Boise | Bin 2377 -> 0 bytes lib/pytz/zoneinfo/America/Buenos_Aires | Bin 1061 -> 0 bytes lib/pytz/zoneinfo/America/Cambridge_Bay | Bin 2084 -> 0 bytes lib/pytz/zoneinfo/America/Campo_Grande | Bin 2001 -> 0 bytes lib/pytz/zoneinfo/America/Cancun | Bin 1466 -> 0 bytes lib/pytz/zoneinfo/America/Caracas | Bin 240 -> 0 bytes lib/pytz/zoneinfo/America/Catamarca | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Cayenne | Bin 186 -> 0 bytes lib/pytz/zoneinfo/America/Cayman | Bin 177 -> 0 bytes lib/pytz/zoneinfo/America/Chicago | Bin 3559 -> 0 bytes lib/pytz/zoneinfo/America/Chihuahua | Bin 1508 -> 0 bytes lib/pytz/zoneinfo/America/Coral_Harbour | Bin 319 -> 0 bytes lib/pytz/zoneinfo/America/Cordoba | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Costa_Rica | Bin 315 -> 0 bytes lib/pytz/zoneinfo/America/Creston | Bin 207 -> 0 bytes lib/pytz/zoneinfo/America/Cuiaba | Bin 1973 -> 0 bytes lib/pytz/zoneinfo/America/Curacao | Bin 194 -> 0 bytes lib/pytz/zoneinfo/America/Danmarkshavn | Bin 700 -> 0 bytes lib/pytz/zoneinfo/America/Dawson | Bin 2067 -> 0 bytes lib/pytz/zoneinfo/America/Dawson_Creek | Bin 1033 -> 0 bytes lib/pytz/zoneinfo/America/Denver | Bin 2427 -> 0 bytes lib/pytz/zoneinfo/America/Detroit | Bin 2202 -> 0 bytes lib/pytz/zoneinfo/America/Dominica | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Edmonton | Bin 2388 -> 0 bytes lib/pytz/zoneinfo/America/Eirunepe | Bin 640 -> 0 bytes lib/pytz/zoneinfo/America/El_Salvador | Bin 236 -> 0 bytes lib/pytz/zoneinfo/America/Ensenada | Bin 2342 -> 0 bytes lib/pytz/zoneinfo/America/Fort_Wayne | Bin 1649 -> 0 bytes lib/pytz/zoneinfo/America/Fortaleza | Bin 714 -> 0 bytes lib/pytz/zoneinfo/America/Glace_Bay | Bin 2192 -> 0 bytes lib/pytz/zoneinfo/America/Godthab | Bin 8296 -> 0 bytes lib/pytz/zoneinfo/America/Goose_Bay | Bin 3193 -> 0 bytes lib/pytz/zoneinfo/America/Grand_Turk | Bin 1871 -> 0 bytes lib/pytz/zoneinfo/America/Grenada | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Guadeloupe | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Guatemala | Bin 292 -> 0 bytes lib/pytz/zoneinfo/America/Guayaquil | Bin 177 -> 0 bytes lib/pytz/zoneinfo/America/Guyana | Bin 256 -> 0 bytes lib/pytz/zoneinfo/America/Halifax | Bin 3424 -> 0 bytes lib/pytz/zoneinfo/America/Havana | Bin 2411 -> 0 bytes lib/pytz/zoneinfo/America/Hermosillo | Bin 440 -> 0 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 1649 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Knox | Bin 2411 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Marengo | Bin 1705 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Petersburg | Bin 1887 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Tell_City | Bin 1709 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Vevay | Bin 1397 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Vincennes | Bin 1677 -> 0 bytes lib/pytz/zoneinfo/America/Indiana/Winamac | Bin 1761 -> 0 bytes lib/pytz/zoneinfo/America/Indianapolis | Bin 1649 -> 0 bytes lib/pytz/zoneinfo/America/Inuvik | Bin 1914 -> 0 bytes lib/pytz/zoneinfo/America/Iqaluit | Bin 2032 -> 0 bytes lib/pytz/zoneinfo/America/Jamaica | Bin 481 -> 0 bytes lib/pytz/zoneinfo/America/Jujuy | Bin 1119 -> 0 bytes lib/pytz/zoneinfo/America/Juneau | Bin 2336 -> 0 bytes lib/pytz/zoneinfo/America/Kentucky/Louisville | Bin 2755 -> 0 bytes lib/pytz/zoneinfo/America/Kentucky/Monticello | Bin 2335 -> 0 bytes lib/pytz/zoneinfo/America/Knox_IN | Bin 2411 -> 0 bytes lib/pytz/zoneinfo/America/Kralendijk | Bin 194 -> 0 bytes lib/pytz/zoneinfo/America/La_Paz | Bin 217 -> 0 bytes lib/pytz/zoneinfo/America/Lima | Bin 395 -> 0 bytes lib/pytz/zoneinfo/America/Los_Angeles | Bin 2819 -> 0 bytes lib/pytz/zoneinfo/America/Louisville | Bin 2755 -> 0 bytes lib/pytz/zoneinfo/America/Lower_Princes | Bin 194 -> 0 bytes lib/pytz/zoneinfo/America/Maceio | Bin 742 -> 0 bytes lib/pytz/zoneinfo/America/Managua | Bin 437 -> 0 bytes lib/pytz/zoneinfo/America/Manaus | Bin 602 -> 0 bytes lib/pytz/zoneinfo/America/Marigot | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Martinique | Bin 231 -> 0 bytes lib/pytz/zoneinfo/America/Matamoros | Bin 1402 -> 0 bytes lib/pytz/zoneinfo/America/Mazatlan | Bin 1550 -> 0 bytes lib/pytz/zoneinfo/America/Mendoza | Bin 1147 -> 0 bytes lib/pytz/zoneinfo/America/Menominee | Bin 2257 -> 0 bytes lib/pytz/zoneinfo/America/Merida | Bin 1442 -> 0 bytes lib/pytz/zoneinfo/America/Metlakatla | Bin 717 -> 0 bytes lib/pytz/zoneinfo/America/Mexico_City | Bin 1604 -> 0 bytes lib/pytz/zoneinfo/America/Miquelon | Bin 1670 -> 0 bytes lib/pytz/zoneinfo/America/Moncton | Bin 3137 -> 0 bytes lib/pytz/zoneinfo/America/Monterrey | Bin 1402 -> 0 bytes lib/pytz/zoneinfo/America/Montevideo | Bin 2134 -> 0 bytes lib/pytz/zoneinfo/America/Montreal | Bin 3477 -> 0 bytes lib/pytz/zoneinfo/America/Montserrat | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Nassau | Bin 2270 -> 0 bytes lib/pytz/zoneinfo/America/New_York | Bin 3519 -> 0 bytes lib/pytz/zoneinfo/America/Nipigon | Bin 2105 -> 0 bytes lib/pytz/zoneinfo/America/Nome | Bin 2350 -> 0 bytes lib/pytz/zoneinfo/America/Noronha | Bin 714 -> 0 bytes lib/pytz/zoneinfo/America/North_Dakota/Beulah | Bin 2363 -> 0 bytes lib/pytz/zoneinfo/America/North_Dakota/Center | Bin 2363 -> 0 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 2363 -> 0 bytes lib/pytz/zoneinfo/America/Ojinaga | Bin 1508 -> 0 bytes lib/pytz/zoneinfo/America/Panama | Bin 177 -> 0 bytes lib/pytz/zoneinfo/America/Pangnirtung | Bin 2094 -> 0 bytes lib/pytz/zoneinfo/America/Paramaribo | Bin 294 -> 0 bytes lib/pytz/zoneinfo/America/Phoenix | Bin 327 -> 0 bytes lib/pytz/zoneinfo/America/Port-au-Prince | Bin 739 -> 0 bytes lib/pytz/zoneinfo/America/Port_of_Spain | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Porto_Acre | Bin 612 -> 0 bytes lib/pytz/zoneinfo/America/Porto_Velho | Bin 574 -> 0 bytes lib/pytz/zoneinfo/America/Puerto_Rico | Bin 229 -> 0 bytes lib/pytz/zoneinfo/America/Rainy_River | Bin 2105 -> 0 bytes lib/pytz/zoneinfo/America/Rankin_Inlet | Bin 1916 -> 0 bytes lib/pytz/zoneinfo/America/Recife | Bin 714 -> 0 bytes lib/pytz/zoneinfo/America/Regina | Bin 980 -> 0 bytes lib/pytz/zoneinfo/America/Resolute | Bin 1916 -> 0 bytes lib/pytz/zoneinfo/America/Rio_Branco | Bin 612 -> 0 bytes lib/pytz/zoneinfo/America/Rosario | Bin 1103 -> 0 bytes lib/pytz/zoneinfo/America/Santa_Isabel | Bin 2342 -> 0 bytes lib/pytz/zoneinfo/America/Santarem | Bin 612 -> 0 bytes lib/pytz/zoneinfo/America/Santiago | Bin 9245 -> 0 bytes lib/pytz/zoneinfo/America/Santo_Domingo | Bin 463 -> 0 bytes lib/pytz/zoneinfo/America/Sao_Paulo | Bin 2001 -> 0 bytes lib/pytz/zoneinfo/America/Scoresbysund | Bin 1911 -> 0 bytes lib/pytz/zoneinfo/America/Shiprock | Bin 2427 -> 0 bytes lib/pytz/zoneinfo/America/Sitka | Bin 2324 -> 0 bytes lib/pytz/zoneinfo/America/St_Barthelemy | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/St_Johns | Bin 3638 -> 0 bytes lib/pytz/zoneinfo/America/St_Kitts | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/St_Lucia | Bin 177 -> 0 bytes lib/pytz/zoneinfo/America/St_Thomas | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/St_Vincent | Bin 177 -> 0 bytes lib/pytz/zoneinfo/America/Swift_Current | Bin 560 -> 0 bytes lib/pytz/zoneinfo/America/Tegucigalpa | Bin 264 -> 0 bytes lib/pytz/zoneinfo/America/Thule | Bin 1514 -> 0 bytes lib/pytz/zoneinfo/America/Thunder_Bay | Bin 2185 -> 0 bytes lib/pytz/zoneinfo/America/Tijuana | Bin 2342 -> 0 bytes lib/pytz/zoneinfo/America/Toronto | Bin 3477 -> 0 bytes lib/pytz/zoneinfo/America/Tortola | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Vancouver | Bin 2875 -> 0 bytes lib/pytz/zoneinfo/America/Virgin | Bin 156 -> 0 bytes lib/pytz/zoneinfo/America/Whitehorse | Bin 2067 -> 0 bytes lib/pytz/zoneinfo/America/Winnipeg | Bin 2865 -> 0 bytes lib/pytz/zoneinfo/America/Yakutat | Bin 2288 -> 0 bytes lib/pytz/zoneinfo/America/Yellowknife | Bin 1966 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Casey | Bin 255 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Davis | Bin 276 -> 0 bytes lib/pytz/zoneinfo/Antarctica/DumontDUrville | Bin 213 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Macquarie | Bin 1549 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Mawson | Bin 190 -> 0 bytes lib/pytz/zoneinfo/Antarctica/McMurdo | Bin 2001 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Palmer | Bin 8780 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Rothera | Bin 159 -> 0 bytes lib/pytz/zoneinfo/Antarctica/South_Pole | Bin 2001 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Syowa | Bin 160 -> 0 bytes lib/pytz/zoneinfo/Antarctica/Vostok | Bin 160 -> 0 bytes lib/pytz/zoneinfo/Arctic/Longyearbyen | Bin 2225 -> 0 bytes lib/pytz/zoneinfo/Asia/Aden | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Asia/Almaty | Bin 922 -> 0 bytes lib/pytz/zoneinfo/Asia/Amman | Bin 8504 -> 0 bytes lib/pytz/zoneinfo/Asia/Anadyr | Bin 1183 -> 0 bytes lib/pytz/zoneinfo/Asia/Aqtau | Bin 1128 -> 0 bytes lib/pytz/zoneinfo/Asia/Aqtobe | Bin 1038 -> 0 bytes lib/pytz/zoneinfo/Asia/Ashgabat | Bin 657 -> 0 bytes lib/pytz/zoneinfo/Asia/Ashkhabad | Bin 657 -> 0 bytes lib/pytz/zoneinfo/Asia/Baghdad | Bin 962 -> 0 bytes lib/pytz/zoneinfo/Asia/Bahrain | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Asia/Baku | Bin 1942 -> 0 bytes lib/pytz/zoneinfo/Asia/Bangkok | Bin 178 -> 0 bytes lib/pytz/zoneinfo/Asia/Beirut | Bin 2149 -> 0 bytes lib/pytz/zoneinfo/Asia/Bishkek | Bin 1047 -> 0 bytes lib/pytz/zoneinfo/Asia/Brunei | Bin 187 -> 0 bytes lib/pytz/zoneinfo/Asia/Calcutta | Bin 265 -> 0 bytes lib/pytz/zoneinfo/Asia/Choibalsan | Bin 890 -> 0 bytes lib/pytz/zoneinfo/Asia/Chongqing | Bin 389 -> 0 bytes lib/pytz/zoneinfo/Asia/Chungking | Bin 389 -> 0 bytes lib/pytz/zoneinfo/Asia/Colombo | Bin 363 -> 0 bytes lib/pytz/zoneinfo/Asia/Dacca | Bin 364 -> 0 bytes lib/pytz/zoneinfo/Asia/Damascus | Bin 2306 -> 0 bytes lib/pytz/zoneinfo/Asia/Dhaka | Bin 364 -> 0 bytes lib/pytz/zoneinfo/Asia/Dili | Bin 293 -> 0 bytes lib/pytz/zoneinfo/Asia/Dubai | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Asia/Dushanbe | Bin 597 -> 0 bytes lib/pytz/zoneinfo/Asia/Gaza | Bin 1562 -> 0 bytes lib/pytz/zoneinfo/Asia/Harbin | Bin 463 -> 0 bytes lib/pytz/zoneinfo/Asia/Hebron | Bin 1590 -> 0 bytes lib/pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 255 -> 0 bytes lib/pytz/zoneinfo/Asia/Hong_Kong | Bin 1175 -> 0 bytes lib/pytz/zoneinfo/Asia/Hovd | Bin 834 -> 0 bytes lib/pytz/zoneinfo/Asia/Irkutsk | Bin 1203 -> 0 bytes lib/pytz/zoneinfo/Asia/Istanbul | Bin 2721 -> 0 bytes lib/pytz/zoneinfo/Asia/Jakarta | Bin 344 -> 0 bytes lib/pytz/zoneinfo/Asia/Jayapura | Bin 225 -> 0 bytes lib/pytz/zoneinfo/Asia/Jerusalem | Bin 2213 -> 0 bytes lib/pytz/zoneinfo/Asia/Kabul | Bin 173 -> 0 bytes lib/pytz/zoneinfo/Asia/Kamchatka | Bin 1167 -> 0 bytes lib/pytz/zoneinfo/Asia/Karachi | Bin 389 -> 0 bytes lib/pytz/zoneinfo/Asia/Kashgar | Bin 419 -> 0 bytes lib/pytz/zoneinfo/Asia/Kathmandu | Bin 198 -> 0 bytes lib/pytz/zoneinfo/Asia/Katmandu | Bin 198 -> 0 bytes lib/pytz/zoneinfo/Asia/Kolkata | Bin 265 -> 0 bytes lib/pytz/zoneinfo/Asia/Krasnoyarsk | Bin 1182 -> 0 bytes lib/pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 372 -> 0 bytes lib/pytz/zoneinfo/Asia/Kuching | Bin 505 -> 0 bytes lib/pytz/zoneinfo/Asia/Kuwait | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Asia/Macao | Bin 781 -> 0 bytes lib/pytz/zoneinfo/Asia/Macau | Bin 781 -> 0 bytes lib/pytz/zoneinfo/Asia/Magadan | Bin 1183 -> 0 bytes lib/pytz/zoneinfo/Asia/Makassar | Bin 263 -> 0 bytes lib/pytz/zoneinfo/Asia/Manila | Bin 335 -> 0 bytes lib/pytz/zoneinfo/Asia/Muscat | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Asia/Nicosia | Bin 2002 -> 0 bytes lib/pytz/zoneinfo/Asia/Novokuznetsk | Bin 1220 -> 0 bytes lib/pytz/zoneinfo/Asia/Novosibirsk | Bin 1196 -> 0 bytes lib/pytz/zoneinfo/Asia/Omsk | Bin 1182 -> 0 bytes lib/pytz/zoneinfo/Asia/Oral | Bin 1086 -> 0 bytes lib/pytz/zoneinfo/Asia/Phnom_Penh | Bin 255 -> 0 bytes lib/pytz/zoneinfo/Asia/Pontianak | Bin 359 -> 0 bytes lib/pytz/zoneinfo/Asia/Pyongyang | Bin 258 -> 0 bytes lib/pytz/zoneinfo/Asia/Qatar | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Asia/Qyzylorda | Bin 1068 -> 0 bytes lib/pytz/zoneinfo/Asia/Rangoon | Bin 259 -> 0 bytes lib/pytz/zoneinfo/Asia/Riyadh | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Asia/Riyadh87 | Bin 8685 -> 0 bytes lib/pytz/zoneinfo/Asia/Riyadh88 | Bin 8539 -> 0 bytes lib/pytz/zoneinfo/Asia/Riyadh89 | Bin 8539 -> 0 bytes lib/pytz/zoneinfo/Asia/Saigon | Bin 255 -> 0 bytes lib/pytz/zoneinfo/Asia/Sakhalin | Bin 1213 -> 0 bytes lib/pytz/zoneinfo/Asia/Samarkand | Bin 677 -> 0 bytes lib/pytz/zoneinfo/Asia/Seoul | Bin 396 -> 0 bytes lib/pytz/zoneinfo/Asia/Shanghai | Bin 405 -> 0 bytes lib/pytz/zoneinfo/Asia/Singapore | Bin 402 -> 0 bytes lib/pytz/zoneinfo/Asia/Taipei | Bin 724 -> 0 bytes lib/pytz/zoneinfo/Asia/Tashkent | Bin 667 -> 0 bytes lib/pytz/zoneinfo/Asia/Tbilisi | Bin 1116 -> 0 bytes lib/pytz/zoneinfo/Asia/Tehran | Bin 1638 -> 0 bytes lib/pytz/zoneinfo/Asia/Tel_Aviv | Bin 2213 -> 0 bytes lib/pytz/zoneinfo/Asia/Thimbu | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Asia/Thimphu | Bin 195 -> 0 bytes lib/pytz/zoneinfo/Asia/Tokyo | Bin 331 -> 0 bytes lib/pytz/zoneinfo/Asia/Ujung_Pandang | Bin 263 -> 0 bytes lib/pytz/zoneinfo/Asia/Ulaanbaatar | Bin 834 -> 0 bytes lib/pytz/zoneinfo/Asia/Ulan_Bator | Bin 834 -> 0 bytes lib/pytz/zoneinfo/Asia/Urumqi | Bin 389 -> 0 bytes lib/pytz/zoneinfo/Asia/Vientiane | Bin 255 -> 0 bytes lib/pytz/zoneinfo/Asia/Vladivostok | Bin 1197 -> 0 bytes lib/pytz/zoneinfo/Asia/Yakutsk | Bin 1183 -> 0 bytes lib/pytz/zoneinfo/Asia/Yekaterinburg | Bin 1252 -> 0 bytes lib/pytz/zoneinfo/Asia/Yerevan | Bin 1263 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Azores | Bin 3462 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Bermuda | Bin 1990 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Canary | Bin 1899 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Cape_Verde | Bin 240 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Faeroe | Bin 1815 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Faroe | Bin 1815 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 2225 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Madeira | Bin 3452 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Reykjavik | Bin 1141 -> 0 bytes lib/pytz/zoneinfo/Atlantic/South_Georgia | Bin 139 -> 0 bytes lib/pytz/zoneinfo/Atlantic/St_Helena | Bin 177 -> 0 bytes lib/pytz/zoneinfo/Atlantic/Stanley | Bin 1220 -> 0 bytes lib/pytz/zoneinfo/Australia/ACT | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/Adelaide | Bin 2202 -> 0 bytes lib/pytz/zoneinfo/Australia/Brisbane | Bin 413 -> 0 bytes lib/pytz/zoneinfo/Australia/Broken_Hill | Bin 2237 -> 0 bytes lib/pytz/zoneinfo/Australia/Canberra | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/Currie | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/Darwin | Bin 288 -> 0 bytes lib/pytz/zoneinfo/Australia/Eucla | Bin 446 -> 0 bytes lib/pytz/zoneinfo/Australia/Hobart | Bin 2295 -> 0 bytes lib/pytz/zoneinfo/Australia/LHI | Bin 1821 -> 0 bytes lib/pytz/zoneinfo/Australia/Lindeman | Bin 483 -> 0 bytes lib/pytz/zoneinfo/Australia/Lord_Howe | Bin 1821 -> 0 bytes lib/pytz/zoneinfo/Australia/Melbourne | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/NSW | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/North | Bin 288 -> 0 bytes lib/pytz/zoneinfo/Australia/Perth | Bin 440 -> 0 bytes lib/pytz/zoneinfo/Australia/Queensland | Bin 413 -> 0 bytes lib/pytz/zoneinfo/Australia/South | Bin 2202 -> 0 bytes lib/pytz/zoneinfo/Australia/Sydney | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/Tasmania | Bin 2295 -> 0 bytes lib/pytz/zoneinfo/Australia/Victoria | Bin 2183 -> 0 bytes lib/pytz/zoneinfo/Australia/West | Bin 440 -> 0 bytes lib/pytz/zoneinfo/Australia/Yancowinna | Bin 2237 -> 0 bytes lib/pytz/zoneinfo/Brazil/Acre | Bin 612 -> 0 bytes lib/pytz/zoneinfo/Brazil/DeNoronha | Bin 714 -> 0 bytes lib/pytz/zoneinfo/Brazil/East | Bin 2001 -> 0 bytes lib/pytz/zoneinfo/Brazil/West | Bin 602 -> 0 bytes lib/pytz/zoneinfo/CET | Bin 2102 -> 0 bytes lib/pytz/zoneinfo/CST6CDT | Bin 2294 -> 0 bytes lib/pytz/zoneinfo/Canada/Atlantic | Bin 3424 -> 0 bytes lib/pytz/zoneinfo/Canada/Central | Bin 2865 -> 0 bytes lib/pytz/zoneinfo/Canada/East-Saskatchewan | Bin 980 -> 0 bytes lib/pytz/zoneinfo/Canada/Eastern | Bin 3477 -> 0 bytes lib/pytz/zoneinfo/Canada/Mountain | Bin 2388 -> 0 bytes lib/pytz/zoneinfo/Canada/Newfoundland | Bin 3638 -> 0 bytes lib/pytz/zoneinfo/Canada/Pacific | Bin 2875 -> 0 bytes lib/pytz/zoneinfo/Canada/Saskatchewan | Bin 980 -> 0 bytes lib/pytz/zoneinfo/Canada/Yukon | Bin 2067 -> 0 bytes lib/pytz/zoneinfo/Chile/Continental | Bin 9245 -> 0 bytes lib/pytz/zoneinfo/Chile/EasterIsland | Bin 9007 -> 0 bytes lib/pytz/zoneinfo/Cuba | Bin 2411 -> 0 bytes lib/pytz/zoneinfo/EET | Bin 1876 -> 0 bytes lib/pytz/zoneinfo/EST | Bin 118 -> 0 bytes lib/pytz/zoneinfo/EST5EDT | Bin 2294 -> 0 bytes lib/pytz/zoneinfo/Egypt | Bin 1901 -> 0 bytes lib/pytz/zoneinfo/Eire | Bin 3533 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+1 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+10 | Bin 130 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+11 | Bin 130 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+12 | Bin 130 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+2 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+3 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+4 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+5 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+6 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+7 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+8 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT+9 | Bin 126 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-1 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-10 | Bin 131 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-11 | Bin 131 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-12 | Bin 131 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-13 | Bin 131 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-14 | Bin 131 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-2 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-3 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-4 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-5 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-6 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-7 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-8 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT-9 | Bin 127 -> 0 bytes lib/pytz/zoneinfo/Etc/GMT0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/Greenwich | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/UCT | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/UTC | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/Universal | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Etc/Zulu | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Europe/Amsterdam | Bin 2917 -> 0 bytes lib/pytz/zoneinfo/Europe/Andorra | Bin 1725 -> 0 bytes lib/pytz/zoneinfo/Europe/Athens | Bin 2245 -> 0 bytes lib/pytz/zoneinfo/Europe/Belfast | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/Europe/Belgrade | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/Berlin | Bin 2309 -> 0 bytes lib/pytz/zoneinfo/Europe/Bratislava | Bin 2246 -> 0 bytes lib/pytz/zoneinfo/Europe/Brussels | Bin 2944 -> 0 bytes lib/pytz/zoneinfo/Europe/Bucharest | Bin 2195 -> 0 bytes lib/pytz/zoneinfo/Europe/Budapest | Bin 2407 -> 0 bytes lib/pytz/zoneinfo/Europe/Chisinau | Bin 2407 -> 0 bytes lib/pytz/zoneinfo/Europe/Copenhagen | Bin 2134 -> 0 bytes lib/pytz/zoneinfo/Europe/Dublin | Bin 3533 -> 0 bytes lib/pytz/zoneinfo/Europe/Gibraltar | Bin 3035 -> 0 bytes lib/pytz/zoneinfo/Europe/Guernsey | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/Europe/Helsinki | Bin 1883 -> 0 bytes lib/pytz/zoneinfo/Europe/Isle_of_Man | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/Europe/Istanbul | Bin 2721 -> 0 bytes lib/pytz/zoneinfo/Europe/Jersey | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/Europe/Kaliningrad | Bin 1494 -> 0 bytes lib/pytz/zoneinfo/Europe/Kiev | Bin 2057 -> 0 bytes lib/pytz/zoneinfo/Europe/Lisbon | Bin 3439 -> 0 bytes lib/pytz/zoneinfo/Europe/Ljubljana | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/London | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/Europe/Luxembourg | Bin 2960 -> 0 bytes lib/pytz/zoneinfo/Europe/Madrid | Bin 2593 -> 0 bytes lib/pytz/zoneinfo/Europe/Malta | Bin 2603 -> 0 bytes lib/pytz/zoneinfo/Europe/Mariehamn | Bin 1883 -> 0 bytes lib/pytz/zoneinfo/Europe/Minsk | Bin 1328 -> 0 bytes lib/pytz/zoneinfo/Europe/Monaco | Bin 2927 -> 0 bytes lib/pytz/zoneinfo/Europe/Moscow | Bin 1464 -> 0 bytes lib/pytz/zoneinfo/Europe/Nicosia | Bin 2002 -> 0 bytes lib/pytz/zoneinfo/Europe/Oslo | Bin 2225 -> 0 bytes lib/pytz/zoneinfo/Europe/Paris | Bin 2945 -> 0 bytes lib/pytz/zoneinfo/Europe/Podgorica | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/Prague | Bin 2246 -> 0 bytes lib/pytz/zoneinfo/Europe/Riga | Bin 2209 -> 0 bytes lib/pytz/zoneinfo/Europe/Rome | Bin 2652 -> 0 bytes lib/pytz/zoneinfo/Europe/Samara | Bin 1330 -> 0 bytes lib/pytz/zoneinfo/Europe/San_Marino | Bin 2652 -> 0 bytes lib/pytz/zoneinfo/Europe/Sarajevo | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/Simferopol | Bin 2113 -> 0 bytes lib/pytz/zoneinfo/Europe/Skopje | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/Sofia | Bin 2104 -> 0 bytes lib/pytz/zoneinfo/Europe/Stockholm | Bin 1892 -> 0 bytes lib/pytz/zoneinfo/Europe/Tallinn | Bin 2175 -> 0 bytes lib/pytz/zoneinfo/Europe/Tirane | Bin 2084 -> 0 bytes lib/pytz/zoneinfo/Europe/Tiraspol | Bin 2407 -> 0 bytes lib/pytz/zoneinfo/Europe/Uzhgorod | Bin 2077 -> 0 bytes lib/pytz/zoneinfo/Europe/Vaduz | Bin 1799 -> 0 bytes lib/pytz/zoneinfo/Europe/Vatican | Bin 2652 -> 0 bytes lib/pytz/zoneinfo/Europe/Vienna | Bin 2211 -> 0 bytes lib/pytz/zoneinfo/Europe/Vilnius | Bin 2173 -> 0 bytes lib/pytz/zoneinfo/Europe/Volgograd | Bin 1234 -> 0 bytes lib/pytz/zoneinfo/Europe/Warsaw | Bin 2679 -> 0 bytes lib/pytz/zoneinfo/Europe/Zagreb | Bin 1931 -> 0 bytes lib/pytz/zoneinfo/Europe/Zaporozhye | Bin 2085 -> 0 bytes lib/pytz/zoneinfo/Europe/Zurich | Bin 1892 -> 0 bytes lib/pytz/zoneinfo/Factory | Bin 255 -> 0 bytes lib/pytz/zoneinfo/GB | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/GB-Eire | Bin 3661 -> 0 bytes lib/pytz/zoneinfo/GMT | Bin 118 -> 0 bytes lib/pytz/zoneinfo/GMT+0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/GMT-0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/GMT0 | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Greenwich | Bin 118 -> 0 bytes lib/pytz/zoneinfo/HST | Bin 119 -> 0 bytes lib/pytz/zoneinfo/Hongkong | Bin 1175 -> 0 bytes lib/pytz/zoneinfo/Iceland | Bin 1141 -> 0 bytes lib/pytz/zoneinfo/Indian/Antananarivo | Bin 227 -> 0 bytes lib/pytz/zoneinfo/Indian/Chagos | Bin 187 -> 0 bytes lib/pytz/zoneinfo/Indian/Christmas | Bin 140 -> 0 bytes lib/pytz/zoneinfo/Indian/Cocos | Bin 143 -> 0 bytes lib/pytz/zoneinfo/Indian/Comoro | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Indian/Kerguelen | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Indian/Mahe | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Indian/Maldives | Bin 178 -> 0 bytes lib/pytz/zoneinfo/Indian/Mauritius | Bin 239 -> 0 bytes lib/pytz/zoneinfo/Indian/Mayotte | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Indian/Reunion | Bin 157 -> 0 bytes lib/pytz/zoneinfo/Iran | Bin 1638 -> 0 bytes lib/pytz/zoneinfo/Israel | Bin 2213 -> 0 bytes lib/pytz/zoneinfo/Jamaica | Bin 481 -> 0 bytes lib/pytz/zoneinfo/Japan | Bin 331 -> 0 bytes lib/pytz/zoneinfo/Kwajalein | Bin 211 -> 0 bytes lib/pytz/zoneinfo/Libya | Bin 599 -> 0 bytes lib/pytz/zoneinfo/MET | Bin 2102 -> 0 bytes lib/pytz/zoneinfo/MST | Bin 118 -> 0 bytes lib/pytz/zoneinfo/MST7MDT | Bin 2294 -> 0 bytes lib/pytz/zoneinfo/Mexico/BajaNorte | Bin 2342 -> 0 bytes lib/pytz/zoneinfo/Mexico/BajaSur | Bin 1550 -> 0 bytes lib/pytz/zoneinfo/Mexico/General | Bin 1604 -> 0 bytes lib/pytz/zoneinfo/Mideast/Riyadh87 | Bin 8685 -> 0 bytes lib/pytz/zoneinfo/Mideast/Riyadh88 | Bin 8539 -> 0 bytes lib/pytz/zoneinfo/Mideast/Riyadh89 | Bin 8539 -> 0 bytes lib/pytz/zoneinfo/NZ | Bin 2434 -> 0 bytes lib/pytz/zoneinfo/NZ-CHAT | Bin 2018 -> 0 bytes lib/pytz/zoneinfo/Navajo | Bin 2427 -> 0 bytes lib/pytz/zoneinfo/PRC | Bin 405 -> 0 bytes lib/pytz/zoneinfo/PST8PDT | Bin 2294 -> 0 bytes lib/pytz/zoneinfo/Pacific/Apia | Bin 343 -> 0 bytes lib/pytz/zoneinfo/Pacific/Auckland | Bin 2434 -> 0 bytes lib/pytz/zoneinfo/Pacific/Chatham | Bin 2018 -> 0 bytes lib/pytz/zoneinfo/Pacific/Chuuk | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Easter | Bin 9007 -> 0 bytes lib/pytz/zoneinfo/Pacific/Efate | Bin 464 -> 0 bytes lib/pytz/zoneinfo/Pacific/Enderbury | Bin 204 -> 0 bytes lib/pytz/zoneinfo/Pacific/Fakaofo | Bin 171 -> 0 bytes lib/pytz/zoneinfo/Pacific/Fiji | Bin 324 -> 0 bytes lib/pytz/zoneinfo/Pacific/Funafuti | Bin 141 -> 0 bytes lib/pytz/zoneinfo/Pacific/Galapagos | Bin 197 -> 0 bytes lib/pytz/zoneinfo/Pacific/Gambier | Bin 159 -> 0 bytes lib/pytz/zoneinfo/Pacific/Guadalcanal | Bin 158 -> 0 bytes lib/pytz/zoneinfo/Pacific/Guam | Bin 199 -> 0 bytes lib/pytz/zoneinfo/Pacific/Honolulu | Bin 250 -> 0 bytes lib/pytz/zoneinfo/Pacific/Johnston | Bin 119 -> 0 bytes lib/pytz/zoneinfo/Pacific/Kiritimati | Bin 204 -> 0 bytes lib/pytz/zoneinfo/Pacific/Kosrae | Bin 204 -> 0 bytes lib/pytz/zoneinfo/Pacific/Kwajalein | Bin 211 -> 0 bytes lib/pytz/zoneinfo/Pacific/Majuro | Bin 171 -> 0 bytes lib/pytz/zoneinfo/Pacific/Marquesas | Bin 162 -> 0 bytes lib/pytz/zoneinfo/Pacific/Midway | Bin 268 -> 0 bytes lib/pytz/zoneinfo/Pacific/Nauru | Bin 240 -> 0 bytes lib/pytz/zoneinfo/Pacific/Niue | Bin 200 -> 0 bytes lib/pytz/zoneinfo/Pacific/Norfolk | Bin 182 -> 0 bytes lib/pytz/zoneinfo/Pacific/Noumea | Bin 300 -> 0 bytes lib/pytz/zoneinfo/Pacific/Pago_Pago | Bin 290 -> 0 bytes lib/pytz/zoneinfo/Pacific/Palau | Bin 140 -> 0 bytes lib/pytz/zoneinfo/Pacific/Pitcairn | Bin 177 -> 0 bytes lib/pytz/zoneinfo/Pacific/Pohnpei | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Ponape | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Port_Moresby | Bin 163 -> 0 bytes lib/pytz/zoneinfo/Pacific/Rarotonga | Bin 548 -> 0 bytes lib/pytz/zoneinfo/Pacific/Saipan | Bin 229 -> 0 bytes lib/pytz/zoneinfo/Pacific/Samoa | Bin 290 -> 0 bytes lib/pytz/zoneinfo/Pacific/Tahiti | Bin 160 -> 0 bytes lib/pytz/zoneinfo/Pacific/Tarawa | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Tongatapu | Bin 313 -> 0 bytes lib/pytz/zoneinfo/Pacific/Truk | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Wake | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Pacific/Wallis | Bin 141 -> 0 bytes lib/pytz/zoneinfo/Pacific/Yap | Bin 144 -> 0 bytes lib/pytz/zoneinfo/Poland | Bin 2679 -> 0 bytes lib/pytz/zoneinfo/Portugal | Bin 3439 -> 0 bytes lib/pytz/zoneinfo/ROC | Bin 724 -> 0 bytes lib/pytz/zoneinfo/ROK | Bin 396 -> 0 bytes lib/pytz/zoneinfo/Singapore | Bin 402 -> 0 bytes lib/pytz/zoneinfo/Turkey | Bin 2721 -> 0 bytes lib/pytz/zoneinfo/UCT | Bin 118 -> 0 bytes lib/pytz/zoneinfo/US/Alaska | Bin 2358 -> 0 bytes lib/pytz/zoneinfo/US/Aleutian | Bin 2353 -> 0 bytes lib/pytz/zoneinfo/US/Arizona | Bin 327 -> 0 bytes lib/pytz/zoneinfo/US/Central | Bin 3559 -> 0 bytes lib/pytz/zoneinfo/US/East-Indiana | Bin 1649 -> 0 bytes lib/pytz/zoneinfo/US/Eastern | Bin 3519 -> 0 bytes lib/pytz/zoneinfo/US/Hawaii | Bin 250 -> 0 bytes lib/pytz/zoneinfo/US/Indiana-Starke | Bin 2411 -> 0 bytes lib/pytz/zoneinfo/US/Michigan | Bin 2202 -> 0 bytes lib/pytz/zoneinfo/US/Mountain | Bin 2427 -> 0 bytes lib/pytz/zoneinfo/US/Pacific | Bin 2819 -> 0 bytes lib/pytz/zoneinfo/US/Pacific-New | Bin 2819 -> 0 bytes lib/pytz/zoneinfo/US/Samoa | Bin 290 -> 0 bytes lib/pytz/zoneinfo/UTC | Bin 118 -> 0 bytes lib/pytz/zoneinfo/Universal | Bin 118 -> 0 bytes lib/pytz/zoneinfo/W-SU | Bin 1464 -> 0 bytes lib/pytz/zoneinfo/WET | Bin 1873 -> 0 bytes lib/pytz/zoneinfo/Zulu | Bin 118 -> 0 bytes lib/pytz/zoneinfo/iso3166.tab | 276 --- lib/pytz/zoneinfo/localtime | Bin 118 -> 0 bytes lib/pytz/zoneinfo/posixrules | Bin 3519 -> 0 bytes lib/pytz/zoneinfo/zone.tab | 441 ---- lib/six.py | 366 --- 622 files changed, 17026 deletions(-) delete mode 100644 lib/dateutil_py2/LICENSE delete mode 100644 lib/dateutil_py2/NEWS delete mode 100644 lib/dateutil_py2/README delete mode 100644 lib/dateutil_py2/__init__.py delete mode 100644 lib/dateutil_py2/easter.py delete mode 100644 lib/dateutil_py2/parser.py delete mode 100644 lib/dateutil_py2/relativedelta.py delete mode 100644 lib/dateutil_py2/rrule.py delete mode 100644 lib/dateutil_py2/tz.py delete mode 100644 lib/dateutil_py2/tzwin.py delete mode 100644 lib/dateutil_py2/zoneinfo/__init__.py delete mode 100644 lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz delete mode 100644 lib/dateutil_py3/LICENSE delete mode 100644 lib/dateutil_py3/NEWS delete mode 100644 lib/dateutil_py3/README delete mode 100644 lib/dateutil_py3/__init__.py delete mode 100644 lib/dateutil_py3/easter.py delete mode 100644 lib/dateutil_py3/parser.py delete mode 100644 lib/dateutil_py3/relativedelta.py delete mode 100644 lib/dateutil_py3/rrule.py delete mode 100644 lib/dateutil_py3/tz.py delete mode 100644 lib/dateutil_py3/tzwin.py delete mode 100644 lib/dateutil_py3/zoneinfo/__init__.py delete mode 100644 lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz delete mode 100644 lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz delete mode 100644 lib/pytz/CHANGES.txt delete mode 100644 lib/pytz/LICENSE.txt delete mode 100644 lib/pytz/README.txt delete mode 100644 lib/pytz/__init__.py delete mode 100644 lib/pytz/exceptions.py delete mode 100644 lib/pytz/reference.py delete mode 100644 lib/pytz/tests/test_docs.py delete mode 100644 lib/pytz/tests/test_tzinfo.py delete mode 100644 lib/pytz/tzfile.py delete mode 100644 lib/pytz/tzinfo.py delete mode 100644 lib/pytz/zoneinfo/Africa/Abidjan delete mode 100644 lib/pytz/zoneinfo/Africa/Accra delete mode 100644 lib/pytz/zoneinfo/Africa/Addis_Ababa delete mode 100644 lib/pytz/zoneinfo/Africa/Algiers delete mode 100644 lib/pytz/zoneinfo/Africa/Asmara delete mode 100644 lib/pytz/zoneinfo/Africa/Asmera delete mode 100644 lib/pytz/zoneinfo/Africa/Bamako delete mode 100644 lib/pytz/zoneinfo/Africa/Bangui delete mode 100644 lib/pytz/zoneinfo/Africa/Banjul delete mode 100644 lib/pytz/zoneinfo/Africa/Bissau delete mode 100644 lib/pytz/zoneinfo/Africa/Blantyre delete mode 100644 lib/pytz/zoneinfo/Africa/Brazzaville delete mode 100644 lib/pytz/zoneinfo/Africa/Bujumbura delete mode 100644 lib/pytz/zoneinfo/Africa/Cairo delete mode 100644 lib/pytz/zoneinfo/Africa/Casablanca delete mode 100644 lib/pytz/zoneinfo/Africa/Ceuta delete mode 100644 lib/pytz/zoneinfo/Africa/Conakry delete mode 100644 lib/pytz/zoneinfo/Africa/Dakar delete mode 100644 lib/pytz/zoneinfo/Africa/Dar_es_Salaam delete mode 100644 lib/pytz/zoneinfo/Africa/Djibouti delete mode 100644 lib/pytz/zoneinfo/Africa/Douala delete mode 100644 lib/pytz/zoneinfo/Africa/El_Aaiun delete mode 100644 lib/pytz/zoneinfo/Africa/Freetown delete mode 100644 lib/pytz/zoneinfo/Africa/Gaborone delete mode 100644 lib/pytz/zoneinfo/Africa/Harare delete mode 100644 lib/pytz/zoneinfo/Africa/Johannesburg delete mode 100644 lib/pytz/zoneinfo/Africa/Juba delete mode 100644 lib/pytz/zoneinfo/Africa/Kampala delete mode 100644 lib/pytz/zoneinfo/Africa/Khartoum delete mode 100644 lib/pytz/zoneinfo/Africa/Kigali delete mode 100644 lib/pytz/zoneinfo/Africa/Kinshasa delete mode 100644 lib/pytz/zoneinfo/Africa/Lagos delete mode 100644 lib/pytz/zoneinfo/Africa/Libreville delete mode 100644 lib/pytz/zoneinfo/Africa/Lome delete mode 100644 lib/pytz/zoneinfo/Africa/Luanda delete mode 100644 lib/pytz/zoneinfo/Africa/Lubumbashi delete mode 100644 lib/pytz/zoneinfo/Africa/Lusaka delete mode 100644 lib/pytz/zoneinfo/Africa/Malabo delete mode 100644 lib/pytz/zoneinfo/Africa/Maputo delete mode 100644 lib/pytz/zoneinfo/Africa/Maseru delete mode 100644 lib/pytz/zoneinfo/Africa/Mbabane delete mode 100644 lib/pytz/zoneinfo/Africa/Mogadishu delete mode 100644 lib/pytz/zoneinfo/Africa/Monrovia delete mode 100644 lib/pytz/zoneinfo/Africa/Nairobi delete mode 100644 lib/pytz/zoneinfo/Africa/Ndjamena delete mode 100644 lib/pytz/zoneinfo/Africa/Niamey delete mode 100644 lib/pytz/zoneinfo/Africa/Nouakchott delete mode 100644 lib/pytz/zoneinfo/Africa/Ouagadougou delete mode 100644 lib/pytz/zoneinfo/Africa/Porto-Novo delete mode 100644 lib/pytz/zoneinfo/Africa/Sao_Tome delete mode 100644 lib/pytz/zoneinfo/Africa/Timbuktu delete mode 100644 lib/pytz/zoneinfo/Africa/Tripoli delete mode 100644 lib/pytz/zoneinfo/Africa/Tunis delete mode 100644 lib/pytz/zoneinfo/Africa/Windhoek delete mode 100644 lib/pytz/zoneinfo/America/Adak delete mode 100644 lib/pytz/zoneinfo/America/Anchorage delete mode 100644 lib/pytz/zoneinfo/America/Anguilla delete mode 100644 lib/pytz/zoneinfo/America/Antigua delete mode 100644 lib/pytz/zoneinfo/America/Araguaina delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Buenos_Aires delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Catamarca delete mode 100644 lib/pytz/zoneinfo/America/Argentina/ComodRivadavia delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Cordoba delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Jujuy delete mode 100644 lib/pytz/zoneinfo/America/Argentina/La_Rioja delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Mendoza delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Salta delete mode 100644 lib/pytz/zoneinfo/America/Argentina/San_Juan delete mode 100644 lib/pytz/zoneinfo/America/Argentina/San_Luis delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Tucuman delete mode 100644 lib/pytz/zoneinfo/America/Argentina/Ushuaia delete mode 100644 lib/pytz/zoneinfo/America/Aruba delete mode 100644 lib/pytz/zoneinfo/America/Asuncion delete mode 100644 lib/pytz/zoneinfo/America/Atikokan delete mode 100644 lib/pytz/zoneinfo/America/Atka delete mode 100644 lib/pytz/zoneinfo/America/Bahia delete mode 100644 lib/pytz/zoneinfo/America/Bahia_Banderas delete mode 100644 lib/pytz/zoneinfo/America/Barbados delete mode 100644 lib/pytz/zoneinfo/America/Belem delete mode 100644 lib/pytz/zoneinfo/America/Belize delete mode 100644 lib/pytz/zoneinfo/America/Blanc-Sablon delete mode 100644 lib/pytz/zoneinfo/America/Boa_Vista delete mode 100644 lib/pytz/zoneinfo/America/Bogota delete mode 100644 lib/pytz/zoneinfo/America/Boise delete mode 100644 lib/pytz/zoneinfo/America/Buenos_Aires delete mode 100644 lib/pytz/zoneinfo/America/Cambridge_Bay delete mode 100644 lib/pytz/zoneinfo/America/Campo_Grande delete mode 100644 lib/pytz/zoneinfo/America/Cancun delete mode 100644 lib/pytz/zoneinfo/America/Caracas delete mode 100644 lib/pytz/zoneinfo/America/Catamarca delete mode 100644 lib/pytz/zoneinfo/America/Cayenne delete mode 100644 lib/pytz/zoneinfo/America/Cayman delete mode 100644 lib/pytz/zoneinfo/America/Chicago delete mode 100644 lib/pytz/zoneinfo/America/Chihuahua delete mode 100644 lib/pytz/zoneinfo/America/Coral_Harbour delete mode 100644 lib/pytz/zoneinfo/America/Cordoba delete mode 100644 lib/pytz/zoneinfo/America/Costa_Rica delete mode 100644 lib/pytz/zoneinfo/America/Creston delete mode 100644 lib/pytz/zoneinfo/America/Cuiaba delete mode 100644 lib/pytz/zoneinfo/America/Curacao delete mode 100644 lib/pytz/zoneinfo/America/Danmarkshavn delete mode 100644 lib/pytz/zoneinfo/America/Dawson delete mode 100644 lib/pytz/zoneinfo/America/Dawson_Creek delete mode 100644 lib/pytz/zoneinfo/America/Denver delete mode 100644 lib/pytz/zoneinfo/America/Detroit delete mode 100644 lib/pytz/zoneinfo/America/Dominica delete mode 100644 lib/pytz/zoneinfo/America/Edmonton delete mode 100644 lib/pytz/zoneinfo/America/Eirunepe delete mode 100644 lib/pytz/zoneinfo/America/El_Salvador delete mode 100644 lib/pytz/zoneinfo/America/Ensenada delete mode 100644 lib/pytz/zoneinfo/America/Fort_Wayne delete mode 100644 lib/pytz/zoneinfo/America/Fortaleza delete mode 100644 lib/pytz/zoneinfo/America/Glace_Bay delete mode 100644 lib/pytz/zoneinfo/America/Godthab delete mode 100644 lib/pytz/zoneinfo/America/Goose_Bay delete mode 100644 lib/pytz/zoneinfo/America/Grand_Turk delete mode 100644 lib/pytz/zoneinfo/America/Grenada delete mode 100644 lib/pytz/zoneinfo/America/Guadeloupe delete mode 100644 lib/pytz/zoneinfo/America/Guatemala delete mode 100644 lib/pytz/zoneinfo/America/Guayaquil delete mode 100644 lib/pytz/zoneinfo/America/Guyana delete mode 100644 lib/pytz/zoneinfo/America/Halifax delete mode 100644 lib/pytz/zoneinfo/America/Havana delete mode 100644 lib/pytz/zoneinfo/America/Hermosillo delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Indianapolis delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Knox delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Marengo delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Petersburg delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Tell_City delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Vevay delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Vincennes delete mode 100644 lib/pytz/zoneinfo/America/Indiana/Winamac delete mode 100644 lib/pytz/zoneinfo/America/Indianapolis delete mode 100644 lib/pytz/zoneinfo/America/Inuvik delete mode 100644 lib/pytz/zoneinfo/America/Iqaluit delete mode 100644 lib/pytz/zoneinfo/America/Jamaica delete mode 100644 lib/pytz/zoneinfo/America/Jujuy delete mode 100644 lib/pytz/zoneinfo/America/Juneau delete mode 100644 lib/pytz/zoneinfo/America/Kentucky/Louisville delete mode 100644 lib/pytz/zoneinfo/America/Kentucky/Monticello delete mode 100644 lib/pytz/zoneinfo/America/Knox_IN delete mode 100644 lib/pytz/zoneinfo/America/Kralendijk delete mode 100644 lib/pytz/zoneinfo/America/La_Paz delete mode 100644 lib/pytz/zoneinfo/America/Lima delete mode 100644 lib/pytz/zoneinfo/America/Los_Angeles delete mode 100644 lib/pytz/zoneinfo/America/Louisville delete mode 100644 lib/pytz/zoneinfo/America/Lower_Princes delete mode 100644 lib/pytz/zoneinfo/America/Maceio delete mode 100644 lib/pytz/zoneinfo/America/Managua delete mode 100644 lib/pytz/zoneinfo/America/Manaus delete mode 100644 lib/pytz/zoneinfo/America/Marigot delete mode 100644 lib/pytz/zoneinfo/America/Martinique delete mode 100644 lib/pytz/zoneinfo/America/Matamoros delete mode 100644 lib/pytz/zoneinfo/America/Mazatlan delete mode 100644 lib/pytz/zoneinfo/America/Mendoza delete mode 100644 lib/pytz/zoneinfo/America/Menominee delete mode 100644 lib/pytz/zoneinfo/America/Merida delete mode 100644 lib/pytz/zoneinfo/America/Metlakatla delete mode 100644 lib/pytz/zoneinfo/America/Mexico_City delete mode 100644 lib/pytz/zoneinfo/America/Miquelon delete mode 100644 lib/pytz/zoneinfo/America/Moncton delete mode 100644 lib/pytz/zoneinfo/America/Monterrey delete mode 100644 lib/pytz/zoneinfo/America/Montevideo delete mode 100644 lib/pytz/zoneinfo/America/Montreal delete mode 100644 lib/pytz/zoneinfo/America/Montserrat delete mode 100644 lib/pytz/zoneinfo/America/Nassau delete mode 100644 lib/pytz/zoneinfo/America/New_York delete mode 100644 lib/pytz/zoneinfo/America/Nipigon delete mode 100644 lib/pytz/zoneinfo/America/Nome delete mode 100644 lib/pytz/zoneinfo/America/Noronha delete mode 100644 lib/pytz/zoneinfo/America/North_Dakota/Beulah delete mode 100644 lib/pytz/zoneinfo/America/North_Dakota/Center delete mode 100644 lib/pytz/zoneinfo/America/North_Dakota/New_Salem delete mode 100644 lib/pytz/zoneinfo/America/Ojinaga delete mode 100644 lib/pytz/zoneinfo/America/Panama delete mode 100644 lib/pytz/zoneinfo/America/Pangnirtung delete mode 100644 lib/pytz/zoneinfo/America/Paramaribo delete mode 100644 lib/pytz/zoneinfo/America/Phoenix delete mode 100644 lib/pytz/zoneinfo/America/Port-au-Prince delete mode 100644 lib/pytz/zoneinfo/America/Port_of_Spain delete mode 100644 lib/pytz/zoneinfo/America/Porto_Acre delete mode 100644 lib/pytz/zoneinfo/America/Porto_Velho delete mode 100644 lib/pytz/zoneinfo/America/Puerto_Rico delete mode 100644 lib/pytz/zoneinfo/America/Rainy_River delete mode 100644 lib/pytz/zoneinfo/America/Rankin_Inlet delete mode 100644 lib/pytz/zoneinfo/America/Recife delete mode 100644 lib/pytz/zoneinfo/America/Regina delete mode 100644 lib/pytz/zoneinfo/America/Resolute delete mode 100644 lib/pytz/zoneinfo/America/Rio_Branco delete mode 100644 lib/pytz/zoneinfo/America/Rosario delete mode 100644 lib/pytz/zoneinfo/America/Santa_Isabel delete mode 100644 lib/pytz/zoneinfo/America/Santarem delete mode 100644 lib/pytz/zoneinfo/America/Santiago delete mode 100644 lib/pytz/zoneinfo/America/Santo_Domingo delete mode 100644 lib/pytz/zoneinfo/America/Sao_Paulo delete mode 100644 lib/pytz/zoneinfo/America/Scoresbysund delete mode 100644 lib/pytz/zoneinfo/America/Shiprock delete mode 100644 lib/pytz/zoneinfo/America/Sitka delete mode 100644 lib/pytz/zoneinfo/America/St_Barthelemy delete mode 100644 lib/pytz/zoneinfo/America/St_Johns delete mode 100644 lib/pytz/zoneinfo/America/St_Kitts delete mode 100644 lib/pytz/zoneinfo/America/St_Lucia delete mode 100644 lib/pytz/zoneinfo/America/St_Thomas delete mode 100644 lib/pytz/zoneinfo/America/St_Vincent delete mode 100644 lib/pytz/zoneinfo/America/Swift_Current delete mode 100644 lib/pytz/zoneinfo/America/Tegucigalpa delete mode 100644 lib/pytz/zoneinfo/America/Thule delete mode 100644 lib/pytz/zoneinfo/America/Thunder_Bay delete mode 100644 lib/pytz/zoneinfo/America/Tijuana delete mode 100644 lib/pytz/zoneinfo/America/Toronto delete mode 100644 lib/pytz/zoneinfo/America/Tortola delete mode 100644 lib/pytz/zoneinfo/America/Vancouver delete mode 100644 lib/pytz/zoneinfo/America/Virgin delete mode 100644 lib/pytz/zoneinfo/America/Whitehorse delete mode 100644 lib/pytz/zoneinfo/America/Winnipeg delete mode 100644 lib/pytz/zoneinfo/America/Yakutat delete mode 100644 lib/pytz/zoneinfo/America/Yellowknife delete mode 100644 lib/pytz/zoneinfo/Antarctica/Casey delete mode 100644 lib/pytz/zoneinfo/Antarctica/Davis delete mode 100644 lib/pytz/zoneinfo/Antarctica/DumontDUrville delete mode 100644 lib/pytz/zoneinfo/Antarctica/Macquarie delete mode 100644 lib/pytz/zoneinfo/Antarctica/Mawson delete mode 100644 lib/pytz/zoneinfo/Antarctica/McMurdo delete mode 100644 lib/pytz/zoneinfo/Antarctica/Palmer delete mode 100644 lib/pytz/zoneinfo/Antarctica/Rothera delete mode 100644 lib/pytz/zoneinfo/Antarctica/South_Pole delete mode 100644 lib/pytz/zoneinfo/Antarctica/Syowa delete mode 100644 lib/pytz/zoneinfo/Antarctica/Vostok delete mode 100644 lib/pytz/zoneinfo/Arctic/Longyearbyen delete mode 100644 lib/pytz/zoneinfo/Asia/Aden delete mode 100644 lib/pytz/zoneinfo/Asia/Almaty delete mode 100644 lib/pytz/zoneinfo/Asia/Amman delete mode 100644 lib/pytz/zoneinfo/Asia/Anadyr delete mode 100644 lib/pytz/zoneinfo/Asia/Aqtau delete mode 100644 lib/pytz/zoneinfo/Asia/Aqtobe delete mode 100644 lib/pytz/zoneinfo/Asia/Ashgabat delete mode 100644 lib/pytz/zoneinfo/Asia/Ashkhabad delete mode 100644 lib/pytz/zoneinfo/Asia/Baghdad delete mode 100644 lib/pytz/zoneinfo/Asia/Bahrain delete mode 100644 lib/pytz/zoneinfo/Asia/Baku delete mode 100644 lib/pytz/zoneinfo/Asia/Bangkok delete mode 100644 lib/pytz/zoneinfo/Asia/Beirut delete mode 100644 lib/pytz/zoneinfo/Asia/Bishkek delete mode 100644 lib/pytz/zoneinfo/Asia/Brunei delete mode 100644 lib/pytz/zoneinfo/Asia/Calcutta delete mode 100644 lib/pytz/zoneinfo/Asia/Choibalsan delete mode 100644 lib/pytz/zoneinfo/Asia/Chongqing delete mode 100644 lib/pytz/zoneinfo/Asia/Chungking delete mode 100644 lib/pytz/zoneinfo/Asia/Colombo delete mode 100644 lib/pytz/zoneinfo/Asia/Dacca delete mode 100644 lib/pytz/zoneinfo/Asia/Damascus delete mode 100644 lib/pytz/zoneinfo/Asia/Dhaka delete mode 100644 lib/pytz/zoneinfo/Asia/Dili delete mode 100644 lib/pytz/zoneinfo/Asia/Dubai delete mode 100644 lib/pytz/zoneinfo/Asia/Dushanbe delete mode 100644 lib/pytz/zoneinfo/Asia/Gaza delete mode 100644 lib/pytz/zoneinfo/Asia/Harbin delete mode 100644 lib/pytz/zoneinfo/Asia/Hebron delete mode 100644 lib/pytz/zoneinfo/Asia/Ho_Chi_Minh delete mode 100644 lib/pytz/zoneinfo/Asia/Hong_Kong delete mode 100644 lib/pytz/zoneinfo/Asia/Hovd delete mode 100644 lib/pytz/zoneinfo/Asia/Irkutsk delete mode 100644 lib/pytz/zoneinfo/Asia/Istanbul delete mode 100644 lib/pytz/zoneinfo/Asia/Jakarta delete mode 100644 lib/pytz/zoneinfo/Asia/Jayapura delete mode 100644 lib/pytz/zoneinfo/Asia/Jerusalem delete mode 100644 lib/pytz/zoneinfo/Asia/Kabul delete mode 100644 lib/pytz/zoneinfo/Asia/Kamchatka delete mode 100644 lib/pytz/zoneinfo/Asia/Karachi delete mode 100644 lib/pytz/zoneinfo/Asia/Kashgar delete mode 100644 lib/pytz/zoneinfo/Asia/Kathmandu delete mode 100644 lib/pytz/zoneinfo/Asia/Katmandu delete mode 100644 lib/pytz/zoneinfo/Asia/Kolkata delete mode 100644 lib/pytz/zoneinfo/Asia/Krasnoyarsk delete mode 100644 lib/pytz/zoneinfo/Asia/Kuala_Lumpur delete mode 100644 lib/pytz/zoneinfo/Asia/Kuching delete mode 100644 lib/pytz/zoneinfo/Asia/Kuwait delete mode 100644 lib/pytz/zoneinfo/Asia/Macao delete mode 100644 lib/pytz/zoneinfo/Asia/Macau delete mode 100644 lib/pytz/zoneinfo/Asia/Magadan delete mode 100644 lib/pytz/zoneinfo/Asia/Makassar delete mode 100644 lib/pytz/zoneinfo/Asia/Manila delete mode 100644 lib/pytz/zoneinfo/Asia/Muscat delete mode 100644 lib/pytz/zoneinfo/Asia/Nicosia delete mode 100644 lib/pytz/zoneinfo/Asia/Novokuznetsk delete mode 100644 lib/pytz/zoneinfo/Asia/Novosibirsk delete mode 100644 lib/pytz/zoneinfo/Asia/Omsk delete mode 100644 lib/pytz/zoneinfo/Asia/Oral delete mode 100644 lib/pytz/zoneinfo/Asia/Phnom_Penh delete mode 100644 lib/pytz/zoneinfo/Asia/Pontianak delete mode 100644 lib/pytz/zoneinfo/Asia/Pyongyang delete mode 100644 lib/pytz/zoneinfo/Asia/Qatar delete mode 100644 lib/pytz/zoneinfo/Asia/Qyzylorda delete mode 100644 lib/pytz/zoneinfo/Asia/Rangoon delete mode 100644 lib/pytz/zoneinfo/Asia/Riyadh delete mode 100644 lib/pytz/zoneinfo/Asia/Riyadh87 delete mode 100644 lib/pytz/zoneinfo/Asia/Riyadh88 delete mode 100644 lib/pytz/zoneinfo/Asia/Riyadh89 delete mode 100644 lib/pytz/zoneinfo/Asia/Saigon delete mode 100644 lib/pytz/zoneinfo/Asia/Sakhalin delete mode 100644 lib/pytz/zoneinfo/Asia/Samarkand delete mode 100644 lib/pytz/zoneinfo/Asia/Seoul delete mode 100644 lib/pytz/zoneinfo/Asia/Shanghai delete mode 100644 lib/pytz/zoneinfo/Asia/Singapore delete mode 100644 lib/pytz/zoneinfo/Asia/Taipei delete mode 100644 lib/pytz/zoneinfo/Asia/Tashkent delete mode 100644 lib/pytz/zoneinfo/Asia/Tbilisi delete mode 100644 lib/pytz/zoneinfo/Asia/Tehran delete mode 100644 lib/pytz/zoneinfo/Asia/Tel_Aviv delete mode 100644 lib/pytz/zoneinfo/Asia/Thimbu delete mode 100644 lib/pytz/zoneinfo/Asia/Thimphu delete mode 100644 lib/pytz/zoneinfo/Asia/Tokyo delete mode 100644 lib/pytz/zoneinfo/Asia/Ujung_Pandang delete mode 100644 lib/pytz/zoneinfo/Asia/Ulaanbaatar delete mode 100644 lib/pytz/zoneinfo/Asia/Ulan_Bator delete mode 100644 lib/pytz/zoneinfo/Asia/Urumqi delete mode 100644 lib/pytz/zoneinfo/Asia/Vientiane delete mode 100644 lib/pytz/zoneinfo/Asia/Vladivostok delete mode 100644 lib/pytz/zoneinfo/Asia/Yakutsk delete mode 100644 lib/pytz/zoneinfo/Asia/Yekaterinburg delete mode 100644 lib/pytz/zoneinfo/Asia/Yerevan delete mode 100644 lib/pytz/zoneinfo/Atlantic/Azores delete mode 100644 lib/pytz/zoneinfo/Atlantic/Bermuda delete mode 100644 lib/pytz/zoneinfo/Atlantic/Canary delete mode 100644 lib/pytz/zoneinfo/Atlantic/Cape_Verde delete mode 100644 lib/pytz/zoneinfo/Atlantic/Faeroe delete mode 100644 lib/pytz/zoneinfo/Atlantic/Faroe delete mode 100644 lib/pytz/zoneinfo/Atlantic/Jan_Mayen delete mode 100644 lib/pytz/zoneinfo/Atlantic/Madeira delete mode 100644 lib/pytz/zoneinfo/Atlantic/Reykjavik delete mode 100644 lib/pytz/zoneinfo/Atlantic/South_Georgia delete mode 100644 lib/pytz/zoneinfo/Atlantic/St_Helena delete mode 100644 lib/pytz/zoneinfo/Atlantic/Stanley delete mode 100644 lib/pytz/zoneinfo/Australia/ACT delete mode 100644 lib/pytz/zoneinfo/Australia/Adelaide delete mode 100644 lib/pytz/zoneinfo/Australia/Brisbane delete mode 100644 lib/pytz/zoneinfo/Australia/Broken_Hill delete mode 100644 lib/pytz/zoneinfo/Australia/Canberra delete mode 100644 lib/pytz/zoneinfo/Australia/Currie delete mode 100644 lib/pytz/zoneinfo/Australia/Darwin delete mode 100644 lib/pytz/zoneinfo/Australia/Eucla delete mode 100644 lib/pytz/zoneinfo/Australia/Hobart delete mode 100644 lib/pytz/zoneinfo/Australia/LHI delete mode 100644 lib/pytz/zoneinfo/Australia/Lindeman delete mode 100644 lib/pytz/zoneinfo/Australia/Lord_Howe delete mode 100644 lib/pytz/zoneinfo/Australia/Melbourne delete mode 100644 lib/pytz/zoneinfo/Australia/NSW delete mode 100644 lib/pytz/zoneinfo/Australia/North delete mode 100644 lib/pytz/zoneinfo/Australia/Perth delete mode 100644 lib/pytz/zoneinfo/Australia/Queensland delete mode 100644 lib/pytz/zoneinfo/Australia/South delete mode 100644 lib/pytz/zoneinfo/Australia/Sydney delete mode 100644 lib/pytz/zoneinfo/Australia/Tasmania delete mode 100644 lib/pytz/zoneinfo/Australia/Victoria delete mode 100644 lib/pytz/zoneinfo/Australia/West delete mode 100644 lib/pytz/zoneinfo/Australia/Yancowinna delete mode 100644 lib/pytz/zoneinfo/Brazil/Acre delete mode 100644 lib/pytz/zoneinfo/Brazil/DeNoronha delete mode 100644 lib/pytz/zoneinfo/Brazil/East delete mode 100644 lib/pytz/zoneinfo/Brazil/West delete mode 100644 lib/pytz/zoneinfo/CET delete mode 100644 lib/pytz/zoneinfo/CST6CDT delete mode 100644 lib/pytz/zoneinfo/Canada/Atlantic delete mode 100644 lib/pytz/zoneinfo/Canada/Central delete mode 100644 lib/pytz/zoneinfo/Canada/East-Saskatchewan delete mode 100644 lib/pytz/zoneinfo/Canada/Eastern delete mode 100644 lib/pytz/zoneinfo/Canada/Mountain delete mode 100644 lib/pytz/zoneinfo/Canada/Newfoundland delete mode 100644 lib/pytz/zoneinfo/Canada/Pacific delete mode 100644 lib/pytz/zoneinfo/Canada/Saskatchewan delete mode 100644 lib/pytz/zoneinfo/Canada/Yukon delete mode 100644 lib/pytz/zoneinfo/Chile/Continental delete mode 100644 lib/pytz/zoneinfo/Chile/EasterIsland delete mode 100644 lib/pytz/zoneinfo/Cuba delete mode 100644 lib/pytz/zoneinfo/EET delete mode 100644 lib/pytz/zoneinfo/EST delete mode 100644 lib/pytz/zoneinfo/EST5EDT delete mode 100644 lib/pytz/zoneinfo/Egypt delete mode 100644 lib/pytz/zoneinfo/Eire delete mode 100644 lib/pytz/zoneinfo/Etc/GMT delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+0 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+1 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+10 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+11 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+12 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+2 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+3 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+4 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+5 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+6 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+7 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+8 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT+9 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-0 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-1 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-10 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-11 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-12 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-13 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-14 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-2 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-3 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-4 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-5 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-6 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-7 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-8 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT-9 delete mode 100644 lib/pytz/zoneinfo/Etc/GMT0 delete mode 100644 lib/pytz/zoneinfo/Etc/Greenwich delete mode 100644 lib/pytz/zoneinfo/Etc/UCT delete mode 100644 lib/pytz/zoneinfo/Etc/UTC delete mode 100644 lib/pytz/zoneinfo/Etc/Universal delete mode 100644 lib/pytz/zoneinfo/Etc/Zulu delete mode 100644 lib/pytz/zoneinfo/Europe/Amsterdam delete mode 100644 lib/pytz/zoneinfo/Europe/Andorra delete mode 100644 lib/pytz/zoneinfo/Europe/Athens delete mode 100644 lib/pytz/zoneinfo/Europe/Belfast delete mode 100644 lib/pytz/zoneinfo/Europe/Belgrade delete mode 100644 lib/pytz/zoneinfo/Europe/Berlin delete mode 100644 lib/pytz/zoneinfo/Europe/Bratislava delete mode 100644 lib/pytz/zoneinfo/Europe/Brussels delete mode 100644 lib/pytz/zoneinfo/Europe/Bucharest delete mode 100644 lib/pytz/zoneinfo/Europe/Budapest delete mode 100644 lib/pytz/zoneinfo/Europe/Chisinau delete mode 100644 lib/pytz/zoneinfo/Europe/Copenhagen delete mode 100644 lib/pytz/zoneinfo/Europe/Dublin delete mode 100644 lib/pytz/zoneinfo/Europe/Gibraltar delete mode 100644 lib/pytz/zoneinfo/Europe/Guernsey delete mode 100644 lib/pytz/zoneinfo/Europe/Helsinki delete mode 100644 lib/pytz/zoneinfo/Europe/Isle_of_Man delete mode 100644 lib/pytz/zoneinfo/Europe/Istanbul delete mode 100644 lib/pytz/zoneinfo/Europe/Jersey delete mode 100644 lib/pytz/zoneinfo/Europe/Kaliningrad delete mode 100644 lib/pytz/zoneinfo/Europe/Kiev delete mode 100644 lib/pytz/zoneinfo/Europe/Lisbon delete mode 100644 lib/pytz/zoneinfo/Europe/Ljubljana delete mode 100644 lib/pytz/zoneinfo/Europe/London delete mode 100644 lib/pytz/zoneinfo/Europe/Luxembourg delete mode 100644 lib/pytz/zoneinfo/Europe/Madrid delete mode 100644 lib/pytz/zoneinfo/Europe/Malta delete mode 100644 lib/pytz/zoneinfo/Europe/Mariehamn delete mode 100644 lib/pytz/zoneinfo/Europe/Minsk delete mode 100644 lib/pytz/zoneinfo/Europe/Monaco delete mode 100644 lib/pytz/zoneinfo/Europe/Moscow delete mode 100644 lib/pytz/zoneinfo/Europe/Nicosia delete mode 100644 lib/pytz/zoneinfo/Europe/Oslo delete mode 100644 lib/pytz/zoneinfo/Europe/Paris delete mode 100644 lib/pytz/zoneinfo/Europe/Podgorica delete mode 100644 lib/pytz/zoneinfo/Europe/Prague delete mode 100644 lib/pytz/zoneinfo/Europe/Riga delete mode 100644 lib/pytz/zoneinfo/Europe/Rome delete mode 100644 lib/pytz/zoneinfo/Europe/Samara delete mode 100644 lib/pytz/zoneinfo/Europe/San_Marino delete mode 100644 lib/pytz/zoneinfo/Europe/Sarajevo delete mode 100644 lib/pytz/zoneinfo/Europe/Simferopol delete mode 100644 lib/pytz/zoneinfo/Europe/Skopje delete mode 100644 lib/pytz/zoneinfo/Europe/Sofia delete mode 100644 lib/pytz/zoneinfo/Europe/Stockholm delete mode 100644 lib/pytz/zoneinfo/Europe/Tallinn delete mode 100644 lib/pytz/zoneinfo/Europe/Tirane delete mode 100644 lib/pytz/zoneinfo/Europe/Tiraspol delete mode 100644 lib/pytz/zoneinfo/Europe/Uzhgorod delete mode 100644 lib/pytz/zoneinfo/Europe/Vaduz delete mode 100644 lib/pytz/zoneinfo/Europe/Vatican delete mode 100644 lib/pytz/zoneinfo/Europe/Vienna delete mode 100644 lib/pytz/zoneinfo/Europe/Vilnius delete mode 100644 lib/pytz/zoneinfo/Europe/Volgograd delete mode 100644 lib/pytz/zoneinfo/Europe/Warsaw delete mode 100644 lib/pytz/zoneinfo/Europe/Zagreb delete mode 100644 lib/pytz/zoneinfo/Europe/Zaporozhye delete mode 100644 lib/pytz/zoneinfo/Europe/Zurich delete mode 100644 lib/pytz/zoneinfo/Factory delete mode 100644 lib/pytz/zoneinfo/GB delete mode 100644 lib/pytz/zoneinfo/GB-Eire delete mode 100644 lib/pytz/zoneinfo/GMT delete mode 100644 lib/pytz/zoneinfo/GMT+0 delete mode 100644 lib/pytz/zoneinfo/GMT-0 delete mode 100644 lib/pytz/zoneinfo/GMT0 delete mode 100644 lib/pytz/zoneinfo/Greenwich delete mode 100644 lib/pytz/zoneinfo/HST delete mode 100644 lib/pytz/zoneinfo/Hongkong delete mode 100644 lib/pytz/zoneinfo/Iceland delete mode 100644 lib/pytz/zoneinfo/Indian/Antananarivo delete mode 100644 lib/pytz/zoneinfo/Indian/Chagos delete mode 100644 lib/pytz/zoneinfo/Indian/Christmas delete mode 100644 lib/pytz/zoneinfo/Indian/Cocos delete mode 100644 lib/pytz/zoneinfo/Indian/Comoro delete mode 100644 lib/pytz/zoneinfo/Indian/Kerguelen delete mode 100644 lib/pytz/zoneinfo/Indian/Mahe delete mode 100644 lib/pytz/zoneinfo/Indian/Maldives delete mode 100644 lib/pytz/zoneinfo/Indian/Mauritius delete mode 100644 lib/pytz/zoneinfo/Indian/Mayotte delete mode 100644 lib/pytz/zoneinfo/Indian/Reunion delete mode 100644 lib/pytz/zoneinfo/Iran delete mode 100644 lib/pytz/zoneinfo/Israel delete mode 100644 lib/pytz/zoneinfo/Jamaica delete mode 100644 lib/pytz/zoneinfo/Japan delete mode 100644 lib/pytz/zoneinfo/Kwajalein delete mode 100644 lib/pytz/zoneinfo/Libya delete mode 100644 lib/pytz/zoneinfo/MET delete mode 100644 lib/pytz/zoneinfo/MST delete mode 100644 lib/pytz/zoneinfo/MST7MDT delete mode 100644 lib/pytz/zoneinfo/Mexico/BajaNorte delete mode 100644 lib/pytz/zoneinfo/Mexico/BajaSur delete mode 100644 lib/pytz/zoneinfo/Mexico/General delete mode 100644 lib/pytz/zoneinfo/Mideast/Riyadh87 delete mode 100644 lib/pytz/zoneinfo/Mideast/Riyadh88 delete mode 100644 lib/pytz/zoneinfo/Mideast/Riyadh89 delete mode 100644 lib/pytz/zoneinfo/NZ delete mode 100644 lib/pytz/zoneinfo/NZ-CHAT delete mode 100644 lib/pytz/zoneinfo/Navajo delete mode 100644 lib/pytz/zoneinfo/PRC delete mode 100644 lib/pytz/zoneinfo/PST8PDT delete mode 100644 lib/pytz/zoneinfo/Pacific/Apia delete mode 100644 lib/pytz/zoneinfo/Pacific/Auckland delete mode 100644 lib/pytz/zoneinfo/Pacific/Chatham delete mode 100644 lib/pytz/zoneinfo/Pacific/Chuuk delete mode 100644 lib/pytz/zoneinfo/Pacific/Easter delete mode 100644 lib/pytz/zoneinfo/Pacific/Efate delete mode 100644 lib/pytz/zoneinfo/Pacific/Enderbury delete mode 100644 lib/pytz/zoneinfo/Pacific/Fakaofo delete mode 100644 lib/pytz/zoneinfo/Pacific/Fiji delete mode 100644 lib/pytz/zoneinfo/Pacific/Funafuti delete mode 100644 lib/pytz/zoneinfo/Pacific/Galapagos delete mode 100644 lib/pytz/zoneinfo/Pacific/Gambier delete mode 100644 lib/pytz/zoneinfo/Pacific/Guadalcanal delete mode 100644 lib/pytz/zoneinfo/Pacific/Guam delete mode 100644 lib/pytz/zoneinfo/Pacific/Honolulu delete mode 100644 lib/pytz/zoneinfo/Pacific/Johnston delete mode 100644 lib/pytz/zoneinfo/Pacific/Kiritimati delete mode 100644 lib/pytz/zoneinfo/Pacific/Kosrae delete mode 100644 lib/pytz/zoneinfo/Pacific/Kwajalein delete mode 100644 lib/pytz/zoneinfo/Pacific/Majuro delete mode 100644 lib/pytz/zoneinfo/Pacific/Marquesas delete mode 100644 lib/pytz/zoneinfo/Pacific/Midway delete mode 100644 lib/pytz/zoneinfo/Pacific/Nauru delete mode 100644 lib/pytz/zoneinfo/Pacific/Niue delete mode 100644 lib/pytz/zoneinfo/Pacific/Norfolk delete mode 100644 lib/pytz/zoneinfo/Pacific/Noumea delete mode 100644 lib/pytz/zoneinfo/Pacific/Pago_Pago delete mode 100644 lib/pytz/zoneinfo/Pacific/Palau delete mode 100644 lib/pytz/zoneinfo/Pacific/Pitcairn delete mode 100644 lib/pytz/zoneinfo/Pacific/Pohnpei delete mode 100644 lib/pytz/zoneinfo/Pacific/Ponape delete mode 100644 lib/pytz/zoneinfo/Pacific/Port_Moresby delete mode 100644 lib/pytz/zoneinfo/Pacific/Rarotonga delete mode 100644 lib/pytz/zoneinfo/Pacific/Saipan delete mode 100644 lib/pytz/zoneinfo/Pacific/Samoa delete mode 100644 lib/pytz/zoneinfo/Pacific/Tahiti delete mode 100644 lib/pytz/zoneinfo/Pacific/Tarawa delete mode 100644 lib/pytz/zoneinfo/Pacific/Tongatapu delete mode 100644 lib/pytz/zoneinfo/Pacific/Truk delete mode 100644 lib/pytz/zoneinfo/Pacific/Wake delete mode 100644 lib/pytz/zoneinfo/Pacific/Wallis delete mode 100644 lib/pytz/zoneinfo/Pacific/Yap delete mode 100644 lib/pytz/zoneinfo/Poland delete mode 100644 lib/pytz/zoneinfo/Portugal delete mode 100644 lib/pytz/zoneinfo/ROC delete mode 100644 lib/pytz/zoneinfo/ROK delete mode 100644 lib/pytz/zoneinfo/Singapore delete mode 100644 lib/pytz/zoneinfo/Turkey delete mode 100644 lib/pytz/zoneinfo/UCT delete mode 100644 lib/pytz/zoneinfo/US/Alaska delete mode 100644 lib/pytz/zoneinfo/US/Aleutian delete mode 100644 lib/pytz/zoneinfo/US/Arizona delete mode 100644 lib/pytz/zoneinfo/US/Central delete mode 100644 lib/pytz/zoneinfo/US/East-Indiana delete mode 100644 lib/pytz/zoneinfo/US/Eastern delete mode 100644 lib/pytz/zoneinfo/US/Hawaii delete mode 100644 lib/pytz/zoneinfo/US/Indiana-Starke delete mode 100644 lib/pytz/zoneinfo/US/Michigan delete mode 100644 lib/pytz/zoneinfo/US/Mountain delete mode 100644 lib/pytz/zoneinfo/US/Pacific delete mode 100644 lib/pytz/zoneinfo/US/Pacific-New delete mode 100644 lib/pytz/zoneinfo/US/Samoa delete mode 100644 lib/pytz/zoneinfo/UTC delete mode 100644 lib/pytz/zoneinfo/Universal delete mode 100644 lib/pytz/zoneinfo/W-SU delete mode 100644 lib/pytz/zoneinfo/WET delete mode 100644 lib/pytz/zoneinfo/Zulu delete mode 100644 lib/pytz/zoneinfo/iso3166.tab delete mode 100644 lib/pytz/zoneinfo/localtime delete mode 100644 lib/pytz/zoneinfo/posixrules delete mode 100644 lib/pytz/zoneinfo/zone.tab delete mode 100644 lib/six.py diff --git a/lib/dateutil_py2/LICENSE b/lib/dateutil_py2/LICENSE deleted file mode 100644 index c5b5923c55e5..000000000000 --- a/lib/dateutil_py2/LICENSE +++ /dev/null @@ -1,259 +0,0 @@ -A. HISTORY OF THE SOFTWARE -========================== - -Python was created in the early 1990s by Guido van Rossum at Stichting -Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands -as a successor of a language called ABC. Guido remains Python's -principal author, although it includes many contributions from others. - -In 1995, Guido continued his work on Python at the Corporation for -National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) -in Reston, Virginia where he released several versions of the -software. - -In May 2000, Guido and the Python core development team moved to -BeOpen.com to form the BeOpen PythonLabs team. In October of the same -year, the PythonLabs team moved to Digital Creations (now Zope -Corporation, see http://www.zope.com). In 2001, the Python Software -Foundation (PSF, see http://www.python.org/psf/) was formed, a -non-profit organization created specifically to own Python-related -Intellectual Property. Zope Corporation is a sponsoring member of -the PSF. - -All Python releases are Open Source (see http://www.opensource.org for -the Open Source Definition). Historically, most, but not all, Python -releases have also been GPL-compatible; the table below summarizes -the various releases. - - Release Derived Year Owner GPL- - from compatible? (1) - - 0.9.0 thru 1.2 1991-1995 CWI yes - 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes - 1.6 1.5.2 2000 CNRI no - 2.0 1.6 2000 BeOpen.com no - 1.6.1 1.6 2001 CNRI yes (2) - 2.1 2.0+1.6.1 2001 PSF no - 2.0.1 2.0+1.6.1 2001 PSF yes - 2.1.1 2.1+2.0.1 2001 PSF yes - 2.2 2.1.1 2001 PSF yes - 2.1.2 2.1.1 2002 PSF yes - 2.1.3 2.1.2 2002 PSF yes - 2.2.1 2.2 2002 PSF yes - 2.2.2 2.2.1 2002 PSF yes - 2.2.3 2.2.2 2003 PSF yes - 2.3 2.2.2 2002-2003 PSF yes - -Footnotes: - -(1) GPL-compatible doesn't mean that we're distributing Python under - the GPL. All Python licenses, unlike the GPL, let you distribute - a modified version without making your changes open source. The - GPL-compatible licenses make it possible to combine Python with - other software that is released under the GPL; the others don't. - -(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, - because its license has a choice of law clause. According to - CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 - is "not incompatible" with the GPL. - -Thanks to the many outside volunteers who have worked under Guido's -direction to make these releases possible. - - -B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON -=============================================================== - -PSF LICENSE AGREEMENT FOR PYTHON 2.3 ------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.3 software in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.3 -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001, 2002, 2003 Python Software Foundation; All Rights Reserved" are -retained in Python 2.3 alone or in any derivative version prepared by -Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.3 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.3. - -4. PSF is making Python 2.3 available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python 2.3, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 -------------------------------------------- - -BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 - -1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an -office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the -Individual or Organization ("Licensee") accessing and otherwise using -this software in source or binary form and its associated -documentation ("the Software"). - -2. Subject to the terms and conditions of this BeOpen Python License -Agreement, BeOpen hereby grants Licensee a non-exclusive, -royalty-free, world-wide license to reproduce, analyze, test, perform -and/or display publicly, prepare derivative works, distribute, and -otherwise use the Software alone or in any derivative version, -provided, however, that the BeOpen Python License is retained in the -Software, alone or in any derivative version prepared by Licensee. - -3. BeOpen is making the Software available to Licensee on an "AS IS" -basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE -SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS -AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY -DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -5. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -6. This License Agreement shall be governed by and interpreted in all -respects by the law of the State of California, excluding conflict of -law provisions. Nothing in this License Agreement shall be deemed to -create any relationship of agency, partnership, or joint venture -between BeOpen and Licensee. This License Agreement does not grant -permission to use BeOpen trademarks or trade names in a trademark -sense to endorse or promote products or services of Licensee, or any -third party. As an exception, the "BeOpen Python" logos available at -http://www.pythonlabs.com/logos.html may be used according to the -permissions granted on that web page. - -7. By copying, installing or otherwise using the software, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - - -CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 ---------------------------------------- - -1. This LICENSE AGREEMENT is between the Corporation for National -Research Initiatives, having an office at 1895 Preston White Drive, -Reston, VA 20191 ("CNRI"), and the Individual or Organization -("Licensee") accessing and otherwise using Python 1.6.1 software in -source or binary form and its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, CNRI -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 1.6.1 -alone or in any derivative version, provided, however, that CNRI's -License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) -1995-2001 Corporation for National Research Initiatives; All Rights -Reserved" are retained in Python 1.6.1 alone or in any derivative -version prepared by Licensee. Alternately, in lieu of CNRI's License -Agreement, Licensee may substitute the following text (omitting the -quotes): "Python 1.6.1 is made available subject to the terms and -conditions in CNRI's License Agreement. This Agreement together with -Python 1.6.1 may be located on the Internet using the following -unique, persistent identifier (known as a handle): 1895.22/1013. This -Agreement may also be obtained from a proxy server on the Internet -using the following URL: http://hdl.handle.net/1895.22/1013". - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 1.6.1 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 1.6.1. - -4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" -basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. This License Agreement shall be governed by the federal -intellectual property law of the United States, including without -limitation the federal copyright law, and, to the extent such -U.S. federal law does not apply, by the law of the Commonwealth of -Virginia, excluding Virginia's conflict of law provisions. -Notwithstanding the foregoing, with regard to derivative works based -on Python 1.6.1 that incorporate non-separable material that was -previously distributed under the GNU General Public License (GPL), the -law of the Commonwealth of Virginia shall govern this License -Agreement only as to issues arising under or with respect to -Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this -License Agreement shall be deemed to create any relationship of -agency, partnership, or joint venture between CNRI and Licensee. This -License Agreement does not grant permission to use CNRI trademarks or -trade name in a trademark sense to endorse or promote products or -services of Licensee, or any third party. - -8. By clicking on the "ACCEPT" button where indicated, or by copying, -installing or otherwise using Python 1.6.1, Licensee agrees to be -bound by the terms and conditions of this License Agreement. - - ACCEPT - - -CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 --------------------------------------------------- - -Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, -The Netherlands. All rights reserved. - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Stichting Mathematisch -Centrum or CWI not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO -THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE -FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/lib/dateutil_py2/NEWS b/lib/dateutil_py2/NEWS deleted file mode 100644 index 8738e849e29c..000000000000 --- a/lib/dateutil_py2/NEWS +++ /dev/null @@ -1,143 +0,0 @@ - -Version 1.5 ------------ - -- As reported by Mathieu Bridon, rrules were matching the bysecond rules - incorrectly against byminute in some circumstances when the SECONDLY - frequency was in use, due to a copy & paste bug. The problem has been - unittested and corrected. - -- Adam Ryan reported a problem in the relativedelta implementation which - affected the yearday parameter in the month of January specifically. - This has been unittested and fixed. - -- Updated timezone information. - - -Version 1.4.1 -------------- - -- Updated timezone information. - - -Version 1.4 ------------ - -- Fixed another parser precision problem on conversion of decimal seconds - to microseconds, as reported by Erik Brown. Now these issues are gone - for real since it's not using floating point arithmetic anymore. - -- Fixed case where tzrange.utcoffset and tzrange.dst() might fail due - to a date being used where a datetime was expected (reported and fixed - by Lennart Regebro). - -- Prevent tzstr from introducing daylight timings in strings that didn't - specify them (reported by Lennart Regebro). - -- Calls like gettz("GMT+3") and gettz("UTC-2") will now return the - expected values, instead of the TZ variable behavior. - -- Fixed DST signal handling in zoneinfo files. Reported by - Nicholas F. Fabry and John-Mark Gurney. - - -Version 1.3 ------------ - -- Fixed precision problem on conversion of decimal seconds to - microseconds, as reported by Skip Montanaro. - -- Fixed bug in constructor of parser, and converted parser classes to - new-style classes. Original report and patch by Michael Elsdörfer. - -- Initialize tzid and comps in tz.py, to prevent the code from ever - raising a NameError (even with broken files). Johan Dahlin suggested - the fix after a pyflakes run. - -- Version is now published in dateutil.__version__, as requested - by Darren Dale. - -- All code is compatible with new-style division. - - -Version 1.2 ------------ - -- Now tzfile will round timezones to full-minutes if necessary, - since Python's datetime doesn't support sub-minute offsets. - Thanks to Ilpo Nyyssönen for reporting the issue. - -- Removed bare string exceptions, as reported and fixed by - Wilfredo Sánchez Vega. - -- Fix bug in leap count parsing (reported and fixed by Eugene Oden). - - -Version 1.1 ------------ - -- Fixed rrule byyearday handling. Abramo Bagnara pointed out that - RFC2445 allows negative numbers. - -- Fixed --prefix handling in setup.py (by Sidnei da Silva). - -- Now tz.gettz() returns a tzlocal instance when not given any - arguments and no other timezone information is found. - -- Updating timezone information to version 2005q. - - -Version 1.0 ------------ - -- Fixed parsing of XXhXXm formatted time after day/month/year - has been parsed. - -- Added patch by Jeffrey Harris optimizing rrule.__contains__. - - -Version 0.9 ------------ - -- Fixed pickling of timezone types, as reported by - Andreas Köhler. - -- Implemented internal timezone information with binary - timezone files [1]. datautil.tz.gettz() function will now - try to use the system timezone files, and fallback to - the internal versions. It's also possible to ask for - the internal versions directly by using - dateutil.zoneinfo.gettz(). - -- New tzwin timezone type, allowing access to Windows - internal timezones (contributed by Jeffrey Harris). - -- Fixed parsing of unicode date strings. - -- Accept parserinfo instances as the parser constructor - parameter, besides parserinfo (sub)classes. - -- Changed weekday to spell the not-set n value as None - instead of 0. - -- Fixed other reported bugs. - -[1] http://www.twinsun.com/tz/tz-link.htm - - -Version 0.5 ------------ - -- Removed FREQ_ prefix from rrule frequency constants - WARNING: this breaks compatibility with previous versions. - -- Fixed rrule.between() for cases where "after" is achieved - before even starting, as reported by Andreas Köhler. - -- Fixed two digit zero-year parsing (such as 31-Dec-00), as - reported by Jim Abramson, and included test case for this. - -- Sort exdate and rdate before iterating over them, so that - it's not necessary to sort them before adding to the rruleset, - as reported by Nicholas Piper. - diff --git a/lib/dateutil_py2/README b/lib/dateutil_py2/README deleted file mode 100644 index dbe7988ce499..000000000000 --- a/lib/dateutil_py2/README +++ /dev/null @@ -1,1970 +0,0 @@ -## This file is in the moin format. The latest version is found -## at https://moin.conectiva.com.br/DateUtil - -== Contents == -[[TableOfContents]] - -== Description == -The '''dateutil''' module provides powerful extensions to -the standard '''datetime''' module, available in Python 2.3+. - -== Features == - - * Computing of relative deltas (next month, next year, - next monday, last week of month, etc); - - * Computing of relative deltas between two given - date and/or datetime objects; - - * Computing of dates based on very flexible recurrence rules, - using a superset of the - [ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] - specification. Parsing of RFC strings is supported as well. - - * Generic parsing of dates in almost any string format; - - * Timezone (tzinfo) implementations for tzfile(5) format - files (/etc/localtime, /usr/share/zoneinfo, etc), TZ - environment string (in all known formats), iCalendar - format files, given ranges (with help from relative deltas), - local machine timezone, fixed offset timezone, UTC timezone, - and Windows registry-based time zones. - - * Internal up-to-date world timezone information based on - Olson's database. - - * Computing of Easter Sunday dates for any given year, - using Western, Orthodox or Julian algorithms; - - * More than 400 test cases. - -== Quick example == -Here's a snapshot, just to give an idea about the power of the -package. For more examples, look at the documentation below. - -Suppose you want to know how much time is left, in -years/months/days/etc, before the next easter happening on a -year with a Friday 13th in August, and you want to get today's -date out of the "date" unix system command. Here is the code: -{{{ -from dateutil.relativedelta import * -from dateutil.easter import * -from dateutil.rrule import * -from dateutil.parser import * -from datetime import * -import commands -import os -now = parse(commands.getoutput("date")) -today = now.date() -year = rrule(YEARLY,bymonth=8,bymonthday=13,byweekday=FR)[0].year -rdelta = relativedelta(easter(year), today) -print "Today is:", today -print "Year with next Aug 13th on a Friday is:", year -print "How far is the Easter of that year:", rdelta -print "And the Easter of that year is:", today+rdelta -}}} - -And here's the output: -{{{ -Today is: 2003-10-11 -Year with next Aug 13th on a Friday is: 2004 -How far is the Easter of that year: relativedelta(months=+6) -And the Easter of that year is: 2004-04-11 -}}} - -{i} Being exactly 6 months ahead was '''really''' a coincidence :) - -== Download == -The following files are available. - * attachment:python-dateutil-1.0.tar.bz2 - * attachment:python-dateutil-1.0-1.noarch.rpm - -== Author == -The dateutil module was written by GustavoNiemeyer . - -== Documentation == -The following modules are available. - -=== relativedelta === -This module offers the '''relativedelta''' type, which is based -on the specification of the excelent work done by M.-A. Lemburg in his -[http://www.egenix.com/files/python/mxDateTime.html mxDateTime] -extension. However, notice that this type '''does not''' implement the -same algorithm as his work. Do not expect it to behave like -{{{mxDateTime}}}'s counterpart. - -==== relativedelta type ==== - -There's two different ways to build a relativedelta instance. The -first one is passing it two {{{date}}}/{{{datetime}}} instances: -{{{ -relativedelta(datetime1, datetime2) -}}} - -This will build the relative difference between {{{datetime1}}} and -{{{datetime2}}}, so that the following constraint is always true: -{{{ -datetime2+relativedelta(datetime1, datetime2) == datetime1 -}}} - -Notice that instead of {{{datetime}}} instances, you may use -{{{date}}} instances, or a mix of both. - -And the other way is to use any of the following keyword arguments: - - year, month, day, hour, minute, second, microsecond:: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds:: - Relative information, may be negative. - - weekday:: - One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These - instances may receive a parameter {{{n}}}, specifying the {{{n}}}th - weekday, which could be positive or negative (like {{{MO(+2)}}} or - {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}. - You can also use an integer, where {{{0=MO}}}. Notice that, - for example, if the calculated date is already Monday, using - {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context), - won't change the day. - - leapdays:: - Will add given days to the date found, but only if the computed - year is a leap year and the computed date is post 28 of february. - - yearday, nlyearday:: - Set the yearday or the non-leap year day (jump leap days). - These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}} - information. - -==== Behavior of operations ==== -If you're curious about exactly how the relative delta will act -on operations, here is a description of its behavior. - - 1. Calculate the absolute year, using the {{{year}}} argument, or the - original datetime year, if the argument is not present. - 1. Add the relative {{{years}}} argument to the absolute year. - 1. Do steps 1 and 2 for {{{month}}}/{{{months}}}. - 1. Calculate the absolute day, using the {{{day}}} argument, or the - original datetime day, if the argument is not present. Then, subtract - from the day until it fits in the year and month found after their - operations. - 1. Add the relative {{{days}}} argument to the absolute day. Notice - that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}. - 1. If {{{leapdays}}} is present, the computed year is a leap year, and - the computed month is after february, remove one day from the found date. - 1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}}, - {{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}. - 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th - occurrence of the given weekday. - -==== Examples ==== - -Let's begin our trip. -{{{ ->>> from datetime import *; from dateutil.relativedelta import * ->>> import calendar -}}} - -Store some values. -{{{ ->>> NOW = datetime.now() ->>> TODAY = date.today() ->>> NOW -datetime.datetime(2003, 9, 17, 20, 54, 47, 282310) ->>> TODAY -datetime.date(2003, 9, 17) -}}} - -Next month. -{{{ ->>> NOW+relativedelta(months=+1) -datetime.datetime(2003, 10, 17, 20, 54, 47, 282310) -}}} - -Next month, plus one week. -{{{ ->>> NOW+relativedelta(months=+1, weeks=+1) -datetime.datetime(2003, 10, 24, 20, 54, 47, 282310) -}}} - -Next month, plus one week, at 10am. -{{{ ->>> TODAY+relativedelta(months=+1, weeks=+1, hour=10) -datetime.datetime(2003, 10, 24, 10, 0) -}}} - -Let's try the other way around. Notice that the -hour setting we get in the relativedelta is relative, -since it's a difference, and the weeks parameter -has gone. -{{{ ->>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY) -relativedelta(months=+1, days=+7, hours=+10) -}}} - -One month before one year. -{{{ ->>> NOW+relativedelta(years=+1, months=-1) -datetime.datetime(2004, 8, 17, 20, 54, 47, 282310) -}}} - -How does it handle months with different numbers of days? -Notice that adding one month will never cross the month -boundary. -{{{ ->>> date(2003,1,27)+relativedelta(months=+1) -datetime.date(2003, 2, 27) ->>> date(2003,1,31)+relativedelta(months=+1) -datetime.date(2003, 2, 28) ->>> date(2003,1,31)+relativedelta(months=+2) -datetime.date(2003, 3, 31) -}}} - -The logic for years is the same, even on leap years. -{{{ ->>> date(2000,2,28)+relativedelta(years=+1) -datetime.date(2001, 2, 28) ->>> date(2000,2,29)+relativedelta(years=+1) -datetime.date(2001, 2, 28) - ->>> date(1999,2,28)+relativedelta(years=+1) -datetime.date(2000, 2, 28) ->>> date(1999,3,1)+relativedelta(years=+1) -datetime.date(2000, 3, 1) - ->>> date(2001,2,28)+relativedelta(years=-1) -datetime.date(2000, 2, 28) ->>> date(2001,3,1)+relativedelta(years=-1) -datetime.date(2000, 3, 1) -}}} - -Next friday. -{{{ ->>> TODAY+relativedelta(weekday=FR) -datetime.date(2003, 9, 19) - ->>> TODAY+relativedelta(weekday=calendar.FRIDAY) -datetime.date(2003, 9, 19) -}}} - -Last friday in this month. -{{{ ->>> TODAY+relativedelta(day=31, weekday=FR(-1)) -datetime.date(2003, 9, 26) -}}} - -Next wednesday (it's today!). -{{{ ->>> TODAY+relativedelta(weekday=WE(+1)) -datetime.date(2003, 9, 17) -}}} - -Next wednesday, but not today. -{{{ ->>> TODAY+relativedelta(days=+1, weekday=WE(+1)) -datetime.date(2003, 9, 24) -}}} - -Following -[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation] -find the first day of the 15th week of 1997. -{{{ ->>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14) -datetime.datetime(1997, 4, 7, 0, 0) -}}} - -How long ago has the millennium changed? -{{{ ->>> relativedelta(NOW, date(2001,1,1)) -relativedelta(years=+2, months=+8, days=+16, - hours=+20, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -How old is John? -{{{ ->>> johnbirthday = datetime(1978, 4, 5, 12, 0) ->>> relativedelta(NOW, johnbirthday) -relativedelta(years=+25, months=+5, days=+12, - hours=+8, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -It works with dates too. -{{{ ->>> relativedelta(TODAY, johnbirthday) -relativedelta(years=+25, months=+5, days=+11, hours=+12) -}}} - -Obtain today's date using the yearday: -{{{ ->>> date(2003, 1, 1)+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -We can use today's date, since yearday should be absolute -in the given year: -{{{ ->>> TODAY+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -Last year it should be in the same day: -{{{ ->>> date(2002, 1, 1)+relativedelta(yearday=260) -datetime.date(2002, 9, 17) -}}} - -But not in a leap year: -{{{ ->>> date(2000, 1, 1)+relativedelta(yearday=260) -datetime.date(2000, 9, 16) -}}} - -We can use the non-leap year day to ignore this: -{{{ ->>> date(2000, 1, 1)+relativedelta(nlyearday=260) -datetime.date(2000, 9, 17) -}}} - -=== rrule === -The rrule module offers a small, complete, and very fast, implementation -of the recurrence rules documented in the -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including -support for caching of results. - -==== rrule type ==== -That's the base of the rrule operation. It accepts all the keywords -defined in the RFC as its constructor parameters (except {{{byday}}}, -which was renamed to {{{byweekday}}}) and more. The constructor -prototype is: -{{{ -rrule(freq) -}}} - -Where {{{freq}}} must be one of {{{YEARLY}}}, {{{MONTHLY}}}, -{{{WEEKLY}}}, {{{DAILY}}}, {{{HOURLY}}}, {{{MINUTELY}}}, -or {{{SECONDLY}}}. - -Additionally, it supports the following keyword arguments: - - cache:: - If given, it must be a boolean value specifying to enable - or disable caching of results. If you will use the same - {{{rrule}}} instance multiple times, enabling caching will - improve the performance considerably. - - dtstart:: - The recurrence start. Besides being the base for the - recurrence, missing parameters in the final recurrence - instances will also be extracted from this date. If not - given, {{{datetime.now()}}} will be used instead. - - interval:: - The interval between each {{{freq}}} iteration. For example, - when using {{{YEARLY}}}, an interval of {{{2}}} means - once every two years, but with {{{HOURLY}}}, it means - once every two hours. The default interval is {{{1}}}. - - wkst:: - The week start day. Must be one of the {{{MO}}}, {{{TU}}}, - {{{WE}}} constants, or an integer, specifying the first day - of the week. This will affect recurrences based on weekly - periods. The default week start is got from - {{{calendar.firstweekday()}}}, and may be modified by - {{{calendar.setfirstweekday()}}}. - - count:: - How many occurrences will be generated. - - until:: - If given, this must be a {{{datetime}}} instance, that will - specify the limit of the recurrence. If a recurrence instance - happens to be the same as the {{{datetime}}} instance given - in the {{{until}}} keyword, this will be the last occurrence. - - bysetpos:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each given integer will - specify an occurrence number, corresponding to the nth - occurrence of the rule inside the frequency period. For - example, a {{{bysetpos}}} of {{{-1}}} if combined with a - {{{MONTHLY}}} frequency, and a {{{byweekday}}} of - {{{(MO, TU, WE, TH, FR)}}}, will result in the last work - day of every month. - - bymonth:: - If given, it must be either an integer, or a sequence of - integers, meaning the months to apply the recurrence to. - - bymonthday:: - If given, it must be either an integer, or a sequence of - integers, meaning the month days to apply the recurrence to. - - byyearday:: - If given, it must be either an integer, or a sequence of - integers, meaning the year days to apply the recurrence to. - - byweekno:: - If given, it must be either an integer, or a sequence of - integers, meaning the week numbers to apply the recurrence - to. Week numbers have the meaning described in ISO8601, - that is, the first week of the year is that containing at - least four days of the new year. - - byweekday:: - If given, it must be either an integer ({{{0 == MO}}}), a - sequence of integers, one of the weekday constants - ({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants. - When given, these variables will define the weekdays where - the recurrence will be applied. It's also possible to use - an argument {{{n}}} for the weekday instances, which will - mean the {{{n}}}''th'' occurrence of this weekday in the - period. For example, with {{{MONTHLY}}}, or with - {{{YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}} - in {{{byweekday}}} will specify the first friday of the - month where the recurrence happens. Notice that in the RFC - documentation, this is specified as {{{BYDAY}}}, but was - renamed to avoid the ambiguity of that keyword. - - byhour:: - If given, it must be either an integer, or a sequence of - integers, meaning the hours to apply the recurrence to. - - byminute:: - If given, it must be either an integer, or a sequence of - integers, meaning the minutes to apply the recurrence to. - - bysecond:: - If given, it must be either an integer, or a sequence of - integers, meaning the seconds to apply the recurrence to. - - byeaster:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each integer will define - an offset from the Easter Sunday. Passing the offset - {{{0}}} to {{{byeaster}}} will yield the Easter Sunday - itself. This is an extension to the RFC specification. - -==== rrule methods ==== -The following methods are available in {{{rrule}}} instances: - - rrule.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.between(after, before, inc=False):: - 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. - - rrule.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rrule}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -rr = rrule(...) -if datetime(...) in rr: - ... -print rr[0] -print rr[-1] -print rr[1:2] -print rr[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== Notes ==== - - * The rrule type has no {{{byday}}} keyword. The equivalent keyword - has been replaced by the {{{byweekday}}} keyword, to remove the - ambiguity present in the original keyword. - - * Unlike documented in the RFC, the starting datetime ({{{dtstart}}}) - is not the first recurrence instance, unless it does fit in the - specified rules. In a python module context, this behavior makes more - sense than otherwise. Notice that you can easily get the original - behavior by using a rruleset and adding the {{{dtstart}}} as an - {{{rdate}}} recurrence. - - * Unlike documented in the RFC, every keyword is valid on every - frequency (the RFC documents that {{{byweekno}}} is only valid - on yearly frequencies, for example). - - * In addition to the documented keywords, a {{{byeaster}}} keyword - was introduced, making it easy to compute recurrent events relative - to the Easter Sunday. - -==== rrule examples ==== -These examples were converted from the RFC. - -Prepare the environment. -{{{ ->>> from dateutil.rrule import * ->>> from dateutil.parser import * ->>> from datetime import * - ->>> import pprint ->>> import sys ->>> sys.displayhook = pprint.pprint -}}} - -Daily, for 10 occurrences. -{{{ ->>> list(rrule(DAILY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0)] -}}} - -Daily until December 24, 1997 -{{{ ->>> list(rrule(DAILY, - dtstart=parse("19970902T090000"), - until=parse("19971224T000000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - (...) - datetime.datetime(1997, 12, 21, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1997, 12, 23, 9, 0)] -}}} - -Every other day, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=2, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0)] -}}} - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=10, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Everyday in January, for 3 years. -{{{ ->>> list(rrule(YEARLY, bymonth=1, byweekday=range(7), - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -[datetime.datetime(1998, 1, 1, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - (...) - datetime.datetime(1998, 1, 30, 9, 0), - datetime.datetime(1998, 1, 31, 9, 0), - datetime.datetime(1999, 1, 1, 9, 0), - datetime.datetime(1999, 1, 2, 9, 0), - (...) - datetime.datetime(1999, 1, 30, 9, 0), - datetime.datetime(1999, 1, 31, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0), - (...) - datetime.datetime(2000, 1, 29, 9, 0), - datetime.datetime(2000, 1, 31, 9, 0)] -}}} - -Same thing, in another way. -{{{ ->>> list(rrule(DAILY, bymonth=1, - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -(...) -}}} - -Weekly for 10 occurrences. -{{{ ->>> list(rrule(WEEKLY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 21, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Every other week, 6 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 11, 9, 0)] -}}} - -Weekly on Tuesday and Thursday for 5 weeks. -{{{ ->>> list(rrule(WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 25, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0)] -}}} - -Every other week on Tuesday and Thursday, for 8 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=8, - wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 16, 9, 0)] -}}} - -Monthly on the 1st Friday for ten occurrences. -{{{ ->>> list(rrule(MONTHLY, count=10, byweekday=FR(1), - dtstart=parse("19970905T090000"))) -[datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 10, 3, 9, 0), - datetime.datetime(1997, 11, 7, 9, 0), - datetime.datetime(1997, 12, 5, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - datetime.datetime(1998, 2, 6, 9, 0), - datetime.datetime(1998, 3, 6, 9, 0), - datetime.datetime(1998, 4, 3, 9, 0), - datetime.datetime(1998, 5, 1, 9, 0), - datetime.datetime(1998, 6, 5, 9, 0)] -}}} - -Every other month on the 1st and last Sunday of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=10, - byweekday=(SU(1), SU(-1)), - dtstart=parse("19970907T090000"))) -[datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0), - datetime.datetime(1998, 1, 4, 9, 0), - datetime.datetime(1998, 1, 25, 9, 0), - datetime.datetime(1998, 3, 1, 9, 0), - datetime.datetime(1998, 3, 29, 9, 0), - datetime.datetime(1998, 5, 3, 9, 0), - datetime.datetime(1998, 5, 31, 9, 0)] -}}} - -Monthly on the second to last Monday of the month for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, byweekday=MO(-2), - dtstart=parse("19970922T090000"))) -[datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 20, 9, 0), - datetime.datetime(1997, 11, 17, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1998, 1, 19, 9, 0), - datetime.datetime(1998, 2, 16, 9, 0)] -}}} - -Monthly on the third to the last day of the month, for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, bymonthday=-3, - dtstart=parse("19970928T090000"))) -[datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 10, 29, 9, 0), - datetime.datetime(1997, 11, 28, 9, 0), - datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1998, 1, 29, 9, 0), - datetime.datetime(1998, 2, 26, 9, 0)] -}}} - -Monthly on the 2nd and 15th of the month for 5 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(2,15), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 15, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0)] -}}} - -Monthly on the first and last day of the month for 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(-1,1,), - dtstart=parse("1997090 -2T090000"))) -[datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 1, 9, 0), - datetime.datetime(1997, 10, 31, 9, 0), - datetime.datetime(1997, 11, 1, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0)] -}}} - -Every 18 months on the 10th thru 15th of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=18, count=10, - bymonthday=range(10,16), - dtstart=parse("19970910T090000"))) -[datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 13, 9, 0), - datetime.datetime(1997, 9, 14, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1999, 3, 10, 9, 0), - datetime.datetime(1999, 3, 11, 9, 0), - datetime.datetime(1999, 3, 12, 9, 0), - datetime.datetime(1999, 3, 13, 9, 0)] -}}} - -Every Tuesday, every other month, 6 occurences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=6, byweekday=TU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Yearly in June and July for 10 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, bymonth=(6,7), - dtstart=parse("19970610T0900 -00"))) -[datetime.datetime(1997, 6, 10, 9, 0), - datetime.datetime(1997, 7, 10, 9, 0), - datetime.datetime(1998, 6, 10, 9, 0), - datetime.datetime(1998, 7, 10, 9, 0)] -}}} - -Every 3rd year on the 1st, 100th and 200th day for 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, interval=3, byyearday=(1,100,200), - dtstart=parse("19970101T090000"))) -[datetime.datetime(1997, 1, 1, 9, 0), - datetime.datetime(1997, 4, 10, 9, 0), - datetime.datetime(1997, 7, 19, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0)] -}}} - -Every 20th Monday of the year, 3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekday=MO(20), - dtstart=parse("19970519T090000"))) -[datetime.datetime(1997, 5, 19, 9, 0), - datetime.datetime(1998, 5, 18, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -Monday of week number 20 (where the default start of the week is Monday), -3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekno=20, byweekday=MO, - dtstart=parse("19970512T090000"))) -[datetime.datetime(1997, 5, 12, 9, 0), - datetime.datetime(1998, 5, 11, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -The week number 1 may be in the last year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=1, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1999, 1, 4, 9, 0), - datetime.datetime(2000, 1, 3, 9, 0)] -}}} - -And the week numbers greater than 51 may be in the next year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=52, byweekday=SU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 28, 9, 0), - datetime.datetime(1998, 12, 27, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0)] -}}} - -Only some years have week number 53: -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=53, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 12, 28, 9, 0), - datetime.datetime(2004, 12, 27, 9, 0), - datetime.datetime(2009, 12, 28, 9, 0)] -}}} - -Every Friday the 13th, 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, byweekday=FR, bymonthday=13, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 2, 13, 9, 0), - datetime.datetime(1998, 3, 13, 9, 0), - datetime.datetime(1998, 11, 13, 9, 0), - datetime.datetime(1999, 8, 13, 9, 0)] -}}} - -Every four years, the first Tuesday after a Monday in November, -3 occurrences (U.S. Presidential Election day): -{{{ ->>> list(rrule(YEARLY, interval=4, count=3, bymonth=11, - byweekday=TU, bymonthday=(2,3,4,5,6,7,8), - dtstart=parse("19961105T090000"))) -[datetime.datetime(1996, 11, 5, 9, 0), - datetime.datetime(2000, 11, 7, 9, 0), - datetime.datetime(2004, 11, 2, 9, 0)] -}}} - -The 3rd instance into the month of one of Tuesday, Wednesday or -Thursday, for the next 3 months: -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(TU,WE,TH), - bysetpos=3, dtstart=parse("19970904T090000"))) -[datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 11, 6, 9, 0)] -}}} - -The 2nd to last weekday of the month, 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), - bysetpos=-2, dtstart=parse("19970929T090000"))) -[datetime.datetime(1997, 9, 29, 9, 0), - datetime.datetime(1997, 10, 30, 9, 0), - datetime.datetime(1997, 11, 27, 9, 0)] -}}} - -Every 3 hours from 9:00 AM to 5:00 PM on a specific day. -{{{ ->>> list(rrule(HOURLY, interval=3, - dtstart=parse("19970902T090000"), - until=parse("19970902T170000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 15, 0)] -}}} - -Every 15 minutes for 6 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=15, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 15), - datetime.datetime(1997, 9, 2, 9, 30), - datetime.datetime(1997, 9, 2, 9, 45), - datetime.datetime(1997, 9, 2, 10, 0), - datetime.datetime(1997, 9, 2, 10, 15)] -}}} - -Every hour and a half for 4 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=90, count=4, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 10, 30), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 13, 30)] -}}} - -Every 20 minutes from 9:00 AM to 4:40 PM for two days. -{{{ ->>> list(rrule(MINUTELY, interval=20, count=48, - byhour=range(9,17), byminute=(0,20,40), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 20), - (...) - datetime.datetime(1997, 9, 2, 16, 20), - datetime.datetime(1997, 9, 2, 16, 40), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 3, 9, 20), - (...) - datetime.datetime(1997, 9, 3, 16, 20), - datetime.datetime(1997, 9, 3, 16, 40)] -}}} - -An example where the days generated makes a difference because of {{{wkst}}}. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=MO, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 10, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 24, 9, 0)] - ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=SU, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 17, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 31, 9, 0)] -}}} - -==== rruleset type ==== -The {{{rruleset}}} type allows more complex recurrence setups, mixing -multiple rules, dates, exclusion rules, and exclusion dates. -The type constructor takes the following keyword arguments: - - cache:: - If True, caching of results will be enabled, improving performance - of multiple queries considerably. - -==== rruleset methods ==== -The following methods are available: - - rruleset.rrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - generation. - - rruleset.rdate(dt):: - Include the given {{{datetime}}} instance in the recurrence - set generation. - - rruleset.exrule(rrule):: - 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. - - rruleset.exdate(dt):: - 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. - - rruleset.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.between(after, before, inc=False):: - 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. - - rruleset.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rruleset}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -set = rruleset(...) -if datetime(...) in set: - ... -print set[0] -print set[-1] -print set[1:2] -print set[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== rruleset examples ==== -Daily, for 7 days, jumping Saturday and Sunday occurrences. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(DAILY, count=7, - dtstart=parse("19970902T090000"))) ->>> set.exrule(rrule(YEARLY, byweekday=(SA,SU), - dtstart=parse("19970902T090000"))) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0)] -}}} - -Weekly, for 4 weeks, plus one time on day 7, and not on day 16. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(WEEKLY, count=4, - dtstart=parse("19970902T090000"))) ->>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0)) ->>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0)) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0)] -}}} - -==== rrulestr() function ==== -The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes. -The function prototype is: -{{{ -rrulestr(str) -}}} - -The string passed as parameter may be a multiple line string, a -single line string, or just the {{{RRULE}}} property value. - -Additionally, it accepts the following keyword arguments: - - cache:: - If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance - will cache its results. Default is not to cache. - - dtstart:: - If given, it must be a {{{datetime}}} instance that will be used - when no {{{DTSTART}}} property is found in the parsed string. If - it is not given, and the property is not found, {{{datetime.now()}}} - will be used instead. - - unfold:: - If set to {{{True}}}, lines will be unfolded following the RFC - specification. It defaults to {{{False}}}, meaning that spaces - before every line will be stripped. - - forceset:: - If set to {{{True}}} a {{{rruleset}}} instance will be returned, - even if only a single rule is found. The default is to return an - {{{rrule}}} if possible, and an {{{rruleset}}} if necessary. - - compatible:: - If set to {{{True}}}, the parser will operate in RFC-compatible - mode. Right now it means that {{{unfold}}} will be turned on, - and if a {{{DTSTART}}} is found, it will be considered the first - recurrence instance, as documented in the RFC. - - ignoretz:: - If set to {{{True}}}, the date parser will ignore timezone - information available in the {{{DTSTART}}} property, or the - {{{UNTIL}}} attribute. - - tzinfos:: - If set, it will be passed to the datetime string parser to - resolve unknown timezone settings. For more information about - what could be used here, check the parser documentation. - -==== rrulestr() examples ==== - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """)) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Same thing, but passing only the {{{RRULE}}} value. -{{{ ->>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Notice that when using a single rule, it returns an -{{{rrule}}} instance, unless {{{forceset}}} was used. -{{{ ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5") - - ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """) - - ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True) - -}}} - -But when an {{{rruleset}}} is needed, it is automatically used. -{{{ ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3 -... """) - -}}} - -=== parser === -This module offers a generic date/time string parser which is -able to parse most known formats to represent a date and/or -time. - -==== parse() function ==== -That's probably the only function you'll need from this module. -It offers you an interface to access the parser functionality and -extract a {{{datetime}}} type out of a string. - -The prototype of this function is: -{{{ -parse(timestr) -}}} - -Additionally, the following keyword arguments are available: - - default:: - If given, this must be a {{{datetime}}} instance. Any fields - missing in the parsed date will be copied from this instance. - The default value is the current date, at 00:00:00am. - - ignoretz:: - If this is true, even if a timezone is found in the string, - the parser will not use it. - - tzinfos:: - Using this keyword argument you may provide custom timezones - to the parser. If given, it must be either a dictionary with - the timezone abbreviation as key, or a function accepting a - timezone abbreviation and offset as argument. The dictionary - values and the function return must be a timezone offset - in seconds, a tzinfo subclass, or a string defining the - timezone (in the TZ environment variable format). - - dayfirst:: - This option allow one to change the precedence in which - days are parsed in date strings. The default is given in the - parserinfo instance (the default parserinfo has it set to - False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}} - format will have precedence over {{{DD-MM-YYYY}}} in an - ambiguous date. - - yearfirst:: - This option allow one to change the precedence in which - years are parsed in date strings. The default is given in - the parserinfo instance (the default parserinfo has it set - to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}} - format will have precedence over {{{YY-MM-DD}}} in an - ambiguous date. - - fuzzy:: - If {{{fuzzy}}} is set to True, unknown tokens in the string - will be ignored. - - parserinfo:: - This parameter allows one to change how the string is parsed, - by using a different parserinfo class instance. Using it you - may, for example, intenationalize the parser strings, or make - it ignore additional words. - -==== Format precedence ==== -Whenever an ambiguous date is found, the {{{dayfirst}}} and -{{{yearfirst}}} parameters will control how the information -is processed. Here is the precedence in each case: - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}}, -(default, if no parameter is given): - - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}: - - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - -==== Converting two digit years ==== -When a two digit year is found, it is processed considering -the current year, so that the computed year is never more -than 49 years after the current year, nor 50 years before the -current year. In other words, if we are in year 2003, and the -year 30 is found, it will be considered as 2030, but if the -year 60 is found, it will be considered 1960. - -==== Examples ==== -The following code will prepare the environment: -{{{ ->>> from dateutil.parser import * ->>> from dateutil.tz import * ->>> from datetime import * ->>> TZOFFSETS = {"BRST": -10800} ->>> BRSTTZ = tzoffset(-10800, "BRST") ->>> DEFAULT = datetime(2003, 9, 25) -}}} - -Some simple examples based on the {{{date}}} command, using the -{{{TZOFFSET}}} dictionary to provide the BRST timezone offset. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) - ->>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) -}}} - -Notice that since BRST is my local timezone, parsing it without -further timezone settings will yield a {{{tzlocal}}} timezone. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal()) -}}} - -We can also ask to ignore the timezone explicitly: -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -That's the same as processing a string without timezone: -{{{ ->>> parse("Thu Sep 25 10:36:28 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Without the year, but passing our {{{DEFAULT}}} datetime to return -the same year, no mattering what year we currently are in: -{{{ ->>> parse("Thu Sep 25 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Strip it further: -{{{ ->>> parse("Thu Sep 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) - ->>> parse("10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) ->>> -}}} - -Strip in a different way: -{{{ ->>> parse("Thu Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Another format, based on {{{date -R}}} (RFC822): -{{{ ->>> parse("Thu, 25 Sep 2003 10:49:41 -0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -ISO format: -{{{ ->>> parse("2003-09-25T10:49:41.5-03:00") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzoffset(None, -10800)) -}}} - -Some variations: -{{{ ->>> parse("2003-09-25T10:49:41") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("2003-09-25T10:49") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("2003-09-25T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -ISO format, without separators: -{{{ ->>> parse("20030925T104941.5-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("20030925T1049") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("20030925T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("20030925") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Everything together. -{{{ ->>> parse("199709020900") -datetime.datetime(1997, 9, 2, 9, 0) ->>> parse("19970902090059") -datetime.datetime(1997, 9, 2, 9, 0, 59) -}}} - -Different date orderings: -{{{ ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003-Sep-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-Sep-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("09-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-09-2003") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Check some ambiguous dates: -{{{ ->>> parse("10-09-2003") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-2003", dayfirst=True) -datetime.datetime(2003, 9, 10, 0, 0) - ->>> parse("10-09-03") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-03", yearfirst=True) -datetime.datetime(2010, 9, 3, 0, 0) -}}} - -Other date separators are allowed: -{{{ ->>> parse("2003.Sep.25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003/09/25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Even with spaces: -{{{ ->>> parse("2003 Sep 25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003 09 25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Hours with letters work: -{{{ ->>> parse("10h36m28.5s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28, 500000) - ->>> parse("01s02h03m", default=DEFAULT) -datetime.datetime(2003, 9, 25, 2, 3, 1) - ->>> parse("01h02m03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 1, 2) - ->>> parse("01h02", default=DEFAULT) -datetime.datetime(2003, 9, 2, 1, 0) - ->>> parse("01h02s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 1, 0, 2) -}}} - -With AM/PM: -{{{ ->>> parse("10h am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("10pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 22, 0) - ->>> parse("12:00am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("12pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 12, 0) -}}} - -Some special treating for ''pertain'' relations: -{{{ ->>> parse("Sep 03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 0, 0) - ->>> parse("Sep of 03", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Fuzzy parsing: -{{{ ->>> s = "Today is 25 of September of 2003, exactly " \ -... "at 10:49:41 with timezone -03:00." ->>> parse(s, fuzzy=True) -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -Other random formats: -{{{ ->>> parse("Wed, July 10, '96") -datetime.datetime(1996, 7, 10, 0, 0) - ->>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True) -datetime.datetime(1996, 7, 10, 15, 8, 56) - ->>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True) -datetime.datetime(1952, 4, 12, 15, 30, 42) - ->>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True) -datetime.datetime(1994, 11, 5, 8, 15, 30) - ->>> parse("3rd of May 2001") -datetime.datetime(2001, 5, 3, 0, 0) - ->>> parse("5:50 A.M. on June 13, 1990") -datetime.datetime(1990, 6, 13, 5, 50) -}}} - -=== easter === -This module offers a generic easter computing method for -any given year, using Western, Orthodox or Julian algorithms. - -==== easter() function ==== -This method was ported from the work done by -[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts], -on top of the algorithm by -[http://www.tondering.dk/claus/calendar.html 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 - 1. Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 1. 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. - -=== tz === -This module offers timezone implementations subclassing -the abstract {{{datetime.tzinfo}}} type. There are -classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile] -format files (usually are in /etc/localtime, -/usr/share/zoneinfo, etc), TZ environment string (in all -known formats), given ranges (with help from relative -deltas), local machine timezone, fixed offset timezone, -and UTC timezone. - -==== tzutc type ==== -This type implements a basic UTC timezone. The constructor of this -type accepts no parameters. - -==== tzutc examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now() -datetime.datetime(2003, 9, 27, 9, 40, 1, 521290) - ->>> datetime.now(tzutc()) -datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc()) - ->>> datetime.now(tzutc()).tzname() -'UTC' -}}} - -==== tzoffset type ==== -This type implements a fixed offset timezone, with no -support to daylight saving times. Here is the prototype of the -type constructor: -{{{ -tzoffset(name, offset) -}}} - -The {{{name}}} parameter may be optionally set to {{{None}}}, and -{{{offset}}} must be given in seconds. - -==== tzoffset examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzoffset("BRST", -10800)) -datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, - tzinfo=tzinfo=tzoffset('BRST', -10800)) - ->>> datetime.now(tzoffset("BRST", -10800)).tzname() -'BRST' - ->>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, - tzinfo=tzutc()) -}}} - -==== tzlocal type ==== -This type implements timezone settings as known by the -operating system. The constructor of this type accepts no -parameters. - -==== tzlocal examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzlocal()) -datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, - tzinfo=tzlocal()) - ->>> datetime.now(tzlocal()).tzname() -'BRST' - ->>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0)) -datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, - tzinfo=tzoffset(None, 0)) -}}} - -==== tzstr type ==== -This type implements timezone settings extracted from a -string in known TZ environment variable formats. Here is the prototype -of the constructor: -{{{ -tzstr(str) -}}} - -==== tzstr examples ==== -Here are examples of the recognized formats: - - * {{{EST5EDT}}} - * {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}} - * {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}} - * {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}} - * {{{EST5EDT4,95/02:00:00,298/02:00}}} - * {{{EST5EDT4,J96/02:00:00,J299/02:00}}} - -Notice that if daylight information is not present, but a -daylight abbreviation was provided, {{{tzstr}}} will follow the -convention of using the first sunday of April to start daylight -saving, and the last sunday of October to end it. If start or -end time is not present, 2AM will be used, and if the daylight -offset is not present, the standard offset plus one hour will -be used. This convention is the same as used in the GNU libc. - -This also means that some of the above examples are exactly -equivalent, and all of these examples are equivalent -in the year of 2003. - -Here is the example mentioned in the -[http://www.python.org/doc/current/lib/module-time.html time module documentation]. -{{{ ->>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'16:08:12 05/08/03 AEST' -}}} - -And here is an example showing the same information using {{{tzstr}}}, -without touching system settings. -{{{ ->>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0') ->>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0') ->>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1) ->>> dt.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> dt.astimezone(tz2).strftime('%X %x %Z') -'16:07:36 05/08/03 AEST' -}}} - -Are these really equivalent? -{{{ ->>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600') -True -}}} - -Check the daylight limit. -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzrange type ==== -This type offers the same functionality as the {{{tzstr}}} type, but -instead of timezone strings, information is passed using -{{{relativedelta}}}s which are applied to a datetime set to the first -day of the year. Here is the prototype of this type's constructor: -{{{ -tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, - start=None, end=None): -}}} - -Offsets must be given in seconds. Information not provided will be -set to the defaults, as explained in the {{{tzstr}}} section above. - -==== tzrange examples ==== -{{{ ->>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT") -True - ->>> from dateutil.relativedelta import * ->>> range1 = tzrange("EST", -18000, "EDT") ->>> range2 = tzrange("EST", -18000, "EDT", -14400, -... relativedelta(hours=+2, month=4, day=1, - weekday=SU(+1)), -... relativedelta(hours=+1, month=10, day=31, - weekday=SU(-1))) ->>> tzstr('EST5EDT') == range1 == range2 -True -}}} - -Notice a minor detail in the last example: while the DST should end -at 2AM, the delta will catch 1AM. That's because the daylight saving -time should end at 2AM standard time (the difference between STD and -DST is 1h in the given example) instead of the DST time. That's how -the {{{tzinfo}}} subtypes should deal with the extra hour that happens -when going back to the standard time. Check -[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation] -for more information. - -==== tzfile type ==== -This type allows one to use tzfile(5) format timezone files to extract -current and historical zone information. Here is the type constructor -prototype: -{{{ -tzfile(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzfile examples ==== -{{{ ->>> tz = tzfile("/etc/localtime") ->>> datetime.now(tz) -datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, - tzinfo=tzfile('/etc/localtime')) - ->>> datetime.now(tz).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, - tzinfo=tzutc()) - ->>> datetime.now(tz).tzname() -'BRST' ->>> datetime(2003, 1, 1, tzinfo=tz).tzname() -'BRDT' -}}} - -Check the daylight limit. -{{{ ->>> tz = tzfile('/usr/share/zoneinfo/EST5EDT') ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzical type ==== -This type is able to parse -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] -style {{{VTIMEZONE}}} sessions into a Python timezone object. -The constuctor prototype is: -{{{ -tzical(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzical methods ==== - - tzical.get(tzid=None):: - Since a single iCalendar file may contain more than one timezone, - you must ask for the timezone you want with this method. If there's - more than one timezone in the parsed file, you'll need to pass the - {{{tzid}}} parameter. Otherwise, leaving it empty will yield the only - available timezone. - -==== tzical examples ==== -Here is a sample file extracted from the RFC. This file defines -the {{{EST5EDT}}} timezone, and will be used in the following example. -{{{ -BEGIN:VTIMEZONE -TZID:US-Eastern -LAST-MODIFIED:19870101T000000Z -TZURL:http://zones.stds_r_us.net/tz/US-Eastern -BEGIN:STANDARD -DTSTART:19671029T020000 -RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 -TZOFFSETFROM:-0400 -TZOFFSETTO:-0500 -TZNAME:EST -END:STANDARD -BEGIN:DAYLIGHT -DTSTART:19870405T020000 -RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 -TZOFFSETFROM:-0500 -TZOFFSETTO:-0400 -TZNAME:EDT -END:DAYLIGHT -END:VTIMEZONE -}}} - -And here is an example exploring a {{{tzical}}} type: -{{{ ->>> from dateutil.tz import *; from datetime import * - ->>> tz = tzical('EST5EDT.ics') ->>> tz.keys() -['US-Eastern'] - ->>> est = tz.get('US-Eastern') ->>> est - - ->>> datetime.now(est) -datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, - tzinfo=) - ->>> est == tz.get() -True -}}} - -Let's check the daylight ranges, as usual: -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname() -'EDT' - ->>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname() -'EST' -}}} - -==== tzwin type ==== -This type offers access to internal registry-based Windows timezones. -The constuctor prototype is: -{{{ -tzwin(name) -}}} - -Where {{{name}}} is the timezone name. There's a static {{{tzwin.list()}}} -method to check the available names, - -==== tzwin methods ==== - - tzwin.display():: - This method returns the timezone extended name. - - tzwin.list():: - This static method lists all available timezone names. - -==== tzwin examples ==== -{{{ ->>> tz = tzwin("E. South America Standard Time") -}}} - -==== tzwinlocal type ==== -This type offers access to internal registry-based Windows timezones. -The constructor accepts no parameters, so the prototype is: -{{{ -tzwinlocal() -}}} - -==== tzwinlocal methods ==== - - tzwinlocal.display():: - This method returns the timezone extended name, and returns - {{{None}}} if one is not available. - -==== tzwinlocal examples ==== -{{{ ->>> tz = tzwinlocal() -}}} - -==== gettz() function ==== -This function is a helper that will try its best to get the right -timezone for your environment, or for the given string. The prototype -is as follows: -{{{ -gettz(name=None) -}}} - -If given, the parameter may be a filename, a path relative to the base -of the timezone information path (the base could be -{{{/usr/share/zoneinfo}}}, for example), a string timezone -specification, or a timezone abbreviation. If {{{name}}} is not given, -and the {{{TZ}}} environment variable is set, it's used instead. If the -parameter is not given, and {{{TZ}}} is not set, the default tzfile -paths will be tried. Then, if no timezone information is found, -an internal compiled database of timezones is used. When running -on Windows, the internal registry-based Windows timezones are also -considered. - -Example: -{{{ ->>> from dateutil.tz import * ->>> gettz() -tzfile('/etc/localtime') - ->>> gettz("America/Sao Paulo") -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> gettz("EST5EDT") -tzfile('/usr/share/zoneinfo/EST5EDT') - ->>> gettz("EST5") -tzstr('EST5') - ->>> gettz('BRST') -tzlocal() - ->>> os.environ["TZ"] = "America/Sao Paulo" ->>> gettz() -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> os.environ["TZ"] = "BRST" ->>> gettz() -tzlocal() - ->>> gettz("Unavailable") ->>> -}}} - -=== zoneinfo === -This module provides direct access to the internal compiled -database of timezones. The timezone data and the compiling tools -are obtained from the following project: - - http://www.twinsun.com/tz/tz-link.htm - -==== gettz() function ==== -This function will try to retrieve the given timezone information -from the internal compiled database, and will cache its results. - -Example: -{{{ ->>> from dateutil import zoneinfo ->>> zoneinfo.gettz("Brazil/East") -tzfile('Brazil/East') -}}} - -## vim:ft=moin diff --git a/lib/dateutil_py2/__init__.py b/lib/dateutil_py2/__init__.py deleted file mode 100644 index 44895a0d388e..000000000000 --- a/lib/dateutil_py2/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" -__version__ = "1.5-mpl" diff --git a/lib/dateutil_py2/easter.py b/lib/dateutil_py2/easter.py deleted file mode 100644 index d7944104beb1..000000000000 --- a/lib/dateutil_py2/easter.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime - -__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] - -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 - -def easter(year, method=EASTER_WESTERN): - """ - This method was ported from the work done by GM Arts, - on top of the algorithm by Claus Tondering, which was - based in part on the algorithm of Ouding (1940), as - quoted in "Explanatory Supplement to the Astronomical - Almanac", P. Kenneth Seidelmann, editor. - - This algorithm implements three different easter - calculation methods: - - 1 - Original calculation in Julian calendar, valid in - dates after 326 AD - 2 - Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 3 - Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - - These methods are represented by the constants: - - EASTER_JULIAN = 1 - EASTER_ORTHODOX = 2 - EASTER_WESTERN = 3 - - The default method is method 3. - - More about the algorithm may be found at: - - http://users.chariot.net.au/~gmarts/eastalg.htm - - and - - http://www.tondering.dk/claus/calendar.html - - """ - - if not (1 <= method <= 3): - raise ValueError, "invalid method" - - # g - Golden year - 1 - # c - Century - # h - (23 - Epact) mod 30 - # i - Number of days from March 21 to Paschal Full Moon - # j - Weekday for PFM (0=Sunday, etc) - # p - Number of days from March 21 to Sunday on or before PFM - # (-6 to 28 methods 1 & 3, to 56 for method 2) - # e - Extra days to add for method 2 (converting Julian - # date to Gregorian date) - - y = year - g = y % 19 - e = 0 - if method < 3: - # Old method - i = (19*g+15)%30 - j = (y+y//4+i)%7 - if method == 2: - # Extra dates to convert Julian to Gregorian date - e = 10 - if y > 1600: - e = e+y//100-16-(y//100-16)//4 - else: - # New method - c = y//100 - h = (c-c//4-(8*c+13)//25+19*g+15)%30 - i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) - j = (y+y//4+i+2-c+c//4)%7 - - # p can be from -6 to 56 corresponding to dates 22 March to 23 May - # (later dates apply to method 2, although 23 May never actually occurs) - p = i-j+e - d = 1+(p+27+(p+6)//40)%31 - m = 3+(p+26)//30 - return datetime.date(int(y),int(m),int(d)) - diff --git a/lib/dateutil_py2/parser.py b/lib/dateutil_py2/parser.py deleted file mode 100644 index 5d824e411f32..000000000000 --- a/lib/dateutil_py2/parser.py +++ /dev/null @@ -1,886 +0,0 @@ -# -*- coding:iso-8859-1 -*- -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import string -import time -import sys -import os - -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -import relativedelta -import tz - - -__all__ = ["parse", "parserinfo"] - - -# Some pointers: -# -# http://www.cl.cam.ac.uk/~mgk25/iso-time.html -# http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html -# http://www.w3.org/TR/NOTE-datetime -# http://ringmaster.arc.nasa.gov/tools/time_formats.html -# http://search.cpan.org/author/MUIR/Time-modules-2003.0211/lib/Time/ParseDate.pm -# http://stein.cshl.org/jade/distrib/docs/java.text.SimpleDateFormat.html - - -class _timelex(object): - - def __init__(self, instream): - if isinstance(instream, basestring): - instream = StringIO(instream) - self.instream = instream - self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' - 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' - 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') - self.numchars = '0123456789' - self.whitespace = ' \t\r\n' - self.charstack = [] - self.tokenstack = [] - self.eof = False - - def get_token(self): - if self.tokenstack: - return self.tokenstack.pop(0) - seenletters = False - token = None - state = None - wordchars = self.wordchars - numchars = self.numchars - whitespace = self.whitespace - while not self.eof: - if self.charstack: - nextchar = self.charstack.pop(0) - else: - nextchar = self.instream.read(1) - while nextchar == '\x00': - nextchar = self.instream.read(1) - if not nextchar: - self.eof = True - break - elif not state: - token = nextchar - if nextchar in wordchars: - state = 'a' - elif nextchar in numchars: - state = '0' - elif nextchar in whitespace: - token = ' ' - break # emit token - else: - break # emit token - elif state == 'a': - seenletters = True - if nextchar in wordchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0': - if nextchar in numchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == 'a.': - seenletters = True - if nextchar == '.' or nextchar in wordchars: - token += nextchar - elif nextchar in numchars and token[-1] == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0.': - if nextchar == '.' or nextchar in numchars: - token += nextchar - elif nextchar in wordchars and token[-1] == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - if (state in ('a.', '0.') and - (seenletters or token.count('.') > 1 or token[-1] == '.')): - l = token.split('.') - token = l[0] - for tok in l[1:]: - self.tokenstack.append('.') - if tok: - self.tokenstack.append(tok) - return token - - def __iter__(self): - return self - - def next(self): - token = self.get_token() - if token is None: - raise StopIteration - return token - - def split(cls, s): - return list(cls(s)) - split = classmethod(split) - - -class _resultbase(object): - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def _repr(self, classname): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (classname, ", ".join(l)) - - def __repr__(self): - return self._repr(self.__class__.__name__) - - -class parserinfo(object): - - # m from a.m/p.m, t from ISO T separator - JUMP = [" ", ".", ",", ";", "-", "/", "'", - "at", "on", "and", "ad", "m", "t", "of", - "st", "nd", "rd", "th"] - - WEEKDAYS = [("Mon", "Monday"), - ("Tue", "Tuesday"), - ("Wed", "Wednesday"), - ("Thu", "Thursday"), - ("Fri", "Friday"), - ("Sat", "Saturday"), - ("Sun", "Sunday")] - MONTHS = [("Jan", "January"), - ("Feb", "February"), - ("Mar", "March"), - ("Apr", "April"), - ("May", "May"), - ("Jun", "June"), - ("Jul", "July"), - ("Aug", "August"), - ("Sep", "September"), - ("Oct", "October"), - ("Nov", "November"), - ("Dec", "December")] - HMS = [("h", "hour", "hours"), - ("m", "minute", "minutes"), - ("s", "second", "seconds")] - AMPM = [("am", "a"), - ("pm", "p")] - UTCZONE = ["UTC", "GMT", "Z"] - PERTAIN = ["of"] - TZOFFSET = {} - - def __init__(self, dayfirst=False, yearfirst=False): - self._jump = self._convert(self.JUMP) - self._weekdays = self._convert(self.WEEKDAYS) - self._months = self._convert(self.MONTHS) - self._hms = self._convert(self.HMS) - self._ampm = self._convert(self.AMPM) - self._utczone = self._convert(self.UTCZONE) - self._pertain = self._convert(self.PERTAIN) - - self.dayfirst = dayfirst - self.yearfirst = yearfirst - - self._year = time.localtime().tm_year - self._century = self._year//100*100 - - def _convert(self, lst): - dct = {} - for i in range(len(lst)): - v = lst[i] - if isinstance(v, tuple): - for v in v: - dct[v.lower()] = i - else: - dct[v.lower()] = i - return dct - - def jump(self, name): - return name.lower() in self._jump - - def weekday(self, name): - if len(name) >= 3: - try: - return self._weekdays[name.lower()] - except KeyError: - pass - return None - - def month(self, name): - if len(name) >= 3: - try: - return self._months[name.lower()]+1 - except KeyError: - pass - return None - - def hms(self, name): - try: - return self._hms[name.lower()] - except KeyError: - return None - - def ampm(self, name): - try: - return self._ampm[name.lower()] - except KeyError: - return None - - def pertain(self, name): - return name.lower() in self._pertain - - def utczone(self, name): - return name.lower() in self._utczone - - def tzoffset(self, name): - if name in self._utczone: - return 0 - return self.TZOFFSET.get(name) - - def convertyear(self, year): - if year < 100: - year += self._century - if abs(year-self._year) >= 50: - if year < self._year: - year += 100 - else: - year -= 100 - return year - - def validate(self, res): - # move to info - if res.year is not None: - res.year = self.convertyear(res.year) - if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z': - res.tzname = "UTC" - res.tzoffset = 0 - elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): - res.tzoffset = 0 - return True - - -class parser(object): - - def __init__(self, info=None): - self.info = info or parserinfo() - - def parse(self, timestr, default=None, - ignoretz=False, tzinfos=None, - **kwargs): - if not default: - default = datetime.datetime.now().replace(hour=0, minute=0, - second=0, microsecond=0) - res = self._parse(timestr, **kwargs) - if res is None: - raise ValueError, "unknown string format" - repl = {} - for attr in ["year", "month", "day", "hour", - "minute", "second", "microsecond"]: - value = getattr(res, attr) - if value is not None: - repl[attr] = value - ret = default.replace(**repl) - if res.weekday is not None and not res.day: - ret = ret+relativedelta.relativedelta(weekday=res.weekday) - if not ignoretz: - if callable(tzinfos) or tzinfos and res.tzname in tzinfos: - if callable(tzinfos): - tzdata = tzinfos(res.tzname, res.tzoffset) - else: - tzdata = tzinfos.get(res.tzname) - if isinstance(tzdata, datetime.tzinfo): - tzinfo = tzdata - elif isinstance(tzdata, basestring): - tzinfo = tz.tzstr(tzdata) - elif isinstance(tzdata, int): - tzinfo = tz.tzoffset(res.tzname, tzdata) - else: - raise ValueError, "offset must be tzinfo subclass, " \ - "tz string, or int offset" - ret = ret.replace(tzinfo=tzinfo) - elif res.tzname and res.tzname in time.tzname: - ret = ret.replace(tzinfo=tz.tzlocal()) - elif res.tzoffset == 0: - ret = ret.replace(tzinfo=tz.tzutc()) - elif res.tzoffset: - ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) - return ret - - class _result(_resultbase): - __slots__ = ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond", - "tzname", "tzoffset"] - - def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False): - info = self.info - if dayfirst is None: - dayfirst = info.dayfirst - if yearfirst is None: - yearfirst = info.yearfirst - res = self._result() - l = _timelex.split(timestr) - try: - - # year/month/day list - ymd = [] - - # Index of the month string in ymd - mstridx = -1 - - len_l = len(l) - i = 0 - while i < len_l: - - # Check if it's a number - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - value = None - - if value is not None: - # Token is a number - len_li = len(l[i]) - i += 1 - if (len(ymd) == 3 and len_li in (2, 4) - and (i >= len_l or (l[i] != ':' and - info.hms(l[i]) is None))): - # 19990101T23[59] - s = l[i-1] - res.hour = int(s[:2]) - if len_li == 4: - res.minute = int(s[2:]) - elif len_li == 6 or (len_li > 6 and l[i-1].find('.') == 6): - # YYMMDD or HHMMSS[.ss] - s = l[i-1] - if not ymd and l[i-1].find('.') == -1: - ymd.append(info.convertyear(int(s[:2]))) - ymd.append(int(s[2:4])) - ymd.append(int(s[4:])) - else: - # 19990101T235959[.59] - res.hour = int(s[:2]) - res.minute = int(s[2:4]) - res.second, res.microsecond = _parsems(s[4:]) - elif len_li == 8: - # YYYYMMDD - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:])) - elif len_li in (12, 14): - # YYYYMMDDhhmm[ss] - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:8])) - res.hour = int(s[8:10]) - res.minute = int(s[10:12]) - if len_li == 14: - res.second = int(s[12:]) - elif ((i < len_l and info.hms(l[i]) is not None) or - (i+1 < len_l and l[i] == ' ' and - info.hms(l[i+1]) is not None)): - # HH[ ]h or MM[ ]m or SS[.ss][ ]s - if l[i] == ' ': - i += 1 - idx = info.hms(l[i]) - while True: - if idx == 0: - res.hour = int(value) - if value%1: - res.minute = int(60*(value%1)) - elif idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - if i >= len_l or idx == 2: - break - # 12h00 - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - break - else: - i += 1 - idx += 1 - if i < len_l: - newidx = info.hms(l[i]) - if newidx is not None: - idx = newidx - elif i+1 < len_l and l[i] == ':': - # HH:MM[:SS[.ss]] - res.hour = int(value) - i += 1 - value = float(l[i]) - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - i += 1 - if i < len_l and l[i] == ':': - res.second, res.microsecond = _parsems(l[i+1]) - i += 2 - elif i < len_l and l[i] in ('-', '/', '.'): - sep = l[i] - ymd.append(int(value)) - i += 1 - if i < len_l and not info.jump(l[i]): - try: - # 01-01[-01] - ymd.append(int(l[i])) - except ValueError: - # 01-Jan[-01] - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - else: - return None - i += 1 - if i < len_l and l[i] == sep: - # We have three members - i += 1 - value = info.month(l[i]) - if value is not None: - ymd.append(value) - mstridx = len(ymd)-1 - assert mstridx == -1 - else: - ymd.append(int(l[i])) - i += 1 - elif i >= len_l or info.jump(l[i]): - if i+1 < len_l and info.ampm(l[i+1]) is not None: - # 12 am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i+1]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i+1]) == 0: - res.hour = 0 - i += 1 - else: - # Year, month or day - ymd.append(int(value)) - i += 1 - elif info.ampm(l[i]) is not None: - # 12am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i]) == 0: - res.hour = 0 - i += 1 - elif not fuzzy: - return None - else: - i += 1 - continue - - # Check weekday - value = info.weekday(l[i]) - if value is not None: - res.weekday = value - i += 1 - continue - - # Check month name - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - i += 1 - if i < len_l: - if l[i] in ('-', '/'): - # Jan-01[-99] - sep = l[i] - i += 1 - ymd.append(int(l[i])) - i += 1 - if i < len_l and l[i] == sep: - # Jan-01-99 - i += 1 - ymd.append(int(l[i])) - i += 1 - elif (i+3 < len_l and l[i] == l[i+2] == ' ' - and info.pertain(l[i+1])): - # Jan of 01 - # In this case, 01 is clearly year - try: - value = int(l[i+3]) - except ValueError: - # Wrong guess - pass - else: - # Convert it here to become unambiguous - ymd.append(info.convertyear(value)) - i += 4 - continue - - # Check am/pm - value = info.ampm(l[i]) - if value is not None: - if value == 1 and res.hour < 12: - res.hour += 12 - elif value == 0 and res.hour == 12: - res.hour = 0 - i += 1 - continue - - # Check for a timezone name - if (res.hour is not None and len(l[i]) <= 5 and - res.tzname is None and res.tzoffset is None and - not [x for x in l[i] if x not in string.ascii_uppercase]): - res.tzname = l[i] - res.tzoffset = info.tzoffset(res.tzname) - i += 1 - - # Check for something like GMT+3, or BRST+3. Notice - # that it doesn't mean "I am 3 hours after GMT", but - # "my time +3 is GMT". If found, we reverse the - # logic so that timezone parsing code will get it - # right. - if i < len_l and l[i] in ('+', '-'): - l[i] = ('+', '-')[l[i] == '+'] - res.tzoffset = None - if info.utczone(res.tzname): - # With something like GMT+3, the timezone - # is *not* GMT. - res.tzname = None - - continue - - # Check for a numbered timezone - if res.hour is not None and l[i] in ('+', '-'): - signal = (-1,1)[l[i] == '+'] - i += 1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - res.tzoffset = int(l[i][:2])*3600+int(l[i][2:])*60 - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - res.tzoffset = int(l[i])*3600+int(l[i+2])*60 - i += 2 - elif len_li <= 2: - # -[0]3 - res.tzoffset = int(l[i][:2])*3600 - else: - return None - i += 1 - res.tzoffset *= signal - - # Look for a timezone name between parenthesis - if (i+3 < len_l and - info.jump(l[i]) and l[i+1] == '(' and l[i+3] == ')' and - 3 <= len(l[i+2]) <= 5 and - not [x for x in l[i+2] - if x not in string.ascii_uppercase]): - # -0300 (BRST) - res.tzname = l[i+2] - i += 4 - continue - - # Check jumps - if not (info.jump(l[i]) or fuzzy): - return None - - i += 1 - - # Process year/month/day - len_ymd = len(ymd) - if len_ymd > 3: - # More than three members!? - return None - elif len_ymd == 1 or (mstridx != -1 and len_ymd == 2): - # One member, or two members with a month string - if mstridx != -1: - res.month = ymd[mstridx] - del ymd[mstridx] - if len_ymd > 1 or mstridx == -1: - if ymd[0] > 31: - res.year = ymd[0] - else: - res.day = ymd[0] - elif len_ymd == 2: - # Two members with numbers - if ymd[0] > 31: - # 99-01 - res.year, res.month = ymd - elif ymd[1] > 31: - # 01-99 - res.month, res.year = ymd - elif dayfirst and ymd[1] <= 12: - # 13-01 - res.day, res.month = ymd - else: - # 01-13 - res.month, res.day = ymd - if len_ymd == 3: - # Three members - if mstridx == 0: - res.month, res.day, res.year = ymd - elif mstridx == 1: - if ymd[0] > 31 or (yearfirst and ymd[2] <= 31): - # 99-Jan-01 - res.year, res.month, res.day = ymd - else: - # 01-Jan-01 - # Give precendence to day-first, since - # two-digit years is usually hand-written. - res.day, res.month, res.year = ymd - elif mstridx == 2: - # WTF!? - if ymd[1] > 31: - # 01-99-Jan - res.day, res.year, res.month = ymd - else: - # 99-01-Jan - res.year, res.day, res.month = ymd - else: - if ymd[0] > 31 or \ - (yearfirst and ymd[1] <= 12 and ymd[2] <= 31): - # 99-01-01 - res.year, res.month, res.day = ymd - elif ymd[0] > 12 or (dayfirst and ymd[1] <= 12): - # 13-01-01 - res.day, res.month, res.year = ymd - else: - # 01-13-01 - res.month, res.day, res.year = ymd - - except (IndexError, ValueError, AssertionError): - return None - - if not info.validate(res): - return None - return res - -DEFAULTPARSER = parser() -def parse(timestr, parserinfo=None, **kwargs): - if parserinfo: - return parser(parserinfo).parse(timestr, **kwargs) - else: - return DEFAULTPARSER.parse(timestr, **kwargs) - - -class _tzparser(object): - - class _result(_resultbase): - - __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", - "start", "end"] - - class _attr(_resultbase): - __slots__ = ["month", "week", "weekday", - "yday", "jyday", "day", "time"] - - def __repr__(self): - return self._repr("") - - def __init__(self): - _resultbase.__init__(self) - self.start = self._attr() - self.end = self._attr() - - def parse(self, tzstr): - res = self._result() - l = _timelex.split(tzstr) - try: - - len_l = len(l) - - i = 0 - while i < len_l: - # BRST+3[BRDT[+2]] - j = i - while j < len_l and not [x for x in l[j] - if x in "0123456789:,-+"]: - j += 1 - if j != i: - if not res.stdabbr: - offattr = "stdoffset" - res.stdabbr = "".join(l[i:j]) - else: - offattr = "dstoffset" - res.dstabbr = "".join(l[i:j]) - i = j - if (i < len_l and - (l[i] in ('+', '-') or l[i][0] in "0123456789")): - if l[i] in ('+', '-'): - # Yes, that's right. See the TZ variable - # documentation. - signal = (1,-1)[l[i] == '+'] - i += 1 - else: - signal = -1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - setattr(res, offattr, - (int(l[i][:2])*3600+int(l[i][2:])*60)*signal) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - setattr(res, offattr, - (int(l[i])*3600+int(l[i+2])*60)*signal) - i += 2 - elif len_li <= 2: - # -[0]3 - setattr(res, offattr, - int(l[i][:2])*3600*signal) - else: - return None - i += 1 - if res.dstabbr: - break - else: - break - - if i < len_l: - for j in range(i, len_l): - if l[j] == ';': l[j] = ',' - - assert l[i] == ',' - - i += 1 - - if i >= len_l: - pass - elif (8 <= l.count(',') <= 9 and - not [y for x in l[i:] if x != ',' - for y in x if y not in "0123456789"]): - # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] - for x in (res.start, res.end): - x.month = int(l[i]) - i += 2 - if l[i] == '-': - value = int(l[i+1])*-1 - i += 1 - else: - value = int(l[i]) - i += 2 - if value: - x.week = value - x.weekday = (int(l[i])-1)%7 - else: - x.day = int(l[i]) - i += 2 - x.time = int(l[i]) - i += 2 - if i < len_l: - if l[i] in ('-','+'): - signal = (-1,1)[l[i] == "+"] - i += 1 - else: - signal = 1 - res.dstoffset = (res.stdoffset+int(l[i]))*signal - elif (l.count(',') == 2 and l[i:].count('/') <= 2 and - not [y for x in l[i:] if x not in (',','/','J','M', - '.','-',':') - for y in x if y not in "0123456789"]): - for x in (res.start, res.end): - if l[i] == 'J': - # non-leap year day (1 based) - i += 1 - x.jyday = int(l[i]) - elif l[i] == 'M': - # month[-.]week[-.]weekday - i += 1 - x.month = int(l[i]) - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.week = int(l[i]) - if x.week == 5: - x.week = -1 - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.weekday = (int(l[i])-1)%7 - else: - # year day (zero based) - x.yday = int(l[i])+1 - - i += 1 - - if i < len_l and l[i] == '/': - i += 1 - # start time - len_li = len(l[i]) - if len_li == 4: - # -0300 - x.time = (int(l[i][:2])*3600+int(l[i][2:])*60) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - x.time = int(l[i])*3600+int(l[i+2])*60 - i += 2 - if i+1 < len_l and l[i+1] == ':': - i += 2 - x.time += int(l[i]) - elif len_li <= 2: - # -[0]3 - x.time = (int(l[i][:2])*3600) - else: - return None - i += 1 - - assert i == len_l or l[i] == ',' - - i += 1 - - assert i >= len_l - - except (IndexError, ValueError, AssertionError): - return None - - return res - - -DEFAULTTZPARSER = _tzparser() -def _parsetz(tzstr): - return DEFAULTTZPARSER.parse(tzstr) - - -def _parsems(value): - """Parse a I[.F] seconds value into (seconds, microseconds).""" - if "." not in value: - return int(value), 0 - else: - i, f = value.split(".") - return int(i), int(f.ljust(6, "0")[:6]) - - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/relativedelta.py b/lib/dateutil_py2/relativedelta.py deleted file mode 100644 index 0c72a8180fb7..000000000000 --- a/lib/dateutil_py2/relativedelta.py +++ /dev/null @@ -1,432 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import calendar - -__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class relativedelta: - """ -The relativedelta type is based on the specification of the excelent -work done by M.-A. Lemburg in his mx.DateTime extension. However, -notice that this type does *NOT* implement the same algorithm as -his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. - -There's two different ways to build a relativedelta instance. The -first one is passing it two date/datetime classes: - - relativedelta(datetime1, datetime2) - -And the other way is to use the following keyword arguments: - - year, month, day, hour, minute, second, microsecond: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds: - Relative information, may be negative. - - weekday: - One of the weekday instances (MO, TU, etc). These instances may - receive a parameter N, specifying the Nth weekday, which could - be positive or negative (like MO(+1) or MO(-2). Not specifying - it is the same as specifying +1. You can also use an integer, - where 0=MO. - - leapdays: - Will add given days to the date found, if year is a leap - year, and the date found is post 28 of february. - - yearday, nlyearday: - Set the yearday or the non-leap year day (jump leap days). - These are converted to day/month/leapdays information. - -Here is the behavior of operations with relativedelta: - -1) Calculate the absolute year, using the 'year' argument, or the - original datetime year, if the argument is not present. - -2) Add the relative 'years' argument to the absolute year. - -3) Do steps 1 and 2 for month/months. - -4) Calculate the absolute day, using the 'day' argument, or the - original datetime day, if the argument is not present. Then, - subtract from the day until it fits in the year and month - found after their operations. - -5) Add the relative 'days' argument to the absolute day. Notice - that the 'weeks' argument is multiplied by 7 and added to - 'days'. - -6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, - microsecond/microseconds. - -7) If the 'weekday' argument is present, calculate the weekday, - with the given (wday, nth) tuple. wday is the index of the - weekday (0-6, 0=Mon), and nth is the number of weeks to add - forward or backward, depending on its signal. Notice that if - the calculated date is already Monday, for example, using - (0, 1) or (0, -1) won't change the day. - """ - - def __init__(self, dt1=None, dt2=None, - years=0, months=0, days=0, leapdays=0, weeks=0, - hours=0, minutes=0, seconds=0, microseconds=0, - year=None, month=None, day=None, weekday=None, - yearday=None, nlyearday=None, - hour=None, minute=None, second=None, microsecond=None): - if dt1 and dt2: - if not isinstance(dt1, datetime.date) or \ - not isinstance(dt2, datetime.date): - raise TypeError, "relativedelta only diffs datetime/date" - if type(dt1) is not type(dt2): - if not isinstance(dt1, datetime.datetime): - dt1 = datetime.datetime.fromordinal(dt1.toordinal()) - elif not isinstance(dt2, datetime.datetime): - dt2 = datetime.datetime.fromordinal(dt2.toordinal()) - self.years = 0 - self.months = 0 - self.days = 0 - self.leapdays = 0 - self.hours = 0 - self.minutes = 0 - self.seconds = 0 - self.microseconds = 0 - self.year = None - self.month = None - self.day = None - self.weekday = None - self.hour = None - self.minute = None - self.second = None - self.microsecond = None - self._has_time = 0 - - months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) - self._set_months(months) - dtm = self.__radd__(dt2) - if dt1 < dt2: - while dt1 > dtm: - months += 1 - self._set_months(months) - dtm = self.__radd__(dt2) - else: - while dt1 < dtm: - months -= 1 - self._set_months(months) - dtm = self.__radd__(dt2) - delta = dt1 - dtm - self.seconds = delta.seconds+delta.days*86400 - self.microseconds = delta.microseconds - else: - self.years = years - self.months = months - self.days = days+weeks*7 - self.leapdays = leapdays - self.hours = hours - self.minutes = minutes - self.seconds = seconds - self.microseconds = microseconds - self.year = year - self.month = month - self.day = day - self.hour = hour - self.minute = minute - self.second = second - self.microsecond = microsecond - - if type(weekday) is int: - self.weekday = weekdays[weekday] - else: - self.weekday = weekday - - yday = 0 - if nlyearday: - yday = nlyearday - elif yearday: - yday = yearday - if yearday > 59: - self.leapdays = -1 - if yday: - ydayidx = [31,59,90,120,151,181,212,243,273,304,334,366] - for idx, ydays in enumerate(ydayidx): - if yday <= ydays: - self.month = idx+1 - if idx == 0: - self.day = yday - else: - self.day = yday-ydayidx[idx-1] - break - else: - raise ValueError, "invalid year day (%d)" % yday - - self._fix() - - def _fix(self): - if abs(self.microseconds) > 999999: - s = self.microseconds//abs(self.microseconds) - div, mod = divmod(self.microseconds*s, 1000000) - self.microseconds = mod*s - self.seconds += div*s - if abs(self.seconds) > 59: - s = self.seconds//abs(self.seconds) - div, mod = divmod(self.seconds*s, 60) - self.seconds = mod*s - self.minutes += div*s - if abs(self.minutes) > 59: - s = self.minutes//abs(self.minutes) - div, mod = divmod(self.minutes*s, 60) - self.minutes = mod*s - self.hours += div*s - if abs(self.hours) > 23: - s = self.hours//abs(self.hours) - div, mod = divmod(self.hours*s, 24) - self.hours = mod*s - self.days += div*s - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years += div*s - if (self.hours or self.minutes or self.seconds or self.microseconds or - self.hour is not None or self.minute is not None or - self.second is not None or self.microsecond is not None): - self._has_time = 1 - else: - self._has_time = 0 - - def _set_months(self, months): - self.months = months - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years = div*s - else: - self.years = 0 - - def __radd__(self, other): - if not isinstance(other, datetime.date): - raise TypeError, "unsupported type for add operation" - elif self._has_time and not isinstance(other, datetime.datetime): - other = datetime.datetime.fromordinal(other.toordinal()) - year = (self.year or other.year)+self.years - month = self.month or other.month - if self.months: - assert 1 <= abs(self.months) <= 12 - month += self.months - if month > 12: - year += 1 - month -= 12 - elif month < 1: - year -= 1 - month += 12 - day = min(calendar.monthrange(year, month)[1], - self.day or other.day) - repl = {"year": year, "month": month, "day": day} - for attr in ["hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - repl[attr] = value - days = self.days - if self.leapdays and month > 2 and calendar.isleap(year): - days += self.leapdays - ret = (other.replace(**repl) - + datetime.timedelta(days=days, - hours=self.hours, - minutes=self.minutes, - seconds=self.seconds, - microseconds=self.microseconds)) - if self.weekday: - weekday, nth = self.weekday.weekday, self.weekday.n or 1 - jumpdays = (abs(nth)-1)*7 - if nth > 0: - jumpdays += (7-ret.weekday()+weekday)%7 - else: - jumpdays += (ret.weekday()-weekday)%7 - jumpdays *= -1 - ret += datetime.timedelta(days=jumpdays) - return ret - - def __rsub__(self, other): - return self.__neg__().__radd__(other) - - def __add__(self, other): - if not isinstance(other, relativedelta): - raise TypeError, "unsupported type for add operation" - return relativedelta(years=other.years+self.years, - months=other.months+self.months, - days=other.days+self.days, - hours=other.hours+self.hours, - minutes=other.minutes+self.minutes, - seconds=other.seconds+self.seconds, - microseconds=other.microseconds+self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.second or self.microsecond) - - def __sub__(self, other): - if not isinstance(other, relativedelta): - raise TypeError, "unsupported type for sub operation" - return relativedelta(years=other.years-self.years, - months=other.months-self.months, - days=other.days-self.days, - hours=other.hours-self.hours, - minutes=other.minutes-self.minutes, - seconds=other.seconds-self.seconds, - microseconds=other.microseconds-self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.second or self.microsecond) - - def __neg__(self): - return relativedelta(years=-self.years, - months=-self.months, - days=-self.days, - hours=-self.hours, - minutes=-self.minutes, - seconds=-self.seconds, - microseconds=-self.microseconds, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __nonzero__(self): - return not (not self.years and - not self.months and - not self.days and - not self.hours and - not self.minutes and - not self.seconds and - not self.microseconds and - not self.leapdays and - self.year is None and - self.month is None and - self.day is None and - self.weekday is None and - self.hour is None and - self.minute is None and - self.second is None and - self.microsecond is None) - - def __mul__(self, other): - f = float(other) - return relativedelta(years=self.years*f, - months=self.months*f, - days=self.days*f, - hours=self.hours*f, - minutes=self.minutes*f, - seconds=self.seconds*f, - microseconds=self.microseconds*f, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __eq__(self, other): - if not isinstance(other, relativedelta): - return False - if self.weekday or other.weekday: - if not self.weekday or not other.weekday: - return False - if self.weekday.weekday != other.weekday.weekday: - return False - n1, n2 = self.weekday.n, other.weekday.n - if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): - return False - return (self.years == other.years and - self.months == other.months and - self.days == other.days and - self.hours == other.hours and - self.minutes == other.minutes and - self.seconds == other.seconds and - self.leapdays == other.leapdays and - self.year == other.year and - self.month == other.month and - self.day == other.day and - self.hour == other.hour and - self.minute == other.minute and - self.second == other.second and - self.microsecond == other.microsecond) - - def __ne__(self, other): - return not self.__eq__(other) - - def __div__(self, other): - return self.__mul__(1/float(other)) - - def __repr__(self): - l = [] - for attr in ["years", "months", "days", "leapdays", - "hours", "minutes", "seconds", "microseconds"]: - value = getattr(self, attr) - if value: - l.append("%s=%+d" % (attr, value)) - for attr in ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/rrule.py b/lib/dateutil_py2/rrule.py deleted file mode 100644 index 6bd83cad3722..000000000000 --- a/lib/dateutil_py2/rrule.py +++ /dev/null @@ -1,1097 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import itertools -import datetime -import calendar -import thread -import sys - -__all__ = ["rrule", "rruleset", "rrulestr", - "YEARLY", "MONTHLY", "WEEKLY", "DAILY", - "HOURLY", "MINUTELY", "SECONDLY", - "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -# Every mask is 7 days longer to handle cross-year weekly periods. -M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+ - [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) -M365MASK = list(M366MASK) -M29, M30, M31 = range(1,30), range(1,31), range(1,32) -MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -MDAY365MASK = list(MDAY366MASK) -M29, M30, M31 = range(-29,0), range(-30,0), range(-31,0) -NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -NMDAY365MASK = list(NMDAY366MASK) -M366RANGE = (0,31,60,91,121,152,182,213,244,274,305,335,366) -M365RANGE = (0,31,59,90,120,151,181,212,243,273,304,334,365) -WDAYMASK = [0,1,2,3,4,5,6]*55 -del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] -MDAY365MASK = tuple(MDAY365MASK) -M365MASK = tuple(M365MASK) - -(YEARLY, - MONTHLY, - WEEKLY, - DAILY, - HOURLY, - MINUTELY, - SECONDLY) = range(7) - -# Imported on demand. -easter = None -parser = None - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - if n == 0: - raise ValueError, "Can't create weekday with n == 0" - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class rrulebase: - def __init__(self, cache=False): - if cache: - self._cache = [] - self._cache_lock = thread.allocate_lock() - self._cache_gen = self._iter() - self._cache_complete = False - else: - self._cache = None - self._cache_complete = False - self._len = None - - def __iter__(self): - if self._cache_complete: - return iter(self._cache) - elif self._cache is None: - return self._iter() - else: - return self._iter_cached() - - def _iter_cached(self): - i = 0 - gen = self._cache_gen - cache = self._cache - acquire = self._cache_lock.acquire - release = self._cache_lock.release - while gen: - if i == len(cache): - acquire() - if self._cache_complete: - break - try: - for j in range(10): - cache.append(gen.next()) - except StopIteration: - self._cache_gen = gen = None - self._cache_complete = True - break - release() - yield cache[i] - i += 1 - while i < self._len: - yield cache[i] - i += 1 - - def __getitem__(self, item): - if self._cache_complete: - return self._cache[item] - elif isinstance(item, slice): - if item.step and item.step < 0: - return list(iter(self))[item] - else: - return list(itertools.islice(self, - item.start or 0, - item.stop or sys.maxint, - item.step or 1)) - elif item >= 0: - gen = iter(self) - try: - for i in range(item+1): - res = gen.next() - except StopIteration: - raise IndexError - return res - else: - return list(iter(self))[item] - - def __contains__(self, item): - if self._cache_complete: - return item in self._cache - else: - for i in self: - if i == item: - return True - elif i > item: - return False - return False - - # __len__() introduces a large performance penality. - def count(self): - if self._len is None: - for x in self: pass - return self._len - - def before(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - last = None - if inc: - for i in gen: - if i > dt: - break - last = i - else: - for i in gen: - if i >= dt: - break - last = i - return last - - def after(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - if inc: - for i in gen: - if i >= dt: - return i - else: - for i in gen: - if i > dt: - return i - return None - - def between(self, after, before, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - started = False - l = [] - if inc: - for i in gen: - if i > before: - break - elif not started: - if i >= after: - started = True - l.append(i) - else: - l.append(i) - else: - for i in gen: - if i >= before: - break - elif not started: - if i > after: - started = True - l.append(i) - else: - l.append(i) - return l - -class rrule(rrulebase): - def __init__(self, freq, dtstart=None, - interval=1, wkst=None, count=None, until=None, bysetpos=None, - bymonth=None, bymonthday=None, byyearday=None, byeaster=None, - byweekno=None, byweekday=None, - byhour=None, byminute=None, bysecond=None, - cache=False): - rrulebase.__init__(self, cache) - global easter - if not dtstart: - dtstart = datetime.datetime.now().replace(microsecond=0) - elif not isinstance(dtstart, datetime.datetime): - dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) - else: - dtstart = dtstart.replace(microsecond=0) - self._dtstart = dtstart - self._tzinfo = dtstart.tzinfo - self._freq = freq - self._interval = interval - self._count = count - if until and not isinstance(until, datetime.datetime): - until = datetime.datetime.fromordinal(until.toordinal()) - self._until = until - if wkst is None: - self._wkst = calendar.firstweekday() - elif type(wkst) is int: - self._wkst = wkst - else: - self._wkst = wkst.weekday - if bysetpos is None: - self._bysetpos = None - elif type(bysetpos) is int: - if bysetpos == 0 or not (-366 <= bysetpos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - self._bysetpos = (bysetpos,) - else: - self._bysetpos = tuple(bysetpos) - for pos in self._bysetpos: - if pos == 0 or not (-366 <= pos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - if not (byweekno or byyearday or bymonthday or - byweekday is not None or byeaster is not None): - if freq == YEARLY: - if not bymonth: - bymonth = dtstart.month - bymonthday = dtstart.day - elif freq == MONTHLY: - bymonthday = dtstart.day - elif freq == WEEKLY: - byweekday = dtstart.weekday() - # bymonth - if not bymonth: - self._bymonth = None - elif type(bymonth) is int: - self._bymonth = (bymonth,) - else: - self._bymonth = tuple(bymonth) - # byyearday - if not byyearday: - self._byyearday = None - elif type(byyearday) is int: - self._byyearday = (byyearday,) - else: - self._byyearday = tuple(byyearday) - # byeaster - if byeaster is not None: - if not easter: - from dateutil import easter - if type(byeaster) is int: - self._byeaster = (byeaster,) - else: - self._byeaster = tuple(byeaster) - else: - self._byeaster = None - # bymonthay - if not bymonthday: - self._bymonthday = () - self._bynmonthday = () - elif type(bymonthday) is int: - if bymonthday < 0: - self._bynmonthday = (bymonthday,) - self._bymonthday = () - else: - self._bymonthday = (bymonthday,) - self._bynmonthday = () - else: - self._bymonthday = tuple([x for x in bymonthday if x > 0]) - self._bynmonthday = tuple([x for x in bymonthday if x < 0]) - # byweekno - if byweekno is None: - self._byweekno = None - elif type(byweekno) is int: - self._byweekno = (byweekno,) - else: - self._byweekno = tuple(byweekno) - # byweekday / bynweekday - if byweekday is None: - self._byweekday = None - self._bynweekday = None - elif type(byweekday) is int: - self._byweekday = (byweekday,) - self._bynweekday = None - elif hasattr(byweekday, "n"): - if not byweekday.n or freq > MONTHLY: - self._byweekday = (byweekday.weekday,) - self._bynweekday = None - else: - self._bynweekday = ((byweekday.weekday, byweekday.n),) - self._byweekday = None - else: - self._byweekday = [] - self._bynweekday = [] - for wday in byweekday: - if type(wday) is int: - self._byweekday.append(wday) - elif not wday.n or freq > MONTHLY: - self._byweekday.append(wday.weekday) - else: - self._bynweekday.append((wday.weekday, wday.n)) - self._byweekday = tuple(self._byweekday) - self._bynweekday = tuple(self._bynweekday) - if not self._byweekday: - self._byweekday = None - elif not self._bynweekday: - self._bynweekday = None - # byhour - if byhour is None: - if freq < HOURLY: - self._byhour = (dtstart.hour,) - else: - self._byhour = None - elif type(byhour) is int: - self._byhour = (byhour,) - else: - self._byhour = tuple(byhour) - # byminute - if byminute is None: - if freq < MINUTELY: - self._byminute = (dtstart.minute,) - else: - self._byminute = None - elif type(byminute) is int: - self._byminute = (byminute,) - else: - self._byminute = tuple(byminute) - # bysecond - if bysecond is None: - if freq < SECONDLY: - self._bysecond = (dtstart.second,) - else: - self._bysecond = None - elif type(bysecond) is int: - self._bysecond = (bysecond,) - else: - self._bysecond = tuple(bysecond) - - if self._freq >= HOURLY: - self._timeset = None - else: - self._timeset = [] - for hour in self._byhour: - for minute in self._byminute: - for second in self._bysecond: - self._timeset.append( - datetime.time(hour, minute, second, - tzinfo=self._tzinfo)) - self._timeset.sort() - self._timeset = tuple(self._timeset) - - def _iter(self): - year, month, day, hour, minute, second, weekday, yearday, _ = \ - self._dtstart.timetuple() - - # Some local variables to speed things up a bit - freq = self._freq - interval = self._interval - wkst = self._wkst - until = self._until - bymonth = self._bymonth - byweekno = self._byweekno - byyearday = self._byyearday - byweekday = self._byweekday - byeaster = self._byeaster - bymonthday = self._bymonthday - bynmonthday = self._bynmonthday - bysetpos = self._bysetpos - byhour = self._byhour - byminute = self._byminute - bysecond = self._bysecond - - ii = _iterinfo(self) - ii.rebuild(year, month) - - getdayset = {YEARLY:ii.ydayset, - MONTHLY:ii.mdayset, - WEEKLY:ii.wdayset, - DAILY:ii.ddayset, - HOURLY:ii.ddayset, - MINUTELY:ii.ddayset, - SECONDLY:ii.ddayset}[freq] - - if freq < HOURLY: - timeset = self._timeset - else: - gettimeset = {HOURLY:ii.htimeset, - MINUTELY:ii.mtimeset, - SECONDLY:ii.stimeset}[freq] - if ((freq >= HOURLY and - self._byhour and hour not in self._byhour) or - (freq >= MINUTELY and - self._byminute and minute not in self._byminute) or - (freq >= SECONDLY and - self._bysecond and second not in self._bysecond)): - timeset = () - else: - timeset = gettimeset(hour, minute, second) - - total = 0 - count = self._count - while True: - # Get dayset with the right frequency - dayset, start, end = getdayset(year, month, day) - - # Do the "hard" work ;-) - filtered = False - for i in dayset[start:end]: - if ((bymonth and ii.mmask[i] not in bymonth) or - (byweekno and not ii.wnomask[i]) or - (byweekday and ii.wdaymask[i] not in byweekday) or - (ii.nwdaymask and not ii.nwdaymask[i]) or - (byeaster and not ii.eastermask[i]) or - ((bymonthday or bynmonthday) and - ii.mdaymask[i] not in bymonthday and - ii.nmdaymask[i] not in bynmonthday) or - (byyearday and - ((i < ii.yearlen and i+1 not in byyearday - and -ii.yearlen+i not in byyearday) or - (i >= ii.yearlen and i+1-ii.yearlen not in byyearday - and -ii.nextyearlen+i-ii.yearlen - not in byyearday)))): - dayset[i] = None - filtered = True - - # Output results - if bysetpos and timeset: - poslist = [] - for pos in bysetpos: - if pos < 0: - daypos, timepos = divmod(pos, len(timeset)) - else: - daypos, timepos = divmod(pos-1, len(timeset)) - try: - i = [x for x in dayset[start:end] - if x is not None][daypos] - time = timeset[timepos] - except IndexError: - pass - else: - date = datetime.date.fromordinal(ii.yearordinal+i) - res = datetime.datetime.combine(date, time) - if res not in poslist: - poslist.append(res) - poslist.sort() - for res in poslist: - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - else: - for i in dayset[start:end]: - if i is not None: - date = datetime.date.fromordinal(ii.yearordinal+i) - for time in timeset: - res = datetime.datetime.combine(date, time) - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - - # Handle frequency and interval - fixday = False - if freq == YEARLY: - year += interval - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == MONTHLY: - month += interval - if month > 12: - div, mod = divmod(month, 12) - month = mod - year += div - if month == 0: - month = 12 - year -= 1 - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == WEEKLY: - if wkst > weekday: - day += -(weekday+1+(6-wkst))+self._interval*7 - else: - day += -(weekday-wkst)+self._interval*7 - weekday = wkst - fixday = True - elif freq == DAILY: - day += interval - fixday = True - elif freq == HOURLY: - if filtered: - # Jump to one iteration before next day - hour += ((23-hour)//interval)*interval - while True: - hour += interval - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if not byhour or hour in byhour: - break - timeset = gettimeset(hour, minute, second) - elif freq == MINUTELY: - if filtered: - # Jump to one iteration before next day - minute += ((1439-(hour*60+minute))//interval)*interval - while True: - minute += interval - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - filtered = False - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute)): - break - timeset = gettimeset(hour, minute, second) - elif freq == SECONDLY: - if filtered: - # Jump to one iteration before next day - second += (((86399-(hour*3600+minute*60+second)) - //interval)*interval) - while True: - second += self._interval - div, mod = divmod(second, 60) - if div: - second = mod - minute += div - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute) and - (not bysecond or second in bysecond)): - break - timeset = gettimeset(hour, minute, second) - - if fixday and day > 28: - daysinmonth = calendar.monthrange(year, month)[1] - if day > daysinmonth: - while day > daysinmonth: - day -= daysinmonth - month += 1 - if month == 13: - month = 1 - year += 1 - if year > datetime.MAXYEAR: - self._len = total - return - daysinmonth = calendar.monthrange(year, month)[1] - ii.rebuild(year, month) - -class _iterinfo(object): - __slots__ = ["rrule", "lastyear", "lastmonth", - "yearlen", "nextyearlen", "yearordinal", "yearweekday", - "mmask", "mrange", "mdaymask", "nmdaymask", - "wdaymask", "wnomask", "nwdaymask", "eastermask"] - - def __init__(self, rrule): - for attr in self.__slots__: - setattr(self, attr, None) - self.rrule = rrule - - def rebuild(self, year, month): - # Every mask is 7 days longer to handle cross-year weekly periods. - rr = self.rrule - if year != self.lastyear: - self.yearlen = 365+calendar.isleap(year) - self.nextyearlen = 365+calendar.isleap(year+1) - firstyday = datetime.date(year, 1, 1) - self.yearordinal = firstyday.toordinal() - self.yearweekday = firstyday.weekday() - - wday = datetime.date(year, 1, 1).weekday() - if self.yearlen == 365: - self.mmask = M365MASK - self.mdaymask = MDAY365MASK - self.nmdaymask = NMDAY365MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M365RANGE - else: - self.mmask = M366MASK - self.mdaymask = MDAY366MASK - self.nmdaymask = NMDAY366MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M366RANGE - - if not rr._byweekno: - self.wnomask = None - else: - self.wnomask = [0]*(self.yearlen+7) - #no1wkst = firstwkst = self.wdaymask.index(rr._wkst) - no1wkst = firstwkst = (7-self.yearweekday+rr._wkst)%7 - if no1wkst >= 4: - no1wkst = 0 - # Number of days in the year, plus the days we got - # from last year. - wyearlen = self.yearlen+(self.yearweekday-rr._wkst)%7 - else: - # Number of days in the year, minus the days we - # left in last year. - wyearlen = self.yearlen-no1wkst - div, mod = divmod(wyearlen, 7) - numweeks = div+mod//4 - for n in rr._byweekno: - if n < 0: - n += numweeks+1 - if not (0 < n <= numweeks): - continue - if n > 1: - i = no1wkst+(n-1)*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - else: - i = no1wkst - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if 1 in rr._byweekno: - # Check week number 1 of next year as well - # TODO: Check -numweeks for next year. - i = no1wkst+numweeks*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - if i < self.yearlen: - # If week starts in next year, we - # don't care about it. - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if no1wkst: - # Check last week number of last year as - # well. If no1wkst is 0, either the year - # started on week start, or week number 1 - # got days from last year, so there are no - # days from last year's last week number in - # this year. - if -1 not in rr._byweekno: - lyearweekday = datetime.date(year-1,1,1).weekday() - lno1wkst = (7-lyearweekday+rr._wkst)%7 - lyearlen = 365+calendar.isleap(year-1) - if lno1wkst >= 4: - lno1wkst = 0 - lnumweeks = 52+(lyearlen+ - (lyearweekday-rr._wkst)%7)%7//4 - else: - lnumweeks = 52+(self.yearlen-no1wkst)%7//4 - else: - lnumweeks = -1 - if lnumweeks in rr._byweekno: - for i in range(no1wkst): - self.wnomask[i] = 1 - - if (rr._bynweekday and - (month != self.lastmonth or year != self.lastyear)): - ranges = [] - if rr._freq == YEARLY: - if rr._bymonth: - for month in rr._bymonth: - ranges.append(self.mrange[month-1:month+1]) - else: - ranges = [(0, self.yearlen)] - elif rr._freq == MONTHLY: - ranges = [self.mrange[month-1:month+1]] - if ranges: - # Weekly frequency won't get here, so we may not - # care about cross-year weekly periods. - self.nwdaymask = [0]*self.yearlen - for first, last in ranges: - last -= 1 - for wday, n in rr._bynweekday: - if n < 0: - i = last+(n+1)*7 - i -= (self.wdaymask[i]-wday)%7 - else: - i = first+(n-1)*7 - i += (7-self.wdaymask[i]+wday)%7 - if first <= i <= last: - self.nwdaymask[i] = 1 - - if rr._byeaster: - self.eastermask = [0]*(self.yearlen+7) - eyday = easter.easter(year).toordinal()-self.yearordinal - for offset in rr._byeaster: - self.eastermask[eyday+offset] = 1 - - self.lastyear = year - self.lastmonth = month - - def ydayset(self, year, month, day): - return range(self.yearlen), 0, self.yearlen - - def mdayset(self, year, month, day): - set = [None]*self.yearlen - start, end = self.mrange[month-1:month+1] - for i in range(start, end): - set[i] = i - return set, start, end - - def wdayset(self, year, month, day): - # We need to handle cross-year weeks here. - set = [None]*(self.yearlen+7) - i = datetime.date(year, month, day).toordinal()-self.yearordinal - start = i - for j in range(7): - set[i] = i - i += 1 - #if (not (0 <= i < self.yearlen) or - # self.wdaymask[i] == self.rrule._wkst): - # This will cross the year boundary, if necessary. - if self.wdaymask[i] == self.rrule._wkst: - break - return set, start, i - - def ddayset(self, year, month, day): - set = [None]*self.yearlen - i = datetime.date(year, month, day).toordinal()-self.yearordinal - set[i] = i - return set, i, i+1 - - def htimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for minute in rr._byminute: - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, - tzinfo=rr._tzinfo)) - set.sort() - return set - - def mtimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) - set.sort() - return set - - def stimeset(self, hour, minute, second): - return (datetime.time(hour, minute, second, - tzinfo=self.rrule._tzinfo),) - - -class rruleset(rrulebase): - - class _genitem: - def __init__(self, genlist, gen): - try: - self.dt = gen() - genlist.append(self) - except StopIteration: - pass - self.genlist = genlist - self.gen = gen - - def next(self): - try: - self.dt = self.gen() - except StopIteration: - self.genlist.remove(self) - - def __cmp__(self, other): - return cmp(self.dt, other.dt) - - def __init__(self, cache=False): - rrulebase.__init__(self, cache) - self._rrule = [] - self._rdate = [] - self._exrule = [] - self._exdate = [] - - def rrule(self, rrule): - self._rrule.append(rrule) - - def rdate(self, rdate): - self._rdate.append(rdate) - - def exrule(self, exrule): - self._exrule.append(exrule) - - def exdate(self, exdate): - self._exdate.append(exdate) - - def _iter(self): - rlist = [] - self._rdate.sort() - self._genitem(rlist, iter(self._rdate).next) - for gen in [iter(x).next for x in self._rrule]: - self._genitem(rlist, gen) - rlist.sort() - exlist = [] - self._exdate.sort() - self._genitem(exlist, iter(self._exdate).next) - for gen in [iter(x).next for x in self._exrule]: - self._genitem(exlist, gen) - exlist.sort() - lastdt = None - total = 0 - while rlist: - ritem = rlist[0] - if not lastdt or lastdt != ritem.dt: - while exlist and exlist[0] < ritem: - exlist[0].next() - exlist.sort() - if not exlist or ritem != exlist[0]: - total += 1 - yield ritem.dt - lastdt = ritem.dt - ritem.next() - rlist.sort() - self._len = total - -class _rrulestr: - - _freq_map = {"YEARLY": YEARLY, - "MONTHLY": MONTHLY, - "WEEKLY": WEEKLY, - "DAILY": DAILY, - "HOURLY": HOURLY, - "MINUTELY": MINUTELY, - "SECONDLY": SECONDLY} - - _weekday_map = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} - - def _handle_int(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = int(value) - - def _handle_int_list(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = [int(x) for x in value.split(',')] - - _handle_INTERVAL = _handle_int - _handle_COUNT = _handle_int - _handle_BYSETPOS = _handle_int_list - _handle_BYMONTH = _handle_int_list - _handle_BYMONTHDAY = _handle_int_list - _handle_BYYEARDAY = _handle_int_list - _handle_BYEASTER = _handle_int_list - _handle_BYWEEKNO = _handle_int_list - _handle_BYHOUR = _handle_int_list - _handle_BYMINUTE = _handle_int_list - _handle_BYSECOND = _handle_int_list - - def _handle_FREQ(self, rrkwargs, name, value, **kwargs): - rrkwargs["freq"] = self._freq_map[value] - - def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): - global parser - if not parser: - from dateutil import parser - try: - rrkwargs["until"] = parser.parse(value, - ignoretz=kwargs.get("ignoretz"), - tzinfos=kwargs.get("tzinfos")) - except ValueError: - raise ValueError, "invalid until date" - - def _handle_WKST(self, rrkwargs, name, value, **kwargs): - rrkwargs["wkst"] = self._weekday_map[value] - - def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwarsg): - l = [] - for wday in value.split(','): - for i in range(len(wday)): - if wday[i] not in '+-0123456789': - break - n = wday[:i] or None - w = wday[i:] - if n: n = int(n) - l.append(weekdays[self._weekday_map[w]](n)) - rrkwargs["byweekday"] = l - - _handle_BYDAY = _handle_BYWEEKDAY - - def _parse_rfc_rrule(self, line, - dtstart=None, - cache=False, - ignoretz=False, - tzinfos=None): - if line.find(':') != -1: - name, value = line.split(':') - if name != "RRULE": - raise ValueError, "unknown parameter name" - else: - value = line - rrkwargs = {} - for pair in value.split(';'): - name, value = pair.split('=') - name = name.upper() - value = value.upper() - try: - getattr(self, "_handle_"+name)(rrkwargs, name, value, - ignoretz=ignoretz, - tzinfos=tzinfos) - except AttributeError: - raise ValueError, "unknown parameter '%s'" % name - except (KeyError, ValueError): - raise ValueError, "invalid '%s': %s" % (name, value) - return rrule(dtstart=dtstart, cache=cache, **rrkwargs) - - def _parse_rfc(self, s, - dtstart=None, - cache=False, - unfold=False, - forceset=False, - compatible=False, - ignoretz=False, - tzinfos=None): - global parser - if compatible: - forceset = True - unfold = True - s = s.upper() - if not s.strip(): - raise ValueError, "empty string" - if unfold: - lines = s.splitlines() - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - else: - lines = s.split() - if (not forceset and len(lines) == 1 and - (s.find(':') == -1 or s.startswith('RRULE:'))): - return self._parse_rfc_rrule(lines[0], cache=cache, - dtstart=dtstart, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - rrulevals = [] - rdatevals = [] - exrulevals = [] - exdatevals = [] - for line in lines: - if not line: - continue - if line.find(':') == -1: - name = "RRULE" - value = line - else: - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError, "empty property name" - name = parms[0] - parms = parms[1:] - if name == "RRULE": - for parm in parms: - raise ValueError, "unsupported RRULE parm: "+parm - rrulevals.append(value) - elif name == "RDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError, "unsupported RDATE parm: "+parm - rdatevals.append(value) - elif name == "EXRULE": - for parm in parms: - raise ValueError, "unsupported EXRULE parm: "+parm - exrulevals.append(value) - elif name == "EXDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError, "unsupported RDATE parm: "+parm - exdatevals.append(value) - elif name == "DTSTART": - for parm in parms: - raise ValueError, "unsupported DTSTART parm: "+parm - if not parser: - from dateutil import parser - dtstart = parser.parse(value, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - raise ValueError, "unsupported property: "+name - if (forceset or len(rrulevals) > 1 or - rdatevals or exrulevals or exdatevals): - if not parser and (rdatevals or exdatevals): - from dateutil import parser - set = rruleset(cache=cache) - for value in rrulevals: - set.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in rdatevals: - for datestr in value.split(','): - set.rdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exrulevals: - set.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exdatevals: - for datestr in value.split(','): - set.exdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - if compatible and dtstart: - set.rdate(dtstart) - return set - else: - return self._parse_rfc_rrule(rrulevals[0], - dtstart=dtstart, - cache=cache, - ignoretz=ignoretz, - tzinfos=tzinfos) - - def __call__(self, s, **kwargs): - return self._parse_rfc(s, **kwargs) - -rrulestr = _rrulestr() - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/tz.py b/lib/dateutil_py2/tz.py deleted file mode 100644 index 0e28d6b33209..000000000000 --- a/lib/dateutil_py2/tz.py +++ /dev/null @@ -1,951 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -import datetime -import struct -import time -import sys -import os - -relativedelta = None -parser = None -rrule = None - -__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", - "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"] - -try: - from dateutil.tzwin import tzwin, tzwinlocal -except (ImportError, OSError): - tzwin, tzwinlocal = None, None - -ZERO = datetime.timedelta(0) -EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() - -class tzutc(datetime.tzinfo): - - def utcoffset(self, dt): - return ZERO - - def dst(self, dt): - return ZERO - - def tzname(self, dt): - return "UTC" - - def __eq__(self, other): - return (isinstance(other, tzutc) or - (isinstance(other, tzoffset) and other._offset == ZERO)) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzoffset(datetime.tzinfo): - - def __init__(self, name, offset): - self._name = name - self._offset = datetime.timedelta(seconds=offset) - - def utcoffset(self, dt): - return self._offset - - def dst(self, dt): - return ZERO - - def tzname(self, dt): - return self._name - - def __eq__(self, other): - return (isinstance(other, tzoffset) and - self._offset == other._offset) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(%s, %s)" % (self.__class__.__name__, - `self._name`, - self._offset.days*86400+self._offset.seconds) - - __reduce__ = object.__reduce__ - -class tzlocal(datetime.tzinfo): - - _std_offset = datetime.timedelta(seconds=-time.timezone) - if time.daylight: - _dst_offset = datetime.timedelta(seconds=-time.altzone) - else: - _dst_offset = _std_offset - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - def tzname(self, dt): - return time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - # We can't use mktime here. It is unstable when deciding if - # the hour near to a change is DST or not. - # - # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, - # dt.minute, dt.second, dt.weekday(), 0, -1)) - # return time.localtime(timestamp).tm_isdst - # - # The code above yields the following result: - # - #>>> import tz, datetime - #>>> t = tz.tzlocal() - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - # - # Here is a more stable implementation: - # - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - return time.localtime(timestamp+time.timezone).tm_isdst - - def __eq__(self, other): - if not isinstance(other, tzlocal): - return False - return (self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset) - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class _ttinfo(object): - __slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"] - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def __repr__(self): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, `value`)) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - - def __eq__(self, other): - if not isinstance(other, _ttinfo): - return False - return (self.offset == other.offset and - self.delta == other.delta and - self.isdst == other.isdst and - self.abbr == other.abbr and - self.isstd == other.isstd and - self.isgmt == other.isgmt) - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - state = {} - for name in self.__slots__: - state[name] = getattr(self, name, None) - return state - - def __setstate__(self, state): - for name in self.__slots__: - if name in state: - setattr(self, name, state[name]) - -class tzfile(datetime.tzinfo): - - # http://www.twinsun.com/tz/tz-link.htm - # ftp://elsie.nci.nih.gov/pub/tz*.tar.gz - - def __init__(self, fileobj): - if isinstance(fileobj, basestring): - self._filename = fileobj - fileobj = open(fileobj) - elif hasattr(fileobj, "name"): - self._filename = fileobj.name - else: - self._filename = `fileobj` - - # From tzfile(5): - # - # The time zone information files used by tzset(3) - # begin with the magic characters "TZif" to identify - # them as time zone information files, followed by - # sixteen bytes reserved for future use, followed by - # six four-byte values of type long, written in a - # ``standard'' byte order (the high-order byte - # of the value is written first). - - if fileobj.read(4) != "TZif": - raise ValueError, "magic not found" - - fileobj.read(16) - - ( - # The number of UTC/local indicators stored in the file. - ttisgmtcnt, - - # The number of standard/wall indicators stored in the file. - ttisstdcnt, - - # The number of leap seconds for which data is - # stored in the file. - leapcnt, - - # The number of "transition times" for which data - # is stored in the file. - timecnt, - - # The number of "local time types" for which data - # is stored in the file (must not be zero). - typecnt, - - # The number of characters of "time zone - # abbreviation strings" stored in the file. - charcnt, - - ) = struct.unpack(">6l", fileobj.read(24)) - - # The above header is followed by tzh_timecnt four-byte - # values of type long, sorted in ascending order. - # These values are written in ``standard'' byte order. - # Each is used as a transition time (as returned by - # time(2)) at which the rules for computing local time - # change. - - if timecnt: - self._trans_list = struct.unpack(">%dl" % timecnt, - fileobj.read(timecnt*4)) - else: - self._trans_list = [] - - # Next come tzh_timecnt one-byte values of type unsigned - # char; each one tells which of the different types of - # ``local time'' types described in the file is associated - # with the same-indexed transition time. These values - # serve as indices into an array of ttinfo structures that - # appears next in the file. - - if timecnt: - self._trans_idx = struct.unpack(">%dB" % timecnt, - fileobj.read(timecnt)) - else: - self._trans_idx = [] - - # Each ttinfo structure is written as a four-byte value - # for tt_gmtoff of type long, in a standard byte - # order, followed by a one-byte value for tt_isdst - # and a one-byte value for tt_abbrind. In each - # structure, tt_gmtoff gives the number of - # seconds to be added to UTC, tt_isdst tells whether - # tm_isdst should be set by localtime(3), and - # tt_abbrind serves as an index into the array of - # time zone abbreviation characters that follow the - # ttinfo structure(s) in the file. - - ttinfo = [] - - for i in range(typecnt): - ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) - - abbr = fileobj.read(charcnt) - - # Then there are tzh_leapcnt pairs of four-byte - # values, written in standard byte order; the - # first value of each pair gives the time (as - # returned by time(2)) at which a leap second - # occurs; the second gives the total number of - # leap seconds to be applied after the given time. - # The pairs of values are sorted in ascending order - # by time. - - # Not used, for now - if leapcnt: - leap = struct.unpack(">%dl" % (leapcnt*2), - fileobj.read(leapcnt*8)) - - # Then there are tzh_ttisstdcnt standard/wall - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as standard - # time or wall clock time, and are used when - # a time zone file is used in handling POSIX-style - # time zone environment variables. - - if ttisstdcnt: - isstd = struct.unpack(">%db" % ttisstdcnt, - fileobj.read(ttisstdcnt)) - - # Finally, there are tzh_ttisgmtcnt UTC/local - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as UTC or - # local time, and are used when a time zone file - # is used in handling POSIX-style time zone envi- - # ronment variables. - - if ttisgmtcnt: - isgmt = struct.unpack(">%db" % ttisgmtcnt, - fileobj.read(ttisgmtcnt)) - - # ** Everything has been read ** - - # Build ttinfo list - self._ttinfo_list = [] - for i in range(typecnt): - gmtoff, isdst, abbrind = ttinfo[i] - # Round to full-minutes if that's not the case. Python's - # datetime doesn't accept sub-minute timezones. Check - # http://python.org/sf/1447945 for some information. - gmtoff = (gmtoff+30)//60*60 - tti = _ttinfo() - tti.offset = gmtoff - tti.delta = datetime.timedelta(seconds=gmtoff) - tti.isdst = isdst - tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] - tti.isstd = (ttisstdcnt > i and isstd[i] != 0) - tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) - self._ttinfo_list.append(tti) - - # Replace ttinfo indexes for ttinfo objects. - trans_idx = [] - for idx in self._trans_idx: - trans_idx.append(self._ttinfo_list[idx]) - self._trans_idx = tuple(trans_idx) - - # Set standard, dst, and before ttinfos. before will be - # used when a given time is before any transitions, - # and will be set to the first non-dst ttinfo, or to - # the first dst, if all of them are dst. - self._ttinfo_std = None - self._ttinfo_dst = None - self._ttinfo_before = None - if self._ttinfo_list: - if not self._trans_list: - self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0] - else: - for i in range(timecnt-1,-1,-1): - tti = self._trans_idx[i] - if not self._ttinfo_std and not tti.isdst: - self._ttinfo_std = tti - elif not self._ttinfo_dst and tti.isdst: - self._ttinfo_dst = tti - if self._ttinfo_std and self._ttinfo_dst: - break - else: - if self._ttinfo_dst and not self._ttinfo_std: - self._ttinfo_std = self._ttinfo_dst - - for tti in self._ttinfo_list: - if not tti.isdst: - self._ttinfo_before = tti - break - else: - self._ttinfo_before = self._ttinfo_list[0] - - # Now fix transition times to become relative to wall time. - # - # I'm not sure about this. In my tests, the tz source file - # is setup to wall time, and in the binary file isstd and - # isgmt are off, so it should be in wall time. OTOH, it's - # always in gmt time. Let me know if you have comments - # about this. - laststdoffset = 0 - self._trans_list = list(self._trans_list) - for i in range(len(self._trans_list)): - tti = self._trans_idx[i] - if not tti.isdst: - # This is std time. - self._trans_list[i] += tti.offset - laststdoffset = tti.offset - else: - # This is dst time. Convert to std. - self._trans_list[i] += laststdoffset - self._trans_list = tuple(self._trans_list) - - def _find_ttinfo(self, dt, laststd=0): - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - idx = 0 - for trans in self._trans_list: - if timestamp < trans: - break - idx += 1 - else: - return self._ttinfo_std - if idx == 0: - return self._ttinfo_before - if laststd: - while idx > 0: - tti = self._trans_idx[idx-1] - if not tti.isdst: - return tti - idx -= 1 - else: - return self._ttinfo_std - else: - return self._trans_idx[idx-1] - - def utcoffset(self, dt): - if not self._ttinfo_std: - return ZERO - return self._find_ttinfo(dt).delta - - def dst(self, dt): - if not self._ttinfo_dst: - return ZERO - tti = self._find_ttinfo(dt) - if not tti.isdst: - return ZERO - - # The documentation says that utcoffset()-dst() must - # be constant for every dt. - return tti.delta-self._find_ttinfo(dt, laststd=1).delta - - # An alternative for that would be: - # - # return self._ttinfo_dst.offset-self._ttinfo_std.offset - # - # However, this class stores historical changes in the - # dst offset, so I belive that this wouldn't be the right - # way to implement this. - - def tzname(self, dt): - if not self._ttinfo_std: - return None - return self._find_ttinfo(dt).abbr - - def __eq__(self, other): - if not isinstance(other, tzfile): - return False - return (self._trans_list == other._trans_list and - self._trans_idx == other._trans_idx and - self._ttinfo_list == other._ttinfo_list) - - def __ne__(self, other): - return not self.__eq__(other) - - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._filename`) - - def __reduce__(self): - if not os.path.isfile(self._filename): - raise ValueError, "Unpickable %s class" % self.__class__.__name__ - return (self.__class__, (self._filename,)) - -class tzrange(datetime.tzinfo): - - def __init__(self, stdabbr, stdoffset=None, - dstabbr=None, dstoffset=None, - start=None, end=None): - global relativedelta - if not relativedelta: - from dateutil import relativedelta - self._std_abbr = stdabbr - self._dst_abbr = dstabbr - if stdoffset is not None: - self._std_offset = datetime.timedelta(seconds=stdoffset) - else: - self._std_offset = ZERO - if dstoffset is not None: - self._dst_offset = datetime.timedelta(seconds=dstoffset) - elif dstabbr and stdoffset is not None: - self._dst_offset = self._std_offset+datetime.timedelta(hours=+1) - else: - self._dst_offset = ZERO - if dstabbr and start is None: - self._start_delta = relativedelta.relativedelta( - hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) - else: - self._start_delta = start - if dstabbr and end is None: - self._end_delta = relativedelta.relativedelta( - hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) - else: - self._end_delta = end - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - def tzname(self, dt): - if self._isdst(dt): - return self._dst_abbr - else: - return self._std_abbr - - def _isdst(self, dt): - if not self._start_delta: - return False - year = datetime.datetime(dt.year,1,1) - start = year+self._start_delta - end = year+self._end_delta - dt = dt.replace(tzinfo=None) - if start < end: - return dt >= start and dt < end - else: - return dt >= start or dt < end - - def __eq__(self, other): - if not isinstance(other, tzrange): - return False - return (self._std_abbr == other._std_abbr and - self._dst_abbr == other._dst_abbr and - self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset and - self._start_delta == other._start_delta and - self._end_delta == other._end_delta) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(...)" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzstr(tzrange): - - def __init__(self, s): - global parser - if not parser: - from dateutil import parser - self._s = s - - res = parser._parsetz(s) - if res is None: - raise ValueError, "unknown string format" - - # Here we break the compatibility with the TZ variable handling. - # GMT-3 actually *means* the timezone -3. - if res.stdabbr in ("GMT", "UTC"): - res.stdoffset *= -1 - - # We must initialize it first, since _delta() needs - # _std_offset and _dst_offset set. Use False in start/end - # to avoid building it two times. - tzrange.__init__(self, res.stdabbr, res.stdoffset, - res.dstabbr, res.dstoffset, - start=False, end=False) - - if not res.dstabbr: - self._start_delta = None - self._end_delta = None - else: - self._start_delta = self._delta(res.start) - if self._start_delta: - self._end_delta = self._delta(res.end, isend=1) - - def _delta(self, x, isend=0): - kwargs = {} - if x.month is not None: - kwargs["month"] = x.month - if x.weekday is not None: - kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) - if x.week > 0: - kwargs["day"] = 1 - else: - kwargs["day"] = 31 - elif x.day: - kwargs["day"] = x.day - elif x.yday is not None: - kwargs["yearday"] = x.yday - elif x.jyday is not None: - kwargs["nlyearday"] = x.jyday - if not kwargs: - # Default is to start on first sunday of april, and end - # on last sunday of october. - if not isend: - kwargs["month"] = 4 - kwargs["day"] = 1 - kwargs["weekday"] = relativedelta.SU(+1) - else: - kwargs["month"] = 10 - kwargs["day"] = 31 - kwargs["weekday"] = relativedelta.SU(-1) - if x.time is not None: - kwargs["seconds"] = x.time - else: - # Default is 2AM. - kwargs["seconds"] = 7200 - if isend: - # Convert to standard time, to follow the documented way - # of working with the extra hour. See the documentation - # of the tzinfo class. - delta = self._dst_offset-self._std_offset - kwargs["seconds"] -= delta.seconds+delta.days*86400 - return relativedelta.relativedelta(**kwargs) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._s`) - -class _tzicalvtzcomp: - def __init__(self, tzoffsetfrom, tzoffsetto, isdst, - tzname=None, rrule=None): - self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) - self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) - self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom - self.isdst = isdst - self.tzname = tzname - self.rrule = rrule - -class _tzicalvtz(datetime.tzinfo): - def __init__(self, tzid, comps=[]): - self._tzid = tzid - self._comps = comps - self._cachedate = [] - self._cachecomp = [] - - def _find_comp(self, dt): - if len(self._comps) == 1: - return self._comps[0] - dt = dt.replace(tzinfo=None) - try: - return self._cachecomp[self._cachedate.index(dt)] - except ValueError: - pass - lastcomp = None - lastcompdt = None - for comp in self._comps: - if not comp.isdst: - # Handle the extra hour in DST -> STD - compdt = comp.rrule.before(dt-comp.tzoffsetdiff, inc=True) - else: - compdt = comp.rrule.before(dt, inc=True) - if compdt and (not lastcompdt or lastcompdt < compdt): - lastcompdt = compdt - lastcomp = comp - if not lastcomp: - # RFC says nothing about what to do when a given - # time is before the first onset date. We'll look for the - # first standard component, or the first component, if - # none is found. - for comp in self._comps: - if not comp.isdst: - lastcomp = comp - break - else: - lastcomp = comp[0] - self._cachedate.insert(0, dt) - self._cachecomp.insert(0, lastcomp) - if len(self._cachedate) > 10: - self._cachedate.pop() - self._cachecomp.pop() - return lastcomp - - def utcoffset(self, dt): - return self._find_comp(dt).tzoffsetto - - def dst(self, dt): - comp = self._find_comp(dt) - if comp.isdst: - return comp.tzoffsetdiff - else: - return ZERO - - def tzname(self, dt): - return self._find_comp(dt).tzname - - def __repr__(self): - return "" % `self._tzid` - - __reduce__ = object.__reduce__ - -class tzical: - def __init__(self, fileobj): - global rrule - if not rrule: - from dateutil import rrule - - if isinstance(fileobj, basestring): - self._s = fileobj - fileobj = open(fileobj) - elif hasattr(fileobj, "name"): - self._s = fileobj.name - else: - self._s = `fileobj` - - self._vtz = {} - - self._parse_rfc(fileobj.read()) - - def keys(self): - return self._vtz.keys() - - def get(self, tzid=None): - if tzid is None: - keys = self._vtz.keys() - if len(keys) == 0: - raise ValueError, "no timezones defined" - elif len(keys) > 1: - raise ValueError, "more than one timezone available" - tzid = keys[0] - return self._vtz.get(tzid) - - def _parse_offset(self, s): - s = s.strip() - if not s: - raise ValueError, "empty offset" - if s[0] in ('+', '-'): - signal = (-1,+1)[s[0]=='+'] - s = s[1:] - else: - signal = +1 - if len(s) == 4: - return (int(s[:2])*3600+int(s[2:])*60)*signal - elif len(s) == 6: - return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal - else: - raise ValueError, "invalid offset: "+s - - def _parse_rfc(self, s): - lines = s.splitlines() - if not lines: - raise ValueError, "empty string" - - # Unfold - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - - tzid = None - comps = [] - invtz = False - comptype = None - for line in lines: - if not line: - continue - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError, "empty property name" - name = parms[0].upper() - parms = parms[1:] - if invtz: - if name == "BEGIN": - if value in ("STANDARD", "DAYLIGHT"): - # Process component - pass - else: - raise ValueError, "unknown component: "+value - comptype = value - founddtstart = False - tzoffsetfrom = None - tzoffsetto = None - rrulelines = [] - tzname = None - elif name == "END": - if value == "VTIMEZONE": - if comptype: - raise ValueError, \ - "component not closed: "+comptype - if not tzid: - raise ValueError, \ - "mandatory TZID not found" - if not comps: - raise ValueError, \ - "at least one component is needed" - # Process vtimezone - self._vtz[tzid] = _tzicalvtz(tzid, comps) - invtz = False - elif value == comptype: - if not founddtstart: - raise ValueError, \ - "mandatory DTSTART not found" - if tzoffsetfrom is None: - raise ValueError, \ - "mandatory TZOFFSETFROM not found" - if tzoffsetto is None: - raise ValueError, \ - "mandatory TZOFFSETFROM not found" - # Process component - rr = None - if rrulelines: - rr = rrule.rrulestr("\n".join(rrulelines), - compatible=True, - ignoretz=True, - cache=True) - comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, - (comptype == "DAYLIGHT"), - tzname, rr) - comps.append(comp) - comptype = None - else: - raise ValueError, \ - "invalid component end: "+value - elif comptype: - if name == "DTSTART": - rrulelines.append(line) - founddtstart = True - elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): - rrulelines.append(line) - elif name == "TZOFFSETFROM": - if parms: - raise ValueError, \ - "unsupported %s parm: %s "%(name, parms[0]) - tzoffsetfrom = self._parse_offset(value) - elif name == "TZOFFSETTO": - if parms: - raise ValueError, \ - "unsupported TZOFFSETTO parm: "+parms[0] - tzoffsetto = self._parse_offset(value) - elif name == "TZNAME": - if parms: - raise ValueError, \ - "unsupported TZNAME parm: "+parms[0] - tzname = value - elif name == "COMMENT": - pass - else: - raise ValueError, "unsupported property: "+name - else: - if name == "TZID": - if parms: - raise ValueError, \ - "unsupported TZID parm: "+parms[0] - tzid = value - elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): - pass - else: - raise ValueError, "unsupported property: "+name - elif name == "BEGIN" and value == "VTIMEZONE": - tzid = None - comps = [] - invtz = True - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, `self._s`) - -if sys.platform != "win32": - TZFILES = ["/etc/localtime", "localtime"] - TZPATHS = ["/usr/share/zoneinfo", "/usr/lib/zoneinfo", "/etc/zoneinfo"] -else: - TZFILES = [] - TZPATHS = [] - -def gettz(name=None): - tz = None - if not name: - try: - name = os.environ["TZ"] - except KeyError: - pass - if name is None or name == ":": - for filepath in TZFILES: - if not os.path.isabs(filepath): - filename = filepath - for path in TZPATHS: - filepath = os.path.join(path, filename) - if os.path.isfile(filepath): - break - else: - continue - if os.path.isfile(filepath): - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = tzlocal() - else: - if name.startswith(":"): - name = name[:-1] - if os.path.isabs(name): - if os.path.isfile(name): - tz = tzfile(name) - else: - tz = None - else: - for path in TZPATHS: - filepath = os.path.join(path, name) - if not os.path.isfile(filepath): - filepath = filepath.replace(' ','_') - if not os.path.isfile(filepath): - continue - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = None - if tzwin: - try: - tz = tzwin(name) - except OSError: - pass - if not tz: - from dateutil.zoneinfo import gettz - tz = gettz(name) - if not tz: - for c in name: - # name must have at least one offset to be a tzstr - if c in "0123456789": - try: - tz = tzstr(name) - except ValueError: - pass - break - else: - if name in ("GMT", "UTC"): - tz = tzutc() - elif name in time.tzname: - tz = tzlocal() - return tz - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py2/tzwin.py b/lib/dateutil_py2/tzwin.py deleted file mode 100644 index 073e0ff68e3f..000000000000 --- a/lib/dateutil_py2/tzwin.py +++ /dev/null @@ -1,180 +0,0 @@ -# This code was originally contributed by Jeffrey Harris. -import datetime -import struct -import _winreg - -__author__ = "Jeffrey Harris & Gustavo Niemeyer " - -__all__ = ["tzwin", "tzwinlocal"] - -ONEWEEK = datetime.timedelta(7) - -TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" -TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" -TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" - -def _settzkeyname(): - global TZKEYNAME - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - try: - _winreg.OpenKey(handle, TZKEYNAMENT).Close() - TZKEYNAME = TZKEYNAMENT - except WindowsError: - TZKEYNAME = TZKEYNAME9X - handle.Close() - -_settzkeyname() - -class tzwinbase(datetime.tzinfo): - """tzinfo class based on win32's timezones available in the registry.""" - - def utcoffset(self, dt): - if self._isdst(dt): - return datetime.timedelta(minutes=self._dstoffset) - else: - return datetime.timedelta(minutes=self._stdoffset) - - def dst(self, dt): - if self._isdst(dt): - minutes = self._dstoffset - self._stdoffset - return datetime.timedelta(minutes=minutes) - else: - return datetime.timedelta(0) - - def tzname(self, dt): - if self._isdst(dt): - return self._dstname - else: - return self._stdname - - def list(): - """Return a list of all time zones known to the system.""" - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - tzkey = _winreg.OpenKey(handle, TZKEYNAME) - result = [_winreg.EnumKey(tzkey, i) - for i in range(_winreg.QueryInfoKey(tzkey)[0])] - tzkey.Close() - handle.Close() - return result - list = staticmethod(list) - - def display(self): - return self._display - - def _isdst(self, dt): - dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, - self._dsthour, self._dstminute, - self._dstweeknumber) - dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, - self._stdhour, self._stdminute, - self._stdweeknumber) - if dston < dstoff: - return dston <= dt.replace(tzinfo=None) < dstoff - else: - return not dstoff <= dt.replace(tzinfo=None) < dston - - -class tzwin(tzwinbase): - - def __init__(self, name): - self._name = name - - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - tzkey = _winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) - keydict = valuestodict(tzkey) - tzkey.Close() - handle.Close() - - self._stdname = keydict["Std"].encode("iso-8859-1") - self._dstname = keydict["Dlt"].encode("iso-8859-1") - - self._display = keydict["Display"] - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=3l16h", keydict["TZI"]) - self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 - self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[4:9] - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[12:17] - - def __repr__(self): - return "tzwin(%s)" % repr(self._name) - - def __reduce__(self): - return (self.__class__, (self._name,)) - - -class tzwinlocal(tzwinbase): - - def __init__(self): - - handle = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) - - tzlocalkey = _winreg.OpenKey(handle, TZLOCALKEYNAME) - keydict = valuestodict(tzlocalkey) - tzlocalkey.Close() - - self._stdname = keydict["StandardName"].encode("iso-8859-1") - self._dstname = keydict["DaylightName"].encode("iso-8859-1") - - try: - tzkey = _winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) - _keydict = valuestodict(tzkey) - self._display = _keydict["Display"] - tzkey.Close() - except OSError: - self._display = None - - handle.Close() - - self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] - self._dstoffset = self._stdoffset-keydict["DaylightBias"] - - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=8h", keydict["StandardStart"]) - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[1:6] - - tup = struct.unpack("=8h", keydict["DaylightStart"]) - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[1:6] - - def __reduce__(self): - return (self.__class__, ()) - -def picknthweekday(year, month, dayofweek, hour, minute, whichweek): - """dayofweek == 0 means Sunday, whichweek 5 means last instance""" - first = datetime.datetime(year, month, 1, hour, minute) - weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) - for n in xrange(whichweek): - dt = weekdayone+(whichweek-n)*ONEWEEK - if dt.month == month: - return dt - -def valuestodict(key): - """Convert a registry key's values to a dictionary.""" - dict = {} - size = _winreg.QueryInfoKey(key)[1] - for i in range(size): - data = _winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict diff --git a/lib/dateutil_py2/zoneinfo/__init__.py b/lib/dateutil_py2/zoneinfo/__init__.py deleted file mode 100644 index 9bed6264c8b9..000000000000 --- a/lib/dateutil_py2/zoneinfo/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -Copyright (c) 2003-2005 Gustavo Niemeyer - -This module offers extensions to the standard python 2.3+ -datetime module. -""" -from dateutil.tz import tzfile -from tarfile import TarFile -import os - -__author__ = "Gustavo Niemeyer " -__license__ = "PSF License" - -__all__ = ["setcachesize", "gettz", "rebuild"] - -CACHE = [] -CACHESIZE = 10 - -class tzfile(tzfile): - def __reduce__(self): - return (gettz, (self._filename,)) - -def getzoneinfofile(): - filenames = os.listdir(os.path.join(os.path.dirname(__file__))) - filenames.sort() - filenames.reverse() - for entry in filenames: - if entry.startswith("zoneinfo") and ".tar." in entry: - return os.path.join(os.path.dirname(__file__), entry) - return None - -ZONEINFOFILE = getzoneinfofile() - -del getzoneinfofile - -def setcachesize(size): - global CACHESIZE, CACHE - CACHESIZE = size - del CACHE[size:] - -def gettz(name): - tzinfo = None - if ZONEINFOFILE: - for cachedname, tzinfo in CACHE: - if cachedname == name: - break - else: - tf = TarFile.open(ZONEINFOFILE) - try: - zonefile = tf.extractfile(name) - except KeyError: - tzinfo = None - else: - tzinfo = tzfile(zonefile) - tf.close() - CACHE.insert(0, (name, tzinfo)) - del CACHE[CACHESIZE:] - return tzinfo - -def rebuild(filename, tag=None, format="gz"): - import tempfile, shutil - tmpdir = tempfile.mkdtemp() - zonedir = os.path.join(tmpdir, "zoneinfo") - moduledir = os.path.dirname(__file__) - if tag: tag = "-"+tag - targetname = "zoneinfo%s.tar.%s" % (tag, format) - try: - tf = TarFile.open(filename) - for name in tf.getnames(): - if not (name.endswith(".sh") or - name.endswith(".tab") or - name == "leapseconds"): - tf.extract(name, tmpdir) - filepath = os.path.join(tmpdir, name) - os.system("zic -d %s %s" % (zonedir, filepath)) - tf.close() - target = os.path.join(moduledir, targetname) - for entry in os.listdir(moduledir): - if entry.startswith("zoneinfo") and ".tar." in entry: - os.unlink(os.path.join(moduledir, entry)) - tf = TarFile.open(target, "w:%s" % format) - for entry in os.listdir(zonedir): - entrypath = os.path.join(zonedir, entry) - tf.add(entrypath, entry) - tf.close() - finally: - shutil.rmtree(tmpdir) diff --git a/lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz b/lib/dateutil_py2/zoneinfo/zoneinfo-2010g.tar.gz deleted file mode 100644 index 8bd4f96402be50779e4b2749688d077347a6eef0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171995 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

*(x6q- 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 -Copyright (c) 2012 - Tomi Pieviläinen - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/dateutil_py3/NEWS b/lib/dateutil_py3/NEWS deleted file mode 100644 index 3a0a8ed12aae..000000000000 --- a/lib/dateutil_py3/NEWS +++ /dev/null @@ -1,164 +0,0 @@ -Version 2.1 ------------ - -- New maintainer - -- Dateutil now works on Python 2.6, 2.7 and 3.2 from same codebase (with six) - -- #704047: Ismael Carnales' patch for a new time format - -- Small bug fixes, thanks for reporters! - - -Version 2.0 ------------ - -- Ported to Python 3, by Brian Jones. If you need dateutil for Python 2.X, - please continue using the 1.X series. - -- There's no such thing as a "PSF License". This source code is now - made available under the Simplified BSD license. See LICENSE for - details. - -Version 1.5 ------------ - -- As reported by Mathieu Bridon, rrules were matching the bysecond rules - incorrectly against byminute in some circumstances when the SECONDLY - frequency was in use, due to a copy & paste bug. The problem has been - unittested and corrected. - -- Adam Ryan reported a problem in the relativedelta implementation which - affected the yearday parameter in the month of January specifically. - This has been unittested and fixed. - -- Updated timezone information. - - -Version 1.4.1 -------------- - -- Updated timezone information. - - -Version 1.4 ------------ - -- Fixed another parser precision problem on conversion of decimal seconds - to microseconds, as reported by Erik Brown. Now these issues are gone - for real since it's not using floating point arithmetic anymore. - -- Fixed case where tzrange.utcoffset and tzrange.dst() might fail due - to a date being used where a datetime was expected (reported and fixed - by Lennart Regebro). - -- Prevent tzstr from introducing daylight timings in strings that didn't - specify them (reported by Lennart Regebro). - -- Calls like gettz("GMT+3") and gettz("UTC-2") will now return the - expected values, instead of the TZ variable behavior. - -- Fixed DST signal handling in zoneinfo files. Reported by - Nicholas F. Fabry and John-Mark Gurney. - - -Version 1.3 ------------ - -- Fixed precision problem on conversion of decimal seconds to - microseconds, as reported by Skip Montanaro. - -- Fixed bug in constructor of parser, and converted parser classes to - new-style classes. Original report and patch by Michael Elsdörfer. - -- Initialize tzid and comps in tz.py, to prevent the code from ever - raising a NameError (even with broken files). Johan Dahlin suggested - the fix after a pyflakes run. - -- Version is now published in dateutil.__version__, as requested - by Darren Dale. - -- All code is compatible with new-style division. - - -Version 1.2 ------------ - -- Now tzfile will round timezones to full-minutes if necessary, - since Python's datetime doesn't support sub-minute offsets. - Thanks to Ilpo Nyyssönen for reporting the issue. - -- Removed bare string exceptions, as reported and fixed by - Wilfredo Sánchez Vega. - -- Fix bug in leap count parsing (reported and fixed by Eugene Oden). - - -Version 1.1 ------------ - -- Fixed rrule byyearday handling. Abramo Bagnara pointed out that - RFC2445 allows negative numbers. - -- Fixed --prefix handling in setup.py (by Sidnei da Silva). - -- Now tz.gettz() returns a tzlocal instance when not given any - arguments and no other timezone information is found. - -- Updating timezone information to version 2005q. - - -Version 1.0 ------------ - -- Fixed parsing of XXhXXm formatted time after day/month/year - has been parsed. - -- Added patch by Jeffrey Harris optimizing rrule.__contains__. - - -Version 0.9 ------------ - -- Fixed pickling of timezone types, as reported by - Andreas Köhler. - -- Implemented internal timezone information with binary - timezone files [1]. datautil.tz.gettz() function will now - try to use the system timezone files, and fallback to - the internal versions. It's also possible to ask for - the internal versions directly by using - dateutil.zoneinfo.gettz(). - -- New tzwin timezone type, allowing access to Windows - internal timezones (contributed by Jeffrey Harris). - -- Fixed parsing of unicode date strings. - -- Accept parserinfo instances as the parser constructor - parameter, besides parserinfo (sub)classes. - -- Changed weekday to spell the not-set n value as None - instead of 0. - -- Fixed other reported bugs. - -[1] http://www.twinsun.com/tz/tz-link.htm - - -Version 0.5 ------------ - -- Removed FREQ_ prefix from rrule frequency constants - WARNING: this breaks compatibility with previous versions. - -- Fixed rrule.between() for cases where "after" is achieved - before even starting, as reported by Andreas Köhler. - -- Fixed two digit zero-year parsing (such as 31-Dec-00), as - reported by Jim Abramson, and included test case for this. - -- Sort exdate and rdate before iterating over them, so that - it's not necessary to sort them before adding to the rruleset, - as reported by Nicholas Piper. - diff --git a/lib/dateutil_py3/README b/lib/dateutil_py3/README deleted file mode 100644 index 9453699e7d54..000000000000 --- a/lib/dateutil_py3/README +++ /dev/null @@ -1,1970 +0,0 @@ -## This file is in the moin format. The latest version is found -## at https://moin.conectiva.com.br/DateUtil - -== Contents == -[[TableOfContents]] - -== Description == -The '''dateutil''' module provides powerful extensions to -the standard '''datetime''' module, available in Python. - -== Features == - - * Computing of relative deltas (next month, next year, - next monday, last week of month, etc); - - * Computing of relative deltas between two given - date and/or datetime objects; - - * Computing of dates based on very flexible recurrence rules, - using a superset of the - [ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] - specification. Parsing of RFC strings is supported as well. - - * Generic parsing of dates in almost any string format; - - * Timezone (tzinfo) implementations for tzfile(5) format - files (/etc/localtime, /usr/share/zoneinfo, etc), TZ - environment string (in all known formats), iCalendar - format files, given ranges (with help from relative deltas), - local machine timezone, fixed offset timezone, UTC timezone, - and Windows registry-based time zones. - - * Internal up-to-date world timezone information based on - Olson's database. - - * Computing of Easter Sunday dates for any given year, - using Western, Orthodox or Julian algorithms; - - * More than 400 test cases. - -== Quick example == -Here's a snapshot, just to give an idea about the power of the -package. For more examples, look at the documentation below. - -Suppose you want to know how much time is left, in -years/months/days/etc, before the next easter happening on a -year with a Friday 13th in August, and you want to get today's -date out of the "date" unix system command. Here is the code: -{{{ -from dateutil.relativedelta import * -from dateutil.easter import * -from dateutil.rrule import * -from dateutil.parser import * -from datetime import * -import commands -import os -now = parse(commands.getoutput("date")) -today = now.date() -year = rrule(YEARLY,bymonth=8,bymonthday=13,byweekday=FR)[0].year -rdelta = relativedelta(easter(year), today) -print "Today is:", today -print "Year with next Aug 13th on a Friday is:", year -print "How far is the Easter of that year:", rdelta -print "And the Easter of that year is:", today+rdelta -}}} - -And here's the output: -{{{ -Today is: 2003-10-11 -Year with next Aug 13th on a Friday is: 2004 -How far is the Easter of that year: relativedelta(months=+6) -And the Easter of that year is: 2004-04-11 -}}} - -{i} Being exactly 6 months ahead was '''really''' a coincidence :) - -== Download == -The following files are available. - * attachment:python-dateutil-1.0.tar.bz2 - * attachment:python-dateutil-1.0-1.noarch.rpm - -== Author == -The dateutil module was written by GustavoNiemeyer . - -== Documentation == -The following modules are available. - -=== relativedelta === -This module offers the '''relativedelta''' type, which is based -on the specification of the excelent work done by M.-A. Lemburg in his -[http://www.egenix.com/files/python/mxDateTime.html mxDateTime] -extension. However, notice that this type '''does not''' implement the -same algorithm as his work. Do not expect it to behave like -{{{mxDateTime}}}'s counterpart. - -==== relativedelta type ==== - -There's two different ways to build a relativedelta instance. The -first one is passing it two {{{date}}}/{{{datetime}}} instances: -{{{ -relativedelta(datetime1, datetime2) -}}} - -This will build the relative difference between {{{datetime1}}} and -{{{datetime2}}}, so that the following constraint is always true: -{{{ -datetime2+relativedelta(datetime1, datetime2) == datetime1 -}}} - -Notice that instead of {{{datetime}}} instances, you may use -{{{date}}} instances, or a mix of both. - -And the other way is to use any of the following keyword arguments: - - year, month, day, hour, minute, second, microsecond:: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds:: - Relative information, may be negative. - - weekday:: - One of the weekday instances ({{{MO}}}, {{{TU}}}, etc). These - instances may receive a parameter {{{n}}}, specifying the {{{n}}}th - weekday, which could be positive or negative (like {{{MO(+2)}}} or - {{{MO(-3)}}}. Not specifying it is the same as specifying {{{+1}}}. - You can also use an integer, where {{{0=MO}}}. Notice that, - for example, if the calculated date is already Monday, using - {{{MO}}} or {{{MO(+1)}}} (which is the same thing in this context), - won't change the day. - - leapdays:: - Will add given days to the date found, but only if the computed - year is a leap year and the computed date is post 28 of february. - - yearday, nlyearday:: - Set the yearday or the non-leap year day (jump leap days). - These are converted to {{{day}}}/{{{month}}}/{{{leapdays}}} - information. - -==== Behavior of operations ==== -If you're curious about exactly how the relative delta will act -on operations, here is a description of its behavior. - - 1. Calculate the absolute year, using the {{{year}}} argument, or the - original datetime year, if the argument is not present. - 1. Add the relative {{{years}}} argument to the absolute year. - 1. Do steps 1 and 2 for {{{month}}}/{{{months}}}. - 1. Calculate the absolute day, using the {{{day}}} argument, or the - original datetime day, if the argument is not present. Then, subtract - from the day until it fits in the year and month found after their - operations. - 1. Add the relative {{{days}}} argument to the absolute day. Notice - that the {{{weeks}}} argument is multiplied by 7 and added to {{{days}}}. - 1. If {{{leapdays}}} is present, the computed year is a leap year, and - the computed month is after february, remove one day from the found date. - 1. Do steps 1 and 2 for {{{hour}}}/{{{hours}}}, {{{minute}}}/{{{minutes}}}, - {{{second}}}/{{{seconds}}}, {{{microsecond}}}/{{{microseconds}}}. - 1. If the {{{weekday}}} argument is present, calculate the {{{n}}}th - occurrence of the given weekday. - -==== Examples ==== - -Let's begin our trip. -{{{ ->>> from datetime import *; from dateutil.relativedelta import * ->>> import calendar -}}} - -Store some values. -{{{ ->>> NOW = datetime.now() ->>> TODAY = date.today() ->>> NOW -datetime.datetime(2003, 9, 17, 20, 54, 47, 282310) ->>> TODAY -datetime.date(2003, 9, 17) -}}} - -Next month. -{{{ ->>> NOW+relativedelta(months=+1) -datetime.datetime(2003, 10, 17, 20, 54, 47, 282310) -}}} - -Next month, plus one week. -{{{ ->>> NOW+relativedelta(months=+1, weeks=+1) -datetime.datetime(2003, 10, 24, 20, 54, 47, 282310) -}}} - -Next month, plus one week, at 10am. -{{{ ->>> TODAY+relativedelta(months=+1, weeks=+1, hour=10) -datetime.datetime(2003, 10, 24, 10, 0) -}}} - -Let's try the other way around. Notice that the -hour setting we get in the relativedelta is relative, -since it's a difference, and the weeks parameter -has gone. -{{{ ->>> relativedelta(datetime(2003, 10, 24, 10, 0), TODAY) -relativedelta(months=+1, days=+7, hours=+10) -}}} - -One month before one year. -{{{ ->>> NOW+relativedelta(years=+1, months=-1) -datetime.datetime(2004, 8, 17, 20, 54, 47, 282310) -}}} - -How does it handle months with different numbers of days? -Notice that adding one month will never cross the month -boundary. -{{{ ->>> date(2003,1,27)+relativedelta(months=+1) -datetime.date(2003, 2, 27) ->>> date(2003,1,31)+relativedelta(months=+1) -datetime.date(2003, 2, 28) ->>> date(2003,1,31)+relativedelta(months=+2) -datetime.date(2003, 3, 31) -}}} - -The logic for years is the same, even on leap years. -{{{ ->>> date(2000,2,28)+relativedelta(years=+1) -datetime.date(2001, 2, 28) ->>> date(2000,2,29)+relativedelta(years=+1) -datetime.date(2001, 2, 28) - ->>> date(1999,2,28)+relativedelta(years=+1) -datetime.date(2000, 2, 28) ->>> date(1999,3,1)+relativedelta(years=+1) -datetime.date(2000, 3, 1) - ->>> date(2001,2,28)+relativedelta(years=-1) -datetime.date(2000, 2, 28) ->>> date(2001,3,1)+relativedelta(years=-1) -datetime.date(2000, 3, 1) -}}} - -Next friday. -{{{ ->>> TODAY+relativedelta(weekday=FR) -datetime.date(2003, 9, 19) - ->>> TODAY+relativedelta(weekday=calendar.FRIDAY) -datetime.date(2003, 9, 19) -}}} - -Last friday in this month. -{{{ ->>> TODAY+relativedelta(day=31, weekday=FR(-1)) -datetime.date(2003, 9, 26) -}}} - -Next wednesday (it's today!). -{{{ ->>> TODAY+relativedelta(weekday=WE(+1)) -datetime.date(2003, 9, 17) -}}} - -Next wednesday, but not today. -{{{ ->>> TODAY+relativedelta(days=+1, weekday=WE(+1)) -datetime.date(2003, 9, 24) -}}} - -Following -[http://www.cl.cam.ac.uk/~mgk25/iso-time.html ISO year week number notation] -find the first day of the 15th week of 1997. -{{{ ->>> datetime(1997,1,1)+relativedelta(day=4, weekday=MO(-1), weeks=+14) -datetime.datetime(1997, 4, 7, 0, 0) -}}} - -How long ago has the millennium changed? -{{{ ->>> relativedelta(NOW, date(2001,1,1)) -relativedelta(years=+2, months=+8, days=+16, - hours=+20, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -How old is John? -{{{ ->>> johnbirthday = datetime(1978, 4, 5, 12, 0) ->>> relativedelta(NOW, johnbirthday) -relativedelta(years=+25, months=+5, days=+12, - hours=+8, minutes=+54, seconds=+47, microseconds=+282310) -}}} - -It works with dates too. -{{{ ->>> relativedelta(TODAY, johnbirthday) -relativedelta(years=+25, months=+5, days=+11, hours=+12) -}}} - -Obtain today's date using the yearday: -{{{ ->>> date(2003, 1, 1)+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -We can use today's date, since yearday should be absolute -in the given year: -{{{ ->>> TODAY+relativedelta(yearday=260) -datetime.date(2003, 9, 17) -}}} - -Last year it should be in the same day: -{{{ ->>> date(2002, 1, 1)+relativedelta(yearday=260) -datetime.date(2002, 9, 17) -}}} - -But not in a leap year: -{{{ ->>> date(2000, 1, 1)+relativedelta(yearday=260) -datetime.date(2000, 9, 16) -}}} - -We can use the non-leap year day to ignore this: -{{{ ->>> date(2000, 1, 1)+relativedelta(nlyearday=260) -datetime.date(2000, 9, 17) -}}} - -=== rrule === -The rrule module offers a small, complete, and very fast, implementation -of the recurrence rules documented in the -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar RFC], including -support for caching of results. - -==== rrule type ==== -That's the base of the rrule operation. It accepts all the keywords -defined in the RFC as its constructor parameters (except {{{byday}}}, -which was renamed to {{{byweekday}}}) and more. The constructor -prototype is: -{{{ -rrule(freq) -}}} - -Where {{{freq}}} must be one of {{{YEARLY}}}, {{{MONTHLY}}}, -{{{WEEKLY}}}, {{{DAILY}}}, {{{HOURLY}}}, {{{MINUTELY}}}, -or {{{SECONDLY}}}. - -Additionally, it supports the following keyword arguments: - - cache:: - If given, it must be a boolean value specifying to enable - or disable caching of results. If you will use the same - {{{rrule}}} instance multiple times, enabling caching will - improve the performance considerably. - - dtstart:: - The recurrence start. Besides being the base for the - recurrence, missing parameters in the final recurrence - instances will also be extracted from this date. If not - given, {{{datetime.now()}}} will be used instead. - - interval:: - The interval between each {{{freq}}} iteration. For example, - when using {{{YEARLY}}}, an interval of {{{2}}} means - once every two years, but with {{{HOURLY}}}, it means - once every two hours. The default interval is {{{1}}}. - - wkst:: - The week start day. Must be one of the {{{MO}}}, {{{TU}}}, - {{{WE}}} constants, or an integer, specifying the first day - of the week. This will affect recurrences based on weekly - periods. The default week start is got from - {{{calendar.firstweekday()}}}, and may be modified by - {{{calendar.setfirstweekday()}}}. - - count:: - How many occurrences will be generated. - - until:: - If given, this must be a {{{datetime}}} instance, that will - specify the limit of the recurrence. If a recurrence instance - happens to be the same as the {{{datetime}}} instance given - in the {{{until}}} keyword, this will be the last occurrence. - - bysetpos:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each given integer will - specify an occurrence number, corresponding to the nth - occurrence of the rule inside the frequency period. For - example, a {{{bysetpos}}} of {{{-1}}} if combined with a - {{{MONTHLY}}} frequency, and a {{{byweekday}}} of - {{{(MO, TU, WE, TH, FR)}}}, will result in the last work - day of every month. - - bymonth:: - If given, it must be either an integer, or a sequence of - integers, meaning the months to apply the recurrence to. - - bymonthday:: - If given, it must be either an integer, or a sequence of - integers, meaning the month days to apply the recurrence to. - - byyearday:: - If given, it must be either an integer, or a sequence of - integers, meaning the year days to apply the recurrence to. - - byweekno:: - If given, it must be either an integer, or a sequence of - integers, meaning the week numbers to apply the recurrence - to. Week numbers have the meaning described in ISO8601, - that is, the first week of the year is that containing at - least four days of the new year. - - byweekday:: - If given, it must be either an integer ({{{0 == MO}}}), a - sequence of integers, one of the weekday constants - ({{{MO}}}, {{{TU}}}, etc), or a sequence of these constants. - When given, these variables will define the weekdays where - the recurrence will be applied. It's also possible to use - an argument {{{n}}} for the weekday instances, which will - mean the {{{n}}}''th'' occurrence of this weekday in the - period. For example, with {{{MONTHLY}}}, or with - {{{YEARLY}}} and {{{BYMONTH}}}, using {{{FR(+1)}}} - in {{{byweekday}}} will specify the first friday of the - month where the recurrence happens. Notice that in the RFC - documentation, this is specified as {{{BYDAY}}}, but was - renamed to avoid the ambiguity of that keyword. - - byhour:: - If given, it must be either an integer, or a sequence of - integers, meaning the hours to apply the recurrence to. - - byminute:: - If given, it must be either an integer, or a sequence of - integers, meaning the minutes to apply the recurrence to. - - bysecond:: - If given, it must be either an integer, or a sequence of - integers, meaning the seconds to apply the recurrence to. - - byeaster:: - If given, it must be either an integer, or a sequence of - integers, positive or negative. Each integer will define - an offset from the Easter Sunday. Passing the offset - {{{0}}} to {{{byeaster}}} will yield the Easter Sunday - itself. This is an extension to the RFC specification. - -==== rrule methods ==== -The following methods are available in {{{rrule}}} instances: - - rrule.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rrule.between(after, before, inc=False):: - 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. - - rrule.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rrule}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -rr = rrule(...) -if datetime(...) in rr: - ... -print rr[0] -print rr[-1] -print rr[1:2] -print rr[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== Notes ==== - - * The rrule type has no {{{byday}}} keyword. The equivalent keyword - has been replaced by the {{{byweekday}}} keyword, to remove the - ambiguity present in the original keyword. - - * Unlike documented in the RFC, the starting datetime ({{{dtstart}}}) - is not the first recurrence instance, unless it does fit in the - specified rules. In a python module context, this behavior makes more - sense than otherwise. Notice that you can easily get the original - behavior by using a rruleset and adding the {{{dtstart}}} as an - {{{rdate}}} recurrence. - - * Unlike documented in the RFC, every keyword is valid on every - frequency (the RFC documents that {{{byweekno}}} is only valid - on yearly frequencies, for example). - - * In addition to the documented keywords, a {{{byeaster}}} keyword - was introduced, making it easy to compute recurrent events relative - to the Easter Sunday. - -==== rrule examples ==== -These examples were converted from the RFC. - -Prepare the environment. -{{{ ->>> from dateutil.rrule import * ->>> from dateutil.parser import * ->>> from datetime import * - ->>> import pprint ->>> import sys ->>> sys.displayhook = pprint.pprint -}}} - -Daily, for 10 occurrences. -{{{ ->>> list(rrule(DAILY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0)] -}}} - -Daily until December 24, 1997 -{{{ ->>> list(rrule(DAILY, - dtstart=parse("19970902T090000"), - until=parse("19971224T000000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - (...) - datetime.datetime(1997, 12, 21, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1997, 12, 23, 9, 0)] -}}} - -Every other day, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=2, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 6, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0), - datetime.datetime(1997, 9, 10, 9, 0)] -}}} - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrule(DAILY, interval=10, count=5, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Everyday in January, for 3 years. -{{{ ->>> list(rrule(YEARLY, bymonth=1, byweekday=range(7), - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -[datetime.datetime(1998, 1, 1, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - (...) - datetime.datetime(1998, 1, 30, 9, 0), - datetime.datetime(1998, 1, 31, 9, 0), - datetime.datetime(1999, 1, 1, 9, 0), - datetime.datetime(1999, 1, 2, 9, 0), - (...) - datetime.datetime(1999, 1, 30, 9, 0), - datetime.datetime(1999, 1, 31, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0), - (...) - datetime.datetime(2000, 1, 29, 9, 0), - datetime.datetime(2000, 1, 31, 9, 0)] -}}} - -Same thing, in another way. -{{{ ->>> list(rrule(DAILY, bymonth=1, - dtstart=parse("19980101T090000"), - until=parse("20000131T090000"))) -(...) -}}} - -Weekly for 10 occurrences. -{{{ ->>> list(rrule(WEEKLY, count=10, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 21, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Every other week, 6 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 28, 9, 0), - datetime.datetime(1997, 11, 11, 9, 0)] -}}} - -Weekly on Tuesday and Thursday for 5 weeks. -{{{ ->>> list(rrule(WEEKLY, count=10, wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 25, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0)] -}}} - -Every other week on Tuesday and Thursday, for 8 occurrences. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=8, - wkst=SU, byweekday=(TU,TH), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 18, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 14, 9, 0), - datetime.datetime(1997, 10, 16, 9, 0)] -}}} - -Monthly on the 1st Friday for ten occurrences. -{{{ ->>> list(rrule(MONTHLY, count=10, byweekday=FR(1), - dtstart=parse("19970905T090000"))) -[datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 10, 3, 9, 0), - datetime.datetime(1997, 11, 7, 9, 0), - datetime.datetime(1997, 12, 5, 9, 0), - datetime.datetime(1998, 1, 2, 9, 0), - datetime.datetime(1998, 2, 6, 9, 0), - datetime.datetime(1998, 3, 6, 9, 0), - datetime.datetime(1998, 4, 3, 9, 0), - datetime.datetime(1998, 5, 1, 9, 0), - datetime.datetime(1998, 6, 5, 9, 0)] -}}} - -Every other month on the 1st and last Sunday of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=10, - byweekday=(SU(1), SU(-1)), - dtstart=parse("19970907T090000"))) -[datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0), - datetime.datetime(1998, 1, 4, 9, 0), - datetime.datetime(1998, 1, 25, 9, 0), - datetime.datetime(1998, 3, 1, 9, 0), - datetime.datetime(1998, 3, 29, 9, 0), - datetime.datetime(1998, 5, 3, 9, 0), - datetime.datetime(1998, 5, 31, 9, 0)] -}}} - -Monthly on the second to last Monday of the month for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, byweekday=MO(-2), - dtstart=parse("19970922T090000"))) -[datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 20, 9, 0), - datetime.datetime(1997, 11, 17, 9, 0), - datetime.datetime(1997, 12, 22, 9, 0), - datetime.datetime(1998, 1, 19, 9, 0), - datetime.datetime(1998, 2, 16, 9, 0)] -}}} - -Monthly on the third to the last day of the month, for 6 months. -{{{ ->>> list(rrule(MONTHLY, count=6, bymonthday=-3, - dtstart=parse("19970928T090000"))) -[datetime.datetime(1997, 9, 28, 9, 0), - datetime.datetime(1997, 10, 29, 9, 0), - datetime.datetime(1997, 11, 28, 9, 0), - datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1998, 1, 29, 9, 0), - datetime.datetime(1998, 2, 26, 9, 0)] -}}} - -Monthly on the 2nd and 15th of the month for 5 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(2,15), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 15, 9, 0), - datetime.datetime(1997, 11, 2, 9, 0)] -}}} - -Monthly on the first and last day of the month for 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=5, bymonthday=(-1,1,), - dtstart=parse("1997090 -2T090000"))) -[datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 10, 1, 9, 0), - datetime.datetime(1997, 10, 31, 9, 0), - datetime.datetime(1997, 11, 1, 9, 0), - datetime.datetime(1997, 11, 30, 9, 0)] -}}} - -Every 18 months on the 10th thru 15th of the month for 10 occurrences. -{{{ ->>> list(rrule(MONTHLY, interval=18, count=10, - bymonthday=range(10,16), - dtstart=parse("19970910T090000"))) -[datetime.datetime(1997, 9, 10, 9, 0), - datetime.datetime(1997, 9, 11, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 13, 9, 0), - datetime.datetime(1997, 9, 14, 9, 0), - datetime.datetime(1997, 9, 15, 9, 0), - datetime.datetime(1999, 3, 10, 9, 0), - datetime.datetime(1999, 3, 11, 9, 0), - datetime.datetime(1999, 3, 12, 9, 0), - datetime.datetime(1999, 3, 13, 9, 0)] -}}} - -Every Tuesday, every other month, 6 occurences. -{{{ ->>> list(rrule(MONTHLY, interval=2, count=6, byweekday=TU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 16, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0), - datetime.datetime(1997, 9, 30, 9, 0), - datetime.datetime(1997, 11, 4, 9, 0)] -}}} - -Yearly in June and July for 10 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, bymonth=(6,7), - dtstart=parse("19970610T0900 -00"))) -[datetime.datetime(1997, 6, 10, 9, 0), - datetime.datetime(1997, 7, 10, 9, 0), - datetime.datetime(1998, 6, 10, 9, 0), - datetime.datetime(1998, 7, 10, 9, 0)] -}}} - -Every 3rd year on the 1st, 100th and 200th day for 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, interval=3, byyearday=(1,100,200), - dtstart=parse("19970101T090000"))) -[datetime.datetime(1997, 1, 1, 9, 0), - datetime.datetime(1997, 4, 10, 9, 0), - datetime.datetime(1997, 7, 19, 9, 0), - datetime.datetime(2000, 1, 1, 9, 0)] -}}} - -Every 20th Monday of the year, 3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekday=MO(20), - dtstart=parse("19970519T090000"))) -[datetime.datetime(1997, 5, 19, 9, 0), - datetime.datetime(1998, 5, 18, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -Monday of week number 20 (where the default start of the week is Monday), -3 occurrences. -{{{ ->>> list(rrule(YEARLY, count=3, byweekno=20, byweekday=MO, - dtstart=parse("19970512T090000"))) -[datetime.datetime(1997, 5, 12, 9, 0), - datetime.datetime(1998, 5, 11, 9, 0), - datetime.datetime(1999, 5, 17, 9, 0)] -}}} - -The week number 1 may be in the last year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=1, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 29, 9, 0), - datetime.datetime(1999, 1, 4, 9, 0), - datetime.datetime(2000, 1, 3, 9, 0)] -}}} - -And the week numbers greater than 51 may be in the next year. -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=52, byweekday=SU, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 12, 28, 9, 0), - datetime.datetime(1998, 12, 27, 9, 0), - datetime.datetime(2000, 1, 2, 9, 0)] -}}} - -Only some years have week number 53: -{{{ ->>> list(rrule(WEEKLY, count=3, byweekno=53, byweekday=MO, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 12, 28, 9, 0), - datetime.datetime(2004, 12, 27, 9, 0), - datetime.datetime(2009, 12, 28, 9, 0)] -}}} - -Every Friday the 13th, 4 occurrences. -{{{ ->>> list(rrule(YEARLY, count=4, byweekday=FR, bymonthday=13, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1998, 2, 13, 9, 0), - datetime.datetime(1998, 3, 13, 9, 0), - datetime.datetime(1998, 11, 13, 9, 0), - datetime.datetime(1999, 8, 13, 9, 0)] -}}} - -Every four years, the first Tuesday after a Monday in November, -3 occurrences (U.S. Presidential Election day): -{{{ ->>> list(rrule(YEARLY, interval=4, count=3, bymonth=11, - byweekday=TU, bymonthday=(2,3,4,5,6,7,8), - dtstart=parse("19961105T090000"))) -[datetime.datetime(1996, 11, 5, 9, 0), - datetime.datetime(2000, 11, 7, 9, 0), - datetime.datetime(2004, 11, 2, 9, 0)] -}}} - -The 3rd instance into the month of one of Tuesday, Wednesday or -Thursday, for the next 3 months: -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(TU,WE,TH), - bysetpos=3, dtstart=parse("19970904T090000"))) -[datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 10, 7, 9, 0), - datetime.datetime(1997, 11, 6, 9, 0)] -}}} - -The 2nd to last weekday of the month, 3 occurrences. -{{{ ->>> list(rrule(MONTHLY, count=3, byweekday=(MO,TU,WE,TH,FR), - bysetpos=-2, dtstart=parse("19970929T090000"))) -[datetime.datetime(1997, 9, 29, 9, 0), - datetime.datetime(1997, 10, 30, 9, 0), - datetime.datetime(1997, 11, 27, 9, 0)] -}}} - -Every 3 hours from 9:00 AM to 5:00 PM on a specific day. -{{{ ->>> list(rrule(HOURLY, interval=3, - dtstart=parse("19970902T090000"), - until=parse("19970902T170000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 15, 0)] -}}} - -Every 15 minutes for 6 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=15, count=6, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 15), - datetime.datetime(1997, 9, 2, 9, 30), - datetime.datetime(1997, 9, 2, 9, 45), - datetime.datetime(1997, 9, 2, 10, 0), - datetime.datetime(1997, 9, 2, 10, 15)] -}}} - -Every hour and a half for 4 occurrences. -{{{ ->>> list(rrule(MINUTELY, interval=90, count=4, - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 10, 30), - datetime.datetime(1997, 9, 2, 12, 0), - datetime.datetime(1997, 9, 2, 13, 30)] -}}} - -Every 20 minutes from 9:00 AM to 4:40 PM for two days. -{{{ ->>> list(rrule(MINUTELY, interval=20, count=48, - byhour=range(9,17), byminute=(0,20,40), - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 2, 9, 20), - (...) - datetime.datetime(1997, 9, 2, 16, 20), - datetime.datetime(1997, 9, 2, 16, 40), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 3, 9, 20), - (...) - datetime.datetime(1997, 9, 3, 16, 20), - datetime.datetime(1997, 9, 3, 16, 40)] -}}} - -An example where the days generated makes a difference because of {{{wkst}}}. -{{{ ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=MO, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 10, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 24, 9, 0)] - ->>> list(rrule(WEEKLY, interval=2, count=4, - byweekday=(TU,SU), wkst=SU, - dtstart=parse("19970805T090000"))) -[datetime.datetime(1997, 8, 5, 9, 0), - datetime.datetime(1997, 8, 17, 9, 0), - datetime.datetime(1997, 8, 19, 9, 0), - datetime.datetime(1997, 8, 31, 9, 0)] -}}} - -==== rruleset type ==== -The {{{rruleset}}} type allows more complex recurrence setups, mixing -multiple rules, dates, exclusion rules, and exclusion dates. -The type constructor takes the following keyword arguments: - - cache:: - If True, caching of results will be enabled, improving performance - of multiple queries considerably. - -==== rruleset methods ==== -The following methods are available: - - rruleset.rrule(rrule):: - Include the given {{{rrule}}} instance in the recurrence set - generation. - - rruleset.rdate(dt):: - Include the given {{{datetime}}} instance in the recurrence - set generation. - - rruleset.exrule(rrule):: - 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. - - rruleset.exdate(dt):: - 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. - - rruleset.before(dt, inc=False):: - Returns the last recurrence before the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.after(dt, inc=False):: - Returns the first recurrence after the given {{{datetime}}} - instance. The {{{inc}}} keyword defines what happens if - {{{dt}}} '''is''' an occurrence. With {{{inc == True}}}, - if {{{dt}}} itself is an occurrence, it will be returned. - - rruleset.between(after, before, inc=False):: - 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. - - rruleset.count():: - Returns the number of recurrences in this set. It will have - go trough the whole recurrence, if this hasn't been done - before. - -Besides these methods, {{{rruleset}}} instances also support -the {{{__getitem__()}}} and {{{__contains__()}}} special methods, -meaning that these are valid expressions: -{{{ -set = rruleset(...) -if datetime(...) in set: - ... -print set[0] -print set[-1] -print set[1:2] -print set[::-2] -}}} - -The getitem/slicing mechanism is smart enough to avoid getting the whole -recurrence set, if possible. - -==== rruleset examples ==== -Daily, for 7 days, jumping Saturday and Sunday occurrences. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(DAILY, count=7, - dtstart=parse("19970902T090000"))) ->>> set.exrule(rrule(YEARLY, byweekday=(SA,SU), - dtstart=parse("19970902T090000"))) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 3, 9, 0), - datetime.datetime(1997, 9, 4, 9, 0), - datetime.datetime(1997, 9, 5, 9, 0), - datetime.datetime(1997, 9, 8, 9, 0)] -}}} - -Weekly, for 4 weeks, plus one time on day 7, and not on day 16. -{{{ ->>> set = rruleset() ->>> set.rrule(rrule(WEEKLY, count=4, - dtstart=parse("19970902T090000"))) ->>> set.rdate(datetime.datetime(1997, 9, 7, 9, 0)) ->>> set.exdate(datetime.datetime(1997, 9, 16, 9, 0)) ->>> list(set) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 7, 9, 0), - datetime.datetime(1997, 9, 9, 9, 0), - datetime.datetime(1997, 9, 23, 9, 0)] -}}} - -==== rrulestr() function ==== -The {{{rrulestr()}}} function is a parser for ''RFC-like'' syntaxes. -The function prototype is: -{{{ -rrulestr(str) -}}} - -The string passed as parameter may be a multiple line string, a -single line string, or just the {{{RRULE}}} property value. - -Additionally, it accepts the following keyword arguments: - - cache:: - If {{{True}}}, the {{{rruleset}}} or {{{rrule}}} created instance - will cache its results. Default is not to cache. - - dtstart:: - If given, it must be a {{{datetime}}} instance that will be used - when no {{{DTSTART}}} property is found in the parsed string. If - it is not given, and the property is not found, {{{datetime.now()}}} - will be used instead. - - unfold:: - If set to {{{True}}}, lines will be unfolded following the RFC - specification. It defaults to {{{False}}}, meaning that spaces - before every line will be stripped. - - forceset:: - If set to {{{True}}} a {{{rruleset}}} instance will be returned, - even if only a single rule is found. The default is to return an - {{{rrule}}} if possible, and an {{{rruleset}}} if necessary. - - compatible:: - If set to {{{True}}}, the parser will operate in RFC-compatible - mode. Right now it means that {{{unfold}}} will be turned on, - and if a {{{DTSTART}}} is found, it will be considered the first - recurrence instance, as documented in the RFC. - - ignoretz:: - If set to {{{True}}}, the date parser will ignore timezone - information available in the {{{DTSTART}}} property, or the - {{{UNTIL}}} attribute. - - tzinfos:: - If set, it will be passed to the datetime string parser to - resolve unknown timezone settings. For more information about - what could be used here, check the parser documentation. - -==== rrulestr() examples ==== - -Every 10 days, 5 occurrences. -{{{ ->>> list(rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """)) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Same thing, but passing only the {{{RRULE}}} value. -{{{ ->>> list(rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", - dtstart=parse("19970902T090000"))) -[datetime.datetime(1997, 9, 2, 9, 0), - datetime.datetime(1997, 9, 12, 9, 0), - datetime.datetime(1997, 9, 22, 9, 0), - datetime.datetime(1997, 10, 2, 9, 0), - datetime.datetime(1997, 10, 12, 9, 0)] -}}} - -Notice that when using a single rule, it returns an -{{{rrule}}} instance, unless {{{forceset}}} was used. -{{{ ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5") - - ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... """) - - ->>> rrulestr("FREQ=DAILY;INTERVAL=10;COUNT=5", forceset=True) - -}}} - -But when an {{{rruleset}}} is needed, it is automatically used. -{{{ ->>> rrulestr(""" -... DTSTART:19970902T090000 -... RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5 -... RRULE:FREQ=DAILY;INTERVAL=5;COUNT=3 -... """) - -}}} - -=== parser === -This module offers a generic date/time string parser which is -able to parse most known formats to represent a date and/or -time. - -==== parse() function ==== -That's probably the only function you'll need from this module. -It offers you an interface to access the parser functionality and -extract a {{{datetime}}} type out of a string. - -The prototype of this function is: -{{{ -parse(timestr) -}}} - -Additionally, the following keyword arguments are available: - - default:: - If given, this must be a {{{datetime}}} instance. Any fields - missing in the parsed date will be copied from this instance. - The default value is the current date, at 00:00:00am. - - ignoretz:: - If this is true, even if a timezone is found in the string, - the parser will not use it. - - tzinfos:: - Using this keyword argument you may provide custom timezones - to the parser. If given, it must be either a dictionary with - the timezone abbreviation as key, or a function accepting a - timezone abbreviation and offset as argument. The dictionary - values and the function return must be a timezone offset - in seconds, a tzinfo subclass, or a string defining the - timezone (in the TZ environment variable format). - - dayfirst:: - This option allow one to change the precedence in which - days are parsed in date strings. The default is given in the - parserinfo instance (the default parserinfo has it set to - False). If {{{dayfirst}}} is False, the {{{MM-DD-YYYY}}} - format will have precedence over {{{DD-MM-YYYY}}} in an - ambiguous date. - - yearfirst:: - This option allow one to change the precedence in which - years are parsed in date strings. The default is given in - the parserinfo instance (the default parserinfo has it set - to False). If {{{yearfirst}}} is false, the {{{MM-DD-YY}}} - format will have precedence over {{{YY-MM-DD}}} in an - ambiguous date. - - fuzzy:: - If {{{fuzzy}}} is set to True, unknown tokens in the string - will be ignored. - - parserinfo:: - This parameter allows one to change how the string is parsed, - by using a different parserinfo class instance. Using it you - may, for example, intenationalize the parser strings, or make - it ignore additional words. - -==== Format precedence ==== -Whenever an ambiguous date is found, the {{{dayfirst}}} and -{{{yearfirst}}} parameters will control how the information -is processed. Here is the precedence in each case: - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{False}}}, -(default, if no parameter is given): - - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{False}}}: - - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - * {{{YY-MM-DD}}} - -If {{{dayfirst}}} is {{{False}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{MM-DD-YY}}} - * {{{DD-MM-YY}}} - -If {{{dayfirst}}} is {{{True}}} and {{{yearfirst}}} is {{{True}}}: - - * {{{YY-MM-DD}}} - * {{{DD-MM-YY}}} - * {{{MM-DD-YY}}} - -==== Converting two digit years ==== -When a two digit year is found, it is processed considering -the current year, so that the computed year is never more -than 49 years after the current year, nor 50 years before the -current year. In other words, if we are in year 2003, and the -year 30 is found, it will be considered as 2030, but if the -year 60 is found, it will be considered 1960. - -==== Examples ==== -The following code will prepare the environment: -{{{ ->>> from dateutil.parser import * ->>> from dateutil.tz import * ->>> from datetime import * ->>> TZOFFSETS = {"BRST": -10800} ->>> BRSTTZ = tzoffset(-10800, "BRST") ->>> DEFAULT = datetime(2003, 9, 25) -}}} - -Some simple examples based on the {{{date}}} command, using the -{{{TZOFFSET}}} dictionary to provide the BRST timezone offset. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) - ->>> parse("2003 10:36:28 BRST 25 Sep Thu", tzinfos=TZOFFSETS) -datetime.datetime(2003, 9, 25, 10, 36, 28, - tzinfo=tzoffset('BRST', -10800)) -}}} - -Notice that since BRST is my local timezone, parsing it without -further timezone settings will yield a {{{tzlocal}}} timezone. -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28, tzinfo=tzlocal()) -}}} - -We can also ask to ignore the timezone explicitly: -{{{ ->>> parse("Thu Sep 25 10:36:28 BRST 2003", ignoretz=True) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -That's the same as processing a string without timezone: -{{{ ->>> parse("Thu Sep 25 10:36:28 2003") -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Without the year, but passing our {{{DEFAULT}}} datetime to return -the same year, no mattering what year we currently are in: -{{{ ->>> parse("Thu Sep 25 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) -}}} - -Strip it further: -{{{ ->>> parse("Thu Sep 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36:28", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28) - ->>> parse("Thu 10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) - ->>> parse("10:36", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36) ->>> -}}} - -Strip in a different way: -{{{ ->>> parse("Thu Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 25 2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep 2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Another format, based on {{{date -R}}} (RFC822): -{{{ ->>> parse("Thu, 25 Sep 2003 10:49:41 -0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -ISO format: -{{{ ->>> parse("2003-09-25T10:49:41.5-03:00") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzoffset(None, -10800)) -}}} - -Some variations: -{{{ ->>> parse("2003-09-25T10:49:41") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("2003-09-25T10:49") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("2003-09-25T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -ISO format, without separators: -{{{ ->>> parse("20030925T104941.5-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, 500000, - tzinfo=tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941-0300") -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) - ->>> parse("20030925T104941") -datetime.datetime(2003, 9, 25, 10, 49, 41) - ->>> parse("20030925T1049") -datetime.datetime(2003, 9, 25, 10, 49) - ->>> parse("20030925T10") -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("20030925") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Everything together. -{{{ ->>> parse("199709020900") -datetime.datetime(1997, 9, 2, 9, 0) ->>> parse("19970902090059") -datetime.datetime(1997, 9, 2, 9, 0, 59) -}}} - -Different date orderings: -{{{ ->>> parse("2003-09-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003-Sep-25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-Sep-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("Sep-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("09-25-2003") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("25-09-2003") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Check some ambiguous dates: -{{{ ->>> parse("10-09-2003") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-2003", dayfirst=True) -datetime.datetime(2003, 9, 10, 0, 0) - ->>> parse("10-09-03") -datetime.datetime(2003, 10, 9, 0, 0) - ->>> parse("10-09-03", yearfirst=True) -datetime.datetime(2010, 9, 3, 0, 0) -}}} - -Other date separators are allowed: -{{{ ->>> parse("2003.Sep.25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003/09/25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Even with spaces: -{{{ ->>> parse("2003 Sep 25") -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("2003 09 25") -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Hours with letters work: -{{{ ->>> parse("10h36m28.5s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 36, 28, 500000) - ->>> parse("01s02h03m", default=DEFAULT) -datetime.datetime(2003, 9, 25, 2, 3, 1) - ->>> parse("01h02m03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 1, 2) - ->>> parse("01h02", default=DEFAULT) -datetime.datetime(2003, 9, 2, 1, 0) - ->>> parse("01h02s", default=DEFAULT) -datetime.datetime(2003, 9, 25, 1, 0, 2) -}}} - -With AM/PM: -{{{ ->>> parse("10h am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 10, 0) - ->>> parse("10pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 22, 0) - ->>> parse("12:00am", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) - ->>> parse("12pm", default=DEFAULT) -datetime.datetime(2003, 9, 25, 12, 0) -}}} - -Some special treating for ''pertain'' relations: -{{{ ->>> parse("Sep 03", default=DEFAULT) -datetime.datetime(2003, 9, 3, 0, 0) - ->>> parse("Sep of 03", default=DEFAULT) -datetime.datetime(2003, 9, 25, 0, 0) -}}} - -Fuzzy parsing: -{{{ ->>> s = "Today is 25 of September of 2003, exactly " \ -... "at 10:49:41 with timezone -03:00." ->>> parse(s, fuzzy=True) -datetime.datetime(2003, 9, 25, 10, 49, 41, - tzinfo=tzoffset(None, -10800)) -}}} - -Other random formats: -{{{ ->>> parse("Wed, July 10, '96") -datetime.datetime(1996, 7, 10, 0, 0) - ->>> parse("1996.07.10 AD at 15:08:56 PDT", ignoretz=True) -datetime.datetime(1996, 7, 10, 15, 8, 56) - ->>> parse("Tuesday, April 12, 1952 AD 3:30:42pm PST", ignoretz=True) -datetime.datetime(1952, 4, 12, 15, 30, 42) - ->>> parse("November 5, 1994, 8:15:30 am EST", ignoretz=True) -datetime.datetime(1994, 11, 5, 8, 15, 30) - ->>> parse("3rd of May 2001") -datetime.datetime(2001, 5, 3, 0, 0) - ->>> parse("5:50 A.M. on June 13, 1990") -datetime.datetime(1990, 6, 13, 5, 50) -}}} - -=== easter === -This module offers a generic easter computing method for -any given year, using Western, Orthodox or Julian algorithms. - -==== easter() function ==== -This method was ported from the work done by -[http://users.chariot.net.au/~gmarts/eastalg.htm GM Arts], -on top of the algorithm by -[http://www.tondering.dk/claus/calendar.html 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 - 1. Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 1. 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. - -=== tz === -This module offers timezone implementations subclassing -the abstract {{{datetime.tzinfo}}} type. There are -classes to handle [http://www.twinsun.com/tz/tz-link.htm tzfile] -format files (usually are in /etc/localtime, -/usr/share/zoneinfo, etc), TZ environment string (in all -known formats), given ranges (with help from relative -deltas), local machine timezone, fixed offset timezone, -and UTC timezone. - -==== tzutc type ==== -This type implements a basic UTC timezone. The constructor of this -type accepts no parameters. - -==== tzutc examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now() -datetime.datetime(2003, 9, 27, 9, 40, 1, 521290) - ->>> datetime.now(tzutc()) -datetime.datetime(2003, 9, 27, 12, 40, 12, 156379, tzinfo=tzutc()) - ->>> datetime.now(tzutc()).tzname() -'UTC' -}}} - -==== tzoffset type ==== -This type implements a fixed offset timezone, with no -support to daylight saving times. Here is the prototype of the -type constructor: -{{{ -tzoffset(name, offset) -}}} - -The {{{name}}} parameter may be optionally set to {{{None}}}, and -{{{offset}}} must be given in seconds. - -==== tzoffset examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzoffset("BRST", -10800)) -datetime.datetime(2003, 9, 27, 9, 52, 43, 624904, - tzinfo=tzinfo=tzoffset('BRST', -10800)) - ->>> datetime.now(tzoffset("BRST", -10800)).tzname() -'BRST' - ->>> datetime.now(tzoffset("BRST", -10800)).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 12, 53, 11, 446419, - tzinfo=tzutc()) -}}} - -==== tzlocal type ==== -This type implements timezone settings as known by the -operating system. The constructor of this type accepts no -parameters. - -==== tzlocal examples ==== -{{{ ->>> from datetime import * ->>> from dateutil.tz import * - ->>> datetime.now(tzlocal()) -datetime.datetime(2003, 9, 27, 10, 1, 43, 673605, - tzinfo=tzlocal()) - ->>> datetime.now(tzlocal()).tzname() -'BRST' - ->>> datetime.now(tzlocal()).astimezone(tzoffset(None, 0)) -datetime.datetime(2003, 9, 27, 13, 3, 0, 11493, - tzinfo=tzoffset(None, 0)) -}}} - -==== tzstr type ==== -This type implements timezone settings extracted from a -string in known TZ environment variable formats. Here is the prototype -of the constructor: -{{{ -tzstr(str) -}}} - -==== tzstr examples ==== -Here are examples of the recognized formats: - - * {{{EST5EDT}}} - * {{{EST5EDT,4,0,6,7200,10,0,26,7200,3600}}} - * {{{EST5EDT,4,1,0,7200,10,-1,0,7200,3600}}} - * {{{EST5EDT4,M4.1.0/02:00:00,M10-5-0/02:00}}} - * {{{EST5EDT4,95/02:00:00,298/02:00}}} - * {{{EST5EDT4,J96/02:00:00,J299/02:00}}} - -Notice that if daylight information is not present, but a -daylight abbreviation was provided, {{{tzstr}}} will follow the -convention of using the first sunday of April to start daylight -saving, and the last sunday of October to end it. If start or -end time is not present, 2AM will be used, and if the daylight -offset is not present, the standard offset plus one hour will -be used. This convention is the same as used in the GNU libc. - -This also means that some of the above examples are exactly -equivalent, and all of these examples are equivalent -in the year of 2003. - -Here is the example mentioned in the -[http://www.python.org/doc/current/lib/module-time.html time module documentation]. -{{{ ->>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0' ->>> time.tzset() ->>> time.strftime('%X %x %Z') -'16:08:12 05/08/03 AEST' -}}} - -And here is an example showing the same information using {{{tzstr}}}, -without touching system settings. -{{{ ->>> tz1 = tzstr('EST+05EDT,M4.1.0,M10.5.0') ->>> tz2 = tzstr('AEST-10AEDT-11,M10.5.0,M3.5.0') ->>> dt = datetime(2003, 5, 8, 2, 7, 36, tzinfo=tz1) ->>> dt.strftime('%X %x %Z') -'02:07:36 05/08/03 EDT' ->>> dt.astimezone(tz2).strftime('%X %x %Z') -'16:07:36 05/08/03 AEST' -}}} - -Are these really equivalent? -{{{ ->>> tzstr('EST5EDT') == tzstr('EST5EDT,4,1,0,7200,10,-1,0,7200,3600') -True -}}} - -Check the daylight limit. -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzrange type ==== -This type offers the same functionality as the {{{tzstr}}} type, but -instead of timezone strings, information is passed using -{{{relativedelta}}}s which are applied to a datetime set to the first -day of the year. Here is the prototype of this type's constructor: -{{{ -tzrange(stdabbr, stdoffset=None, dstabbr=None, dstoffset=None, - start=None, end=None): -}}} - -Offsets must be given in seconds. Information not provided will be -set to the defaults, as explained in the {{{tzstr}}} section above. - -==== tzrange examples ==== -{{{ ->>> tzstr('EST5EDT') == tzrange("EST", -18000, "EDT") -True - ->>> from dateutil.relativedelta import * ->>> range1 = tzrange("EST", -18000, "EDT") ->>> range2 = tzrange("EST", -18000, "EDT", -14400, -... relativedelta(hours=+2, month=4, day=1, - weekday=SU(+1)), -... relativedelta(hours=+1, month=10, day=31, - weekday=SU(-1))) ->>> tzstr('EST5EDT') == range1 == range2 -True -}}} - -Notice a minor detail in the last example: while the DST should end -at 2AM, the delta will catch 1AM. That's because the daylight saving -time should end at 2AM standard time (the difference between STD and -DST is 1h in the given example) instead of the DST time. That's how -the {{{tzinfo}}} subtypes should deal with the extra hour that happens -when going back to the standard time. Check -[http://www.python.org/doc/current/lib/datetime-tzinfo.html tzinfo documentation] -for more information. - -==== tzfile type ==== -This type allows one to use tzfile(5) format timezone files to extract -current and historical zone information. Here is the type constructor -prototype: -{{{ -tzfile(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzfile examples ==== -{{{ ->>> tz = tzfile("/etc/localtime") ->>> datetime.now(tz) -datetime.datetime(2003, 9, 27, 12, 3, 48, 392138, - tzinfo=tzfile('/etc/localtime')) - ->>> datetime.now(tz).astimezone(tzutc()) -datetime.datetime(2003, 9, 27, 15, 3, 53, 70863, - tzinfo=tzutc()) - ->>> datetime.now(tz).tzname() -'BRST' ->>> datetime(2003, 1, 1, tzinfo=tz).tzname() -'BRDT' -}}} - -Check the daylight limit. -{{{ ->>> tz = tzfile('/usr/share/zoneinfo/EST5EDT') ->>> datetime(2003, 4, 6, 1, 59, tzinfo=tz).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 0, 59, tzinfo=tz).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=tz).tzname() -'EST' -}}} - -==== tzical type ==== -This type is able to parse -[ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt iCalendar] -style {{{VTIMEZONE}}} sessions into a Python timezone object. -The constuctor prototype is: -{{{ -tzical(fileobj) -}}} - -Where {{{fileobj}}} is either a filename or a file-like object with -a {{{read()}}} method. - -==== tzical methods ==== - - tzical.get(tzid=None):: - Since a single iCalendar file may contain more than one timezone, - you must ask for the timezone you want with this method. If there's - more than one timezone in the parsed file, you'll need to pass the - {{{tzid}}} parameter. Otherwise, leaving it empty will yield the only - available timezone. - -==== tzical examples ==== -Here is a sample file extracted from the RFC. This file defines -the {{{EST5EDT}}} timezone, and will be used in the following example. -{{{ -BEGIN:VTIMEZONE -TZID:US-Eastern -LAST-MODIFIED:19870101T000000Z -TZURL:http://zones.stds_r_us.net/tz/US-Eastern -BEGIN:STANDARD -DTSTART:19671029T020000 -RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 -TZOFFSETFROM:-0400 -TZOFFSETTO:-0500 -TZNAME:EST -END:STANDARD -BEGIN:DAYLIGHT -DTSTART:19870405T020000 -RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 -TZOFFSETFROM:-0500 -TZOFFSETTO:-0400 -TZNAME:EDT -END:DAYLIGHT -END:VTIMEZONE -}}} - -And here is an example exploring a {{{tzical}}} type: -{{{ ->>> from dateutil.tz import *; from datetime import * - ->>> tz = tzical('EST5EDT.ics') ->>> tz.keys() -['US-Eastern'] - ->>> est = tz.get('US-Eastern') ->>> est - - ->>> datetime.now(est) -datetime.datetime(2003, 10, 6, 19, 44, 18, 667987, - tzinfo=) - ->>> est == tz.get() -True -}}} - -Let's check the daylight ranges, as usual: -{{{ ->>> datetime(2003, 4, 6, 1, 59, tzinfo=est).tzname() -'EST' ->>> datetime(2003, 4, 6, 2, 00, tzinfo=est).tzname() -'EDT' - ->>> datetime(2003, 10, 26, 0, 59, tzinfo=est).tzname() -'EDT' ->>> datetime(2003, 10, 26, 1, 00, tzinfo=est).tzname() -'EST' -}}} - -==== tzwin type ==== -This type offers access to internal registry-based Windows timezones. -The constuctor prototype is: -{{{ -tzwin(name) -}}} - -Where {{{name}}} is the timezone name. There's a static {{{tzwin.list()}}} -method to check the available names, - -==== tzwin methods ==== - - tzwin.display():: - This method returns the timezone extended name. - - tzwin.list():: - This static method lists all available timezone names. - -==== tzwin examples ==== -{{{ ->>> tz = tzwin("E. South America Standard Time") -}}} - -==== tzwinlocal type ==== -This type offers access to internal registry-based Windows timezones. -The constructor accepts no parameters, so the prototype is: -{{{ -tzwinlocal() -}}} - -==== tzwinlocal methods ==== - - tzwinlocal.display():: - This method returns the timezone extended name, and returns - {{{None}}} if one is not available. - -==== tzwinlocal examples ==== -{{{ ->>> tz = tzwinlocal() -}}} - -==== gettz() function ==== -This function is a helper that will try its best to get the right -timezone for your environment, or for the given string. The prototype -is as follows: -{{{ -gettz(name=None) -}}} - -If given, the parameter may be a filename, a path relative to the base -of the timezone information path (the base could be -{{{/usr/share/zoneinfo}}}, for example), a string timezone -specification, or a timezone abbreviation. If {{{name}}} is not given, -and the {{{TZ}}} environment variable is set, it's used instead. If the -parameter is not given, and {{{TZ}}} is not set, the default tzfile -paths will be tried. Then, if no timezone information is found, -an internal compiled database of timezones is used. When running -on Windows, the internal registry-based Windows timezones are also -considered. - -Example: -{{{ ->>> from dateutil.tz import * ->>> gettz() -tzfile('/etc/localtime') - ->>> gettz("America/Sao Paulo") -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> gettz("EST5EDT") -tzfile('/usr/share/zoneinfo/EST5EDT') - ->>> gettz("EST5") -tzstr('EST5') - ->>> gettz('BRST') -tzlocal() - ->>> os.environ["TZ"] = "America/Sao Paulo" ->>> gettz() -tzfile('/usr/share/zoneinfo/America/Sao_Paulo') - ->>> os.environ["TZ"] = "BRST" ->>> gettz() -tzlocal() - ->>> gettz("Unavailable") ->>> -}}} - -=== zoneinfo === -This module provides direct access to the internal compiled -database of timezones. The timezone data and the compiling tools -are obtained from the following project: - - http://www.twinsun.com/tz/tz-link.htm - -==== gettz() function ==== -This function will try to retrieve the given timezone information -from the internal compiled database, and will cache its results. - -Example: -{{{ ->>> from dateutil import zoneinfo ->>> zoneinfo.gettz("Brazil/East") -tzfile('Brazil/East') -}}} - -## vim:ft=moin diff --git a/lib/dateutil_py3/__init__.py b/lib/dateutil_py3/__init__.py deleted file mode 100644 index a23cea5218cc..000000000000 --- a/lib/dateutil_py3/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__author__ = "Tomi Pieviläinen " -__license__ = "Simplified BSD" -__version__ = "2.1-mpl" diff --git a/lib/dateutil_py3/easter.py b/lib/dateutil_py3/easter.py deleted file mode 100644 index d8a38844f9e3..000000000000 --- a/lib/dateutil_py3/easter.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import datetime - -__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"] - -EASTER_JULIAN = 1 -EASTER_ORTHODOX = 2 -EASTER_WESTERN = 3 - -def easter(year, method=EASTER_WESTERN): - """ - This method was ported from the work done by GM Arts, - on top of the algorithm by Claus Tondering, which was - based in part on the algorithm of Ouding (1940), as - quoted in "Explanatory Supplement to the Astronomical - Almanac", P. Kenneth Seidelmann, editor. - - This algorithm implements three different easter - calculation methods: - - 1 - Original calculation in Julian calendar, valid in - dates after 326 AD - 2 - Original method, with date converted to Gregorian - calendar, valid in years 1583 to 4099 - 3 - Revised method, in Gregorian calendar, valid in - years 1583 to 4099 as well - - These methods are represented by the constants: - - EASTER_JULIAN = 1 - EASTER_ORTHODOX = 2 - EASTER_WESTERN = 3 - - The default method is method 3. - - More about the algorithm may be found at: - - http://users.chariot.net.au/~gmarts/eastalg.htm - - and - - http://www.tondering.dk/claus/calendar.html - - """ - - if not (1 <= method <= 3): - raise ValueError("invalid method") - - # g - Golden year - 1 - # c - Century - # h - (23 - Epact) mod 30 - # i - Number of days from March 21 to Paschal Full Moon - # j - Weekday for PFM (0=Sunday, etc) - # p - Number of days from March 21 to Sunday on or before PFM - # (-6 to 28 methods 1 & 3, to 56 for method 2) - # e - Extra days to add for method 2 (converting Julian - # date to Gregorian date) - - y = year - g = y % 19 - e = 0 - if method < 3: - # Old method - i = (19*g+15)%30 - j = (y+y//4+i)%7 - if method == 2: - # Extra dates to convert Julian to Gregorian date - e = 10 - if y > 1600: - e = e+y//100-16-(y//100-16)//4 - else: - # New method - c = y//100 - h = (c-c//4-(8*c+13)//25+19*g+15)%30 - i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11)) - j = (y+y//4+i+2-c+c//4)%7 - - # p can be from -6 to 56 corresponding to dates 22 March to 23 May - # (later dates apply to method 2, although 23 May never actually occurs) - p = i-j+e - d = 1+(p+27+(p+6)//40)%31 - m = 3+(p+26)//30 - return datetime.date(int(y), int(m), int(d)) - diff --git a/lib/dateutil_py3/parser.py b/lib/dateutil_py3/parser.py deleted file mode 100644 index a2604a35ba06..000000000000 --- a/lib/dateutil_py3/parser.py +++ /dev/null @@ -1,909 +0,0 @@ -# -*- coding:iso-8859-1 -*- -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -from __future__ import unicode_literals -__license__ = "Simplified BSD" - - -import datetime -import string -import time -import sys -import os -import collections - -try: - from io import StringIO -except ImportError: - from io import StringIO - -from six import text_type, binary_type, integer_types - -from . import relativedelta -from . import tz - - -__all__ = ["parse", "parserinfo"] - - -# Some pointers: -# -# http://www.cl.cam.ac.uk/~mgk25/iso-time.html -# http://www.iso.ch/iso/en/prods-services/popstds/datesandtime.html -# http://www.w3.org/TR/NOTE-datetime -# http://ringmaster.arc.nasa.gov/tools/time_formats.html -# http://search.cpan.org/author/MUIR/Time-modules-2003.0211/lib/Time/ParseDate.pm -# http://stein.cshl.org/jade/distrib/docs/java.text.SimpleDateFormat.html - - -class _timelex(object): - - def __init__(self, instream): - if isinstance(instream, text_type): - instream = StringIO(instream) - self.instream = instream - self.wordchars = ('abcdfeghijklmnopqrstuvwxyz' - 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_' - 'ßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ' - 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ') - self.numchars = '0123456789' - self.whitespace = ' \t\r\n' - self.charstack = [] - self.tokenstack = [] - self.eof = False - - def get_token(self): - if self.tokenstack: - return self.tokenstack.pop(0) - seenletters = False - token = None - state = None - wordchars = self.wordchars - numchars = self.numchars - whitespace = self.whitespace - while not self.eof: - if self.charstack: - nextchar = self.charstack.pop(0) - else: - nextchar = self.instream.read(1) - while nextchar == '\x00': - nextchar = self.instream.read(1) - if not nextchar: - self.eof = True - break - elif not state: - token = nextchar - if nextchar in wordchars: - state = 'a' - elif nextchar in numchars: - state = '0' - elif nextchar in whitespace: - token = ' ' - break # emit token - else: - break # emit token - elif state == 'a': - seenletters = True - if nextchar in wordchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0': - if nextchar in numchars: - token += nextchar - elif nextchar == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == 'a.': - seenletters = True - if nextchar == '.' or nextchar in wordchars: - token += nextchar - elif nextchar in numchars and token[-1] == '.': - token += nextchar - state = '0.' - else: - self.charstack.append(nextchar) - break # emit token - elif state == '0.': - if nextchar == '.' or nextchar in numchars: - token += nextchar - elif nextchar in wordchars and token[-1] == '.': - token += nextchar - state = 'a.' - else: - self.charstack.append(nextchar) - break # emit token - if (state in ('a.', '0.') and - (seenletters or token.count('.') > 1 or token[-1] == '.')): - l = token.split('.') - token = l[0] - for tok in l[1:]: - self.tokenstack.append('.') - if tok: - self.tokenstack.append(tok) - return token - - def __iter__(self): - return self - - def __next__(self): - token = self.get_token() - if token is None: - raise StopIteration - return token - - def next(self): - return self.__next__() # Python 2.x support - - def split(cls, s): - return list(cls(s)) - split = classmethod(split) - - -class _resultbase(object): - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def _repr(self, classname): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (classname, ", ".join(l)) - - def __repr__(self): - return self._repr(self.__class__.__name__) - - -class parserinfo(object): - - # m from a.m/p.m, t from ISO T separator - JUMP = [" ", ".", ",", ";", "-", "/", "'", - "at", "on", "and", "ad", "m", "t", "of", - "st", "nd", "rd", "th"] - - WEEKDAYS = [("Mon", "Monday"), - ("Tue", "Tuesday"), - ("Wed", "Wednesday"), - ("Thu", "Thursday"), - ("Fri", "Friday"), - ("Sat", "Saturday"), - ("Sun", "Sunday")] - MONTHS = [("Jan", "January"), - ("Feb", "February"), - ("Mar", "March"), - ("Apr", "April"), - ("May", "May"), - ("Jun", "June"), - ("Jul", "July"), - ("Aug", "August"), - ("Sep", "Sept", "September"), - ("Oct", "October"), - ("Nov", "November"), - ("Dec", "December")] - HMS = [("h", "hour", "hours"), - ("m", "minute", "minutes"), - ("s", "second", "seconds")] - AMPM = [("am", "a"), - ("pm", "p")] - UTCZONE = ["UTC", "GMT", "Z"] - PERTAIN = ["of"] - TZOFFSET = {} - - def __init__(self, dayfirst=False, yearfirst=False): - self._jump = self._convert(self.JUMP) - self._weekdays = self._convert(self.WEEKDAYS) - self._months = self._convert(self.MONTHS) - self._hms = self._convert(self.HMS) - self._ampm = self._convert(self.AMPM) - self._utczone = self._convert(self.UTCZONE) - self._pertain = self._convert(self.PERTAIN) - - self.dayfirst = dayfirst - self.yearfirst = yearfirst - - self._year = time.localtime().tm_year - self._century = self._year//100*100 - - def _convert(self, lst): - dct = {} - for i in range(len(lst)): - v = lst[i] - if isinstance(v, tuple): - for v in v: - dct[v.lower()] = i - else: - dct[v.lower()] = i - return dct - - def jump(self, name): - return name.lower() in self._jump - - def weekday(self, name): - if len(name) >= 3: - try: - return self._weekdays[name.lower()] - except KeyError: - pass - return None - - def month(self, name): - if len(name) >= 3: - try: - return self._months[name.lower()]+1 - except KeyError: - pass - return None - - def hms(self, name): - try: - return self._hms[name.lower()] - except KeyError: - return None - - def ampm(self, name): - try: - return self._ampm[name.lower()] - except KeyError: - return None - - def pertain(self, name): - return name.lower() in self._pertain - - def utczone(self, name): - return name.lower() in self._utczone - - def tzoffset(self, name): - if name in self._utczone: - return 0 - return self.TZOFFSET.get(name) - - def convertyear(self, year): - if year < 100: - year += self._century - if abs(year-self._year) >= 50: - if year < self._year: - year += 100 - else: - year -= 100 - return year - - def validate(self, res): - # move to info - if res.year is not None: - res.year = self.convertyear(res.year) - if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z': - res.tzname = "UTC" - res.tzoffset = 0 - elif res.tzoffset != 0 and res.tzname and self.utczone(res.tzname): - res.tzoffset = 0 - return True - - -class parser(object): - - def __init__(self, info=None): - self.info = info or parserinfo() - - def parse(self, timestr, default=None, - ignoretz=False, tzinfos=None, - **kwargs): - if not default: - default = datetime.datetime.now().replace(hour=0, minute=0, - second=0, microsecond=0) - res = self._parse(timestr, **kwargs) - if res is None: - raise ValueError("unknown string format") - repl = {} - for attr in ["year", "month", "day", "hour", - "minute", "second", "microsecond"]: - value = getattr(res, attr) - if value is not None: - repl[attr] = value - ret = default.replace(**repl) - if res.weekday is not None and not res.day: - ret = ret+relativedelta.relativedelta(weekday=res.weekday) - if not ignoretz: - if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos: - if isinstance(tzinfos, collections.Callable): - tzdata = tzinfos(res.tzname, res.tzoffset) - else: - tzdata = tzinfos.get(res.tzname) - if isinstance(tzdata, datetime.tzinfo): - tzinfo = tzdata - elif isinstance(tzdata, text_type): - tzinfo = tz.tzstr(tzdata) - elif isinstance(tzdata, integer_types): - tzinfo = tz.tzoffset(res.tzname, tzdata) - else: - raise ValueError("offset must be tzinfo subclass, " \ - "tz string, or int offset") - ret = ret.replace(tzinfo=tzinfo) - elif res.tzname and res.tzname in time.tzname: - ret = ret.replace(tzinfo=tz.tzlocal()) - elif res.tzoffset == 0: - ret = ret.replace(tzinfo=tz.tzutc()) - elif res.tzoffset: - ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset)) - return ret - - class _result(_resultbase): - __slots__ = ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond", - "tzname", "tzoffset"] - - def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False): - info = self.info - if dayfirst is None: - dayfirst = info.dayfirst - if yearfirst is None: - yearfirst = info.yearfirst - res = self._result() - l = _timelex.split(timestr) - try: - - # year/month/day list - ymd = [] - - # Index of the month string in ymd - mstridx = -1 - - len_l = len(l) - i = 0 - while i < len_l: - - # Check if it's a number - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - value = None - - if value is not None: - # Token is a number - len_li = len(l[i]) - i += 1 - if (len(ymd) == 3 and len_li in (2, 4) - and (i >= len_l or (l[i] != ':' and - info.hms(l[i]) is None))): - # 19990101T23[59] - s = l[i-1] - res.hour = int(s[:2]) - if len_li == 4: - res.minute = int(s[2:]) - elif len_li == 6 or (len_li > 6 and l[i-1].find('.') == 6): - # YYMMDD or HHMMSS[.ss] - s = l[i-1] - if not ymd and l[i-1].find('.') == -1: - ymd.append(info.convertyear(int(s[:2]))) - ymd.append(int(s[2:4])) - ymd.append(int(s[4:])) - else: - # 19990101T235959[.59] - res.hour = int(s[:2]) - res.minute = int(s[2:4]) - res.second, res.microsecond = _parsems(s[4:]) - elif len_li == 8: - # YYYYMMDD - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:])) - elif len_li in (12, 14): - # YYYYMMDDhhmm[ss] - s = l[i-1] - ymd.append(int(s[:4])) - ymd.append(int(s[4:6])) - ymd.append(int(s[6:8])) - res.hour = int(s[8:10]) - res.minute = int(s[10:12]) - if len_li == 14: - res.second = int(s[12:]) - elif ((i < len_l and info.hms(l[i]) is not None) or - (i+1 < len_l and l[i] == ' ' and - info.hms(l[i+1]) is not None)): - # HH[ ]h or MM[ ]m or SS[.ss][ ]s - if l[i] == ' ': - i += 1 - idx = info.hms(l[i]) - while True: - if idx == 0: - res.hour = int(value) - if value%1: - res.minute = int(60*(value%1)) - elif idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - if i >= len_l or idx == 2: - break - # 12h00 - try: - value_repr = l[i] - value = float(value_repr) - except ValueError: - break - else: - i += 1 - idx += 1 - if i < len_l: - newidx = info.hms(l[i]) - if newidx is not None: - idx = newidx - elif i == len_l and l[i-2] == ' ' and info.hms(l[i-3]) is not None: - # X h MM or X m SS - idx = info.hms(l[i-3]) + 1 - if idx == 1: - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - elif idx == 2: - res.second, res.microsecond = \ - _parsems(value_repr) - i += 1 - elif i+1 < len_l and l[i] == ':': - # HH:MM[:SS[.ss]] - res.hour = int(value) - i += 1 - value = float(l[i]) - res.minute = int(value) - if value%1: - res.second = int(60*(value%1)) - i += 1 - if i < len_l and l[i] == ':': - res.second, res.microsecond = _parsems(l[i+1]) - i += 2 - elif i < len_l and l[i] in ('-', '/', '.'): - sep = l[i] - ymd.append(int(value)) - i += 1 - if i < len_l and not info.jump(l[i]): - try: - # 01-01[-01] - ymd.append(int(l[i])) - except ValueError: - # 01-Jan[-01] - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - else: - return None - i += 1 - if i < len_l and l[i] == sep: - # We have three members - i += 1 - value = info.month(l[i]) - if value is not None: - ymd.append(value) - mstridx = len(ymd)-1 - assert mstridx == -1 - else: - ymd.append(int(l[i])) - i += 1 - elif i >= len_l or info.jump(l[i]): - if i+1 < len_l and info.ampm(l[i+1]) is not None: - # 12 am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i+1]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i+1]) == 0: - res.hour = 0 - i += 1 - else: - # Year, month or day - ymd.append(int(value)) - i += 1 - elif info.ampm(l[i]) is not None: - # 12am - res.hour = int(value) - if res.hour < 12 and info.ampm(l[i]) == 1: - res.hour += 12 - elif res.hour == 12 and info.ampm(l[i]) == 0: - res.hour = 0 - i += 1 - elif not fuzzy: - return None - else: - i += 1 - continue - - # Check weekday - value = info.weekday(l[i]) - if value is not None: - res.weekday = value - i += 1 - continue - - # Check month name - value = info.month(l[i]) - if value is not None: - ymd.append(value) - assert mstridx == -1 - mstridx = len(ymd)-1 - i += 1 - if i < len_l: - if l[i] in ('-', '/'): - # Jan-01[-99] - sep = l[i] - i += 1 - ymd.append(int(l[i])) - i += 1 - if i < len_l and l[i] == sep: - # Jan-01-99 - i += 1 - ymd.append(int(l[i])) - i += 1 - elif (i+3 < len_l and l[i] == l[i+2] == ' ' - and info.pertain(l[i+1])): - # Jan of 01 - # In this case, 01 is clearly year - try: - value = int(l[i+3]) - except ValueError: - # Wrong guess - pass - else: - # Convert it here to become unambiguous - ymd.append(info.convertyear(value)) - i += 4 - continue - - # Check am/pm - value = info.ampm(l[i]) - if value is not None: - if value == 1 and res.hour < 12: - res.hour += 12 - elif value == 0 and res.hour == 12: - res.hour = 0 - i += 1 - continue - - # Check for a timezone name - if (res.hour is not None and len(l[i]) <= 5 and - res.tzname is None and res.tzoffset is None and - not [x for x in l[i] if x not in string.ascii_uppercase]): - res.tzname = l[i] - res.tzoffset = info.tzoffset(res.tzname) - i += 1 - - # Check for something like GMT+3, or BRST+3. Notice - # that it doesn't mean "I am 3 hours after GMT", but - # "my time +3 is GMT". If found, we reverse the - # logic so that timezone parsing code will get it - # right. - if i < len_l and l[i] in ('+', '-'): - l[i] = ('+', '-')[l[i] == '+'] - res.tzoffset = None - if info.utczone(res.tzname): - # With something like GMT+3, the timezone - # is *not* GMT. - res.tzname = None - - continue - - # Check for a numbered timezone - if res.hour is not None and l[i] in ('+', '-'): - signal = (-1, 1)[l[i] == '+'] - i += 1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - res.tzoffset = int(l[i][:2])*3600+int(l[i][2:])*60 - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - res.tzoffset = int(l[i])*3600+int(l[i+2])*60 - i += 2 - elif len_li <= 2: - # -[0]3 - res.tzoffset = int(l[i][:2])*3600 - else: - return None - i += 1 - res.tzoffset *= signal - - # Look for a timezone name between parenthesis - if (i+3 < len_l and - info.jump(l[i]) and l[i+1] == '(' and l[i+3] == ')' and - 3 <= len(l[i+2]) <= 5 and - not [x for x in l[i+2] - if x not in string.ascii_uppercase]): - # -0300 (BRST) - res.tzname = l[i+2] - i += 4 - continue - - # Check jumps - if not (info.jump(l[i]) or fuzzy): - return None - - i += 1 - - # Process year/month/day - len_ymd = len(ymd) - if len_ymd > 3: - # More than three members!? - return None - elif len_ymd == 1 or (mstridx != -1 and len_ymd == 2): - # One member, or two members with a month string - if mstridx != -1: - res.month = ymd[mstridx] - del ymd[mstridx] - if len_ymd > 1 or mstridx == -1: - if ymd[0] > 31: - res.year = ymd[0] - else: - res.day = ymd[0] - elif len_ymd == 2: - # Two members with numbers - if ymd[0] > 31: - # 99-01 - res.year, res.month = ymd - elif ymd[1] > 31: - # 01-99 - res.month, res.year = ymd - elif dayfirst and ymd[1] <= 12: - # 13-01 - res.day, res.month = ymd - else: - # 01-13 - res.month, res.day = ymd - if len_ymd == 3: - # Three members - if mstridx == 0: - res.month, res.day, res.year = ymd - elif mstridx == 1: - if ymd[0] > 31 or (yearfirst and ymd[2] <= 31): - # 99-Jan-01 - res.year, res.month, res.day = ymd - else: - # 01-Jan-01 - # Give precendence to day-first, since - # two-digit years is usually hand-written. - res.day, res.month, res.year = ymd - elif mstridx == 2: - # WTF!? - if ymd[1] > 31: - # 01-99-Jan - res.day, res.year, res.month = ymd - else: - # 99-01-Jan - res.year, res.day, res.month = ymd - else: - if ymd[0] > 31 or \ - (yearfirst and ymd[1] <= 12 and ymd[2] <= 31): - # 99-01-01 - res.year, res.month, res.day = ymd - elif ymd[0] > 12 or (dayfirst and ymd[1] <= 12): - # 13-01-01 - res.day, res.month, res.year = ymd - else: - # 01-13-01 - res.month, res.day, res.year = ymd - - except (IndexError, ValueError, AssertionError): - return None - - if not info.validate(res): - return None - return res - -DEFAULTPARSER = parser() -def parse(timestr, parserinfo=None, **kwargs): - # Python 2.x support: datetimes return their string presentation as - # bytes in 2.x and unicode in 3.x, so it's reasonable to expect that - # the parser will get both kinds. Internally we use unicode only. - if isinstance(timestr, binary_type): - timestr = timestr.decode() - if parserinfo: - return parser(parserinfo).parse(timestr, **kwargs) - else: - return DEFAULTPARSER.parse(timestr, **kwargs) - - -class _tzparser(object): - - class _result(_resultbase): - - __slots__ = ["stdabbr", "stdoffset", "dstabbr", "dstoffset", - "start", "end"] - - class _attr(_resultbase): - __slots__ = ["month", "week", "weekday", - "yday", "jyday", "day", "time"] - - def __repr__(self): - return self._repr("") - - def __init__(self): - _resultbase.__init__(self) - self.start = self._attr() - self.end = self._attr() - - def parse(self, tzstr): - res = self._result() - l = _timelex.split(tzstr) - try: - - len_l = len(l) - - i = 0 - while i < len_l: - # BRST+3[BRDT[+2]] - j = i - while j < len_l and not [x for x in l[j] - if x in "0123456789:,-+"]: - j += 1 - if j != i: - if not res.stdabbr: - offattr = "stdoffset" - res.stdabbr = "".join(l[i:j]) - else: - offattr = "dstoffset" - res.dstabbr = "".join(l[i:j]) - i = j - if (i < len_l and - (l[i] in ('+', '-') or l[i][0] in "0123456789")): - if l[i] in ('+', '-'): - # Yes, that's right. See the TZ variable - # documentation. - signal = (1, -1)[l[i] == '+'] - i += 1 - else: - signal = -1 - len_li = len(l[i]) - if len_li == 4: - # -0300 - setattr(res, offattr, - (int(l[i][:2])*3600+int(l[i][2:])*60)*signal) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - setattr(res, offattr, - (int(l[i])*3600+int(l[i+2])*60)*signal) - i += 2 - elif len_li <= 2: - # -[0]3 - setattr(res, offattr, - int(l[i][:2])*3600*signal) - else: - return None - i += 1 - if res.dstabbr: - break - else: - break - - if i < len_l: - for j in range(i, len_l): - if l[j] == ';': l[j] = ',' - - assert l[i] == ',' - - i += 1 - - if i >= len_l: - pass - elif (8 <= l.count(',') <= 9 and - not [y for x in l[i:] if x != ',' - for y in x if y not in "0123456789"]): - # GMT0BST,3,0,30,3600,10,0,26,7200[,3600] - for x in (res.start, res.end): - x.month = int(l[i]) - i += 2 - if l[i] == '-': - value = int(l[i+1])*-1 - i += 1 - else: - value = int(l[i]) - i += 2 - if value: - x.week = value - x.weekday = (int(l[i])-1)%7 - else: - x.day = int(l[i]) - i += 2 - x.time = int(l[i]) - i += 2 - if i < len_l: - if l[i] in ('-', '+'): - signal = (-1, 1)[l[i] == "+"] - i += 1 - else: - signal = 1 - res.dstoffset = (res.stdoffset+int(l[i]))*signal - elif (l.count(',') == 2 and l[i:].count('/') <= 2 and - not [y for x in l[i:] if x not in (',', '/', 'J', 'M', - '.', '-', ':') - for y in x if y not in "0123456789"]): - for x in (res.start, res.end): - if l[i] == 'J': - # non-leap year day (1 based) - i += 1 - x.jyday = int(l[i]) - elif l[i] == 'M': - # month[-.]week[-.]weekday - i += 1 - x.month = int(l[i]) - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.week = int(l[i]) - if x.week == 5: - x.week = -1 - i += 1 - assert l[i] in ('-', '.') - i += 1 - x.weekday = (int(l[i])-1)%7 - else: - # year day (zero based) - x.yday = int(l[i])+1 - - i += 1 - - if i < len_l and l[i] == '/': - i += 1 - # start time - len_li = len(l[i]) - if len_li == 4: - # -0300 - x.time = (int(l[i][:2])*3600+int(l[i][2:])*60) - elif i+1 < len_l and l[i+1] == ':': - # -03:00 - x.time = int(l[i])*3600+int(l[i+2])*60 - i += 2 - if i+1 < len_l and l[i+1] == ':': - i += 2 - x.time += int(l[i]) - elif len_li <= 2: - # -[0]3 - x.time = (int(l[i][:2])*3600) - else: - return None - i += 1 - - assert i == len_l or l[i] == ',' - - i += 1 - - assert i >= len_l - - except (IndexError, ValueError, AssertionError): - return None - - return res - - -DEFAULTTZPARSER = _tzparser() -def _parsetz(tzstr): - return DEFAULTTZPARSER.parse(tzstr) - - -def _parsems(value): - """Parse a I[.F] seconds value into (seconds, microseconds).""" - if "." not in value: - return int(value), 0 - else: - i, f = value.split(".") - return int(i), int(f.ljust(6, "0")[:6]) - - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/relativedelta.py b/lib/dateutil_py3/relativedelta.py deleted file mode 100644 index 4393bcbcde22..000000000000 --- a/lib/dateutil_py3/relativedelta.py +++ /dev/null @@ -1,436 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import datetime -import calendar - -from six import integer_types - -__all__ = ["relativedelta", "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class relativedelta(object): - """ -The relativedelta type is based on the specification of the excelent -work done by M.-A. Lemburg in his mx.DateTime extension. However, -notice that this type does *NOT* implement the same algorithm as -his work. Do *NOT* expect it to behave like mx.DateTime's counterpart. - -There's two different ways to build a relativedelta instance. The -first one is passing it two date/datetime classes: - - relativedelta(datetime1, datetime2) - -And the other way is to use the following keyword arguments: - - year, month, day, hour, minute, second, microsecond: - Absolute information. - - years, months, weeks, days, hours, minutes, seconds, microseconds: - Relative information, may be negative. - - weekday: - One of the weekday instances (MO, TU, etc). These instances may - receive a parameter N, specifying the Nth weekday, which could - be positive or negative (like MO(+1) or MO(-2). Not specifying - it is the same as specifying +1. You can also use an integer, - where 0=MO. - - leapdays: - Will add given days to the date found, if year is a leap - year, and the date found is post 28 of february. - - yearday, nlyearday: - Set the yearday or the non-leap year day (jump leap days). - These are converted to day/month/leapdays information. - -Here is the behavior of operations with relativedelta: - -1) Calculate the absolute year, using the 'year' argument, or the - original datetime year, if the argument is not present. - -2) Add the relative 'years' argument to the absolute year. - -3) Do steps 1 and 2 for month/months. - -4) Calculate the absolute day, using the 'day' argument, or the - original datetime day, if the argument is not present. Then, - subtract from the day until it fits in the year and month - found after their operations. - -5) Add the relative 'days' argument to the absolute day. Notice - that the 'weeks' argument is multiplied by 7 and added to - 'days'. - -6) Do steps 1 and 2 for hour/hours, minute/minutes, second/seconds, - microsecond/microseconds. - -7) If the 'weekday' argument is present, calculate the weekday, - with the given (wday, nth) tuple. wday is the index of the - weekday (0-6, 0=Mon), and nth is the number of weeks to add - forward or backward, depending on its signal. Notice that if - the calculated date is already Monday, for example, using - (0, 1) or (0, -1) won't change the day. - """ - - def __init__(self, dt1=None, dt2=None, - years=0, months=0, days=0, leapdays=0, weeks=0, - hours=0, minutes=0, seconds=0, microseconds=0, - year=None, month=None, day=None, weekday=None, - yearday=None, nlyearday=None, - hour=None, minute=None, second=None, microsecond=None): - if dt1 and dt2: - if (not isinstance(dt1, datetime.date)) or (not isinstance(dt2, datetime.date)): - raise TypeError("relativedelta only diffs datetime/date") - if not type(dt1) == type(dt2): #isinstance(dt1, type(dt2)): - if not isinstance(dt1, datetime.datetime): - dt1 = datetime.datetime.fromordinal(dt1.toordinal()) - elif not isinstance(dt2, datetime.datetime): - dt2 = datetime.datetime.fromordinal(dt2.toordinal()) - self.years = 0 - self.months = 0 - self.days = 0 - self.leapdays = 0 - self.hours = 0 - self.minutes = 0 - self.seconds = 0 - self.microseconds = 0 - self.year = None - self.month = None - self.day = None - self.weekday = None - self.hour = None - self.minute = None - self.second = None - self.microsecond = None - self._has_time = 0 - - months = (dt1.year*12+dt1.month)-(dt2.year*12+dt2.month) - self._set_months(months) - dtm = self.__radd__(dt2) - if dt1 < dt2: - while dt1 > dtm: - months += 1 - self._set_months(months) - dtm = self.__radd__(dt2) - else: - while dt1 < dtm: - months -= 1 - self._set_months(months) - dtm = self.__radd__(dt2) - delta = dt1 - dtm - self.seconds = delta.seconds+delta.days*86400 - self.microseconds = delta.microseconds - else: - self.years = years - self.months = months - self.days = days+weeks*7 - self.leapdays = leapdays - self.hours = hours - self.minutes = minutes - self.seconds = seconds - self.microseconds = microseconds - self.year = year - self.month = month - self.day = day - self.hour = hour - self.minute = minute - self.second = second - self.microsecond = microsecond - - if isinstance(weekday, integer_types): - self.weekday = weekdays[weekday] - else: - self.weekday = weekday - - yday = 0 - if nlyearday: - yday = nlyearday - elif yearday: - yday = yearday - if yearday > 59: - self.leapdays = -1 - if yday: - ydayidx = [31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 366] - for idx, ydays in enumerate(ydayidx): - if yday <= ydays: - self.month = idx+1 - if idx == 0: - self.day = yday - else: - self.day = yday-ydayidx[idx-1] - break - else: - raise ValueError("invalid year day (%d)" % yday) - - self._fix() - - def _fix(self): - if abs(self.microseconds) > 999999: - s = self.microseconds//abs(self.microseconds) - div, mod = divmod(self.microseconds*s, 1000000) - self.microseconds = mod*s - self.seconds += div*s - if abs(self.seconds) > 59: - s = self.seconds//abs(self.seconds) - div, mod = divmod(self.seconds*s, 60) - self.seconds = mod*s - self.minutes += div*s - if abs(self.minutes) > 59: - s = self.minutes//abs(self.minutes) - div, mod = divmod(self.minutes*s, 60) - self.minutes = mod*s - self.hours += div*s - if abs(self.hours) > 23: - s = self.hours//abs(self.hours) - div, mod = divmod(self.hours*s, 24) - self.hours = mod*s - self.days += div*s - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years += div*s - if (self.hours or self.minutes or self.seconds or self.microseconds or - self.hour is not None or self.minute is not None or - self.second is not None or self.microsecond is not None): - self._has_time = 1 - else: - self._has_time = 0 - - def _set_months(self, months): - self.months = months - if abs(self.months) > 11: - s = self.months//abs(self.months) - div, mod = divmod(self.months*s, 12) - self.months = mod*s - self.years = div*s - else: - self.years = 0 - - def __add__(self, other): - if isinstance(other, relativedelta): - return relativedelta(years=other.years+self.years, - months=other.months+self.months, - days=other.days+self.days, - hours=other.hours+self.hours, - minutes=other.minutes+self.minutes, - seconds=other.seconds+self.seconds, - microseconds=other.microseconds+self.microseconds, - leapdays=other.leapdays or self.leapdays, - year=other.year or self.year, - month=other.month or self.month, - day=other.day or self.day, - weekday=other.weekday or self.weekday, - hour=other.hour or self.hour, - minute=other.minute or self.minute, - second=other.second or self.second, - microsecond=other.microsecond or self.microsecond) - if not isinstance(other, datetime.date): - raise TypeError("unsupported type for add operation") - elif self._has_time and not isinstance(other, datetime.datetime): - other = datetime.datetime.fromordinal(other.toordinal()) - year = (self.year or other.year)+self.years - month = self.month or other.month - if self.months: - assert 1 <= abs(self.months) <= 12 - month += self.months - if month > 12: - year += 1 - month -= 12 - elif month < 1: - year -= 1 - month += 12 - day = min(calendar.monthrange(year, month)[1], - self.day or other.day) - repl = {"year": year, "month": month, "day": day} - for attr in ["hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - repl[attr] = value - days = self.days - if self.leapdays and month > 2 and calendar.isleap(year): - days += self.leapdays - ret = (other.replace(**repl) - + datetime.timedelta(days=days, - hours=self.hours, - minutes=self.minutes, - seconds=self.seconds, - microseconds=self.microseconds)) - if self.weekday: - weekday, nth = self.weekday.weekday, self.weekday.n or 1 - jumpdays = (abs(nth)-1)*7 - if nth > 0: - jumpdays += (7-ret.weekday()+weekday)%7 - else: - jumpdays += (ret.weekday()-weekday)%7 - jumpdays *= -1 - ret += datetime.timedelta(days=jumpdays) - return ret - - def __radd__(self, other): - return self.__add__(other) - - def __rsub__(self, other): - return self.__neg__().__radd__(other) - - def __sub__(self, other): - if not isinstance(other, relativedelta): - raise TypeError("unsupported type for sub operation") - return relativedelta(years=self.years-other.years, - months=self.months-other.months, - days=self.days-other.days, - hours=self.hours-other.hours, - minutes=self.minutes-other.minutes, - seconds=self.seconds-other.seconds, - microseconds=self.microseconds-other.microseconds, - leapdays=self.leapdays or other.leapdays, - year=self.year or other.year, - month=self.month or other.month, - day=self.day or other.day, - weekday=self.weekday or other.weekday, - hour=self.hour or other.hour, - minute=self.minute or other.minute, - second=self.second or other.second, - microsecond=self.microsecond or other.microsecond) - - def __neg__(self): - return relativedelta(years=-self.years, - months=-self.months, - days=-self.days, - hours=-self.hours, - minutes=-self.minutes, - seconds=-self.seconds, - microseconds=-self.microseconds, - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - def __bool__(self): - return not (not self.years and - not self.months and - not self.days and - not self.hours and - not self.minutes and - not self.seconds and - not self.microseconds and - not self.leapdays and - self.year is None and - self.month is None and - self.day is None and - self.weekday is None and - self.hour is None and - self.minute is None and - self.second is None and - self.microsecond is None) - - def __mul__(self, other): - f = float(other) - return relativedelta(years=int(self.years*f), - months=int(self.months*f), - days=int(self.days*f), - hours=int(self.hours*f), - minutes=int(self.minutes*f), - seconds=int(self.seconds*f), - microseconds=int(self.microseconds*f), - leapdays=self.leapdays, - year=self.year, - month=self.month, - day=self.day, - weekday=self.weekday, - hour=self.hour, - minute=self.minute, - second=self.second, - microsecond=self.microsecond) - - __rmul__ = __mul__ - - def __eq__(self, other): - if not isinstance(other, relativedelta): - return False - if self.weekday or other.weekday: - if not self.weekday or not other.weekday: - return False - if self.weekday.weekday != other.weekday.weekday: - return False - n1, n2 = self.weekday.n, other.weekday.n - if n1 != n2 and not ((not n1 or n1 == 1) and (not n2 or n2 == 1)): - return False - return (self.years == other.years and - self.months == other.months and - self.days == other.days and - self.hours == other.hours and - self.minutes == other.minutes and - self.seconds == other.seconds and - self.leapdays == other.leapdays and - self.year == other.year and - self.month == other.month and - self.day == other.day and - self.hour == other.hour and - self.minute == other.minute and - self.second == other.second and - self.microsecond == other.microsecond) - - def __ne__(self, other): - return not self.__eq__(other) - - def __div__(self, other): - return self.__mul__(1/float(other)) - - __truediv__ = __div__ - - def __repr__(self): - l = [] - for attr in ["years", "months", "days", "leapdays", - "hours", "minutes", "seconds", "microseconds"]: - value = getattr(self, attr) - if value: - l.append("%s=%+d" % (attr, value)) - for attr in ["year", "month", "day", "weekday", - "hour", "minute", "second", "microsecond"]: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/rrule.py b/lib/dateutil_py3/rrule.py deleted file mode 100644 index ad4d3ba70c4e..000000000000 --- a/lib/dateutil_py3/rrule.py +++ /dev/null @@ -1,1112 +0,0 @@ -""" -Copyright (c) 2003-2010 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -import itertools -import datetime -import calendar -try: - import _thread -except ImportError: - import thread as _thread -import sys - -from six import advance_iterator, integer_types - -__all__ = ["rrule", "rruleset", "rrulestr", - "YEARLY", "MONTHLY", "WEEKLY", "DAILY", - "HOURLY", "MINUTELY", "SECONDLY", - "MO", "TU", "WE", "TH", "FR", "SA", "SU"] - -# Every mask is 7 days longer to handle cross-year weekly periods. -M366MASK = tuple([1]*31+[2]*29+[3]*31+[4]*30+[5]*31+[6]*30+ - [7]*31+[8]*31+[9]*30+[10]*31+[11]*30+[12]*31+[1]*7) -M365MASK = list(M366MASK) -M29, M30, M31 = list(range(1, 30)), list(range(1, 31)), list(range(1, 32)) -MDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -MDAY365MASK = list(MDAY366MASK) -M29, M30, M31 = list(range(-29, 0)), list(range(-30, 0)), list(range(-31, 0)) -NMDAY366MASK = tuple(M31+M29+M31+M30+M31+M30+M31+M31+M30+M31+M30+M31+M31[:7]) -NMDAY365MASK = list(NMDAY366MASK) -M366RANGE = (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366) -M365RANGE = (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365) -WDAYMASK = [0, 1, 2, 3, 4, 5, 6]*55 -del M29, M30, M31, M365MASK[59], MDAY365MASK[59], NMDAY365MASK[31] -MDAY365MASK = tuple(MDAY365MASK) -M365MASK = tuple(M365MASK) - -(YEARLY, - MONTHLY, - WEEKLY, - DAILY, - HOURLY, - MINUTELY, - SECONDLY) = list(range(7)) - -# Imported on demand. -easter = None -parser = None - -class weekday(object): - __slots__ = ["weekday", "n"] - - def __init__(self, weekday, n=None): - if n == 0: - raise ValueError("Can't create weekday with n == 0") - self.weekday = weekday - self.n = n - - def __call__(self, n): - if n == self.n: - return self - else: - return self.__class__(self.weekday, n) - - def __eq__(self, other): - try: - if self.weekday != other.weekday or self.n != other.n: - return False - except AttributeError: - return False - return True - - def __repr__(self): - s = ("MO", "TU", "WE", "TH", "FR", "SA", "SU")[self.weekday] - if not self.n: - return s - else: - return "%s(%+d)" % (s, self.n) - -MO, TU, WE, TH, FR, SA, SU = weekdays = tuple([weekday(x) for x in range(7)]) - -class rrulebase(object): - def __init__(self, cache=False): - if cache: - self._cache = [] - self._cache_lock = _thread.allocate_lock() - self._cache_gen = self._iter() - self._cache_complete = False - else: - self._cache = None - self._cache_complete = False - self._len = None - - def __iter__(self): - if self._cache_complete: - return iter(self._cache) - elif self._cache is None: - return self._iter() - else: - return self._iter_cached() - - def _iter_cached(self): - i = 0 - gen = self._cache_gen - cache = self._cache - acquire = self._cache_lock.acquire - release = self._cache_lock.release - while gen: - if i == len(cache): - acquire() - if self._cache_complete: - break - try: - for j in range(10): - cache.append(advance_iterator(gen)) - except StopIteration: - self._cache_gen = gen = None - self._cache_complete = True - break - release() - yield cache[i] - i += 1 - while i < self._len: - yield cache[i] - i += 1 - - def __getitem__(self, item): - if self._cache_complete: - return self._cache[item] - elif isinstance(item, slice): - if item.step and item.step < 0: - return list(iter(self))[item] - else: - return list(itertools.islice(self, - item.start or 0, - item.stop or sys.maxsize, - item.step or 1)) - elif item >= 0: - gen = iter(self) - try: - for i in range(item+1): - res = advance_iterator(gen) - except StopIteration: - raise IndexError - return res - else: - return list(iter(self))[item] - - def __contains__(self, item): - if self._cache_complete: - return item in self._cache - else: - for i in self: - if i == item: - return True - elif i > item: - return False - return False - - # __len__() introduces a large performance penality. - def count(self): - if self._len is None: - for x in self: pass - return self._len - - def before(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - last = None - if inc: - for i in gen: - if i > dt: - break - last = i - else: - for i in gen: - if i >= dt: - break - last = i - return last - - def after(self, dt, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - if inc: - for i in gen: - if i >= dt: - return i - else: - for i in gen: - if i > dt: - return i - return None - - def between(self, after, before, inc=False): - if self._cache_complete: - gen = self._cache - else: - gen = self - started = False - l = [] - if inc: - for i in gen: - if i > before: - break - elif not started: - if i >= after: - started = True - l.append(i) - else: - l.append(i) - else: - for i in gen: - if i >= before: - break - elif not started: - if i > after: - started = True - l.append(i) - else: - l.append(i) - return l - -class rrule(rrulebase): - def __init__(self, freq, dtstart=None, - interval=1, wkst=None, count=None, until=None, bysetpos=None, - bymonth=None, bymonthday=None, byyearday=None, byeaster=None, - byweekno=None, byweekday=None, - byhour=None, byminute=None, bysecond=None, - cache=False): - super(rrule, self).__init__(cache) - global easter - if not dtstart: - dtstart = datetime.datetime.now().replace(microsecond=0) - elif not isinstance(dtstart, datetime.datetime): - dtstart = datetime.datetime.fromordinal(dtstart.toordinal()) - else: - dtstart = dtstart.replace(microsecond=0) - self._dtstart = dtstart - self._tzinfo = dtstart.tzinfo - self._freq = freq - self._interval = interval - self._count = count - if until and not isinstance(until, datetime.datetime): - until = datetime.datetime.fromordinal(until.toordinal()) - self._until = until - if wkst is None: - self._wkst = calendar.firstweekday() - elif isinstance(wkst, integer_types): - self._wkst = wkst - else: - self._wkst = wkst.weekday - if bysetpos is None: - self._bysetpos = None - elif isinstance(bysetpos, integer_types): - if bysetpos == 0 or not (-366 <= bysetpos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - self._bysetpos = (bysetpos,) - else: - self._bysetpos = tuple(bysetpos) - for pos in self._bysetpos: - if pos == 0 or not (-366 <= pos <= 366): - raise ValueError("bysetpos must be between 1 and 366, " - "or between -366 and -1") - if not (byweekno or byyearday or bymonthday or - byweekday is not None or byeaster is not None): - if freq == YEARLY: - if not bymonth: - bymonth = dtstart.month - bymonthday = dtstart.day - elif freq == MONTHLY: - bymonthday = dtstart.day - elif freq == WEEKLY: - byweekday = dtstart.weekday() - # bymonth - if not bymonth: - self._bymonth = None - elif isinstance(bymonth, integer_types): - self._bymonth = (bymonth,) - else: - self._bymonth = tuple(bymonth) - # byyearday - if not byyearday: - self._byyearday = None - elif isinstance(byyearday, integer_types): - self._byyearday = (byyearday,) - else: - self._byyearday = tuple(byyearday) - # byeaster - if byeaster is not None: - if not easter: - from dateutil import easter - if isinstance(byeaster, integer_types): - self._byeaster = (byeaster,) - else: - self._byeaster = tuple(byeaster) - else: - self._byeaster = None - # bymonthay - if not bymonthday: - self._bymonthday = () - self._bynmonthday = () - elif isinstance(bymonthday, integer_types): - if bymonthday < 0: - self._bynmonthday = (bymonthday,) - self._bymonthday = () - else: - self._bymonthday = (bymonthday,) - self._bynmonthday = () - else: - self._bymonthday = tuple([x for x in bymonthday if x > 0]) - self._bynmonthday = tuple([x for x in bymonthday if x < 0]) - # byweekno - if byweekno is None: - self._byweekno = None - elif isinstance(byweekno, integer_types): - self._byweekno = (byweekno,) - else: - self._byweekno = tuple(byweekno) - # byweekday / bynweekday - if byweekday is None: - self._byweekday = None - self._bynweekday = None - elif isinstance(byweekday, integer_types): - self._byweekday = (byweekday,) - self._bynweekday = None - elif hasattr(byweekday, "n"): - if not byweekday.n or freq > MONTHLY: - self._byweekday = (byweekday.weekday,) - self._bynweekday = None - else: - self._bynweekday = ((byweekday.weekday, byweekday.n),) - self._byweekday = None - else: - self._byweekday = [] - self._bynweekday = [] - for wday in byweekday: - if isinstance(wday, integer_types): - self._byweekday.append(wday) - elif not wday.n or freq > MONTHLY: - self._byweekday.append(wday.weekday) - else: - self._bynweekday.append((wday.weekday, wday.n)) - self._byweekday = tuple(self._byweekday) - self._bynweekday = tuple(self._bynweekday) - if not self._byweekday: - self._byweekday = None - elif not self._bynweekday: - self._bynweekday = None - # byhour - if byhour is None: - if freq < HOURLY: - self._byhour = (dtstart.hour,) - else: - self._byhour = None - elif isinstance(byhour, integer_types): - self._byhour = (byhour,) - else: - self._byhour = tuple(byhour) - # byminute - if byminute is None: - if freq < MINUTELY: - self._byminute = (dtstart.minute,) - else: - self._byminute = None - elif isinstance(byminute, integer_types): - self._byminute = (byminute,) - else: - self._byminute = tuple(byminute) - # bysecond - if bysecond is None: - if freq < SECONDLY: - self._bysecond = (dtstart.second,) - else: - self._bysecond = None - elif isinstance(bysecond, integer_types): - self._bysecond = (bysecond,) - else: - self._bysecond = tuple(bysecond) - - if self._freq >= HOURLY: - self._timeset = None - else: - self._timeset = [] - for hour in self._byhour: - for minute in self._byminute: - for second in self._bysecond: - self._timeset.append( - datetime.time(hour, minute, second, - tzinfo=self._tzinfo)) - self._timeset.sort() - self._timeset = tuple(self._timeset) - - def _iter(self): - year, month, day, hour, minute, second, weekday, yearday, _ = \ - self._dtstart.timetuple() - - # Some local variables to speed things up a bit - freq = self._freq - interval = self._interval - wkst = self._wkst - until = self._until - bymonth = self._bymonth - byweekno = self._byweekno - byyearday = self._byyearday - byweekday = self._byweekday - byeaster = self._byeaster - bymonthday = self._bymonthday - bynmonthday = self._bynmonthday - bysetpos = self._bysetpos - byhour = self._byhour - byminute = self._byminute - bysecond = self._bysecond - - ii = _iterinfo(self) - ii.rebuild(year, month) - - getdayset = {YEARLY:ii.ydayset, - MONTHLY:ii.mdayset, - WEEKLY:ii.wdayset, - DAILY:ii.ddayset, - HOURLY:ii.ddayset, - MINUTELY:ii.ddayset, - SECONDLY:ii.ddayset}[freq] - - if freq < HOURLY: - timeset = self._timeset - else: - gettimeset = {HOURLY:ii.htimeset, - MINUTELY:ii.mtimeset, - SECONDLY:ii.stimeset}[freq] - if ((freq >= HOURLY and - self._byhour and hour not in self._byhour) or - (freq >= MINUTELY and - self._byminute and minute not in self._byminute) or - (freq >= SECONDLY and - self._bysecond and second not in self._bysecond)): - timeset = () - else: - timeset = gettimeset(hour, minute, second) - - total = 0 - count = self._count - while True: - # Get dayset with the right frequency - dayset, start, end = getdayset(year, month, day) - - # Do the "hard" work ;-) - filtered = False - for i in dayset[start:end]: - if ((bymonth and ii.mmask[i] not in bymonth) or - (byweekno and not ii.wnomask[i]) or - (byweekday and ii.wdaymask[i] not in byweekday) or - (ii.nwdaymask and not ii.nwdaymask[i]) or - (byeaster and not ii.eastermask[i]) or - ((bymonthday or bynmonthday) and - ii.mdaymask[i] not in bymonthday and - ii.nmdaymask[i] not in bynmonthday) or - (byyearday and - ((i < ii.yearlen and i+1 not in byyearday - and -ii.yearlen+i not in byyearday) or - (i >= ii.yearlen and i+1-ii.yearlen not in byyearday - and -ii.nextyearlen+i-ii.yearlen - not in byyearday)))): - dayset[i] = None - filtered = True - - # Output results - if bysetpos and timeset: - poslist = [] - for pos in bysetpos: - if pos < 0: - daypos, timepos = divmod(pos, len(timeset)) - else: - daypos, timepos = divmod(pos-1, len(timeset)) - try: - i = [x for x in dayset[start:end] - if x is not None][daypos] - time = timeset[timepos] - except IndexError: - pass - else: - date = datetime.date.fromordinal(ii.yearordinal+i) - res = datetime.datetime.combine(date, time) - if res not in poslist: - poslist.append(res) - poslist.sort() - for res in poslist: - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - else: - for i in dayset[start:end]: - if i is not None: - date = datetime.date.fromordinal(ii.yearordinal+i) - for time in timeset: - res = datetime.datetime.combine(date, time) - if until and res > until: - self._len = total - return - elif res >= self._dtstart: - total += 1 - yield res - if count: - count -= 1 - if not count: - self._len = total - return - - # Handle frequency and interval - fixday = False - if freq == YEARLY: - year += interval - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == MONTHLY: - month += interval - if month > 12: - div, mod = divmod(month, 12) - month = mod - year += div - if month == 0: - month = 12 - year -= 1 - if year > datetime.MAXYEAR: - self._len = total - return - ii.rebuild(year, month) - elif freq == WEEKLY: - if wkst > weekday: - day += -(weekday+1+(6-wkst))+self._interval*7 - else: - day += -(weekday-wkst)+self._interval*7 - weekday = wkst - fixday = True - elif freq == DAILY: - day += interval - fixday = True - elif freq == HOURLY: - if filtered: - # Jump to one iteration before next day - hour += ((23-hour)//interval)*interval - while True: - hour += interval - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if not byhour or hour in byhour: - break - timeset = gettimeset(hour, minute, second) - elif freq == MINUTELY: - if filtered: - # Jump to one iteration before next day - minute += ((1439-(hour*60+minute))//interval)*interval - while True: - minute += interval - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - filtered = False - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute)): - break - timeset = gettimeset(hour, minute, second) - elif freq == SECONDLY: - if filtered: - # Jump to one iteration before next day - second += (((86399-(hour*3600+minute*60+second)) - //interval)*interval) - while True: - second += self._interval - div, mod = divmod(second, 60) - if div: - second = mod - minute += div - div, mod = divmod(minute, 60) - if div: - minute = mod - hour += div - div, mod = divmod(hour, 24) - if div: - hour = mod - day += div - fixday = True - if ((not byhour or hour in byhour) and - (not byminute or minute in byminute) and - (not bysecond or second in bysecond)): - break - timeset = gettimeset(hour, minute, second) - - if fixday and day > 28: - daysinmonth = calendar.monthrange(year, month)[1] - if day > daysinmonth: - while day > daysinmonth: - day -= daysinmonth - month += 1 - if month == 13: - month = 1 - year += 1 - if year > datetime.MAXYEAR: - self._len = total - return - daysinmonth = calendar.monthrange(year, month)[1] - ii.rebuild(year, month) - -class _iterinfo(object): - __slots__ = ["rrule", "lastyear", "lastmonth", - "yearlen", "nextyearlen", "yearordinal", "yearweekday", - "mmask", "mrange", "mdaymask", "nmdaymask", - "wdaymask", "wnomask", "nwdaymask", "eastermask"] - - def __init__(self, rrule): - for attr in self.__slots__: - setattr(self, attr, None) - self.rrule = rrule - - def rebuild(self, year, month): - # Every mask is 7 days longer to handle cross-year weekly periods. - rr = self.rrule - if year != self.lastyear: - self.yearlen = 365+calendar.isleap(year) - self.nextyearlen = 365+calendar.isleap(year+1) - firstyday = datetime.date(year, 1, 1) - self.yearordinal = firstyday.toordinal() - self.yearweekday = firstyday.weekday() - - wday = datetime.date(year, 1, 1).weekday() - if self.yearlen == 365: - self.mmask = M365MASK - self.mdaymask = MDAY365MASK - self.nmdaymask = NMDAY365MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M365RANGE - else: - self.mmask = M366MASK - self.mdaymask = MDAY366MASK - self.nmdaymask = NMDAY366MASK - self.wdaymask = WDAYMASK[wday:] - self.mrange = M366RANGE - - if not rr._byweekno: - self.wnomask = None - else: - self.wnomask = [0]*(self.yearlen+7) - #no1wkst = firstwkst = self.wdaymask.index(rr._wkst) - no1wkst = firstwkst = (7-self.yearweekday+rr._wkst)%7 - if no1wkst >= 4: - no1wkst = 0 - # Number of days in the year, plus the days we got - # from last year. - wyearlen = self.yearlen+(self.yearweekday-rr._wkst)%7 - else: - # Number of days in the year, minus the days we - # left in last year. - wyearlen = self.yearlen-no1wkst - div, mod = divmod(wyearlen, 7) - numweeks = div+mod//4 - for n in rr._byweekno: - if n < 0: - n += numweeks+1 - if not (0 < n <= numweeks): - continue - if n > 1: - i = no1wkst+(n-1)*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - else: - i = no1wkst - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if 1 in rr._byweekno: - # Check week number 1 of next year as well - # TODO: Check -numweeks for next year. - i = no1wkst+numweeks*7 - if no1wkst != firstwkst: - i -= 7-firstwkst - if i < self.yearlen: - # If week starts in next year, we - # don't care about it. - for j in range(7): - self.wnomask[i] = 1 - i += 1 - if self.wdaymask[i] == rr._wkst: - break - if no1wkst: - # Check last week number of last year as - # well. If no1wkst is 0, either the year - # started on week start, or week number 1 - # got days from last year, so there are no - # days from last year's last week number in - # this year. - if -1 not in rr._byweekno: - lyearweekday = datetime.date(year-1, 1, 1).weekday() - lno1wkst = (7-lyearweekday+rr._wkst)%7 - lyearlen = 365+calendar.isleap(year-1) - if lno1wkst >= 4: - lno1wkst = 0 - lnumweeks = 52+(lyearlen+ - (lyearweekday-rr._wkst)%7)%7//4 - else: - lnumweeks = 52+(self.yearlen-no1wkst)%7//4 - else: - lnumweeks = -1 - if lnumweeks in rr._byweekno: - for i in range(no1wkst): - self.wnomask[i] = 1 - - if (rr._bynweekday and - (month != self.lastmonth or year != self.lastyear)): - ranges = [] - if rr._freq == YEARLY: - if rr._bymonth: - for month in rr._bymonth: - ranges.append(self.mrange[month-1:month+1]) - else: - ranges = [(0, self.yearlen)] - elif rr._freq == MONTHLY: - ranges = [self.mrange[month-1:month+1]] - if ranges: - # Weekly frequency won't get here, so we may not - # care about cross-year weekly periods. - self.nwdaymask = [0]*self.yearlen - for first, last in ranges: - last -= 1 - for wday, n in rr._bynweekday: - if n < 0: - i = last+(n+1)*7 - i -= (self.wdaymask[i]-wday)%7 - else: - i = first+(n-1)*7 - i += (7-self.wdaymask[i]+wday)%7 - if first <= i <= last: - self.nwdaymask[i] = 1 - - if rr._byeaster: - self.eastermask = [0]*(self.yearlen+7) - eyday = easter.easter(year).toordinal()-self.yearordinal - for offset in rr._byeaster: - self.eastermask[eyday+offset] = 1 - - self.lastyear = year - self.lastmonth = month - - def ydayset(self, year, month, day): - return list(range(self.yearlen)), 0, self.yearlen - - def mdayset(self, year, month, day): - set = [None]*self.yearlen - start, end = self.mrange[month-1:month+1] - for i in range(start, end): - set[i] = i - return set, start, end - - def wdayset(self, year, month, day): - # We need to handle cross-year weeks here. - set = [None]*(self.yearlen+7) - i = datetime.date(year, month, day).toordinal()-self.yearordinal - start = i - for j in range(7): - set[i] = i - i += 1 - #if (not (0 <= i < self.yearlen) or - # self.wdaymask[i] == self.rrule._wkst): - # This will cross the year boundary, if necessary. - if self.wdaymask[i] == self.rrule._wkst: - break - return set, start, i - - def ddayset(self, year, month, day): - set = [None]*self.yearlen - i = datetime.date(year, month, day).toordinal()-self.yearordinal - set[i] = i - return set, i, i+1 - - def htimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for minute in rr._byminute: - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, - tzinfo=rr._tzinfo)) - set.sort() - return set - - def mtimeset(self, hour, minute, second): - set = [] - rr = self.rrule - for second in rr._bysecond: - set.append(datetime.time(hour, minute, second, tzinfo=rr._tzinfo)) - set.sort() - return set - - def stimeset(self, hour, minute, second): - return (datetime.time(hour, minute, second, - tzinfo=self.rrule._tzinfo),) - - -class rruleset(rrulebase): - - class _genitem(object): - def __init__(self, genlist, gen): - try: - self.dt = advance_iterator(gen) - genlist.append(self) - except StopIteration: - pass - self.genlist = genlist - self.gen = gen - - def __next__(self): - try: - self.dt = advance_iterator(self.gen) - except StopIteration: - self.genlist.remove(self) - - next = __next__ - - def __lt__(self, other): - return self.dt < other.dt - - def __gt__(self, other): - return self.dt > other.dt - - def __eq__(self, other): - return self.dt == other.dt - - def __ne__(self, other): - return self.dt != other.dt - - def __init__(self, cache=False): - super(rruleset, self).__init__(cache) - self._rrule = [] - self._rdate = [] - self._exrule = [] - self._exdate = [] - - def rrule(self, rrule): - self._rrule.append(rrule) - - def rdate(self, rdate): - self._rdate.append(rdate) - - def exrule(self, exrule): - self._exrule.append(exrule) - - def exdate(self, exdate): - self._exdate.append(exdate) - - def _iter(self): - rlist = [] - self._rdate.sort() - self._genitem(rlist, iter(self._rdate)) - for gen in [iter(x) for x in self._rrule]: - self._genitem(rlist, gen) - rlist.sort() - exlist = [] - self._exdate.sort() - self._genitem(exlist, iter(self._exdate)) - for gen in [iter(x) for x in self._exrule]: - self._genitem(exlist, gen) - exlist.sort() - lastdt = None - total = 0 - while rlist: - ritem = rlist[0] - if not lastdt or lastdt != ritem.dt: - while exlist and exlist[0] < ritem: - advance_iterator(exlist[0]) - exlist.sort() - if not exlist or ritem != exlist[0]: - total += 1 - yield ritem.dt - lastdt = ritem.dt - advance_iterator(ritem) - rlist.sort() - self._len = total - -class _rrulestr(object): - - _freq_map = {"YEARLY": YEARLY, - "MONTHLY": MONTHLY, - "WEEKLY": WEEKLY, - "DAILY": DAILY, - "HOURLY": HOURLY, - "MINUTELY": MINUTELY, - "SECONDLY": SECONDLY} - - _weekday_map = {"MO":0,"TU":1,"WE":2,"TH":3,"FR":4,"SA":5,"SU":6} - - def _handle_int(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = int(value) - - def _handle_int_list(self, rrkwargs, name, value, **kwargs): - rrkwargs[name.lower()] = [int(x) for x in value.split(',')] - - _handle_INTERVAL = _handle_int - _handle_COUNT = _handle_int - _handle_BYSETPOS = _handle_int_list - _handle_BYMONTH = _handle_int_list - _handle_BYMONTHDAY = _handle_int_list - _handle_BYYEARDAY = _handle_int_list - _handle_BYEASTER = _handle_int_list - _handle_BYWEEKNO = _handle_int_list - _handle_BYHOUR = _handle_int_list - _handle_BYMINUTE = _handle_int_list - _handle_BYSECOND = _handle_int_list - - def _handle_FREQ(self, rrkwargs, name, value, **kwargs): - rrkwargs["freq"] = self._freq_map[value] - - def _handle_UNTIL(self, rrkwargs, name, value, **kwargs): - global parser - if not parser: - from dateutil import parser - try: - rrkwargs["until"] = parser.parse(value, - ignoretz=kwargs.get("ignoretz"), - tzinfos=kwargs.get("tzinfos")) - except ValueError: - raise ValueError("invalid until date") - - def _handle_WKST(self, rrkwargs, name, value, **kwargs): - rrkwargs["wkst"] = self._weekday_map[value] - - def _handle_BYWEEKDAY(self, rrkwargs, name, value, **kwarsg): - l = [] - for wday in value.split(','): - for i in range(len(wday)): - if wday[i] not in '+-0123456789': - break - n = wday[:i] or None - w = wday[i:] - if n: n = int(n) - l.append(weekdays[self._weekday_map[w]](n)) - rrkwargs["byweekday"] = l - - _handle_BYDAY = _handle_BYWEEKDAY - - def _parse_rfc_rrule(self, line, - dtstart=None, - cache=False, - ignoretz=False, - tzinfos=None): - if line.find(':') != -1: - name, value = line.split(':') - if name != "RRULE": - raise ValueError("unknown parameter name") - else: - value = line - rrkwargs = {} - for pair in value.split(';'): - name, value = pair.split('=') - name = name.upper() - value = value.upper() - try: - getattr(self, "_handle_"+name)(rrkwargs, name, value, - ignoretz=ignoretz, - tzinfos=tzinfos) - except AttributeError: - raise ValueError("unknown parameter '%s'" % name) - except (KeyError, ValueError): - raise ValueError("invalid '%s': %s" % (name, value)) - return rrule(dtstart=dtstart, cache=cache, **rrkwargs) - - def _parse_rfc(self, s, - dtstart=None, - cache=False, - unfold=False, - forceset=False, - compatible=False, - ignoretz=False, - tzinfos=None): - global parser - if compatible: - forceset = True - unfold = True - s = s.upper() - if not s.strip(): - raise ValueError("empty string") - if unfold: - lines = s.splitlines() - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - else: - lines = s.split() - if (not forceset and len(lines) == 1 and - (s.find(':') == -1 or s.startswith('RRULE:'))): - return self._parse_rfc_rrule(lines[0], cache=cache, - dtstart=dtstart, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - rrulevals = [] - rdatevals = [] - exrulevals = [] - exdatevals = [] - for line in lines: - if not line: - continue - if line.find(':') == -1: - name = "RRULE" - value = line - else: - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError("empty property name") - name = parms[0] - parms = parms[1:] - if name == "RRULE": - for parm in parms: - raise ValueError("unsupported RRULE parm: "+parm) - rrulevals.append(value) - elif name == "RDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError("unsupported RDATE parm: "+parm) - rdatevals.append(value) - elif name == "EXRULE": - for parm in parms: - raise ValueError("unsupported EXRULE parm: "+parm) - exrulevals.append(value) - elif name == "EXDATE": - for parm in parms: - if parm != "VALUE=DATE-TIME": - raise ValueError("unsupported RDATE parm: "+parm) - exdatevals.append(value) - elif name == "DTSTART": - for parm in parms: - raise ValueError("unsupported DTSTART parm: "+parm) - if not parser: - from dateutil import parser - dtstart = parser.parse(value, ignoretz=ignoretz, - tzinfos=tzinfos) - else: - raise ValueError("unsupported property: "+name) - if (forceset or len(rrulevals) > 1 or - rdatevals or exrulevals or exdatevals): - if not parser and (rdatevals or exdatevals): - from dateutil import parser - set = rruleset(cache=cache) - for value in rrulevals: - set.rrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in rdatevals: - for datestr in value.split(','): - set.rdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exrulevals: - set.exrule(self._parse_rfc_rrule(value, dtstart=dtstart, - ignoretz=ignoretz, - tzinfos=tzinfos)) - for value in exdatevals: - for datestr in value.split(','): - set.exdate(parser.parse(datestr, - ignoretz=ignoretz, - tzinfos=tzinfos)) - if compatible and dtstart: - set.rdate(dtstart) - return set - else: - return self._parse_rfc_rrule(rrulevals[0], - dtstart=dtstart, - cache=cache, - ignoretz=ignoretz, - tzinfos=tzinfos) - - def __call__(self, s, **kwargs): - return self._parse_rfc(s, **kwargs) - -rrulestr = _rrulestr() - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/tz.py b/lib/dateutil_py3/tz.py deleted file mode 100644 index e849fc24b5e2..000000000000 --- a/lib/dateutil_py3/tz.py +++ /dev/null @@ -1,960 +0,0 @@ -""" -Copyright (c) 2003-2007 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -__license__ = "Simplified BSD" - -from six import string_types, PY3 - -import datetime -import struct -import time -import sys -import os - -relativedelta = None -parser = None -rrule = None - -__all__ = ["tzutc", "tzoffset", "tzlocal", "tzfile", "tzrange", - "tzstr", "tzical", "tzwin", "tzwinlocal", "gettz"] - -try: - from dateutil.tzwin import tzwin, tzwinlocal -except (ImportError, OSError): - tzwin, tzwinlocal = None, None - -def tzname_in_python2(myfunc): - """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 - """ - def inner_func(*args, **kwargs): - if PY3: - return myfunc(*args, **kwargs) - else: - return myfunc(*args, **kwargs).encode() - return inner_func - -ZERO = datetime.timedelta(0) -EPOCHORDINAL = datetime.datetime.utcfromtimestamp(0).toordinal() - -class tzutc(datetime.tzinfo): - - def utcoffset(self, dt): - return ZERO - - def dst(self, dt): - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return "UTC" - - def __eq__(self, other): - return (isinstance(other, tzutc) or - (isinstance(other, tzoffset) and other._offset == ZERO)) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzoffset(datetime.tzinfo): - - def __init__(self, name, offset): - self._name = name - self._offset = datetime.timedelta(seconds=offset) - - def utcoffset(self, dt): - return self._offset - - def dst(self, dt): - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return self._name - - def __eq__(self, other): - return (isinstance(other, tzoffset) and - self._offset == other._offset) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(%s, %s)" % (self.__class__.__name__, - repr(self._name), - self._offset.days*86400+self._offset.seconds) - - __reduce__ = object.__reduce__ - -class tzlocal(datetime.tzinfo): - - _std_offset = datetime.timedelta(seconds=-time.timezone) - if time.daylight: - _dst_offset = datetime.timedelta(seconds=-time.altzone) - else: - _dst_offset = _std_offset - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - # We can't use mktime here. It is unstable when deciding if - # the hour near to a change is DST or not. - # - # timestamp = time.mktime((dt.year, dt.month, dt.day, dt.hour, - # dt.minute, dt.second, dt.weekday(), 0, -1)) - # return time.localtime(timestamp).tm_isdst - # - # The code above yields the following result: - # - #>>> import tz, datetime - #>>> t = tz.tzlocal() - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,16,0,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRST' - #>>> datetime.datetime(2003,2,15,22,tzinfo=t).tzname() - #'BRDT' - #>>> datetime.datetime(2003,2,15,23,tzinfo=t).tzname() - #'BRDT' - # - # Here is a more stable implementation: - # - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - return time.localtime(timestamp+time.timezone).tm_isdst - - def __eq__(self, other): - if not isinstance(other, tzlocal): - return False - return (self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset) - return True - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s()" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class _ttinfo(object): - __slots__ = ["offset", "delta", "isdst", "abbr", "isstd", "isgmt"] - - def __init__(self): - for attr in self.__slots__: - setattr(self, attr, None) - - def __repr__(self): - l = [] - for attr in self.__slots__: - value = getattr(self, attr) - if value is not None: - l.append("%s=%s" % (attr, repr(value))) - return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) - - def __eq__(self, other): - if not isinstance(other, _ttinfo): - return False - return (self.offset == other.offset and - self.delta == other.delta and - self.isdst == other.isdst and - self.abbr == other.abbr and - self.isstd == other.isstd and - self.isgmt == other.isgmt) - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - state = {} - for name in self.__slots__: - state[name] = getattr(self, name, None) - return state - - def __setstate__(self, state): - for name in self.__slots__: - if name in state: - setattr(self, name, state[name]) - -class tzfile(datetime.tzinfo): - - # http://www.twinsun.com/tz/tz-link.htm - # ftp://ftp.iana.org/tz/tz*.tar.gz - - def __init__(self, fileobj): - if isinstance(fileobj, string_types): - self._filename = fileobj - fileobj = open(fileobj, 'rb') - elif hasattr(fileobj, "name"): - self._filename = fileobj.name - else: - self._filename = repr(fileobj) - - # From tzfile(5): - # - # The time zone information files used by tzset(3) - # begin with the magic characters "TZif" to identify - # them as time zone information files, followed by - # sixteen bytes reserved for future use, followed by - # six four-byte values of type long, written in a - # ``standard'' byte order (the high-order byte - # of the value is written first). - - if fileobj.read(4).decode() != "TZif": - raise ValueError("magic not found") - - fileobj.read(16) - - ( - # The number of UTC/local indicators stored in the file. - ttisgmtcnt, - - # The number of standard/wall indicators stored in the file. - ttisstdcnt, - - # The number of leap seconds for which data is - # stored in the file. - leapcnt, - - # The number of "transition times" for which data - # is stored in the file. - timecnt, - - # The number of "local time types" for which data - # is stored in the file (must not be zero). - typecnt, - - # The number of characters of "time zone - # abbreviation strings" stored in the file. - charcnt, - - ) = struct.unpack(">6l", fileobj.read(24)) - - # The above header is followed by tzh_timecnt four-byte - # values of type long, sorted in ascending order. - # These values are written in ``standard'' byte order. - # Each is used as a transition time (as returned by - # time(2)) at which the rules for computing local time - # change. - - if timecnt: - self._trans_list = struct.unpack(">%dl" % timecnt, - fileobj.read(timecnt*4)) - else: - self._trans_list = [] - - # Next come tzh_timecnt one-byte values of type unsigned - # char; each one tells which of the different types of - # ``local time'' types described in the file is associated - # with the same-indexed transition time. These values - # serve as indices into an array of ttinfo structures that - # appears next in the file. - - if timecnt: - self._trans_idx = struct.unpack(">%dB" % timecnt, - fileobj.read(timecnt)) - else: - self._trans_idx = [] - - # Each ttinfo structure is written as a four-byte value - # for tt_gmtoff of type long, in a standard byte - # order, followed by a one-byte value for tt_isdst - # and a one-byte value for tt_abbrind. In each - # structure, tt_gmtoff gives the number of - # seconds to be added to UTC, tt_isdst tells whether - # tm_isdst should be set by localtime(3), and - # tt_abbrind serves as an index into the array of - # time zone abbreviation characters that follow the - # ttinfo structure(s) in the file. - - ttinfo = [] - - for i in range(typecnt): - ttinfo.append(struct.unpack(">lbb", fileobj.read(6))) - - abbr = fileobj.read(charcnt).decode() - - # Then there are tzh_leapcnt pairs of four-byte - # values, written in standard byte order; the - # first value of each pair gives the time (as - # returned by time(2)) at which a leap second - # occurs; the second gives the total number of - # leap seconds to be applied after the given time. - # The pairs of values are sorted in ascending order - # by time. - - # Not used, for now - if leapcnt: - leap = struct.unpack(">%dl" % (leapcnt*2), - fileobj.read(leapcnt*8)) - - # Then there are tzh_ttisstdcnt standard/wall - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as standard - # time or wall clock time, and are used when - # a time zone file is used in handling POSIX-style - # time zone environment variables. - - if ttisstdcnt: - isstd = struct.unpack(">%db" % ttisstdcnt, - fileobj.read(ttisstdcnt)) - - # Finally, there are tzh_ttisgmtcnt UTC/local - # indicators, each stored as a one-byte value; - # they tell whether the transition times associated - # with local time types were specified as UTC or - # local time, and are used when a time zone file - # is used in handling POSIX-style time zone envi- - # ronment variables. - - if ttisgmtcnt: - isgmt = struct.unpack(">%db" % ttisgmtcnt, - fileobj.read(ttisgmtcnt)) - - # ** Everything has been read ** - - # Build ttinfo list - self._ttinfo_list = [] - for i in range(typecnt): - gmtoff, isdst, abbrind = ttinfo[i] - # Round to full-minutes if that's not the case. Python's - # datetime doesn't accept sub-minute timezones. Check - # http://python.org/sf/1447945 for some information. - gmtoff = (gmtoff+30)//60*60 - tti = _ttinfo() - tti.offset = gmtoff - tti.delta = datetime.timedelta(seconds=gmtoff) - tti.isdst = isdst - tti.abbr = abbr[abbrind:abbr.find('\x00', abbrind)] - tti.isstd = (ttisstdcnt > i and isstd[i] != 0) - tti.isgmt = (ttisgmtcnt > i and isgmt[i] != 0) - self._ttinfo_list.append(tti) - - # Replace ttinfo indexes for ttinfo objects. - trans_idx = [] - for idx in self._trans_idx: - trans_idx.append(self._ttinfo_list[idx]) - self._trans_idx = tuple(trans_idx) - - # Set standard, dst, and before ttinfos. before will be - # used when a given time is before any transitions, - # and will be set to the first non-dst ttinfo, or to - # the first dst, if all of them are dst. - self._ttinfo_std = None - self._ttinfo_dst = None - self._ttinfo_before = None - if self._ttinfo_list: - if not self._trans_list: - self._ttinfo_std = self._ttinfo_first = self._ttinfo_list[0] - else: - for i in range(timecnt-1, -1, -1): - tti = self._trans_idx[i] - if not self._ttinfo_std and not tti.isdst: - self._ttinfo_std = tti - elif not self._ttinfo_dst and tti.isdst: - self._ttinfo_dst = tti - if self._ttinfo_std and self._ttinfo_dst: - break - else: - if self._ttinfo_dst and not self._ttinfo_std: - self._ttinfo_std = self._ttinfo_dst - - for tti in self._ttinfo_list: - if not tti.isdst: - self._ttinfo_before = tti - break - else: - self._ttinfo_before = self._ttinfo_list[0] - - # Now fix transition times to become relative to wall time. - # - # I'm not sure about this. In my tests, the tz source file - # is setup to wall time, and in the binary file isstd and - # isgmt are off, so it should be in wall time. OTOH, it's - # always in gmt time. Let me know if you have comments - # about this. - laststdoffset = 0 - self._trans_list = list(self._trans_list) - for i in range(len(self._trans_list)): - tti = self._trans_idx[i] - if not tti.isdst: - # This is std time. - self._trans_list[i] += tti.offset - laststdoffset = tti.offset - else: - # This is dst time. Convert to std. - self._trans_list[i] += laststdoffset - self._trans_list = tuple(self._trans_list) - - def _find_ttinfo(self, dt, laststd=0): - timestamp = ((dt.toordinal() - EPOCHORDINAL) * 86400 - + dt.hour * 3600 - + dt.minute * 60 - + dt.second) - idx = 0 - for trans in self._trans_list: - if timestamp < trans: - break - idx += 1 - else: - return self._ttinfo_std - if idx == 0: - return self._ttinfo_before - if laststd: - while idx > 0: - tti = self._trans_idx[idx-1] - if not tti.isdst: - return tti - idx -= 1 - else: - return self._ttinfo_std - else: - return self._trans_idx[idx-1] - - def utcoffset(self, dt): - if not self._ttinfo_std: - return ZERO - return self._find_ttinfo(dt).delta - - def dst(self, dt): - if not self._ttinfo_dst: - return ZERO - tti = self._find_ttinfo(dt) - if not tti.isdst: - return ZERO - - # The documentation says that utcoffset()-dst() must - # be constant for every dt. - return tti.delta-self._find_ttinfo(dt, laststd=1).delta - - # An alternative for that would be: - # - # return self._ttinfo_dst.offset-self._ttinfo_std.offset - # - # However, this class stores historical changes in the - # dst offset, so I belive that this wouldn't be the right - # way to implement this. - - @tzname_in_python2 - def tzname(self, dt): - if not self._ttinfo_std: - return None - return self._find_ttinfo(dt).abbr - - def __eq__(self, other): - if not isinstance(other, tzfile): - return False - return (self._trans_list == other._trans_list and - self._trans_idx == other._trans_idx and - self._ttinfo_list == other._ttinfo_list) - - def __ne__(self, other): - return not self.__eq__(other) - - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._filename)) - - def __reduce__(self): - if not os.path.isfile(self._filename): - raise ValueError("Unpickable %s class" % self.__class__.__name__) - return (self.__class__, (self._filename,)) - -class tzrange(datetime.tzinfo): - - def __init__(self, stdabbr, stdoffset=None, - dstabbr=None, dstoffset=None, - start=None, end=None): - global relativedelta - if not relativedelta: - from dateutil import relativedelta - self._std_abbr = stdabbr - self._dst_abbr = dstabbr - if stdoffset is not None: - self._std_offset = datetime.timedelta(seconds=stdoffset) - else: - self._std_offset = ZERO - if dstoffset is not None: - self._dst_offset = datetime.timedelta(seconds=dstoffset) - elif dstabbr and stdoffset is not None: - self._dst_offset = self._std_offset+datetime.timedelta(hours=+1) - else: - self._dst_offset = ZERO - if dstabbr and start is None: - self._start_delta = relativedelta.relativedelta( - hours=+2, month=4, day=1, weekday=relativedelta.SU(+1)) - else: - self._start_delta = start - if dstabbr and end is None: - self._end_delta = relativedelta.relativedelta( - hours=+1, month=10, day=31, weekday=relativedelta.SU(-1)) - else: - self._end_delta = end - - def utcoffset(self, dt): - if self._isdst(dt): - return self._dst_offset - else: - return self._std_offset - - def dst(self, dt): - if self._isdst(dt): - return self._dst_offset-self._std_offset - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - if self._isdst(dt): - return self._dst_abbr - else: - return self._std_abbr - - def _isdst(self, dt): - if not self._start_delta: - return False - year = datetime.datetime(dt.year, 1, 1) - start = year+self._start_delta - end = year+self._end_delta - dt = dt.replace(tzinfo=None) - if start < end: - return dt >= start and dt < end - else: - return dt >= start or dt < end - - def __eq__(self, other): - if not isinstance(other, tzrange): - return False - return (self._std_abbr == other._std_abbr and - self._dst_abbr == other._dst_abbr and - self._std_offset == other._std_offset and - self._dst_offset == other._dst_offset and - self._start_delta == other._start_delta and - self._end_delta == other._end_delta) - - def __ne__(self, other): - return not self.__eq__(other) - - def __repr__(self): - return "%s(...)" % self.__class__.__name__ - - __reduce__ = object.__reduce__ - -class tzstr(tzrange): - - def __init__(self, s): - global parser - if not parser: - from dateutil import parser - self._s = s - - res = parser._parsetz(s) - if res is None: - raise ValueError("unknown string format") - - # Here we break the compatibility with the TZ variable handling. - # GMT-3 actually *means* the timezone -3. - if res.stdabbr in ("GMT", "UTC"): - res.stdoffset *= -1 - - # We must initialize it first, since _delta() needs - # _std_offset and _dst_offset set. Use False in start/end - # to avoid building it two times. - tzrange.__init__(self, res.stdabbr, res.stdoffset, - res.dstabbr, res.dstoffset, - start=False, end=False) - - if not res.dstabbr: - self._start_delta = None - self._end_delta = None - else: - self._start_delta = self._delta(res.start) - if self._start_delta: - self._end_delta = self._delta(res.end, isend=1) - - def _delta(self, x, isend=0): - kwargs = {} - if x.month is not None: - kwargs["month"] = x.month - if x.weekday is not None: - kwargs["weekday"] = relativedelta.weekday(x.weekday, x.week) - if x.week > 0: - kwargs["day"] = 1 - else: - kwargs["day"] = 31 - elif x.day: - kwargs["day"] = x.day - elif x.yday is not None: - kwargs["yearday"] = x.yday - elif x.jyday is not None: - kwargs["nlyearday"] = x.jyday - if not kwargs: - # Default is to start on first sunday of april, and end - # on last sunday of october. - if not isend: - kwargs["month"] = 4 - kwargs["day"] = 1 - kwargs["weekday"] = relativedelta.SU(+1) - else: - kwargs["month"] = 10 - kwargs["day"] = 31 - kwargs["weekday"] = relativedelta.SU(-1) - if x.time is not None: - kwargs["seconds"] = x.time - else: - # Default is 2AM. - kwargs["seconds"] = 7200 - if isend: - # Convert to standard time, to follow the documented way - # of working with the extra hour. See the documentation - # of the tzinfo class. - delta = self._dst_offset-self._std_offset - kwargs["seconds"] -= delta.seconds+delta.days*86400 - return relativedelta.relativedelta(**kwargs) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._s)) - -class _tzicalvtzcomp(object): - def __init__(self, tzoffsetfrom, tzoffsetto, isdst, - tzname=None, rrule=None): - self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) - self.tzoffsetto = datetime.timedelta(seconds=tzoffsetto) - self.tzoffsetdiff = self.tzoffsetto-self.tzoffsetfrom - self.isdst = isdst - self.tzname = tzname - self.rrule = rrule - -class _tzicalvtz(datetime.tzinfo): - def __init__(self, tzid, comps=[]): - self._tzid = tzid - self._comps = comps - self._cachedate = [] - self._cachecomp = [] - - def _find_comp(self, dt): - if len(self._comps) == 1: - return self._comps[0] - dt = dt.replace(tzinfo=None) - try: - return self._cachecomp[self._cachedate.index(dt)] - except ValueError: - pass - lastcomp = None - lastcompdt = None - for comp in self._comps: - if not comp.isdst: - # Handle the extra hour in DST -> STD - compdt = comp.rrule.before(dt-comp.tzoffsetdiff, inc=True) - else: - compdt = comp.rrule.before(dt, inc=True) - if compdt and (not lastcompdt or lastcompdt < compdt): - lastcompdt = compdt - lastcomp = comp - if not lastcomp: - # RFC says nothing about what to do when a given - # time is before the first onset date. We'll look for the - # first standard component, or the first component, if - # none is found. - for comp in self._comps: - if not comp.isdst: - lastcomp = comp - break - else: - lastcomp = comp[0] - self._cachedate.insert(0, dt) - self._cachecomp.insert(0, lastcomp) - if len(self._cachedate) > 10: - self._cachedate.pop() - self._cachecomp.pop() - return lastcomp - - def utcoffset(self, dt): - return self._find_comp(dt).tzoffsetto - - def dst(self, dt): - comp = self._find_comp(dt) - if comp.isdst: - return comp.tzoffsetdiff - else: - return ZERO - - @tzname_in_python2 - def tzname(self, dt): - return self._find_comp(dt).tzname - - def __repr__(self): - return "" % repr(self._tzid) - - __reduce__ = object.__reduce__ - -class tzical(object): - def __init__(self, fileobj): - global rrule - if not rrule: - from dateutil import rrule - - if isinstance(fileobj, string_types): - self._s = fileobj - fileobj = open(fileobj, 'r') # ical should be encoded in UTF-8 with CRLF - elif hasattr(fileobj, "name"): - self._s = fileobj.name - else: - self._s = repr(fileobj) - - self._vtz = {} - - self._parse_rfc(fileobj.read()) - - def keys(self): - return list(self._vtz.keys()) - - def get(self, tzid=None): - if tzid is None: - keys = list(self._vtz.keys()) - if len(keys) == 0: - raise ValueError("no timezones defined") - elif len(keys) > 1: - raise ValueError("more than one timezone available") - tzid = keys[0] - return self._vtz.get(tzid) - - def _parse_offset(self, s): - s = s.strip() - if not s: - raise ValueError("empty offset") - if s[0] in ('+', '-'): - signal = (-1, +1)[s[0]=='+'] - s = s[1:] - else: - signal = +1 - if len(s) == 4: - return (int(s[:2])*3600+int(s[2:])*60)*signal - elif len(s) == 6: - return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal - else: - raise ValueError("invalid offset: "+s) - - def _parse_rfc(self, s): - lines = s.splitlines() - if not lines: - raise ValueError("empty string") - - # Unfold - i = 0 - while i < len(lines): - line = lines[i].rstrip() - if not line: - del lines[i] - elif i > 0 and line[0] == " ": - lines[i-1] += line[1:] - del lines[i] - else: - i += 1 - - tzid = None - comps = [] - invtz = False - comptype = None - for line in lines: - if not line: - continue - name, value = line.split(':', 1) - parms = name.split(';') - if not parms: - raise ValueError("empty property name") - name = parms[0].upper() - parms = parms[1:] - if invtz: - if name == "BEGIN": - if value in ("STANDARD", "DAYLIGHT"): - # Process component - pass - else: - raise ValueError("unknown component: "+value) - comptype = value - founddtstart = False - tzoffsetfrom = None - tzoffsetto = None - rrulelines = [] - tzname = None - elif name == "END": - if value == "VTIMEZONE": - if comptype: - raise ValueError("component not closed: "+comptype) - if not tzid: - raise ValueError("mandatory TZID not found") - if not comps: - raise ValueError("at least one component is needed") - # Process vtimezone - self._vtz[tzid] = _tzicalvtz(tzid, comps) - invtz = False - elif value == comptype: - if not founddtstart: - raise ValueError("mandatory DTSTART not found") - if tzoffsetfrom is None: - raise ValueError("mandatory TZOFFSETFROM not found") - if tzoffsetto is None: - raise ValueError("mandatory TZOFFSETFROM not found") - # Process component - rr = None - if rrulelines: - rr = rrule.rrulestr("\n".join(rrulelines), - compatible=True, - ignoretz=True, - cache=True) - comp = _tzicalvtzcomp(tzoffsetfrom, tzoffsetto, - (comptype == "DAYLIGHT"), - tzname, rr) - comps.append(comp) - comptype = None - else: - raise ValueError("invalid component end: "+value) - elif comptype: - if name == "DTSTART": - rrulelines.append(line) - founddtstart = True - elif name in ("RRULE", "RDATE", "EXRULE", "EXDATE"): - rrulelines.append(line) - elif name == "TZOFFSETFROM": - if parms: - raise ValueError("unsupported %s parm: %s "%(name, parms[0])) - tzoffsetfrom = self._parse_offset(value) - elif name == "TZOFFSETTO": - if parms: - raise ValueError("unsupported TZOFFSETTO parm: "+parms[0]) - tzoffsetto = self._parse_offset(value) - elif name == "TZNAME": - if parms: - raise ValueError("unsupported TZNAME parm: "+parms[0]) - tzname = value - elif name == "COMMENT": - pass - else: - raise ValueError("unsupported property: "+name) - else: - if name == "TZID": - if parms: - raise ValueError("unsupported TZID parm: "+parms[0]) - tzid = value - elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): - pass - else: - raise ValueError("unsupported property: "+name) - elif name == "BEGIN" and value == "VTIMEZONE": - tzid = None - comps = [] - invtz = True - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self._s)) - -if sys.platform != "win32": - TZFILES = ["/etc/localtime", "localtime"] - TZPATHS = ["/usr/share/zoneinfo", "/usr/lib/zoneinfo", "/etc/zoneinfo"] -else: - TZFILES = [] - TZPATHS = [] - -def gettz(name=None): - tz = None - if not name: - try: - name = os.environ["TZ"] - except KeyError: - pass - if name is None or name == ":": - for filepath in TZFILES: - if not os.path.isabs(filepath): - filename = filepath - for path in TZPATHS: - filepath = os.path.join(path, filename) - if os.path.isfile(filepath): - break - else: - continue - if os.path.isfile(filepath): - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = tzlocal() - else: - if name.startswith(":"): - name = name[:-1] - if os.path.isabs(name): - if os.path.isfile(name): - tz = tzfile(name) - else: - tz = None - else: - for path in TZPATHS: - filepath = os.path.join(path, name) - if not os.path.isfile(filepath): - filepath = filepath.replace(' ', '_') - if not os.path.isfile(filepath): - continue - try: - tz = tzfile(filepath) - break - except (IOError, OSError, ValueError): - pass - else: - tz = None - if tzwin: - try: - tz = tzwin(name) - except OSError: - pass - if not tz: - from dateutil.zoneinfo import gettz - tz = gettz(name) - if not tz: - for c in name: - # name must have at least one offset to be a tzstr - if c in "0123456789": - try: - tz = tzstr(name) - except ValueError: - pass - break - else: - if name in ("GMT", "UTC"): - tz = tzutc() - elif name in time.tzname: - tz = tzlocal() - return tz - -# vim:ts=4:sw=4:et diff --git a/lib/dateutil_py3/tzwin.py b/lib/dateutil_py3/tzwin.py deleted file mode 100644 index 041c6cc3d645..000000000000 --- a/lib/dateutil_py3/tzwin.py +++ /dev/null @@ -1,179 +0,0 @@ -# This code was originally contributed by Jeffrey Harris. -import datetime -import struct -import winreg - - -__all__ = ["tzwin", "tzwinlocal"] - -ONEWEEK = datetime.timedelta(7) - -TZKEYNAMENT = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" -TZKEYNAME9X = r"SOFTWARE\Microsoft\Windows\CurrentVersion\Time Zones" -TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" - -def _settzkeyname(): - global TZKEYNAME - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - try: - winreg.OpenKey(handle, TZKEYNAMENT).Close() - TZKEYNAME = TZKEYNAMENT - except WindowsError: - TZKEYNAME = TZKEYNAME9X - handle.Close() - -_settzkeyname() - -class tzwinbase(datetime.tzinfo): - """tzinfo class based on win32's timezones available in the registry.""" - - def utcoffset(self, dt): - if self._isdst(dt): - return datetime.timedelta(minutes=self._dstoffset) - else: - return datetime.timedelta(minutes=self._stdoffset) - - def dst(self, dt): - if self._isdst(dt): - minutes = self._dstoffset - self._stdoffset - return datetime.timedelta(minutes=minutes) - else: - return datetime.timedelta(0) - - def tzname(self, dt): - if self._isdst(dt): - return self._dstname - else: - return self._stdname - - def list(): - """Return a list of all time zones known to the system.""" - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - tzkey = winreg.OpenKey(handle, TZKEYNAME) - result = [winreg.EnumKey(tzkey, i) - for i in range(winreg.QueryInfoKey(tzkey)[0])] - tzkey.Close() - handle.Close() - return result - list = staticmethod(list) - - def display(self): - return self._display - - def _isdst(self, dt): - dston = picknthweekday(dt.year, self._dstmonth, self._dstdayofweek, - self._dsthour, self._dstminute, - self._dstweeknumber) - dstoff = picknthweekday(dt.year, self._stdmonth, self._stddayofweek, - self._stdhour, self._stdminute, - self._stdweeknumber) - if dston < dstoff: - return dston <= dt.replace(tzinfo=None) < dstoff - else: - return not dstoff <= dt.replace(tzinfo=None) < dston - - -class tzwin(tzwinbase): - - def __init__(self, name): - self._name = name - - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - tzkey = winreg.OpenKey(handle, "%s\%s" % (TZKEYNAME, name)) - keydict = valuestodict(tzkey) - tzkey.Close() - handle.Close() - - self._stdname = keydict["Std"].encode("iso-8859-1") - self._dstname = keydict["Dlt"].encode("iso-8859-1") - - self._display = keydict["Display"] - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=3l16h", keydict["TZI"]) - self._stdoffset = -tup[0]-tup[1] # Bias + StandardBias * -1 - self._dstoffset = self._stdoffset-tup[2] # + DaylightBias * -1 - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[4:9] - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[12:17] - - def __repr__(self): - return "tzwin(%s)" % repr(self._name) - - def __reduce__(self): - return (self.__class__, (self._name,)) - - -class tzwinlocal(tzwinbase): - - def __init__(self): - - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - - tzlocalkey = winreg.OpenKey(handle, TZLOCALKEYNAME) - keydict = valuestodict(tzlocalkey) - tzlocalkey.Close() - - self._stdname = keydict["StandardName"].encode("iso-8859-1") - self._dstname = keydict["DaylightName"].encode("iso-8859-1") - - try: - tzkey = winreg.OpenKey(handle, "%s\%s"%(TZKEYNAME, self._stdname)) - _keydict = valuestodict(tzkey) - self._display = _keydict["Display"] - tzkey.Close() - except OSError: - self._display = None - - handle.Close() - - self._stdoffset = -keydict["Bias"]-keydict["StandardBias"] - self._dstoffset = self._stdoffset-keydict["DaylightBias"] - - - # See http://ww_winreg.jsiinc.com/SUBA/tip0300/rh0398.htm - tup = struct.unpack("=8h", keydict["StandardStart"]) - - (self._stdmonth, - self._stddayofweek, # Sunday = 0 - self._stdweeknumber, # Last = 5 - self._stdhour, - self._stdminute) = tup[1:6] - - tup = struct.unpack("=8h", keydict["DaylightStart"]) - - (self._dstmonth, - self._dstdayofweek, # Sunday = 0 - self._dstweeknumber, # Last = 5 - self._dsthour, - self._dstminute) = tup[1:6] - - def __reduce__(self): - return (self.__class__, ()) - -def picknthweekday(year, month, dayofweek, hour, minute, whichweek): - """dayofweek == 0 means Sunday, whichweek 5 means last instance""" - first = datetime.datetime(year, month, 1, hour, minute) - weekdayone = first.replace(day=((dayofweek-first.isoweekday())%7+1)) - for n in range(whichweek): - dt = weekdayone+(whichweek-n)*ONEWEEK - if dt.month == month: - return dt - -def valuestodict(key): - """Convert a registry key's values to a dictionary.""" - dict = {} - size = winreg.QueryInfoKey(key)[1] - for i in range(size): - data = winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict diff --git a/lib/dateutil_py3/zoneinfo/__init__.py b/lib/dateutil_py3/zoneinfo/__init__.py deleted file mode 100644 index a1b34874baa3..000000000000 --- a/lib/dateutil_py3/zoneinfo/__init__.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Copyright (c) 2003-2005 Gustavo Niemeyer - -This module offers extensions to the standard Python -datetime module. -""" -from dateutil.tz import tzfile -from tarfile import TarFile -import os - -__author__ = "Tomi Pieviläinen " -__license__ = "Simplified BSD" - -__all__ = ["setcachesize", "gettz", "rebuild"] - -CACHE = [] -CACHESIZE = 10 - -class tzfile(tzfile): - def __reduce__(self): - return (gettz, (self._filename,)) - -def getzoneinfofile(): - filenames = sorted(os.listdir(os.path.join(os.path.dirname(__file__)))) - filenames.reverse() - for entry in filenames: - if entry.startswith("zoneinfo") and ".tar." in entry: - return os.path.join(os.path.dirname(__file__), entry) - return None - -ZONEINFOFILE = getzoneinfofile() - -del getzoneinfofile - -def setcachesize(size): - global CACHESIZE, CACHE - CACHESIZE = size - del CACHE[size:] - -def gettz(name): - tzinfo = None - if ZONEINFOFILE: - for cachedname, tzinfo in CACHE: - if cachedname == name: - break - else: - tf = TarFile.open(ZONEINFOFILE) - try: - zonefile = tf.extractfile(name) - except KeyError: - tzinfo = None - else: - tzinfo = tzfile(zonefile) - tf.close() - CACHE.insert(0, (name, tzinfo)) - del CACHE[CACHESIZE:] - return tzinfo - -def rebuild(filename, tag=None, format="gz"): - import tempfile, shutil - tmpdir = tempfile.mkdtemp() - zonedir = os.path.join(tmpdir, "zoneinfo") - moduledir = os.path.dirname(__file__) - if tag: tag = "-"+tag - targetname = "zoneinfo%s.tar.%s" % (tag, format) - try: - tf = TarFile.open(filename) - # The "backwards" zone file contains links to other files, so must be - # processed as last - for name in sorted(tf.getnames(), - key=lambda k: k != "backward" and k or "z"): - if not (name.endswith(".sh") or - name.endswith(".tab") or - name == "leapseconds"): - tf.extract(name, tmpdir) - filepath = os.path.join(tmpdir, name) - os.system("zic -d %s %s" % (zonedir, filepath)) - tf.close() - target = os.path.join(moduledir, targetname) - for entry in os.listdir(moduledir): - if entry.startswith("zoneinfo") and ".tar." in entry: - os.unlink(os.path.join(moduledir, entry)) - tf = TarFile.open(target, "w:%s" % format) - for entry in os.listdir(zonedir): - entrypath = os.path.join(zonedir, entry) - tf.add(entrypath, entry) - tf.close() - finally: - shutil.rmtree(tmpdir) diff --git a/lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz b/lib/dateutil_py3/zoneinfo/zoneinfo--latest.tar.gz deleted file mode 100644 index 12eadffb098afd7cc74615e72f7480c4d043c4c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 86784 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 diff --git a/lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz b/lib/dateutil_py3/zoneinfo/zoneinfo-2011d.tar.gz deleted file mode 100644 index a8c96074d8a27427eb8b0d282a1de220e8278bbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197294 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%0Ai^L~VtxoVj>m+NkU&I6qGbON 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 z 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

bawY;=>3~te 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 z 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%0AJNc;mGINL3y=Ua= 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

}F&?Qk5@`hO0r0XTz5>b+C{{N(hIYYo_< zD0rH@uvHRF*H8Y53I^;9dF#6ov6IV-hwlWHf&Ker%lm+K&xX^53!FC~VHH~g7=asD z8}VXFxJ;;E@KV+H4P7064E0X5AZT^~cVEM$(bpI`5rySeBdD+QsM9GRo4G|(LM5^k z`~_?)yO$%v+#1|e#3G%4LEr-E8OT~foQ$7>rz~>QKS+4nymv>a$5I3dA^d&@uRDdW z{|?UIhetCKlE}Y`Xs@_Slfs|9`bx Qbpk - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/lib/pytz/README.txt b/lib/pytz/README.txt deleted file mode 100644 index 3a174dda94a0..000000000000 --- a/lib/pytz/README.txt +++ /dev/null @@ -1,552 +0,0 @@ -pytz - World Timezone Definitions for Python -============================================ - -:Author: Stuart Bishop - -Introduction -~~~~~~~~~~~~ - -pytz brings the Olson tz database into Python. This library allows -accurate and cross platform timezone calculations using Python 2.4 -or higher. It also solves the issue of ambiguous times at the end -of daylight savings, which you can read more about in the Python -Library Reference (``datetime.tzinfo``). - -Amost all of the Olson timezones are supported. - -Note that this library differs from the documented Python API for -tzinfo implementations; if you want to create local wallclock -times you need to use the ``localize()`` method documented in this -document. In addition, if you perform date arithmetic on local -times that cross DST boundaries, the results may be in an incorrect -timezone (ie. subtract 1 minute from 2002-10-27 1:00 EST and you get -2002-10-27 0:59 EST instead of the correct 2002-10-27 1:59 EDT). A -``normalize()`` method is provided to correct this. Unfortunatly these -issues cannot be resolved without modifying the Python datetime -implementation. - - -Installation -~~~~~~~~~~~~ - -This package can either be installed from a .egg file using setuptools, -or from the tarball using the standard Python distutils. - -If you are installing from a tarball, run the following command as an -administrative user:: - - python setup.py install - -If you are installing using setuptools, you don't even need to download -anything as the latest version will be downloaded for you -from the Python package index:: - - easy_install --upgrade pytz - -If you already have the .egg file, you can use that too:: - - easy_install pytz-2008g-py2.6.egg - - -Example & Usage -~~~~~~~~~~~~~~~ - -Localized times and date arithmetic ------------------------------------ - ->>> from datetime import datetime, timedelta ->>> from pytz import timezone ->>> import pytz ->>> utc = pytz.utc ->>> utc.zone -'UTC' ->>> eastern = timezone('US/Eastern') ->>> eastern.zone -'US/Eastern' ->>> amsterdam = timezone('Europe/Amsterdam') ->>> fmt = '%Y-%m-%d %H:%M:%S %Z%z' - -This library only supports two ways of building a localized time. The -first is to use the ``localize()`` method provided by the pytz library. -This is used to localize a naive datetime (datetime with no timezone -information): - ->>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0)) ->>> print(loc_dt.strftime(fmt)) -2002-10-27 06:00:00 EST-0500 - -The second way of building a localized time is by converting an existing -localized time using the standard ``astimezone()`` method: - ->>> ams_dt = loc_dt.astimezone(amsterdam) ->>> ams_dt.strftime(fmt) -'2002-10-27 12:00:00 CET+0100' - -Unfortunately using the tzinfo argument of the standard datetime -constructors ''does not work'' with pytz for many timezones. - ->>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt) -'2002-10-27 12:00:00 AMT+0020' - -It is safe for timezones without daylight savings trasitions though, such -as UTC: - ->>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=pytz.utc).strftime(fmt) -'2002-10-27 12:00:00 UTC+0000' - -The preferred way of dealing with times is to always work in UTC, -converting to localtime only when generating output to be read -by humans. - ->>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) ->>> loc_dt = utc_dt.astimezone(eastern) ->>> loc_dt.strftime(fmt) -'2002-10-27 01:00:00 EST-0500' - -This library also allows you to do date arithmetic using local -times, although it is more complicated than working in UTC as you -need to use the ``normalize()`` method to handle daylight savings time -and other timezone transitions. In this example, ``loc_dt`` is set -to the instant when daylight savings time ends in the US/Eastern -timezone. - ->>> before = loc_dt - timedelta(minutes=10) ->>> before.strftime(fmt) -'2002-10-27 00:50:00 EST-0500' ->>> eastern.normalize(before).strftime(fmt) -'2002-10-27 01:50:00 EDT-0400' ->>> after = eastern.normalize(before + timedelta(minutes=20)) ->>> after.strftime(fmt) -'2002-10-27 01:10:00 EST-0500' - -Creating localtimes is also tricky, and the reason why working with -local times is not recommended. Unfortunately, you cannot just pass -a ``tzinfo`` argument when constructing a datetime (see the next -section for more details) - ->>> dt = datetime(2002, 10, 27, 1, 30, 0) ->>> dt1 = eastern.localize(dt, is_dst=True) ->>> dt1.strftime(fmt) -'2002-10-27 01:30:00 EDT-0400' ->>> dt2 = eastern.localize(dt, is_dst=False) ->>> dt2.strftime(fmt) -'2002-10-27 01:30:00 EST-0500' - -Converting between timezones also needs special attention. This also -needs to use the ``normalize()`` method to ensure the conversion is -correct. - ->>> utc_dt = utc.localize(datetime.utcfromtimestamp(1143408899)) ->>> utc_dt.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' ->>> au_tz = timezone('Australia/Sydney') ->>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz)) ->>> au_dt.strftime(fmt) -'2006-03-27 08:34:59 EST+1100' ->>> utc_dt2 = utc.normalize(au_dt.astimezone(utc)) ->>> utc_dt2.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' - -You can take shortcuts when dealing with the UTC side of timezone -conversions. ``normalize()`` and ``localize()`` are not really -necessary when there are no daylight savings time transitions to -deal with. - ->>> utc_dt = datetime.utcfromtimestamp(1143408899).replace(tzinfo=utc) ->>> utc_dt.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' ->>> au_tz = timezone('Australia/Sydney') ->>> au_dt = au_tz.normalize(utc_dt.astimezone(au_tz)) ->>> au_dt.strftime(fmt) -'2006-03-27 08:34:59 EST+1100' ->>> utc_dt2 = au_dt.astimezone(utc) ->>> utc_dt2.strftime(fmt) -'2006-03-26 21:34:59 UTC+0000' - - -``tzinfo`` API --------------- - -The ``tzinfo`` instances returned by the ``timezone()`` function have -been extended to cope with ambiguous times by adding an ``is_dst`` -parameter to the ``utcoffset()``, ``dst()`` && ``tzname()`` methods. - ->>> tz = timezone('America/St_Johns') - ->>> normal = datetime(2009, 9, 1) ->>> ambiguous = datetime(2009, 10, 31, 23, 30) - -The ``is_dst`` parameter is ignored for most timestamps. It is only used -during DST transition ambiguous periods to resulve that ambiguity. - ->>> tz.utcoffset(normal, is_dst=True) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal, is_dst=True) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal, is_dst=True) -'NDT' - ->>> tz.utcoffset(ambiguous, is_dst=True) -datetime.timedelta(-1, 77400) ->>> tz.dst(ambiguous, is_dst=True) -datetime.timedelta(0, 3600) ->>> tz.tzname(ambiguous, is_dst=True) -'NDT' - ->>> tz.utcoffset(normal, is_dst=False) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal, is_dst=False) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal, is_dst=False) -'NDT' - ->>> tz.utcoffset(ambiguous, is_dst=False) -datetime.timedelta(-1, 73800) ->>> tz.dst(ambiguous, is_dst=False) -datetime.timedelta(0) ->>> tz.tzname(ambiguous, is_dst=False) -'NST' - -If ``is_dst`` is not specified, ambiguous timestamps will raise -an ``pytz.exceptions.AmbiguousTimeError`` exception. - ->>> tz.utcoffset(normal) -datetime.timedelta(-1, 77400) ->>> tz.dst(normal) -datetime.timedelta(0, 3600) ->>> tz.tzname(normal) -'NDT' - ->>> import pytz.exceptions ->>> try: -... tz.utcoffset(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 ->>> try: -... tz.dst(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 ->>> try: -... tz.tzname(ambiguous) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % ambiguous) -pytz.exceptions.AmbiguousTimeError: 2009-10-31 23:30:00 - - -Problems with Localtime -~~~~~~~~~~~~~~~~~~~~~~~ - -The major problem we have to deal with is that certain datetimes -may occur twice in a year. For example, in the US/Eastern timezone -on the last Sunday morning in October, the following sequence -happens: - - - 01:00 EDT occurs - - 1 hour later, instead of 2:00am the clock is turned back 1 hour - and 01:00 happens again (this time 01:00 EST) - -In fact, every instant between 01:00 and 02:00 occurs twice. This means -that if you try and create a time in the 'US/Eastern' timezone using -the standard datetime syntax, there is no way to specify if you meant -before of after the end-of-daylight-savings-time transition. - ->>> loc_dt = datetime(2002, 10, 27, 1, 30, 00, tzinfo=eastern) ->>> loc_dt.strftime(fmt) -'2002-10-27 01:30:00 EST-0500' - -As you can see, the system has chosen one for you and there is a 50% -chance of it being out by one hour. For some applications, this does -not matter. However, if you are trying to schedule meetings with people -in different timezones or analyze log files it is not acceptable. - -The best and simplest solution is to stick with using UTC. The pytz -package encourages using UTC for internal timezone representation by -including a special UTC implementation based on the standard Python -reference implementation in the Python documentation. - -The UTC timezone unpickles to be the same instance, and pickles to a -smaller size than other pytz tzinfo instances. The UTC implementation -can be obtained as pytz.utc, pytz.UTC, or pytz.timezone('UTC'). - ->>> import pickle, pytz ->>> dt = datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) ->>> naive = dt.replace(tzinfo=None) ->>> p = pickle.dumps(dt, 1) ->>> naive_p = pickle.dumps(naive, 1) ->>> len(p) - len(naive_p) -17 ->>> new = pickle.loads(p) ->>> new == dt -True ->>> new is dt -False ->>> new.tzinfo is dt.tzinfo -True ->>> pytz.utc is pytz.UTC is pytz.timezone('UTC') -True - -Note that this instance is not the same instance (or implementation) as -other timezones with the same meaning (GMT, Greenwich, Universal, etc.). - ->>> utc is pytz.timezone('GMT') -False - -If you insist on working with local times, this library provides a -facility for constructing them unambiguously: - ->>> loc_dt = datetime(2002, 10, 27, 1, 30, 00) ->>> est_dt = eastern.localize(loc_dt, is_dst=True) ->>> edt_dt = eastern.localize(loc_dt, is_dst=False) ->>> print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt)) -2002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500 - -If you pass None as the is_dst flag to localize(), pytz will refuse to -guess and raise exceptions if you try to build ambiguous or non-existent -times. - -For example, 1:30am on 27th Oct 2002 happened twice in the US/Eastern -timezone when the clocks where put back at the end of Daylight Savings -Time: - ->>> dt = datetime(2002, 10, 27, 1, 30, 00) ->>> try: -... eastern.localize(dt, is_dst=None) -... except pytz.exceptions.AmbiguousTimeError: -... print('pytz.exceptions.AmbiguousTimeError: %s' % dt) -pytz.exceptions.AmbiguousTimeError: 2002-10-27 01:30:00 - -Similarly, 2:30am on 7th April 2002 never happened at all in the -US/Eastern timezone, as the clocks where put forward at 2:00am skipping -the entire hour: - ->>> dt = datetime(2002, 4, 7, 2, 30, 00) ->>> try: -... eastern.localize(dt, is_dst=None) -... except pytz.exceptions.NonExistentTimeError: -... print('pytz.exceptions.NonExistentTimeError: %s' % dt) -pytz.exceptions.NonExistentTimeError: 2002-04-07 02:30:00 - -Both of these exceptions share a common base class to make error handling -easier: - ->>> isinstance(pytz.AmbiguousTimeError(), pytz.InvalidTimeError) -True ->>> isinstance(pytz.NonExistentTimeError(), pytz.InvalidTimeError) -True - -Although ``localize()`` handles many cases, it is still not possible -to handle all. In cases where countries change their timezone definitions, -cases like the end-of-daylight-savings-time occur with no way of resolving -the ambiguity. For example, in 1915 Warsaw switched from Warsaw time to -Central European time. So at the stroke of midnight on August 5th 1915 -the clocks were wound back 24 minutes creating an ambiguous time period -that cannot be specified without referring to the timezone abbreviation -or the actual UTC offset. In this case midnight happened twice, neither -time during a daylight savings time period: - ->>> warsaw = pytz.timezone('Europe/Warsaw') ->>> loc_dt1 = warsaw.localize(datetime(1915, 8, 4, 23, 59, 59), is_dst=False) ->>> loc_dt1.strftime(fmt) -'1915-08-04 23:59:59 WMT+0124' ->>> loc_dt2 = warsaw.localize(datetime(1915, 8, 5, 00, 00, 00), is_dst=False) ->>> loc_dt2.strftime(fmt) -'1915-08-05 00:00:00 CET+0100' ->>> str(loc_dt2 - loc_dt1) -'0:24:01' - -The only way of creating a time during the missing 24 minutes is -converting from another timezone - because neither of the timezones -involved where in daylight savings mode the API simply provides no way -to express it: - ->>> utc_dt = datetime(1915, 8, 4, 22, 36, tzinfo=pytz.utc) ->>> utc_dt.astimezone(warsaw).strftime(fmt) -'1915-08-04 23:36:00 CET+0100' - -The standard Python way of handling all these ambiguities is not to -handle them, such as demonstrated in this example using the US/Eastern -timezone definition from the Python documentation (Note that this -implementation only works for dates between 1987 and 2006 - it is -included for tests only!): - ->>> from pytz.reference import Eastern # pytz.reference only for tests ->>> dt = datetime(2002, 10, 27, 0, 30, tzinfo=Eastern) ->>> str(dt) -'2002-10-27 00:30:00-04:00' ->>> str(dt + timedelta(hours=1)) -'2002-10-27 01:30:00-05:00' ->>> str(dt + timedelta(hours=2)) -'2002-10-27 02:30:00-05:00' ->>> str(dt + timedelta(hours=3)) -'2002-10-27 03:30:00-05:00' - -Notice the first two results? At first glance you might think they are -correct, but taking the UTC offset into account you find that they are -actually two hours appart instead of the 1 hour we asked for. - ->>> from pytz.reference import UTC # pytz.reference only for tests ->>> str(dt.astimezone(UTC)) -'2002-10-27 04:30:00+00:00' ->>> str((dt + timedelta(hours=1)).astimezone(UTC)) -'2002-10-27 06:30:00+00:00' - - -Country Information -~~~~~~~~~~~~~~~~~~~ - -A mechanism is provided to access the timezones commonly in use -for a particular country, looked up using the ISO 3166 country code. -It returns a list of strings that can be used to retrieve the relevant -tzinfo instance using ``pytz.timezone()``: - ->>> print(' '.join(pytz.country_timezones['nz'])) -Pacific/Auckland Pacific/Chatham - -The Olson database comes with a ISO 3166 country code to English country -name mapping that pytz exposes as a dictionary: - ->>> print(pytz.country_names['nz']) -New Zealand - - -What is UTC -~~~~~~~~~~~ - -'UTC' is Universal Time, also known as Greenwich Mean Time or GMT -in the United Kingdom. All other timezones are given as offsets from -UTC. No daylight savings time occurs in UTC, making it a useful timezone -to perform date arithmetic without worrying about the confusion and -ambiguities caused by daylight savings time transitions, your country -changing its timezone, or mobile computers that move roam through -multiple timezones. - - -Helpers -~~~~~~~ - -There are two lists of timezones provided. - -``all_timezones`` is the exhaustive list of the timezone names that can -be used. - ->>> from pytz import all_timezones ->>> len(all_timezones) >= 500 -True ->>> 'Etc/Greenwich' in all_timezones -True - -``common_timezones`` is a list of useful, current timezones. It doesn't -contain deprecated zones or historical zones, except for a few I've -deemed in common usage, such as US/Eastern (open a bug report if you -think other timezones are deserving of being included here). It is also -a sequence of strings. - ->>> from pytz import common_timezones ->>> len(common_timezones) < len(all_timezones) -True ->>> 'Etc/Greenwich' in common_timezones -False ->>> 'Australia/Melbourne' in common_timezones -True ->>> 'US/Eastern' in common_timezones -True ->>> 'Canada/Eastern' in common_timezones -True ->>> 'US/Pacific-New' in all_timezones -True ->>> 'US/Pacific-New' in common_timezones -False - -Both ``common_timezones`` and ``all_timezones`` are alphabetically -sorted: - ->>> common_timezones_dupe = common_timezones[:] ->>> common_timezones_dupe.sort() ->>> common_timezones == common_timezones_dupe -True ->>> all_timezones_dupe = all_timezones[:] ->>> all_timezones_dupe.sort() ->>> all_timezones == all_timezones_dupe -True - -``all_timezones`` and ``common_timezones`` are also available as sets. - ->>> from pytz import all_timezones_set, common_timezones_set ->>> 'US/Eastern' in all_timezones_set -True ->>> 'US/Eastern' in common_timezones_set -True ->>> 'Australia/Victoria' in common_timezones_set -False - -You can also retrieve lists of timezones used by particular countries -using the ``country_timezones()`` function. It requires an ISO-3166 -two letter country code. - ->>> from pytz import country_timezones ->>> print(' '.join(country_timezones('ch'))) -Europe/Zurich ->>> print(' '.join(country_timezones('CH'))) -Europe/Zurich - - -License -~~~~~~~ - -MIT license. - -This code is also available as part of Zope 3 under the Zope Public -License, Version 2.1 (ZPL). - -I'm happy to relicense this code if necessary for inclusion in other -open source projects. - - -Latest Versions -~~~~~~~~~~~~~~~ - -This package will be updated after releases of the Olson timezone -database. The latest version can be downloaded from the `Python Package -Index `_. The code that is used -to generate this distribution is hosted on launchpad.net and available -using the `Bazaar version control system `_ -using:: - - bzr branch lp:pytz - - -Bugs, Feature Requests & Patches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Bugs can be reported using `Launchpad `_. - - -Issues & Limitations -~~~~~~~~~~~~~~~~~~~~ - -- Offsets from UTC are rounded to the nearest whole minute, so timezones - such as Europe/Amsterdam pre 1937 will be up to 30 seconds out. This - is a limitation of the Python datetime library. - -- If you think a timezone definition is incorrect, I probably can't fix - it. pytz is a direct translation of the Olson timezone database, and - changes to the timezone definitions need to be made to this source. - If you find errors they should be reported to the time zone mailing - list, linked from http://www.twinsun.com/tz/tz-link.htm - - -Further Reading -~~~~~~~~~~~~~~~ - -More info than you want to know about timezones: -http://www.twinsun.com/tz/tz-link.htm - - -Contact -~~~~~~~ - -Stuart Bishop - - diff --git a/lib/pytz/__init__.py b/lib/pytz/__init__.py deleted file mode 100644 index 17149b45111a..000000000000 --- a/lib/pytz/__init__.py +++ /dev/null @@ -1,1537 +0,0 @@ -''' -datetime.tzinfo timezone definitions generated from the -Olson timezone database: - - ftp://elsie.nci.nih.gov/pub/tz*.tar.gz - -See the datetime section of the Python Library Reference for information -on how to use these modules. -''' - -# The Olson database is updated several times a year. -OLSON_VERSION = '2012d' -VERSION = OLSON_VERSION -# Version format for a patch release - only one so far. -#VERSION = OLSON_VERSION + '.2' -__version__ = OLSON_VERSION + "-mpl" - -OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling - -__all__ = [ - 'timezone', 'utc', 'country_timezones', 'country_names', - 'AmbiguousTimeError', 'InvalidTimeError', - 'NonExistentTimeError', 'UnknownTimeZoneError', - 'all_timezones', 'all_timezones_set', - 'common_timezones', 'common_timezones_set', - ] - -import sys, datetime, os.path, gettext -try: - from UserDict import DictMixin -except ImportError: - from collections import Mapping as DictMixin - -try: - from pkg_resources import resource_stream -except ImportError: - resource_stream = None - -from pytz.exceptions import AmbiguousTimeError -from pytz.exceptions import InvalidTimeError -from pytz.exceptions import NonExistentTimeError -from pytz.exceptions import UnknownTimeZoneError -from pytz.tzinfo import unpickler -from pytz.tzfile import build_tzinfo, _byte_string - - -try: - unicode - -except NameError: # Python 3.x - - # Python 3.x doesn't have unicode(), making writing code - # for Python 2.3 and Python 3.x a pain. - unicode = str - - def ascii(s): - r""" - >>> ascii('Hello') - 'Hello' - >>> ascii('\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - UnicodeEncodeError: ... - """ - s.encode('US-ASCII') # Raise an exception if not ASCII - return s # But return the original string - not a byte string. - -else: # Python 2.x - - def ascii(s): - r""" - >>> ascii('Hello') - 'Hello' - >>> ascii(u'Hello') - 'Hello' - >>> ascii(u'\N{TRADE MARK SIGN}') #doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - UnicodeEncodeError: ... - """ - return s.encode('US-ASCII') - - -def open_resource(name): - """Open a resource from the zoneinfo subdir for reading. - - Uses the pkg_resources module if available and no standard file - found at the calculated location. - """ - name_parts = name.lstrip('/').split('/') - for part in name_parts: - if part == os.path.pardir or os.path.sep in part: - raise ValueError('Bad path segment: %r' % part) - filename = os.path.join(os.path.dirname(__file__), - 'zoneinfo', *name_parts) - if not os.path.exists(filename) and resource_stream is not None: - # http://bugs.launchpad.net/bugs/383171 - we avoid using this - # unless absolutely necessary to help when a broken version of - # pkg_resources is installed. - return resource_stream(__name__, 'zoneinfo/' + name) - return open(filename, 'rb') - - -def resource_exists(name): - """Return true if the given resource exists""" - try: - open_resource(name).close() - return True - except IOError: - return False - - -# Enable this when we get some translations? -# We want an i18n API that is useful to programs using Python's gettext -# module, as well as the Zope3 i18n package. Perhaps we should just provide -# the POT file and translations, and leave it up to callers to make use -# of them. -# -# t = gettext.translation( -# 'pytz', os.path.join(os.path.dirname(__file__), 'locales'), -# fallback=True -# ) -# def _(timezone_name): -# """Translate a timezone name using the current locale, returning Unicode""" -# return t.ugettext(timezone_name) - - -_tzinfo_cache = {} - -def timezone(zone): - r''' Return a datetime.tzinfo implementation for the given timezone - - >>> from datetime import datetime, timedelta - >>> utc = timezone('UTC') - >>> eastern = timezone('US/Eastern') - >>> eastern.zone - 'US/Eastern' - >>> timezone(unicode('US/Eastern')) is eastern - True - >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) - >>> loc_dt = utc_dt.astimezone(eastern) - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> loc_dt.strftime(fmt) - '2002-10-27 01:00:00 EST (-0500)' - >>> (loc_dt - timedelta(minutes=10)).strftime(fmt) - '2002-10-27 00:50:00 EST (-0500)' - >>> eastern.normalize(loc_dt - timedelta(minutes=10)).strftime(fmt) - '2002-10-27 01:50:00 EDT (-0400)' - >>> (loc_dt + timedelta(minutes=10)).strftime(fmt) - '2002-10-27 01:10:00 EST (-0500)' - - Raises UnknownTimeZoneError if passed an unknown zone. - - >>> try: - ... timezone('Asia/Shangri-La') - ... except UnknownTimeZoneError: - ... print('Unknown') - Unknown - - >>> try: - ... timezone(unicode('\N{TRADE MARK SIGN}')) - ... except UnknownTimeZoneError: - ... print('Unknown') - Unknown - - ''' - if zone.upper() == 'UTC': - return utc - - try: - zone = ascii(zone) - except UnicodeEncodeError: - # All valid timezones are ASCII - raise UnknownTimeZoneError(zone) - - zone = _unmunge_zone(zone) - if zone not in _tzinfo_cache: - if zone in all_timezones_set: - fp = open_resource(zone) - try: - _tzinfo_cache[zone] = build_tzinfo(zone, fp) - finally: - fp.close() - else: - raise UnknownTimeZoneError(zone) - - return _tzinfo_cache[zone] - - -def _unmunge_zone(zone): - """Undo the time zone name munging done by older versions of pytz.""" - return zone.replace('_plus_', '+').replace('_minus_', '-') - - -ZERO = datetime.timedelta(0) -HOUR = datetime.timedelta(hours=1) - - -class UTC(datetime.tzinfo): - """UTC - - Optimized UTC implementation. It unpickles using the single module global - instance defined beneath this class declaration. - """ - zone = "UTC" - - _utcoffset = ZERO - _dst = ZERO - _tzname = zone - - def fromutc(self, dt): - if dt.tzinfo is None: - return self.localize(dt) - return super(utc.__class__, self).fromutc(dt) - - def utcoffset(self, dt): - return ZERO - - def tzname(self, dt): - return "UTC" - - def dst(self, dt): - return ZERO - - def __reduce__(self): - return _UTC, () - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError('Not naive datetime (tzinfo is already set)') - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' - if dt.tzinfo is self: - return dt - if dt.tzinfo is None: - raise ValueError('Naive time - no tzinfo set') - return dt.astimezone(self) - - def __repr__(self): - return "" - - def __str__(self): - return "UTC" - - -UTC = utc = UTC() # UTC is a singleton - - -def _UTC(): - """Factory function for utc unpickling. - - Makes sure that unpickling a utc instance always returns the same - module global. - - These examples belong in the UTC class above, but it is obscured; or in - the README.txt, but we are not depending on Python 2.4 so integrating - the README.txt examples with the unit tests is not trivial. - - >>> import datetime, pickle - >>> dt = datetime.datetime(2005, 3, 1, 14, 13, 21, tzinfo=utc) - >>> naive = dt.replace(tzinfo=None) - >>> p = pickle.dumps(dt, 1) - >>> naive_p = pickle.dumps(naive, 1) - >>> len(p) - len(naive_p) - 17 - >>> new = pickle.loads(p) - >>> new == dt - True - >>> new is dt - False - >>> new.tzinfo is dt.tzinfo - True - >>> utc is UTC is timezone('UTC') - True - >>> utc is timezone('GMT') - False - """ - return utc -_UTC.__safe_for_unpickling__ = True - - -def _p(*args): - """Factory function for unpickling pytz tzinfo instances. - - Just a wrapper around tzinfo.unpickler to save a few bytes in each pickle - by shortening the path. - """ - return unpickler(*args) -_p.__safe_for_unpickling__ = True - - -class _LazyDict(DictMixin): - """Dictionary populated on first use.""" - data = None - def __getitem__(self, key): - if self.data is None: - self._fill() - return self.data[key.upper()] - - def __contains__(self, key): - if self.data is None: - self._fill() - return key in self.data - - def __iter__(self): - if self.data is None: - self._fill() - return iter(self.data) - - def __len__(self): - if self.data is None: - self._fill() - return len(self.data) - - def keys(self): - if self.data is None: - self._fill() - return self.data.keys() - - -class _CountryTimezoneDict(_LazyDict): - """Map ISO 3166 country code to a list of timezone names commonly used - in that country. - - iso3166_code is the two letter code used to identify the country. - - >>> def print_list(list_of_strings): - ... 'We use a helper so doctests work under Python 2.3 -> 3.x' - ... for s in list_of_strings: - ... print(s) - - >>> print_list(country_timezones['nz']) - Pacific/Auckland - Pacific/Chatham - >>> print_list(country_timezones['ch']) - Europe/Zurich - >>> print_list(country_timezones['CH']) - Europe/Zurich - >>> print_list(country_timezones[unicode('ch')]) - Europe/Zurich - >>> print_list(country_timezones['XXX']) - Traceback (most recent call last): - ... - KeyError: 'XXX' - - Previously, this information was exposed as a function rather than a - dictionary. This is still supported:: - - >>> print_list(country_timezones('nz')) - Pacific/Auckland - Pacific/Chatham - """ - def __call__(self, iso3166_code): - """Backwards compatibility.""" - return self[iso3166_code] - - def _fill(self): - data = {} - zone_tab = open_resource('zone.tab') - try: - for line in zone_tab: - line = line.decode('US-ASCII') - if line.startswith('#'): - continue - code, coordinates, zone = line.split(None, 4)[:3] - if zone not in all_timezones_set: - continue - try: - data[code].append(zone) - except KeyError: - data[code] = [zone] - self.data = data - finally: - zone_tab.close() - -country_timezones = _CountryTimezoneDict() - - -class _CountryNameDict(_LazyDict): - '''Dictionary proving ISO3166 code -> English name. - - >>> print(country_names['au']) - Australia - ''' - def _fill(self): - data = {} - zone_tab = open_resource('iso3166.tab') - try: - for line in zone_tab.readlines(): - line = line.decode('US-ASCII') - if line.startswith('#'): - continue - code, name = line.split(None, 1) - data[code] = name.strip() - self.data = data - finally: - zone_tab.close() - -country_names = _CountryNameDict() - - -# Time-zone info based solely on fixed offsets - -class _FixedOffset(datetime.tzinfo): - - zone = None # to match the standard pytz API - - def __init__(self, minutes): - if abs(minutes) >= 1440: - raise ValueError("absolute offset is too large", minutes) - self._minutes = minutes - self._offset = datetime.timedelta(minutes=minutes) - - def utcoffset(self, dt): - return self._offset - - def __reduce__(self): - return FixedOffset, (self._minutes, ) - - def dst(self, dt): - return ZERO - - def tzname(self, dt): - return None - - def __repr__(self): - return 'pytz.FixedOffset(%d)' % self._minutes - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError('Not naive datetime (tzinfo is already set)') - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime''' - if dt.tzinfo is None: - raise ValueError('Naive time - no tzinfo set') - return dt.replace(tzinfo=self) - - -def FixedOffset(offset, _tzinfos = {}): - """return a fixed-offset timezone based off a number of minutes. - - >>> one = FixedOffset(-330) - >>> one - pytz.FixedOffset(-330) - >>> one.utcoffset(datetime.datetime.now()) - datetime.timedelta(-1, 66600) - >>> one.dst(datetime.datetime.now()) - datetime.timedelta(0) - - >>> two = FixedOffset(1380) - >>> two - pytz.FixedOffset(1380) - >>> two.utcoffset(datetime.datetime.now()) - datetime.timedelta(0, 82800) - >>> two.dst(datetime.datetime.now()) - datetime.timedelta(0) - - The datetime.timedelta must be between the range of -1 and 1 day, - non-inclusive. - - >>> FixedOffset(1440) - Traceback (most recent call last): - ... - ValueError: ('absolute offset is too large', 1440) - - >>> FixedOffset(-1440) - Traceback (most recent call last): - ... - ValueError: ('absolute offset is too large', -1440) - - An offset of 0 is special-cased to return UTC. - - >>> FixedOffset(0) is UTC - True - - There should always be only one instance of a FixedOffset per timedelta. - This should be true for multiple creation calls. - - >>> FixedOffset(-330) is one - True - >>> FixedOffset(1380) is two - True - - It should also be true for pickling. - - >>> import pickle - >>> pickle.loads(pickle.dumps(one)) is one - True - >>> pickle.loads(pickle.dumps(two)) is two - True - """ - if offset == 0: - return UTC - - info = _tzinfos.get(offset) - if info is None: - # We haven't seen this one before. we need to save it. - - # Use setdefault to avoid a race condition and make sure we have - # only one - info = _tzinfos.setdefault(offset, _FixedOffset(offset)) - - return info - -FixedOffset.__safe_for_unpickling__ = True - - -def _test(): - import doctest, os, sys - sys.path.insert(0, os.pardir) - import pytz - return doctest.testmod(pytz) - -if __name__ == '__main__': - _test() - -all_timezones = \ -['Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Asmera', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Juba', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Timbuktu', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Argentina/Buenos_Aires', - 'America/Argentina/Catamarca', - 'America/Argentina/ComodRivadavia', - 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja', - 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos', - 'America/Argentina/Salta', - 'America/Argentina/San_Juan', - 'America/Argentina/San_Luis', - 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Atka', - 'America/Bahia', - 'America/Bahia_Banderas', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Buenos_Aires', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Catamarca', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Coral_Harbour', - 'America/Cordoba', - 'America/Costa_Rica', - 'America/Creston', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Ensenada', - 'America/Fort_Wayne', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indiana/Indianapolis', - 'America/Indiana/Knox', - 'America/Indiana/Marengo', - 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City', - 'America/Indiana/Vevay', - 'America/Indiana/Vincennes', - 'America/Indiana/Winamac', - 'America/Indianapolis', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Jujuy', - 'America/Juneau', - 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello', - 'America/Knox_IN', - 'America/Kralendijk', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Louisville', - 'America/Lower_Princes', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Matamoros', - 'America/Mazatlan', - 'America/Mendoza', - 'America/Menominee', - 'America/Merida', - 'America/Metlakatla', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/North_Dakota/Beulah', - 'America/North_Dakota/Center', - 'America/North_Dakota/New_Salem', - 'America/Ojinaga', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Acre', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Rosario', - 'America/Santa_Isabel', - 'America/Santarem', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/Sitka', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Virgin', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Ashkhabad', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Calcutta', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Chungking', - 'Asia/Colombo', - 'Asia/Dacca', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hebron', - 'Asia/Ho_Chi_Minh', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Istanbul', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Kathmandu', - 'Asia/Katmandu', - 'Asia/Kolkata', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macao', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novokuznetsk', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Saigon', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Tel_Aviv', - 'Asia/Thimbu', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Ujung_Pandang', - 'Asia/Ulaanbaatar', - 'Asia/Ulan_Bator', - 'Asia/Urumqi', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faeroe', - 'Atlantic/Faroe', - 'Atlantic/Jan_Mayen', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/ACT', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Canberra', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/LHI', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/NSW', - 'Australia/North', - 'Australia/Perth', - 'Australia/Queensland', - 'Australia/South', - 'Australia/Sydney', - 'Australia/Tasmania', - 'Australia/Victoria', - 'Australia/West', - 'Australia/Yancowinna', - 'Brazil/Acre', - 'Brazil/DeNoronha', - 'Brazil/East', - 'Brazil/West', - 'CET', - 'CST6CDT', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/East-Saskatchewan', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Canada/Saskatchewan', - 'Canada/Yukon', - 'Chile/Continental', - 'Chile/EasterIsland', - 'Cuba', - 'EET', - 'EST', - 'EST5EDT', - 'Egypt', - 'Eire', - 'Etc/GMT', - 'Etc/GMT+0', - 'Etc/GMT+1', - 'Etc/GMT+10', - 'Etc/GMT+11', - 'Etc/GMT+12', - 'Etc/GMT+2', - 'Etc/GMT+3', - 'Etc/GMT+4', - 'Etc/GMT+5', - 'Etc/GMT+6', - 'Etc/GMT+7', - 'Etc/GMT+8', - 'Etc/GMT+9', - 'Etc/GMT-0', - 'Etc/GMT-1', - 'Etc/GMT-10', - 'Etc/GMT-11', - 'Etc/GMT-12', - 'Etc/GMT-13', - 'Etc/GMT-14', - 'Etc/GMT-2', - 'Etc/GMT-3', - 'Etc/GMT-4', - 'Etc/GMT-5', - 'Etc/GMT-6', - 'Etc/GMT-7', - 'Etc/GMT-8', - 'Etc/GMT-9', - 'Etc/GMT0', - 'Etc/Greenwich', - 'Etc/UCT', - 'Etc/UTC', - 'Etc/Universal', - 'Etc/Zulu', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Athens', - 'Europe/Belfast', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Nicosia', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Tiraspol', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GB', - 'GB-Eire', - 'GMT', - 'GMT+0', - 'GMT-0', - 'GMT0', - 'Greenwich', - 'HST', - 'Hongkong', - 'Iceland', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Iran', - 'Israel', - 'Jamaica', - 'Japan', - 'Kwajalein', - 'Libya', - 'MET', - 'MST', - 'MST7MDT', - 'Mexico/BajaNorte', - 'Mexico/BajaSur', - 'Mexico/General', - 'NZ', - 'NZ-CHAT', - 'Navajo', - 'PRC', - 'PST8PDT', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Chatham', - 'Pacific/Chuuk', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Pohnpei', - 'Pacific/Ponape', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Samoa', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Truk', - 'Pacific/Wake', - 'Pacific/Wallis', - 'Pacific/Yap', - 'Poland', - 'Portugal', - 'ROC', - 'ROK', - 'Singapore', - 'Turkey', - 'UCT', - 'US/Alaska', - 'US/Aleutian', - 'US/Arizona', - 'US/Central', - 'US/East-Indiana', - 'US/Eastern', - 'US/Hawaii', - 'US/Indiana-Starke', - 'US/Michigan', - 'US/Mountain', - 'US/Pacific', - 'US/Pacific-New', - 'US/Samoa', - 'UTC', - 'Universal', - 'W-SU', - 'WET', - 'Zulu'] -all_timezones = [ - tz for tz in all_timezones if resource_exists(tz)] - -all_timezones_set = set(all_timezones) -common_timezones = \ -['Africa/Abidjan', - 'Africa/Accra', - 'Africa/Addis_Ababa', - 'Africa/Algiers', - 'Africa/Asmara', - 'Africa/Bamako', - 'Africa/Bangui', - 'Africa/Banjul', - 'Africa/Bissau', - 'Africa/Blantyre', - 'Africa/Brazzaville', - 'Africa/Bujumbura', - 'Africa/Cairo', - 'Africa/Casablanca', - 'Africa/Ceuta', - 'Africa/Conakry', - 'Africa/Dakar', - 'Africa/Dar_es_Salaam', - 'Africa/Djibouti', - 'Africa/Douala', - 'Africa/El_Aaiun', - 'Africa/Freetown', - 'Africa/Gaborone', - 'Africa/Harare', - 'Africa/Johannesburg', - 'Africa/Juba', - 'Africa/Kampala', - 'Africa/Khartoum', - 'Africa/Kigali', - 'Africa/Kinshasa', - 'Africa/Lagos', - 'Africa/Libreville', - 'Africa/Lome', - 'Africa/Luanda', - 'Africa/Lubumbashi', - 'Africa/Lusaka', - 'Africa/Malabo', - 'Africa/Maputo', - 'Africa/Maseru', - 'Africa/Mbabane', - 'Africa/Mogadishu', - 'Africa/Monrovia', - 'Africa/Nairobi', - 'Africa/Ndjamena', - 'Africa/Niamey', - 'Africa/Nouakchott', - 'Africa/Ouagadougou', - 'Africa/Porto-Novo', - 'Africa/Sao_Tome', - 'Africa/Tripoli', - 'Africa/Tunis', - 'Africa/Windhoek', - 'America/Adak', - 'America/Anchorage', - 'America/Anguilla', - 'America/Antigua', - 'America/Araguaina', - 'America/Argentina/Buenos_Aires', - 'America/Argentina/Catamarca', - 'America/Argentina/Cordoba', - 'America/Argentina/Jujuy', - 'America/Argentina/La_Rioja', - 'America/Argentina/Mendoza', - 'America/Argentina/Rio_Gallegos', - 'America/Argentina/Salta', - 'America/Argentina/San_Juan', - 'America/Argentina/San_Luis', - 'America/Argentina/Tucuman', - 'America/Argentina/Ushuaia', - 'America/Aruba', - 'America/Asuncion', - 'America/Atikokan', - 'America/Bahia', - 'America/Bahia_Banderas', - 'America/Barbados', - 'America/Belem', - 'America/Belize', - 'America/Blanc-Sablon', - 'America/Boa_Vista', - 'America/Bogota', - 'America/Boise', - 'America/Cambridge_Bay', - 'America/Campo_Grande', - 'America/Cancun', - 'America/Caracas', - 'America/Cayenne', - 'America/Cayman', - 'America/Chicago', - 'America/Chihuahua', - 'America/Costa_Rica', - 'America/Creston', - 'America/Cuiaba', - 'America/Curacao', - 'America/Danmarkshavn', - 'America/Dawson', - 'America/Dawson_Creek', - 'America/Denver', - 'America/Detroit', - 'America/Dominica', - 'America/Edmonton', - 'America/Eirunepe', - 'America/El_Salvador', - 'America/Fortaleza', - 'America/Glace_Bay', - 'America/Godthab', - 'America/Goose_Bay', - 'America/Grand_Turk', - 'America/Grenada', - 'America/Guadeloupe', - 'America/Guatemala', - 'America/Guayaquil', - 'America/Guyana', - 'America/Halifax', - 'America/Havana', - 'America/Hermosillo', - 'America/Indiana/Indianapolis', - 'America/Indiana/Knox', - 'America/Indiana/Marengo', - 'America/Indiana/Petersburg', - 'America/Indiana/Tell_City', - 'America/Indiana/Vevay', - 'America/Indiana/Vincennes', - 'America/Indiana/Winamac', - 'America/Inuvik', - 'America/Iqaluit', - 'America/Jamaica', - 'America/Juneau', - 'America/Kentucky/Louisville', - 'America/Kentucky/Monticello', - 'America/Kralendijk', - 'America/La_Paz', - 'America/Lima', - 'America/Los_Angeles', - 'America/Lower_Princes', - 'America/Maceio', - 'America/Managua', - 'America/Manaus', - 'America/Marigot', - 'America/Martinique', - 'America/Matamoros', - 'America/Mazatlan', - 'America/Menominee', - 'America/Merida', - 'America/Metlakatla', - 'America/Mexico_City', - 'America/Miquelon', - 'America/Moncton', - 'America/Monterrey', - 'America/Montevideo', - 'America/Montreal', - 'America/Montserrat', - 'America/Nassau', - 'America/New_York', - 'America/Nipigon', - 'America/Nome', - 'America/Noronha', - 'America/North_Dakota/Beulah', - 'America/North_Dakota/Center', - 'America/North_Dakota/New_Salem', - 'America/Ojinaga', - 'America/Panama', - 'America/Pangnirtung', - 'America/Paramaribo', - 'America/Phoenix', - 'America/Port-au-Prince', - 'America/Port_of_Spain', - 'America/Porto_Velho', - 'America/Puerto_Rico', - 'America/Rainy_River', - 'America/Rankin_Inlet', - 'America/Recife', - 'America/Regina', - 'America/Resolute', - 'America/Rio_Branco', - 'America/Santa_Isabel', - 'America/Santarem', - 'America/Santiago', - 'America/Santo_Domingo', - 'America/Sao_Paulo', - 'America/Scoresbysund', - 'America/Shiprock', - 'America/Sitka', - 'America/St_Barthelemy', - 'America/St_Johns', - 'America/St_Kitts', - 'America/St_Lucia', - 'America/St_Thomas', - 'America/St_Vincent', - 'America/Swift_Current', - 'America/Tegucigalpa', - 'America/Thule', - 'America/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - 'America/Whitehorse', - 'America/Winnipeg', - 'America/Yakutat', - 'America/Yellowknife', - 'Antarctica/Casey', - 'Antarctica/Davis', - 'Antarctica/DumontDUrville', - 'Antarctica/Macquarie', - 'Antarctica/Mawson', - 'Antarctica/McMurdo', - 'Antarctica/Palmer', - 'Antarctica/Rothera', - 'Antarctica/South_Pole', - 'Antarctica/Syowa', - 'Antarctica/Vostok', - 'Arctic/Longyearbyen', - 'Asia/Aden', - 'Asia/Almaty', - 'Asia/Amman', - 'Asia/Anadyr', - 'Asia/Aqtau', - 'Asia/Aqtobe', - 'Asia/Ashgabat', - 'Asia/Baghdad', - 'Asia/Bahrain', - 'Asia/Baku', - 'Asia/Bangkok', - 'Asia/Beirut', - 'Asia/Bishkek', - 'Asia/Brunei', - 'Asia/Choibalsan', - 'Asia/Chongqing', - 'Asia/Colombo', - 'Asia/Damascus', - 'Asia/Dhaka', - 'Asia/Dili', - 'Asia/Dubai', - 'Asia/Dushanbe', - 'Asia/Gaza', - 'Asia/Harbin', - 'Asia/Hebron', - 'Asia/Ho_Chi_Minh', - 'Asia/Hong_Kong', - 'Asia/Hovd', - 'Asia/Irkutsk', - 'Asia/Jakarta', - 'Asia/Jayapura', - 'Asia/Jerusalem', - 'Asia/Kabul', - 'Asia/Kamchatka', - 'Asia/Karachi', - 'Asia/Kashgar', - 'Asia/Kathmandu', - 'Asia/Kolkata', - 'Asia/Krasnoyarsk', - 'Asia/Kuala_Lumpur', - 'Asia/Kuching', - 'Asia/Kuwait', - 'Asia/Macau', - 'Asia/Magadan', - 'Asia/Makassar', - 'Asia/Manila', - 'Asia/Muscat', - 'Asia/Nicosia', - 'Asia/Novokuznetsk', - 'Asia/Novosibirsk', - 'Asia/Omsk', - 'Asia/Oral', - 'Asia/Phnom_Penh', - 'Asia/Pontianak', - 'Asia/Pyongyang', - 'Asia/Qatar', - 'Asia/Qyzylorda', - 'Asia/Rangoon', - 'Asia/Riyadh', - 'Asia/Sakhalin', - 'Asia/Samarkand', - 'Asia/Seoul', - 'Asia/Shanghai', - 'Asia/Singapore', - 'Asia/Taipei', - 'Asia/Tashkent', - 'Asia/Tbilisi', - 'Asia/Tehran', - 'Asia/Thimphu', - 'Asia/Tokyo', - 'Asia/Ulaanbaatar', - 'Asia/Urumqi', - 'Asia/Vientiane', - 'Asia/Vladivostok', - 'Asia/Yakutsk', - 'Asia/Yekaterinburg', - 'Asia/Yerevan', - 'Atlantic/Azores', - 'Atlantic/Bermuda', - 'Atlantic/Canary', - 'Atlantic/Cape_Verde', - 'Atlantic/Faroe', - 'Atlantic/Madeira', - 'Atlantic/Reykjavik', - 'Atlantic/South_Georgia', - 'Atlantic/St_Helena', - 'Atlantic/Stanley', - 'Australia/Adelaide', - 'Australia/Brisbane', - 'Australia/Broken_Hill', - 'Australia/Currie', - 'Australia/Darwin', - 'Australia/Eucla', - 'Australia/Hobart', - 'Australia/Lindeman', - 'Australia/Lord_Howe', - 'Australia/Melbourne', - 'Australia/Perth', - 'Australia/Sydney', - 'Canada/Atlantic', - 'Canada/Central', - 'Canada/Eastern', - 'Canada/Mountain', - 'Canada/Newfoundland', - 'Canada/Pacific', - 'Europe/Amsterdam', - 'Europe/Andorra', - 'Europe/Athens', - 'Europe/Belgrade', - 'Europe/Berlin', - 'Europe/Bratislava', - 'Europe/Brussels', - 'Europe/Bucharest', - 'Europe/Budapest', - 'Europe/Chisinau', - 'Europe/Copenhagen', - 'Europe/Dublin', - 'Europe/Gibraltar', - 'Europe/Guernsey', - 'Europe/Helsinki', - 'Europe/Isle_of_Man', - 'Europe/Istanbul', - 'Europe/Jersey', - 'Europe/Kaliningrad', - 'Europe/Kiev', - 'Europe/Lisbon', - 'Europe/Ljubljana', - 'Europe/London', - 'Europe/Luxembourg', - 'Europe/Madrid', - 'Europe/Malta', - 'Europe/Mariehamn', - 'Europe/Minsk', - 'Europe/Monaco', - 'Europe/Moscow', - 'Europe/Oslo', - 'Europe/Paris', - 'Europe/Podgorica', - 'Europe/Prague', - 'Europe/Riga', - 'Europe/Rome', - 'Europe/Samara', - 'Europe/San_Marino', - 'Europe/Sarajevo', - 'Europe/Simferopol', - 'Europe/Skopje', - 'Europe/Sofia', - 'Europe/Stockholm', - 'Europe/Tallinn', - 'Europe/Tirane', - 'Europe/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - 'Europe/Zurich', - 'GMT', - 'Indian/Antananarivo', - 'Indian/Chagos', - 'Indian/Christmas', - 'Indian/Cocos', - 'Indian/Comoro', - 'Indian/Kerguelen', - 'Indian/Mahe', - 'Indian/Maldives', - 'Indian/Mauritius', - 'Indian/Mayotte', - 'Indian/Reunion', - 'Pacific/Apia', - 'Pacific/Auckland', - 'Pacific/Chatham', - 'Pacific/Chuuk', - 'Pacific/Easter', - 'Pacific/Efate', - 'Pacific/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - 'Pacific/Johnston', - 'Pacific/Kiritimati', - 'Pacific/Kosrae', - 'Pacific/Kwajalein', - 'Pacific/Majuro', - 'Pacific/Marquesas', - 'Pacific/Midway', - 'Pacific/Nauru', - 'Pacific/Niue', - 'Pacific/Norfolk', - 'Pacific/Noumea', - 'Pacific/Pago_Pago', - 'Pacific/Palau', - 'Pacific/Pitcairn', - 'Pacific/Pohnpei', - 'Pacific/Port_Moresby', - 'Pacific/Rarotonga', - 'Pacific/Saipan', - 'Pacific/Tahiti', - 'Pacific/Tarawa', - 'Pacific/Tongatapu', - 'Pacific/Wake', - 'Pacific/Wallis', - 'US/Alaska', - 'US/Arizona', - 'US/Central', - 'US/Eastern', - 'US/Hawaii', - 'US/Mountain', - 'US/Pacific', - 'UTC'] -common_timezones = [ - tz for tz in common_timezones if tz in all_timezones] - -common_timezones_set = set(common_timezones) diff --git a/lib/pytz/exceptions.py b/lib/pytz/exceptions.py deleted file mode 100644 index 0376108e14bb..000000000000 --- a/lib/pytz/exceptions.py +++ /dev/null @@ -1,48 +0,0 @@ -''' -Custom exceptions raised by pytz. -''' - -__all__ = [ - 'UnknownTimeZoneError', 'InvalidTimeError', 'AmbiguousTimeError', - 'NonExistentTimeError', - ] - - -class UnknownTimeZoneError(KeyError): - '''Exception raised when pytz is passed an unknown timezone. - - >>> isinstance(UnknownTimeZoneError(), LookupError) - True - - This class is actually a subclass of KeyError to provide backwards - compatibility with code relying on the undocumented behavior of earlier - pytz releases. - - >>> isinstance(UnknownTimeZoneError(), KeyError) - True - ''' - pass - - -class InvalidTimeError(Exception): - '''Base class for invalid time exceptions.''' - - -class AmbiguousTimeError(InvalidTimeError): - '''Exception raised when attempting to create an ambiguous wallclock time. - - At the end of a DST transition period, a particular wallclock time will - occur twice (once before the clocks are set back, once after). Both - possibilities may be correct, unless further information is supplied. - - See DstTzInfo.normalize() for more info - ''' - - -class NonExistentTimeError(InvalidTimeError): - '''Exception raised when attempting to create a wallclock time that - cannot exist. - - At the start of a DST transition period, the wallclock time jumps forward. - The instants jumped over never occur. - ''' diff --git a/lib/pytz/reference.py b/lib/pytz/reference.py deleted file mode 100644 index 3dda13e75cd4..000000000000 --- a/lib/pytz/reference.py +++ /dev/null @@ -1,127 +0,0 @@ -''' -Reference tzinfo implementations from the Python docs. -Used for testing against as they are only correct for the years -1987 to 2006. Do not use these for real code. -''' - -from datetime import tzinfo, timedelta, datetime -from pytz import utc, UTC, HOUR, ZERO - -# A class building tzinfo objects for fixed-offset time zones. -# Note that FixedOffset(0, "UTC") is a different way to build a -# UTC tzinfo object. - -class FixedOffset(tzinfo): - """Fixed offset in minutes east from UTC.""" - - def __init__(self, offset, name): - self.__offset = timedelta(minutes = offset) - self.__name = name - - def utcoffset(self, dt): - return self.__offset - - def tzname(self, dt): - return self.__name - - def dst(self, dt): - return ZERO - -# A class capturing the platform's idea of local time. - -import time as _time - -STDOFFSET = timedelta(seconds = -_time.timezone) -if _time.daylight: - DSTOFFSET = timedelta(seconds = -_time.altzone) -else: - DSTOFFSET = STDOFFSET - -DSTDIFF = DSTOFFSET - STDOFFSET - -class LocalTimezone(tzinfo): - - def utcoffset(self, dt): - if self._isdst(dt): - return DSTOFFSET - else: - return STDOFFSET - - def dst(self, dt): - if self._isdst(dt): - return DSTDIFF - else: - return ZERO - - def tzname(self, dt): - return _time.tzname[self._isdst(dt)] - - def _isdst(self, dt): - tt = (dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second, - dt.weekday(), 0, -1) - stamp = _time.mktime(tt) - tt = _time.localtime(stamp) - return tt.tm_isdst > 0 - -Local = LocalTimezone() - -# A complete implementation of current DST rules for major US time zones. - -def first_sunday_on_or_after(dt): - days_to_go = 6 - dt.weekday() - if days_to_go: - dt += timedelta(days_to_go) - return dt - -# In the US, DST starts at 2am (standard time) on the first Sunday in April. -DSTSTART = datetime(1, 4, 1, 2) -# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. -# which is the first Sunday on or after Oct 25. -DSTEND = datetime(1, 10, 25, 1) - -class USTimeZone(tzinfo): - - def __init__(self, hours, reprname, stdname, dstname): - self.stdoffset = timedelta(hours=hours) - self.reprname = reprname - self.stdname = stdname - self.dstname = dstname - - def __repr__(self): - return self.reprname - - def tzname(self, dt): - if self.dst(dt): - return self.dstname - else: - return self.stdname - - def utcoffset(self, dt): - return self.stdoffset + self.dst(dt) - - def dst(self, dt): - if dt is None or dt.tzinfo is None: - # An exception may be sensible here, in one or both cases. - # It depends on how you want to treat them. The default - # fromutc() implementation (called by the default astimezone() - # implementation) passes a datetime with dt.tzinfo is self. - return ZERO - assert dt.tzinfo is self - - # Find first Sunday in April & the last in October. - start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) - end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) - - # Can't compare naive to aware objects, so strip the timezone from - # dt first. - if start <= dt.replace(tzinfo=None) < end: - return HOUR - else: - return ZERO - -Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") -Central = USTimeZone(-6, "Central", "CST", "CDT") -Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") -Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") - diff --git a/lib/pytz/tests/test_docs.py b/lib/pytz/tests/test_docs.py deleted file mode 100644 index 4302dcab233c..000000000000 --- a/lib/pytz/tests/test_docs.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: ascii -*- - -from doctest import DocTestSuite -import unittest, os, os.path, sys -import warnings - -# We test the documentation this way instead of using DocFileSuite so -# we can run the tests under Python 2.3 -def test_README(): - pass - -this_dir = os.path.dirname(__file__) -locs = [ - os.path.join(this_dir, os.pardir, 'README.txt'), - os.path.join(this_dir, os.pardir, os.pardir, 'README.txt'), - ] -for loc in locs: - if os.path.exists(loc): - test_README.__doc__ = open(loc).read() - break -if test_README.__doc__ is None: - raise RuntimeError('README.txt not found') - - -def test_suite(): - "For the Z3 test runner" - return DocTestSuite() - - -if __name__ == '__main__': - sys.path.insert(0, os.path.abspath(os.path.join( - this_dir, os.pardir, os.pardir - ))) - unittest.main(defaultTest='test_suite') - - diff --git a/lib/pytz/tests/test_tzinfo.py b/lib/pytz/tests/test_tzinfo.py deleted file mode 100644 index 24abb91ee844..000000000000 --- a/lib/pytz/tests/test_tzinfo.py +++ /dev/null @@ -1,813 +0,0 @@ -# -*- coding: ascii -*- - -import sys, os, os.path -import unittest, doctest -try: - import cPickle as pickle -except ImportError: - import pickle -from datetime import datetime, time, timedelta, tzinfo -import warnings - -if __name__ == '__main__': - # Only munge path if invoked as a script. Testrunners should have setup - # the paths already - sys.path.insert(0, os.path.abspath(os.path.join(os.pardir, os.pardir))) - -import pytz -from pytz import reference -from pytz.tzfile import _byte_string -from pytz.tzinfo import DstTzInfo, StaticTzInfo - -# I test for expected version to ensure the correct version of pytz is -# actually being tested. -EXPECTED_VERSION='2012d' - -fmt = '%Y-%m-%d %H:%M:%S %Z%z' - -NOTIME = timedelta(0) - -# GMT is a tzinfo.StaticTzInfo--the class we primarily want to test--while -# UTC is reference implementation. They both have the same timezone meaning. -UTC = pytz.timezone('UTC') -GMT = pytz.timezone('GMT') -assert isinstance(GMT, StaticTzInfo), 'GMT is no longer a StaticTzInfo' - -def prettydt(dt): - """datetime as a string using a known format. - - We don't use strftime as it doesn't handle years earlier than 1900 - per http://bugs.python.org/issue1777412 - """ - if dt.utcoffset() >= timedelta(0): - offset = '+%s' % (dt.utcoffset(),) - else: - offset = '-%s' % (-1 * dt.utcoffset(),) - return '%04d-%02d-%02d %02d:%02d:%02d %s %s' % ( - dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second, - dt.tzname(), offset) - - -try: - unicode -except NameError: - # Python 3.x doesn't have unicode(), making writing code - # for Python 2.3 and Python 3.x a pain. - unicode = str - - -class BasicTest(unittest.TestCase): - - def testVersion(self): - # Ensuring the correct version of pytz has been loaded - self.assertEqual(EXPECTED_VERSION, pytz.__version__, - 'Incorrect pytz version loaded. Import path is stuffed ' - 'or this test needs updating. (Wanted %s, got %s)' - % (EXPECTED_VERSION, pytz.__version__) - ) - - def testGMT(self): - now = datetime.now(tz=GMT) - self.assertTrue(now.utcoffset() == NOTIME) - self.assertTrue(now.dst() == NOTIME) - self.assertTrue(now.timetuple() == now.utctimetuple()) - self.assertTrue(now==now.replace(tzinfo=UTC)) - - def testReferenceUTC(self): - now = datetime.now(tz=UTC) - self.assertTrue(now.utcoffset() == NOTIME) - self.assertTrue(now.dst() == NOTIME) - self.assertTrue(now.timetuple() == now.utctimetuple()) - - def testUnknownOffsets(self): - # This tzinfo behavior is required to make - # datetime.time.{utcoffset, dst, tzname} work as documented. - - dst_tz = pytz.timezone('US/Eastern') - - # This information is not known when we don't have a date, - # so return None per API. - self.assertTrue(dst_tz.utcoffset(None) is None) - self.assertTrue(dst_tz.dst(None) is None) - # We don't know the abbreviation, but this is still a valid - # tzname per the Python documentation. - self.assertEqual(dst_tz.tzname(None), 'US/Eastern') - - def clearCache(self): - pytz._tzinfo_cache.clear() - - def testUnicodeTimezone(self): - # We need to ensure that cold lookups work for both Unicode - # and traditional strings, and that the desired singleton is - # returned. - self.clearCache() - eastern = pytz.timezone(unicode('US/Eastern')) - self.assertTrue(eastern is pytz.timezone('US/Eastern')) - - self.clearCache() - eastern = pytz.timezone('US/Eastern') - self.assertTrue(eastern is pytz.timezone(unicode('US/Eastern'))) - - -class PicklingTest(unittest.TestCase): - - def _roundtrip_tzinfo(self, tz): - p = pickle.dumps(tz) - unpickled_tz = pickle.loads(p) - self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone) - - def _roundtrip_datetime(self, dt): - # Ensure that the tzinfo attached to a datetime instance - # is identical to the one returned. This is important for - # DST timezones, as some state is stored in the tzinfo. - tz = dt.tzinfo - p = pickle.dumps(dt) - unpickled_dt = pickle.loads(p) - unpickled_tz = unpickled_dt.tzinfo - self.assertTrue(tz is unpickled_tz, '%s did not roundtrip' % tz.zone) - - def testDst(self): - tz = pytz.timezone('Europe/Amsterdam') - dt = datetime(2004, 2, 1, 0, 0, 0) - - for localized_tz in tz._tzinfos.values(): - self._roundtrip_tzinfo(localized_tz) - self._roundtrip_datetime(dt.replace(tzinfo=localized_tz)) - - def testRoundtrip(self): - dt = datetime(2004, 2, 1, 0, 0, 0) - for zone in pytz.all_timezones: - tz = pytz.timezone(zone) - self._roundtrip_tzinfo(tz) - - def testDatabaseFixes(self): - # Hack the pickle to make it refer to a timezone abbreviation - # that does not match anything. The unpickler should be able - # to repair this case - tz = pytz.timezone('Australia/Melbourne') - p = pickle.dumps(tz) - tzname = tz._tzname - hacked_p = p.replace(_byte_string(tzname), _byte_string('???')) - self.assertNotEqual(p, hacked_p) - unpickled_tz = pickle.loads(hacked_p) - self.assertTrue(tz is unpickled_tz) - - # Simulate a database correction. In this case, the incorrect - # data will continue to be used. - p = pickle.dumps(tz) - new_utcoffset = tz._utcoffset.seconds + 42 - - # Python 3 introduced a new pickle protocol where numbers are stored in - # hexadecimal representation. Here we extract the pickle - # representation of the number for the current Python version. - old_pickle_pattern = pickle.dumps(tz._utcoffset.seconds)[3:-1] - new_pickle_pattern = pickle.dumps(new_utcoffset)[3:-1] - hacked_p = p.replace(old_pickle_pattern, new_pickle_pattern) - - self.assertNotEqual(p, hacked_p) - unpickled_tz = pickle.loads(hacked_p) - self.assertEqual(unpickled_tz._utcoffset.seconds, new_utcoffset) - self.assertTrue(tz is not unpickled_tz) - - def testOldPickles(self): - # Ensure that applications serializing pytz instances as pickles - # have no troubles upgrading to a new pytz release. These pickles - # where created with pytz2006j - east1 = pickle.loads(_byte_string( - "cpytz\n_p\np1\n(S'US/Eastern'\np2\nI-18000\n" - "I0\nS'EST'\np3\ntRp4\n." - )) - east2 = pytz.timezone('US/Eastern') - self.assertTrue(east1 is east2) - - # Confirm changes in name munging between 2006j and 2007c cause - # no problems. - pap1 = pickle.loads(_byte_string( - "cpytz\n_p\np1\n(S'America/Port_minus_au_minus_Prince'" - "\np2\nI-17340\nI0\nS'PPMT'\np3\ntRp4\n.")) - pap2 = pytz.timezone('America/Port-au-Prince') - self.assertTrue(pap1 is pap2) - - gmt1 = pickle.loads(_byte_string( - "cpytz\n_p\np1\n(S'Etc/GMT_plus_10'\np2\ntRp3\n.")) - gmt2 = pytz.timezone('Etc/GMT+10') - self.assertTrue(gmt1 is gmt2) - - -class USEasternDSTStartTestCase(unittest.TestCase): - tzinfo = pytz.timezone('US/Eastern') - - # 24 hours before DST changeover - transition_time = datetime(2002, 4, 7, 7, 0, 0, tzinfo=UTC) - - # Increase for 'flexible' DST transitions due to 1 minute granularity - # of Python's datetime library - instant = timedelta(seconds=1) - - # before transition - before = { - 'tzname': 'EST', - 'utcoffset': timedelta(hours = -5), - 'dst': timedelta(hours = 0), - } - - # after transition - after = { - 'tzname': 'EDT', - 'utcoffset': timedelta(hours = -4), - 'dst': timedelta(hours = 1), - } - - def _test_tzname(self, utc_dt, wanted): - tzname = wanted['tzname'] - dt = utc_dt.astimezone(self.tzinfo) - self.assertEqual(dt.tzname(), tzname, - 'Expected %s as tzname for %s. Got %s' % ( - tzname, str(utc_dt), dt.tzname() - ) - ) - - def _test_utcoffset(self, utc_dt, wanted): - utcoffset = wanted['utcoffset'] - dt = utc_dt.astimezone(self.tzinfo) - self.assertEqual( - dt.utcoffset(), wanted['utcoffset'], - 'Expected %s as utcoffset for %s. Got %s' % ( - utcoffset, utc_dt, dt.utcoffset() - ) - ) - - def _test_dst(self, utc_dt, wanted): - dst = wanted['dst'] - dt = utc_dt.astimezone(self.tzinfo) - self.assertEqual(dt.dst(),dst, - 'Expected %s as dst for %s. Got %s' % ( - dst, utc_dt, dt.dst() - ) - ) - - def test_arithmetic(self): - utc_dt = self.transition_time - - for days in range(-420, 720, 20): - delta = timedelta(days=days) - - # Make sure we can get back where we started - dt = utc_dt.astimezone(self.tzinfo) - dt2 = dt + delta - dt2 = dt2 - delta - self.assertEqual(dt, dt2) - - # Make sure arithmetic crossing DST boundaries ends - # up in the correct timezone after normalization - utc_plus_delta = (utc_dt + delta).astimezone(self.tzinfo) - local_plus_delta = self.tzinfo.normalize(dt + delta) - self.assertEqual( - prettydt(utc_plus_delta), - prettydt(local_plus_delta), - 'Incorrect result for delta==%d days. Wanted %r. Got %r'%( - days, - prettydt(utc_plus_delta), - prettydt(local_plus_delta), - ) - ) - - def _test_all(self, utc_dt, wanted): - self._test_utcoffset(utc_dt, wanted) - self._test_tzname(utc_dt, wanted) - self._test_dst(utc_dt, wanted) - - def testDayBefore(self): - self._test_all( - self.transition_time - timedelta(days=1), self.before - ) - - def testTwoHoursBefore(self): - self._test_all( - self.transition_time - timedelta(hours=2), self.before - ) - - def testHourBefore(self): - self._test_all( - self.transition_time - timedelta(hours=1), self.before - ) - - def testInstantBefore(self): - self._test_all( - self.transition_time - self.instant, self.before - ) - - def testTransition(self): - self._test_all( - self.transition_time, self.after - ) - - def testInstantAfter(self): - self._test_all( - self.transition_time + self.instant, self.after - ) - - def testHourAfter(self): - self._test_all( - self.transition_time + timedelta(hours=1), self.after - ) - - def testTwoHoursAfter(self): - self._test_all( - self.transition_time + timedelta(hours=1), self.after - ) - - def testDayAfter(self): - self._test_all( - self.transition_time + timedelta(days=1), self.after - ) - - -class USEasternDSTEndTestCase(USEasternDSTStartTestCase): - tzinfo = pytz.timezone('US/Eastern') - transition_time = datetime(2002, 10, 27, 6, 0, 0, tzinfo=UTC) - before = { - 'tzname': 'EDT', - 'utcoffset': timedelta(hours = -4), - 'dst': timedelta(hours = 1), - } - after = { - 'tzname': 'EST', - 'utcoffset': timedelta(hours = -5), - 'dst': timedelta(hours = 0), - } - - -class USEasternEPTStartTestCase(USEasternDSTStartTestCase): - transition_time = datetime(1945, 8, 14, 23, 0, 0, tzinfo=UTC) - before = { - 'tzname': 'EWT', - 'utcoffset': timedelta(hours = -4), - 'dst': timedelta(hours = 1), - } - after = { - 'tzname': 'EPT', - 'utcoffset': timedelta(hours = -4), - 'dst': timedelta(hours = 1), - } - - -class USEasternEPTEndTestCase(USEasternDSTStartTestCase): - transition_time = datetime(1945, 9, 30, 6, 0, 0, tzinfo=UTC) - before = { - 'tzname': 'EPT', - 'utcoffset': timedelta(hours = -4), - 'dst': timedelta(hours = 1), - } - after = { - 'tzname': 'EST', - 'utcoffset': timedelta(hours = -5), - 'dst': timedelta(hours = 0), - } - - -class WarsawWMTEndTestCase(USEasternDSTStartTestCase): - # In 1915, Warsaw changed from Warsaw to Central European time. - # This involved the clocks being set backwards, causing a end-of-DST - # like situation without DST being involved. - tzinfo = pytz.timezone('Europe/Warsaw') - transition_time = datetime(1915, 8, 4, 22, 36, 0, tzinfo=UTC) - before = { - 'tzname': 'WMT', - 'utcoffset': timedelta(hours=1, minutes=24), - 'dst': timedelta(0), - } - after = { - 'tzname': 'CET', - 'utcoffset': timedelta(hours=1), - 'dst': timedelta(0), - } - - -class VilniusWMTEndTestCase(USEasternDSTStartTestCase): - # At the end of 1916, Vilnius changed timezones putting its clock - # forward by 11 minutes 35 seconds. Neither timezone was in DST mode. - tzinfo = pytz.timezone('Europe/Vilnius') - instant = timedelta(seconds=31) - transition_time = datetime(1916, 12, 31, 22, 36, 00, tzinfo=UTC) - before = { - 'tzname': 'WMT', - 'utcoffset': timedelta(hours=1, minutes=24), - 'dst': timedelta(0), - } - after = { - 'tzname': 'KMT', - 'utcoffset': timedelta(hours=1, minutes=36), # Really 1:35:36 - 'dst': timedelta(0), - } - - -class VilniusCESTStartTestCase(USEasternDSTStartTestCase): - # In 1941, Vilnius changed from MSG to CEST, switching to summer - # time while simultaneously reducing its UTC offset by two hours, - # causing the clocks to go backwards for this summer time - # switchover. - tzinfo = pytz.timezone('Europe/Vilnius') - transition_time = datetime(1941, 6, 23, 21, 00, 00, tzinfo=UTC) - before = { - 'tzname': 'MSK', - 'utcoffset': timedelta(hours=3), - 'dst': timedelta(0), - } - after = { - 'tzname': 'CEST', - 'utcoffset': timedelta(hours=2), - 'dst': timedelta(hours=1), - } - - -class LondonHistoryStartTestCase(USEasternDSTStartTestCase): - # The first known timezone transition in London was in 1847 when - # clocks where synchronized to GMT. However, we currently only - # understand v1 format tzfile(5) files which does handle years - # this far in the past, so our earliest known transition is in - # 1916. - tzinfo = pytz.timezone('Europe/London') - # transition_time = datetime(1847, 12, 1, 1, 15, 00, tzinfo=UTC) - # before = { - # 'tzname': 'LMT', - # 'utcoffset': timedelta(minutes=-75), - # 'dst': timedelta(0), - # } - # after = { - # 'tzname': 'GMT', - # 'utcoffset': timedelta(0), - # 'dst': timedelta(0), - # } - transition_time = datetime(1916, 5, 21, 2, 00, 00, tzinfo=UTC) - before = { - 'tzname': 'GMT', - 'utcoffset': timedelta(0), - 'dst': timedelta(0), - } - after = { - 'tzname': 'BST', - 'utcoffset': timedelta(hours=1), - 'dst': timedelta(hours=1), - } - - -class LondonHistoryEndTestCase(USEasternDSTStartTestCase): - # Timezone switchovers are projected into the future, even - # though no official statements exist or could be believed even - # if they did exist. We currently only check the last known - # transition in 2037, as we are still using v1 format tzfile(5) - # files. - tzinfo = pytz.timezone('Europe/London') - # transition_time = datetime(2499, 10, 25, 1, 0, 0, tzinfo=UTC) - transition_time = datetime(2037, 10, 25, 1, 0, 0, tzinfo=UTC) - before = { - 'tzname': 'BST', - 'utcoffset': timedelta(hours=1), - 'dst': timedelta(hours=1), - } - after = { - 'tzname': 'GMT', - 'utcoffset': timedelta(0), - 'dst': timedelta(0), - } - - -class NoumeaHistoryStartTestCase(USEasternDSTStartTestCase): - # Noumea adopted a whole hour offset in 1912. Previously - # it was 11 hours, 5 minutes and 48 seconds off UTC. However, - # due to limitations of the Python datetime library, we need - # to round that to 11 hours 6 minutes. - tzinfo = pytz.timezone('Pacific/Noumea') - transition_time = datetime(1912, 1, 12, 12, 54, 12, tzinfo=UTC) - before = { - 'tzname': 'LMT', - 'utcoffset': timedelta(hours=11, minutes=6), - 'dst': timedelta(0), - } - after = { - 'tzname': 'NCT', - 'utcoffset': timedelta(hours=11), - 'dst': timedelta(0), - } - - -class NoumeaDSTEndTestCase(USEasternDSTStartTestCase): - # Noumea dropped DST in 1997. - tzinfo = pytz.timezone('Pacific/Noumea') - transition_time = datetime(1997, 3, 1, 15, 00, 00, tzinfo=UTC) - before = { - 'tzname': 'NCST', - 'utcoffset': timedelta(hours=12), - 'dst': timedelta(hours=1), - } - after = { - 'tzname': 'NCT', - 'utcoffset': timedelta(hours=11), - 'dst': timedelta(0), - } - - -class NoumeaNoMoreDSTTestCase(NoumeaDSTEndTestCase): - # Noumea dropped DST in 1997. Here we test that it stops occuring. - transition_time = ( - NoumeaDSTEndTestCase.transition_time + timedelta(days=365*10)) - before = NoumeaDSTEndTestCase.after - after = NoumeaDSTEndTestCase.after - - -class TahitiTestCase(USEasternDSTStartTestCase): - # Tahiti has had a single transition in its history. - tzinfo = pytz.timezone('Pacific/Tahiti') - transition_time = datetime(1912, 10, 1, 9, 58, 16, tzinfo=UTC) - before = { - 'tzname': 'LMT', - 'utcoffset': timedelta(hours=-9, minutes=-58), - 'dst': timedelta(0), - } - after = { - 'tzname': 'TAHT', - 'utcoffset': timedelta(hours=-10), - 'dst': timedelta(0), - } - - -class SamoaInternationalDateLineChange(USEasternDSTStartTestCase): - # At the end of 2011, Samoa will switch from being east of the - # international dateline to the west. There will be no Dec 30th - # 2011 and it will switch from UTC-10 to UTC+14. - tzinfo = pytz.timezone('Pacific/Apia') - transition_time = datetime(2011, 12, 30, 10, 0, 0, tzinfo=UTC) - before = { - 'tzname': 'WSDT', - 'utcoffset': timedelta(hours=-10), - 'dst': timedelta(hours=1), - } - after = { - 'tzname': 'WSDT', - 'utcoffset': timedelta(hours=14), - 'dst': timedelta(hours=1), - } - - -class ReferenceUSEasternDSTStartTestCase(USEasternDSTStartTestCase): - tzinfo = reference.Eastern - def test_arithmetic(self): - # Reference implementation cannot handle this - pass - - -class ReferenceUSEasternDSTEndTestCase(USEasternDSTEndTestCase): - tzinfo = reference.Eastern - - def testHourBefore(self): - # Python's datetime library has a bug, where the hour before - # a daylight savings transition is one hour out. For example, - # at the end of US/Eastern daylight savings time, 01:00 EST - # occurs twice (once at 05:00 UTC and once at 06:00 UTC), - # whereas the first should actually be 01:00 EDT. - # Note that this bug is by design - by accepting this ambiguity - # for one hour one hour per year, an is_dst flag on datetime.time - # became unnecessary. - self._test_all( - self.transition_time - timedelta(hours=1), self.after - ) - - def testInstantBefore(self): - self._test_all( - self.transition_time - timedelta(seconds=1), self.after - ) - - def test_arithmetic(self): - # Reference implementation cannot handle this - pass - - -class LocalTestCase(unittest.TestCase): - def testLocalize(self): - loc_tz = pytz.timezone('Europe/Amsterdam') - - loc_time = loc_tz.localize(datetime(1930, 5, 10, 0, 0, 0)) - # Actually +00:19:32, but Python datetime rounds this - self.assertEqual(loc_time.strftime('%Z%z'), 'AMT+0020') - - loc_time = loc_tz.localize(datetime(1930, 5, 20, 0, 0, 0)) - # Actually +00:19:32, but Python datetime rounds this - self.assertEqual(loc_time.strftime('%Z%z'), 'NST+0120') - - loc_time = loc_tz.localize(datetime(1940, 5, 10, 0, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'NET+0020') - - loc_time = loc_tz.localize(datetime(1940, 5, 20, 0, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200') - - loc_time = loc_tz.localize(datetime(2004, 2, 1, 0, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100') - - loc_time = loc_tz.localize(datetime(2004, 4, 1, 0, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'CEST+0200') - - tz = pytz.timezone('Europe/Amsterdam') - loc_time = loc_tz.localize(datetime(1943, 3, 29, 1, 59, 59)) - self.assertEqual(loc_time.strftime('%Z%z'), 'CET+0100') - - - # Switch to US - loc_tz = pytz.timezone('US/Eastern') - - # End of DST ambiguity check - loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=1) - self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400') - - loc_time = loc_tz.localize(datetime(1918, 10, 27, 1, 59, 59), is_dst=0) - self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') - - self.assertRaises(pytz.AmbiguousTimeError, - loc_tz.localize, datetime(1918, 10, 27, 1, 59, 59), is_dst=None - ) - - # Start of DST non-existent times - loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=0) - self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') - - loc_time = loc_tz.localize(datetime(1918, 3, 31, 2, 0, 0), is_dst=1) - self.assertEqual(loc_time.strftime('%Z%z'), 'EDT-0400') - - self.assertRaises(pytz.NonExistentTimeError, - loc_tz.localize, datetime(1918, 3, 31, 2, 0, 0), is_dst=None - ) - - # Weird changes - war time and peace time both is_dst==True - - loc_time = loc_tz.localize(datetime(1942, 2, 9, 3, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'EWT-0400') - - loc_time = loc_tz.localize(datetime(1945, 8, 14, 19, 0, 0)) - self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400') - - loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=1) - self.assertEqual(loc_time.strftime('%Z%z'), 'EPT-0400') - - loc_time = loc_tz.localize(datetime(1945, 9, 30, 1, 0, 0), is_dst=0) - self.assertEqual(loc_time.strftime('%Z%z'), 'EST-0500') - - def testNormalize(self): - tz = pytz.timezone('US/Eastern') - dt = datetime(2004, 4, 4, 7, 0, 0, tzinfo=UTC).astimezone(tz) - dt2 = dt - timedelta(minutes=10) - self.assertEqual( - dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'), - '2004-04-04 02:50:00 EDT-0400' - ) - - dt2 = tz.normalize(dt2) - self.assertEqual( - dt2.strftime('%Y-%m-%d %H:%M:%S %Z%z'), - '2004-04-04 01:50:00 EST-0500' - ) - - def testPartialMinuteOffsets(self): - # utcoffset in Amsterdam was not a whole minute until 1937 - # However, we fudge this by rounding them, as the Python - # datetime library - tz = pytz.timezone('Europe/Amsterdam') - utc_dt = datetime(1914, 1, 1, 13, 40, 28, tzinfo=UTC) # correct - utc_dt = utc_dt.replace(second=0) # But we need to fudge it - loc_dt = utc_dt.astimezone(tz) - self.assertEqual( - loc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'), - '1914-01-01 14:00:00 AMT+0020' - ) - - # And get back... - utc_dt = loc_dt.astimezone(UTC) - self.assertEqual( - utc_dt.strftime('%Y-%m-%d %H:%M:%S %Z%z'), - '1914-01-01 13:40:00 UTC+0000' - ) - - def no_testCreateLocaltime(self): - # It would be nice if this worked, but it doesn't. - tz = pytz.timezone('Europe/Amsterdam') - dt = datetime(2004, 10, 31, 2, 0, 0, tzinfo=tz) - self.assertEqual( - dt.strftime(fmt), - '2004-10-31 02:00:00 CET+0100' - ) - - -class CommonTimezonesTestCase(unittest.TestCase): - def test_bratislava(self): - # Bratislava is the default timezone for Slovakia, but our - # heuristics where not adding it to common_timezones. Ideally, - # common_timezones should be populated from zone.tab at runtime, - # but I'm hesitant to pay the startup cost as loading the list - # on demand whilst remaining backwards compatible seems - # difficult. - self.assertTrue('Europe/Bratislava' in pytz.common_timezones) - self.assertTrue('Europe/Bratislava' in pytz.common_timezones_set) - - def test_us_eastern(self): - self.assertTrue('US/Eastern' in pytz.common_timezones) - self.assertTrue('US/Eastern' in pytz.common_timezones_set) - - def test_belfast(self): - # Belfast uses London time. - self.assertTrue('Europe/Belfast' in pytz.all_timezones_set) - self.assertFalse('Europe/Belfast' in pytz.common_timezones) - self.assertFalse('Europe/Belfast' in pytz.common_timezones_set) - - -class BaseTzInfoTestCase: - '''Ensure UTC, StaticTzInfo and DstTzInfo work consistently. - - These tests are run for each type of tzinfo. - ''' - tz = None # override - tz_class = None # override - - def test_expectedclass(self): - self.assertTrue(isinstance(self.tz, self.tz_class)) - - def test_fromutc(self): - # naive datetime. - dt1 = datetime(2011, 10, 31) - - # localized datetime, same timezone. - dt2 = self.tz.localize(dt1) - - # Both should give the same results. Note that the standard - # Python tzinfo.fromutc() only supports the second. - for dt in [dt1, dt2]: - loc_dt = self.tz.fromutc(dt) - loc_dt2 = pytz.utc.localize(dt1).astimezone(self.tz) - self.assertEqual(loc_dt, loc_dt2) - - # localized datetime, different timezone. - new_tz = pytz.timezone('Europe/Paris') - self.assertTrue(self.tz is not new_tz) - dt3 = new_tz.localize(dt1) - self.assertRaises(ValueError, self.tz.fromutc, dt3) - - def test_normalize(self): - other_tz = pytz.timezone('Europe/Paris') - self.assertTrue(self.tz is not other_tz) - - dt = datetime(2012, 3, 26, 12, 0) - other_dt = other_tz.localize(dt) - - local_dt = self.tz.normalize(other_dt) - - self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo) - self.assertNotEqual( - local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None)) - - def test_astimezone(self): - other_tz = pytz.timezone('Europe/Paris') - self.assertTrue(self.tz is not other_tz) - - dt = datetime(2012, 3, 26, 12, 0) - other_dt = other_tz.localize(dt) - - local_dt = other_dt.astimezone(self.tz) - - self.assertTrue(local_dt.tzinfo is not other_dt.tzinfo) - self.assertNotEqual( - local_dt.replace(tzinfo=None), other_dt.replace(tzinfo=None)) - - -class OptimizedUTCTestCase(unittest.TestCase, BaseTzInfoTestCase): - tz = pytz.utc - tz_class = tz.__class__ - - -class LegacyUTCTestCase(unittest.TestCase, BaseTzInfoTestCase): - # Deprecated timezone, but useful for comparison tests. - tz = pytz.timezone('Etc/UTC') - tz_class = StaticTzInfo - - -class StaticTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase): - tz = pytz.timezone('GMT') - tz_class = StaticTzInfo - - -class DstTzInfoTestCase(unittest.TestCase, BaseTzInfoTestCase): - tz = pytz.timezone('Australia/Melbourne') - tz_class = DstTzInfo - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(doctest.DocTestSuite('pytz')) - suite.addTest(doctest.DocTestSuite('pytz.tzinfo')) - import test_tzinfo - suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_tzinfo)) - return suite - - -if __name__ == '__main__': - warnings.simplefilter("error") # Warnings should be fatal in tests. - unittest.main(defaultTest='test_suite') - diff --git a/lib/pytz/tzfile.py b/lib/pytz/tzfile.py deleted file mode 100644 index 9c007c80995a..000000000000 --- a/lib/pytz/tzfile.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -''' -$Id: tzfile.py,v 1.8 2004/06/03 00:15:24 zenzen Exp $ -''' - -try: - from cStringIO import StringIO -except ImportError: - from io import StringIO -from datetime import datetime, timedelta -from struct import unpack, calcsize - -from pytz.tzinfo import StaticTzInfo, DstTzInfo, memorized_ttinfo -from pytz.tzinfo import memorized_datetime, memorized_timedelta - -def _byte_string(s): - """Cast a string or byte string to an ASCII byte string.""" - return s.encode('US-ASCII') - -_NULL = _byte_string('\0') - -def _std_string(s): - """Cast a string or byte string to an ASCII string.""" - return str(s.decode('US-ASCII')) - -def build_tzinfo(zone, fp): - head_fmt = '>4s c 15x 6l' - head_size = calcsize(head_fmt) - (magic, format, ttisgmtcnt, ttisstdcnt,leapcnt, timecnt, - typecnt, charcnt) = unpack(head_fmt, fp.read(head_size)) - - # Make sure it is a tzfile(5) file - assert magic == _byte_string('TZif'), 'Got magic %s' % repr(magic) - - # Read out the transition times, localtime indices and ttinfo structures. - data_fmt = '>%(timecnt)dl %(timecnt)dB %(ttinfo)s %(charcnt)ds' % dict( - timecnt=timecnt, ttinfo='lBB'*typecnt, charcnt=charcnt) - data_size = calcsize(data_fmt) - data = unpack(data_fmt, fp.read(data_size)) - - # make sure we unpacked the right number of values - assert len(data) == 2 * timecnt + 3 * typecnt + 1 - transitions = [memorized_datetime(trans) - for trans in data[:timecnt]] - lindexes = list(data[timecnt:2 * timecnt]) - ttinfo_raw = data[2 * timecnt:-1] - tznames_raw = data[-1] - del data - - # Process ttinfo into separate structs - ttinfo = [] - tznames = {} - i = 0 - while i < len(ttinfo_raw): - # have we looked up this timezone name yet? - tzname_offset = ttinfo_raw[i+2] - if tzname_offset not in tznames: - nul = tznames_raw.find(_NULL, tzname_offset) - if nul < 0: - nul = len(tznames_raw) - tznames[tzname_offset] = _std_string( - tznames_raw[tzname_offset:nul]) - ttinfo.append((ttinfo_raw[i], - bool(ttinfo_raw[i+1]), - tznames[tzname_offset])) - i += 3 - - # Now build the timezone object - if len(transitions) == 0: - ttinfo[0][0], ttinfo[0][2] - cls = type(zone, (StaticTzInfo,), dict( - zone=zone, - _utcoffset=memorized_timedelta(ttinfo[0][0]), - _tzname=ttinfo[0][2])) - else: - # Early dates use the first standard time ttinfo - i = 0 - while ttinfo[i][1]: - i += 1 - if ttinfo[i] == ttinfo[lindexes[0]]: - transitions[0] = datetime.min - else: - transitions.insert(0, datetime.min) - lindexes.insert(0, i) - - # calculate transition info - transition_info = [] - for i in range(len(transitions)): - inf = ttinfo[lindexes[i]] - utcoffset = inf[0] - if not inf[1]: - dst = 0 - else: - for j in range(i-1, -1, -1): - prev_inf = ttinfo[lindexes[j]] - if not prev_inf[1]: - break - dst = inf[0] - prev_inf[0] # dst offset - - # Bad dst? Look further. DST > 24 hours happens when - # a timzone has moved across the international dateline. - if dst <= 0 or dst > 3600*3: - for j in range(i+1, len(transitions)): - stdinf = ttinfo[lindexes[j]] - if not stdinf[1]: - dst = inf[0] - stdinf[0] - if dst > 0: - break # Found a useful std time. - - tzname = inf[2] - - # Round utcoffset and dst to the nearest minute or the - # datetime library will complain. Conversions to these timezones - # might be up to plus or minus 30 seconds out, but it is - # the best we can do. - utcoffset = int((utcoffset + 30) // 60) * 60 - dst = int((dst + 30) // 60) * 60 - transition_info.append(memorized_ttinfo(utcoffset, dst, tzname)) - - cls = type(zone, (DstTzInfo,), dict( - zone=zone, - _utc_transition_times=transitions, - _transition_info=transition_info)) - - return cls() - -if __name__ == '__main__': - import os.path - from pprint import pprint - base = os.path.join(os.path.dirname(__file__), 'zoneinfo') - tz = build_tzinfo('Australia/Melbourne', - open(os.path.join(base,'Australia','Melbourne'), 'rb')) - tz = build_tzinfo('US/Eastern', - open(os.path.join(base,'US','Eastern'), 'rb')) - pprint(tz._utc_transition_times) - #print tz.asPython(4) - #print tz.transitions_mapping diff --git a/lib/pytz/tzinfo.py b/lib/pytz/tzinfo.py deleted file mode 100644 index a1e43cdf0c01..000000000000 --- a/lib/pytz/tzinfo.py +++ /dev/null @@ -1,563 +0,0 @@ -'''Base classes and helpers for building zone specific tzinfo classes''' - -from datetime import datetime, timedelta, tzinfo -from bisect import bisect_right -try: - set -except NameError: - from sets import Set as set - -import pytz -from pytz.exceptions import AmbiguousTimeError, NonExistentTimeError - -__all__ = [] - -_timedelta_cache = {} -def memorized_timedelta(seconds): - '''Create only one instance of each distinct timedelta''' - try: - return _timedelta_cache[seconds] - except KeyError: - delta = timedelta(seconds=seconds) - _timedelta_cache[seconds] = delta - return delta - -_epoch = datetime.utcfromtimestamp(0) -_datetime_cache = {0: _epoch} -def memorized_datetime(seconds): - '''Create only one instance of each distinct datetime''' - try: - return _datetime_cache[seconds] - except KeyError: - # NB. We can't just do datetime.utcfromtimestamp(seconds) as this - # fails with negative values under Windows (Bug #90096) - dt = _epoch + timedelta(seconds=seconds) - _datetime_cache[seconds] = dt - return dt - -_ttinfo_cache = {} -def memorized_ttinfo(*args): - '''Create only one instance of each distinct tuple''' - try: - return _ttinfo_cache[args] - except KeyError: - ttinfo = ( - memorized_timedelta(args[0]), - memorized_timedelta(args[1]), - args[2] - ) - _ttinfo_cache[args] = ttinfo - return ttinfo - -_notime = memorized_timedelta(0) - -def _to_seconds(td): - '''Convert a timedelta to seconds''' - return td.seconds + td.days * 24 * 60 * 60 - - -class BaseTzInfo(tzinfo): - # Overridden in subclass - _utcoffset = None - _tzname = None - zone = None - - def __str__(self): - return self.zone - - -class StaticTzInfo(BaseTzInfo): - '''A timezone that has a constant offset from UTC - - These timezones are rare, as most locations have changed their - offset at some point in their history - ''' - def fromutc(self, dt): - '''See datetime.tzinfo.fromutc''' - if dt.tzinfo is not None and dt.tzinfo is not self: - raise ValueError('fromutc: dt.tzinfo is not self') - return (dt + self._utcoffset).replace(tzinfo=self) - - def utcoffset(self, dt, is_dst=None): - '''See datetime.tzinfo.utcoffset - - is_dst is ignored for StaticTzInfo, and exists only to - retain compatibility with DstTzInfo. - ''' - return self._utcoffset - - def dst(self, dt, is_dst=None): - '''See datetime.tzinfo.dst - - is_dst is ignored for StaticTzInfo, and exists only to - retain compatibility with DstTzInfo. - ''' - return _notime - - def tzname(self, dt, is_dst=None): - '''See datetime.tzinfo.tzname - - is_dst is ignored for StaticTzInfo, and exists only to - retain compatibility with DstTzInfo. - ''' - return self._tzname - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time''' - if dt.tzinfo is not None: - raise ValueError('Not naive datetime (tzinfo is already set)') - return dt.replace(tzinfo=self) - - def normalize(self, dt, is_dst=False): - '''Correct the timezone information on the given datetime. - - This is normally a no-op, as StaticTzInfo timezones never have - ambiguous cases to correct: - - >>> from pytz import timezone - >>> gmt = timezone('GMT') - >>> isinstance(gmt, StaticTzInfo) - True - >>> dt = datetime(2011, 5, 8, 1, 2, 3, tzinfo=gmt) - >>> gmt.normalize(dt) is dt - True - - The supported method of converting between timezones is to use - datetime.astimezone(). Currently normalize() also works: - - >>> la = timezone('America/Los_Angeles') - >>> dt = la.localize(datetime(2011, 5, 7, 1, 2, 3)) - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> gmt.normalize(dt).strftime(fmt) - '2011-05-07 08:02:03 GMT (+0000)' - ''' - if dt.tzinfo is self: - return dt - if dt.tzinfo is None: - raise ValueError('Naive time - no tzinfo set') - return dt.astimezone(self) - - def __repr__(self): - return '' % (self.zone,) - - def __reduce__(self): - # Special pickle to zone remains a singleton and to cope with - # database changes. - return pytz._p, (self.zone,) - - -class DstTzInfo(BaseTzInfo): - '''A timezone that has a variable offset from UTC - - The offset might change if daylight savings time comes into effect, - or at a point in history when the region decides to change their - timezone definition. - ''' - # Overridden in subclass - _utc_transition_times = None # Sorted list of DST transition times in UTC - _transition_info = None # [(utcoffset, dstoffset, tzname)] corresponding - # to _utc_transition_times entries - zone = None - - # Set in __init__ - _tzinfos = None - _dst = None # DST offset - - def __init__(self, _inf=None, _tzinfos=None): - if _inf: - self._tzinfos = _tzinfos - self._utcoffset, self._dst, self._tzname = _inf - else: - _tzinfos = {} - self._tzinfos = _tzinfos - self._utcoffset, self._dst, self._tzname = self._transition_info[0] - _tzinfos[self._transition_info[0]] = self - for inf in self._transition_info[1:]: - if inf not in _tzinfos: - _tzinfos[inf] = self.__class__(inf, _tzinfos) - - def fromutc(self, dt): - '''See datetime.tzinfo.fromutc''' - if (dt.tzinfo is not None - and getattr(dt.tzinfo, '_tzinfos', None) is not self._tzinfos): - raise ValueError('fromutc: dt.tzinfo is not self') - dt = dt.replace(tzinfo=None) - idx = max(0, bisect_right(self._utc_transition_times, dt) - 1) - inf = self._transition_info[idx] - return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf]) - - def normalize(self, dt): - '''Correct the timezone information on the given datetime - - If date arithmetic crosses DST boundaries, the tzinfo - is not magically adjusted. This method normalizes the - tzinfo to the correct one. - - To test, first we need to do some setup - - >>> from pytz import timezone - >>> utc = timezone('UTC') - >>> eastern = timezone('US/Eastern') - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - - We next create a datetime right on an end-of-DST transition point, - the instant when the wallclocks are wound back one hour. - - >>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc) - >>> loc_dt = utc_dt.astimezone(eastern) - >>> loc_dt.strftime(fmt) - '2002-10-27 01:00:00 EST (-0500)' - - Now, if we subtract a few minutes from it, note that the timezone - information has not changed. - - >>> before = loc_dt - timedelta(minutes=10) - >>> before.strftime(fmt) - '2002-10-27 00:50:00 EST (-0500)' - - But we can fix that by calling the normalize method - - >>> before = eastern.normalize(before) - >>> before.strftime(fmt) - '2002-10-27 01:50:00 EDT (-0400)' - - The supported method of converting between timezones is to use - datetime.astimezone(). Currently, normalize() also works: - - >>> th = timezone('Asia/Bangkok') - >>> am = timezone('Europe/Amsterdam') - >>> dt = th.localize(datetime(2011, 5, 7, 1, 2, 3)) - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> am.normalize(dt).strftime(fmt) - '2011-05-06 20:02:03 CEST (+0200)' - ''' - if dt.tzinfo is None: - raise ValueError('Naive time - no tzinfo set') - - # Convert dt in localtime to UTC - offset = dt.tzinfo._utcoffset - dt = dt.replace(tzinfo=None) - dt = dt - offset - # convert it back, and return it - return self.fromutc(dt) - - def localize(self, dt, is_dst=False): - '''Convert naive time to local time. - - This method should be used to construct localtimes, rather - than passing a tzinfo argument to a datetime constructor. - - is_dst is used to determine the correct timezone in the ambigous - period at the end of daylight savings time. - - >>> from pytz import timezone - >>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)' - >>> amdam = timezone('Europe/Amsterdam') - >>> dt = datetime(2004, 10, 31, 2, 0, 0) - >>> loc_dt1 = amdam.localize(dt, is_dst=True) - >>> loc_dt2 = amdam.localize(dt, is_dst=False) - >>> loc_dt1.strftime(fmt) - '2004-10-31 02:00:00 CEST (+0200)' - >>> loc_dt2.strftime(fmt) - '2004-10-31 02:00:00 CET (+0100)' - >>> str(loc_dt2 - loc_dt1) - '1:00:00' - - Use is_dst=None to raise an AmbiguousTimeError for ambiguous - times at the end of daylight savings - - >>> try: - ... loc_dt1 = amdam.localize(dt, is_dst=None) - ... except AmbiguousTimeError: - ... print('Ambiguous') - Ambiguous - - is_dst defaults to False - - >>> amdam.localize(dt) == amdam.localize(dt, False) - True - - is_dst is also used to determine the correct timezone in the - wallclock times jumped over at the start of daylight savings time. - - >>> pacific = timezone('US/Pacific') - >>> dt = datetime(2008, 3, 9, 2, 0, 0) - >>> ploc_dt1 = pacific.localize(dt, is_dst=True) - >>> ploc_dt2 = pacific.localize(dt, is_dst=False) - >>> ploc_dt1.strftime(fmt) - '2008-03-09 02:00:00 PDT (-0700)' - >>> ploc_dt2.strftime(fmt) - '2008-03-09 02:00:00 PST (-0800)' - >>> str(ploc_dt2 - ploc_dt1) - '1:00:00' - - Use is_dst=None to raise a NonExistentTimeError for these skipped - times. - - >>> try: - ... loc_dt1 = pacific.localize(dt, is_dst=None) - ... except NonExistentTimeError: - ... print('Non-existent') - Non-existent - ''' - if dt.tzinfo is not None: - raise ValueError('Not naive datetime (tzinfo is already set)') - - # Find the two best possibilities. - possible_loc_dt = set() - for delta in [timedelta(days=-1), timedelta(days=1)]: - loc_dt = dt + delta - idx = max(0, bisect_right( - self._utc_transition_times, loc_dt) - 1) - inf = self._transition_info[idx] - tzinfo = self._tzinfos[inf] - loc_dt = tzinfo.normalize(dt.replace(tzinfo=tzinfo)) - if loc_dt.replace(tzinfo=None) == dt: - possible_loc_dt.add(loc_dt) - - if len(possible_loc_dt) == 1: - return possible_loc_dt.pop() - - # If there are no possibly correct timezones, we are attempting - # to convert a time that never happened - the time period jumped - # during the start-of-DST transition period. - if len(possible_loc_dt) == 0: - # If we refuse to guess, raise an exception. - if is_dst is None: - raise NonExistentTimeError(dt) - - # If we are forcing the pre-DST side of the DST transition, we - # obtain the correct timezone by winding the clock forward a few - # hours. - elif is_dst: - return self.localize( - dt + timedelta(hours=6), is_dst=True) - timedelta(hours=6) - - # If we are forcing the post-DST side of the DST transition, we - # obtain the correct timezone by winding the clock back. - else: - return self.localize( - dt - timedelta(hours=6), is_dst=False) + timedelta(hours=6) - - - # If we get this far, we have multiple possible timezones - this - # is an ambiguous case occuring during the end-of-DST transition. - - # If told to be strict, raise an exception since we have an - # ambiguous case - if is_dst is None: - raise AmbiguousTimeError(dt) - - # Filter out the possiblilities that don't match the requested - # is_dst - filtered_possible_loc_dt = [ - p for p in possible_loc_dt - if bool(p.tzinfo._dst) == is_dst - ] - - # Hopefully we only have one possibility left. Return it. - if len(filtered_possible_loc_dt) == 1: - return filtered_possible_loc_dt[0] - - if len(filtered_possible_loc_dt) == 0: - filtered_possible_loc_dt = list(possible_loc_dt) - - # If we get this far, we have in a wierd timezone transition - # where the clocks have been wound back but is_dst is the same - # in both (eg. Europe/Warsaw 1915 when they switched to CET). - # At this point, we just have to guess unless we allow more - # hints to be passed in (such as the UTC offset or abbreviation), - # but that is just getting silly. - # - # Choose the earliest (by UTC) applicable timezone. - sorting_keys = {} - for local_dt in filtered_possible_loc_dt: - key = local_dt.replace(tzinfo=None) - local_dt.tzinfo._utcoffset - sorting_keys[key] = local_dt - first_key = sorted(sorting_keys)[0] - return sorting_keys[first_key] - - def utcoffset(self, dt, is_dst=None): - '''See datetime.tzinfo.utcoffset - - The is_dst parameter may be used to remove ambiguity during DST - transitions. - - >>> from pytz import timezone - >>> tz = timezone('America/St_Johns') - >>> ambiguous = datetime(2009, 10, 31, 23, 30) - - >>> tz.utcoffset(ambiguous, is_dst=False) - datetime.timedelta(-1, 73800) - - >>> tz.utcoffset(ambiguous, is_dst=True) - datetime.timedelta(-1, 77400) - - >>> try: - ... tz.utcoffset(ambiguous) - ... except AmbiguousTimeError: - ... print('Ambiguous') - Ambiguous - - ''' - if dt is None: - return None - elif dt.tzinfo is not self: - dt = self.localize(dt, is_dst) - return dt.tzinfo._utcoffset - else: - return self._utcoffset - - def dst(self, dt, is_dst=None): - '''See datetime.tzinfo.dst - - The is_dst parameter may be used to remove ambiguity during DST - transitions. - - >>> from pytz import timezone - >>> tz = timezone('America/St_Johns') - - >>> normal = datetime(2009, 9, 1) - - >>> tz.dst(normal) - datetime.timedelta(0, 3600) - >>> tz.dst(normal, is_dst=False) - datetime.timedelta(0, 3600) - >>> tz.dst(normal, is_dst=True) - datetime.timedelta(0, 3600) - - >>> ambiguous = datetime(2009, 10, 31, 23, 30) - - >>> tz.dst(ambiguous, is_dst=False) - datetime.timedelta(0) - >>> tz.dst(ambiguous, is_dst=True) - datetime.timedelta(0, 3600) - >>> try: - ... tz.dst(ambiguous) - ... except AmbiguousTimeError: - ... print('Ambiguous') - Ambiguous - - ''' - if dt is None: - return None - elif dt.tzinfo is not self: - dt = self.localize(dt, is_dst) - return dt.tzinfo._dst - else: - return self._dst - - def tzname(self, dt, is_dst=None): - '''See datetime.tzinfo.tzname - - The is_dst parameter may be used to remove ambiguity during DST - transitions. - - >>> from pytz import timezone - >>> tz = timezone('America/St_Johns') - - >>> normal = datetime(2009, 9, 1) - - >>> tz.tzname(normal) - 'NDT' - >>> tz.tzname(normal, is_dst=False) - 'NDT' - >>> tz.tzname(normal, is_dst=True) - 'NDT' - - >>> ambiguous = datetime(2009, 10, 31, 23, 30) - - >>> tz.tzname(ambiguous, is_dst=False) - 'NST' - >>> tz.tzname(ambiguous, is_dst=True) - 'NDT' - >>> try: - ... tz.tzname(ambiguous) - ... except AmbiguousTimeError: - ... print('Ambiguous') - Ambiguous - ''' - if dt is None: - return self.zone - elif dt.tzinfo is not self: - dt = self.localize(dt, is_dst) - return dt.tzinfo._tzname - else: - return self._tzname - - def __repr__(self): - if self._dst: - dst = 'DST' - else: - dst = 'STD' - if self._utcoffset > _notime: - return '' % ( - self.zone, self._tzname, self._utcoffset, dst - ) - else: - return '' % ( - self.zone, self._tzname, self._utcoffset, dst - ) - - def __reduce__(self): - # Special pickle to zone remains a singleton and to cope with - # database changes. - return pytz._p, ( - self.zone, - _to_seconds(self._utcoffset), - _to_seconds(self._dst), - self._tzname - ) - - - -def unpickler(zone, utcoffset=None, dstoffset=None, tzname=None): - """Factory function for unpickling pytz tzinfo instances. - - This is shared for both StaticTzInfo and DstTzInfo instances, because - database changes could cause a zones implementation to switch between - these two base classes and we can't break pickles on a pytz version - upgrade. - """ - # Raises a KeyError if zone no longer exists, which should never happen - # and would be a bug. - tz = pytz.timezone(zone) - - # A StaticTzInfo - just return it - if utcoffset is None: - return tz - - # This pickle was created from a DstTzInfo. We need to - # determine which of the list of tzinfo instances for this zone - # to use in order to restore the state of any datetime instances using - # it correctly. - utcoffset = memorized_timedelta(utcoffset) - dstoffset = memorized_timedelta(dstoffset) - try: - return tz._tzinfos[(utcoffset, dstoffset, tzname)] - except KeyError: - # The particular state requested in this timezone no longer exists. - # This indicates a corrupt pickle, or the timezone database has been - # corrected violently enough to make this particular - # (utcoffset,dstoffset) no longer exist in the zone, or the - # abbreviation has been changed. - pass - - # See if we can find an entry differing only by tzname. Abbreviations - # get changed from the initial guess by the database maintainers to - # match reality when this information is discovered. - for localized_tz in tz._tzinfos.values(): - if (localized_tz._utcoffset == utcoffset - and localized_tz._dst == dstoffset): - return localized_tz - - # This (utcoffset, dstoffset) information has been removed from the - # zone. Add it back. This might occur when the database maintainers have - # corrected incorrect information. datetime instances using this - # incorrect information will continue to do so, exactly as they were - # before being pickled. This is purely an overly paranoid safety net - I - # doubt this will ever been needed in real life. - inf = (utcoffset, dstoffset, tzname) - tz._tzinfos[inf] = tz.__class__(inf, tz._tzinfos) - return tz._tzinfos[inf] - diff --git a/lib/pytz/zoneinfo/Africa/Abidjan b/lib/pytz/zoneinfo/Africa/Abidjan deleted file mode 100644 index 65d19ec2651aeb46c42ce7a74ae6ecbf3001edbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL@uTK{Uv%U>fLN5DjuOmo0ssr78}CcD`!UFH4Q3$=WF^#yf4~s(HDwBuVkNSiU*l`3EF}vz zSQ%e6B?}w-Q})LD+({AM(|Mn_bM7?vKEFhAezrsXs-T>(sYcn%k<3hdbh9s|H}kFD z)_KO;zUbFGYaiZjwnb-Wj`Uu-T<^Ds^}+IxKI~f6ho_ErRdBrPiL>{lFeLKkXpDIc!j8f=<+GbAle}6Ao?H*AsQhnAvz&SAzFQkT8LhV zVxOWJq8g$bq8y?fq8_3j5&<7W43H=waZp48iG?B>NIZ~;ATdFrGOU34ZCQ>j%W~v2 t$Ply~`M(#Qmc%40Nv!BpQj(G`iB0L%aXA3rc~ pK-fOMAq?(79PStb761_;Bv|tw2tZbWXpnUvnhYzsfNn700szD1FVy?NMT?AlPv%LfBe9} t0aDGth73jmNhB7*<` diff --git a/lib/pytz/zoneinfo/Africa/Blantyre b/lib/pytz/zoneinfo/Africa/Blantyre deleted file mode 100644 index 2972580dad6a37f9e7728bb828905fbb62df03b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIhx!KZvb)>E`UU36c|{1d_x$V9Ya7|h7b}A`VRzn M4dVius%yjr0NP*^CIA2c diff --git a/lib/pytz/zoneinfo/Africa/Brazzaville b/lib/pytz/zoneinfo/Africa/Brazzaville deleted file mode 100644 index abb0c08700a29d787d8682e020c7cf6fcac69cb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL@8&;fGzLO`N?0t_rZz99_Zj$kfB2nh!L2Lil? LaRE)$HRJ*SfPWF& diff --git a/lib/pytz/zoneinfo/Africa/Bujumbura b/lib/pytz/zoneinfo/Africa/Bujumbura deleted file mode 100644 index cac56524574480a440cb06b171274ad1e1292e58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmWHE%1kq2zyORu5fFv}5SxX8K}Lar!Pzkc$O*x&j|nIR!XN@(ks)h^n@Fw411QLs3b>bkejlD zh*BA$`$H*6$%;~YG0j?}kU`Cv?MYcef}Kg^Qk$o_DZ9GX`5vSK#s54Hm(Rn-h5d29 zzm+dqzI3v<<)qu6@Zr?h5AS^&>ksP2RBdqV#%0~~eOqw+_{aVazm5-1>}%COe%Bc^ zzp+#YAFd64+UV<(uYTmU6)o}GIwyJ;`Zf3$TKwSRrIfk!`HSMu<~q~9y+d67^nf&L z^VDBke>WYA7K$s?BV_0FEvl~3umsqPYU{b-N6aps8W zd2fUI`|A$byXlY+Z|9lNvOiR~ZlO$@8x!eOXJy8OcSPo_sOgj4qO!&&WLA4$5y^Pj zM4IEO-}xSsz5g54|5%|Mu&qnnv*!gfa8167zP3XSs;Cr$SH|8PS z`EfEYZ-II+{;eFBxmo1LuA2PwU#S97YYLi5)r8hh!}4n@Mvj+E{c2>6zBi!7hh@iO0vH6OHS?grnSB4Pd`xa#T(c8 zkJZ2A&G=xkUt0Z)H*;%^e!Q|ecw%*>o)xbMWJ$X>Nkxgz8L?}@~Ma*;@s z+h2wFy(qu^wY6X3i|*9keDB|D&-%mj4yIRWWPqfA^W~7R(`JmMjO2_YjbzOsZ6t3baU^pNsUx{_NFK=^Ngv6d!vr|( z3?NhBv~z$=0x}C6rU97;WFnB6K&Aqj3uH2o*+8ZPnGa+_oOVW#DRJ64K_&&66=YhF zc|j%ynHgkikhwu72bmpYdXV`+Cdg@L2$>?Mog-wDkXb^e37IFSohYZBsc`5nJ!$E8 ke8M67-!PWs&#-G{-|br2+x_2raz11A?_%AYED?$P16^j0-~a#s diff --git a/lib/pytz/zoneinfo/Africa/Casablanca b/lib/pytz/zoneinfo/Africa/Casablanca deleted file mode 100644 index d3d6da917d16c409ff41894e5fd23b8547cd3ec0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1362 zcmd7ROGs2v9LMo%C5`42DncqwMNA7*GhIYNNtj|zIyz~ZR+gEQnO7^dvbuyDq1S4X zkobp^1Vt^vBq6LwiEz^cETacx1z`;?!VsFy_p}IX5$!s|ozI<_#Vqdk=PUD9r&@oU zaQzJz$Ez>y;{)FBor9sd&d}Ct_Rx!Q=gH;N;AnccHTuOJoLb(ve(L^L+g01{G83=kBr-ZeOt$FQ^aZWPWgR`j^_d%Mz^IGtcc!uLhjF ziZR=Bq0iZzb~>2fDN^9-mx5InRl(jK@wT3l!t8b_Dz6fsyH>VjY?R{J9w}M4LP|a+ zOKEtPDjkZKvN5;Xb~8zpKa5Zn=i}7&?$2sR{e;@tHmoZ1pQ&9{H`MOrURC9JEPG-* zRQ1a1QayP~YNF3c%}7A};|;Q}uSIHyi)4RCnbh^#>Of0|)CUTcU0JFcn$lEb=2~^I zc)mKcWRW_YKB=0lkZPXyQZ>JQr&@k|lOqEU)X~=?a_s6GX}x<#jm1Gt1=Cd~F>-X{f!;=r`!_!9! zKq@fm5|A2@B8<8Uqzt33gMX(Gqpk!gg+nb!F-SE?IY>Q7K^!VVN;2x2kfMybDx@r= zE~GG|GNd%5Hlr@isH;QDL+V2cL@Go|L~2BeH0mmmGL5=Uq)?<%q*SCqZJkDo093YDbDksz=I4>PHrUtN>X8vIb-k$SRO!81*`k pg&-?ImV&GWSq!ooWI6bMttV0sDurbwdeV~8lTs2rYan@b`LMkDNsDX66DT7ijEvD5N z`?@ikYnD!jjU}0*T%*=<0RZl5v%9@FkPGd?Q?c~ogLiZkMntl z)^2UecWyfI<_$Ne)7(5yd;QCu-W!KoHw^f$cmo&fqsK>%MF)>%MBhHN$~&>w7k%gD z=IBXpo_F%QeO=?3;br5euXqW~-CYT1wncBdl;k8elt+_CO1n~efAentqN+=>j(B&T z>UZY!sHE?DLFTrE<*xM`WnM){GKzz8x4%d-)3W5Aq&p^Xkq^et1XitqU`=Au%w@cAPL>ABL z)5RAWWXX7&F8wed4}4Rr#r^eKGQ3nD+_PLuUrWpqEO|Kdq6PyK zQsx`c@{Dh#{PIt-BKBihF?v=W`QeB>IyfK|=RVTP-X2-`)?r=M+A5Fryr@+*ujuNQ zO91h zZ&Wtak4eMsU-YTcQ?jw{oHnK(kWD3n+LZ9FZl0~W`O>SpWg@Iw&vxk37ed z+FUo8_s-OsV92QnR)?H`c?j^}IIj7NUHji%H}wDCdV={eHz#6lo@e}HPG`~keK$hwKm8AhJVbi^v|4O(MHQwu$T$*(kD8WUI(t zk>QKpJ8-9YI=x^aN=N(iNmFNMDe~Ae}*4 zgY*Vz4$>W@JxG6$23bvqkQO05LYjnh32773C!|qGr;t`5y+WFWbPH)0(l4Z8R?{)0 zWmeNOq-jXkkhURxLmG#44sGjV+}OCu%Z<5l`KH9*n#)ANM9!Yc*qIoa@J;5)zHv!=H+5eLE^u>76cps diff --git a/lib/pytz/zoneinfo/Africa/Conakry b/lib/pytz/zoneinfo/Africa/Conakry deleted file mode 100644 index 75b8523fb2991ed402751e087afe8898e4bfb25d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmWHE%1kq2zyK^j5fBCeW*`Q!c_uxZ9kXZBj)u1eViOpd82|tOtOAk;0+#>(KYn1~ pfUtdhLm1qFINUJ=EC3=xNU-KV5P+-#(ID$UG#OTM0o`E01pxUHF}DB! diff --git a/lib/pytz/zoneinfo/Africa/Dakar b/lib/pytz/zoneinfo/Africa/Dakar deleted file mode 100644 index 31104133c293ab4358a8b52e7b6f66cd22150d6b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_uxZcjJ_`zywC7|Nq~wU|{(F|KkS+7LXDK4j-yyn{6`U~%c(ylNvF)}cyTmi{z8GxkK)-Z5D s*gn1?46cqL3{I|&p&=jzU=TurMgM^SWEqGCSqP%ZvXl$x4qam|0AMpL82|tP diff --git a/lib/pytz/zoneinfo/Africa/Djibouti b/lib/pytz/zoneinfo/Africa/Djibouti deleted file mode 100644 index 297d93a3e464f417f88e8719af0ca9410294b4ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOI-!~^7Llz>FF3>a8^d_x#q9Ya7|h7b}A`VRzn M4dVius%y*z0M_pl4*&oF diff --git a/lib/pytz/zoneinfo/Africa/Douala b/lib/pytz/zoneinfo/Africa/Douala deleted file mode 100644 index 8627f2e05e95e60f75766d0100db6224616289bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL@8%>Z&ZB|xHl0t_rZz99_Zjv*i}LkI~5{RaZP MhH(K+)ivY-0D}n;+W-In diff --git a/lib/pytz/zoneinfo/Africa/El_Aaiun b/lib/pytz/zoneinfo/Africa/El_Aaiun deleted file mode 100644 index 3275161b17a180e7788b534f24c65df108549a34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}dG>gGc))#e!vsdA|NlQPU|{(F|KkS+7N86R1BZ`q h2t&9d5W9we1sE7YNHF<75P(bvX(iqUE}&%wTmVZxCoKQ~ diff --git a/lib/pytz/zoneinfo/Africa/Freetown b/lib/pytz/zoneinfo/Africa/Freetown deleted file mode 100644 index 720b8e3c905ea30f521204e3c75c29e55a5edcf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 665 zcmaLUze@sf7{~GF@-!8!a}XM$hH5`VB4`St7K6x(%0D0o94-igXt=$gBdWPkg5U14hYYzisPI2W)D}J0frAf^$RiE|p;IvlG zN1fX4wpLGBR=s>~HWE2%oVMI%tY$U$M$DJ@jP<&nHCvCzm@nRA zf+xL|ZKB{nL4tw>1q})w6htVPP*9=ZLP3Ut4F#Pn^PwP=WkwW~vdoEs6a}j+)1u&& zWnvV}vP_MF8wEKEb`p@?;Y?acn7?RpxgxO^Cp52q^NvGl8pcF LHi*K!AU*sAqmnM! diff --git a/lib/pytz/zoneinfo/Africa/Gaborone b/lib/pytz/zoneinfo/Africa/Gaborone deleted file mode 100644 index ffc77950e1dcd6f5a117786228ab9fdbdf92f08f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyM4@5fBCe7@PB4UtYucy1)WPprDKbNJ`6qk;U0Dgu&S{I0VFJ2*GX~ zGf)bIK>)_){SO2Q@&zU!8e}wx1{===v_QfKq!wrk3)mJ8A779yNH#GrZ~^(cMqB_{ CJ0Udy diff --git a/lib/pytz/zoneinfo/Africa/Harare b/lib/pytz/zoneinfo/Africa/Harare deleted file mode 100644 index 258b393637294912a6d6c78973c09424136ed50e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIhx##rvN#!G9XbI1qK!$-w+08#}E*gA%p~j{sRGC M!?=K^>KbtY08XPjBr({OfPe!;oEyoU32fdx#AK*+!#Dgjcd zWxxm|WfT|~f*pfHKq5d8g53rdpcDv$02>g4*qr}?Ah+7l0Yrmr1JNKGK{Uu#5Dl^! rM1yQ+WM%?F1_mhypl*;OfTjQ)0VIKrVDa${L3RiO0~g3yx<*_84V*eb diff --git a/lib/pytz/zoneinfo/Africa/Juba b/lib/pytz/zoneinfo/Africa/Juba deleted file mode 100644 index 20284ff94b9bb40c738448781e8191b492d73305..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 669 zcmcK1%_~Gv7=ZCJpJuKZjIS}wQO8*c zZH?&g_J>54DmH4W5*vH9@d+b!-M&uvQ<79=>#1Jxp7wOT#3gl`(&?KQX*e6VjTbS~ zw7aP@`_HDia&B8z?@jA$(YDQ8n)c$d&h{Oej?|IOB{od%?M`>TA4r#-)A@&WDO^?U z=uXKGhkkh?N)=ArjaC0($lW~et0ZTYo?i&m^kkV=ph|9kuiy_EKHaLN;AfWuNP=WR z(ja+|L`Wti6_N`{hGeVh(jobfgh)mtC6W_KieyF7B6*R-NMw!i!N8!lhJhC%;^P~_;OZE{-~=T?LqKYwAcO>~{{sQYdJqkA0*D4V14L87DO^DJ I=^AqZ084x~F#rGn diff --git a/lib/pytz/zoneinfo/Africa/Khartoum b/lib/pytz/zoneinfo/Africa/Khartoum deleted file mode 100644 index 6f62fd764cef89254550b1e8204ffc6c98932605..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 669 zcmcK1y)Oho7=ZEjKHaT5oUd~nHlh$0iJ;JkuUsNNl1XkW3R5`>QRpNtS0NFNKR_cS zqS9zJBGHXjH7W`UrHXkjQ7J@WHnYFUCYwy2H(1_S8<8I?>b|g9eQtBkT%SIQoMdfi zXH126KWt>BY@)hiV-v3?KBaA4udfpRj7>_(c+zjZr+rm#<2H4hQt6u)+i*5%8ZTnH zX>VI)4xV*$`P{Uu-|N=-f@zz()a`{;l^r1(p$O*x&j|nIR!XN!#3=CXAGj$EQ0N4o))Bpeg diff --git a/lib/pytz/zoneinfo/Africa/Lagos b/lib/pytz/zoneinfo/Africa/Lagos deleted file mode 100644 index cbdc0450fc3b97bc436f6d90798a30ebe0ac30b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UITi+f4ghkP4M3uN0t_rZz99_Zjv*i}LkI~5{RaZP MhH(K+)ivY-0B~s$p8x;= diff --git a/lib/pytz/zoneinfo/Africa/Libreville b/lib/pytz/zoneinfo/Africa/Libreville deleted file mode 100644 index d7691ae56f56a0c15e753bf3c5e64b3b2b577d93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL@8T>|8A+yRO52{5qu_=YfqJBEO`3?U>K^dAWD M8pZ`QRo9RU014?6*#H0l diff --git a/lib/pytz/zoneinfo/Africa/Lome b/lib/pytz/zoneinfo/Africa/Lome deleted file mode 100644 index 297ec5dae3787fd9d0a549b19af4d403f4032301..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 139 zcmWHE%1kq2zyORu5fFv}5SsK#=QcCIO!#3=CXAGj)x)0NS<<)c^nh diff --git a/lib/pytz/zoneinfo/Africa/Lusaka b/lib/pytz/zoneinfo/Africa/Lusaka deleted file mode 100644 index 87d7a95fc7f19a45ba90bb27009c65616a0b521d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIhx!~{sD5NT0o*Q3Jfehz99_Gjv*i}LkI~5{RaZP MhH(K+)ivS*0Ns=mCIA2c diff --git a/lib/pytz/zoneinfo/Africa/Malabo b/lib/pytz/zoneinfo/Africa/Malabo deleted file mode 100644 index c70de1f99d9f6c8af5e8f6691ddeb3ac822fdd74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmWHE%1kq2zyQoZ5fBCeCLji}c_uw;bNMoVUjrjhgu@0T1q3V%4159%96r7w4DLW2 c?id0QX9yv|jDcHnHU)uBu{|kWfT}#7#Oq+7+HLL kLl}Y`gF`@~KoCNL+5dq6WIl)n*#V-7wTBC2r>+qf0FFx~#{d8T diff --git a/lib/pytz/zoneinfo/Africa/Mbabane b/lib/pytz/zoneinfo/Africa/Mbabane deleted file mode 100644 index be6ed60baaf85c3760f7f974b128490c5052f52f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160 zcmWHE%1kq2zyM4@5fBCeMj!^UIh)*$M*ump8X!>_1qK!$-w=ji$KVhUpCN<=IR=80RW`q5>o&G diff --git a/lib/pytz/zoneinfo/Africa/Mogadishu b/lib/pytz/zoneinfo/Africa/Mogadishu deleted file mode 100644 index bd08463429debfd950433c6fc8c1d53d5e732013..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmWHE%1kq2zyQoZ5fBCeCLji}Ikzo77x28t>joo`qh$aj7?d>_SRiay#}Ec55CH)p z*o_4$25A5TkdYuZ?|&dD*pu=DM1!mV(O_$sfEH00b9rcl4RiV0a}D< MDFXu+&;N& IPuG|W0PW#A0RR91 diff --git a/lib/pytz/zoneinfo/Africa/Ndjamena b/lib/pytz/zoneinfo/Africa/Ndjamena deleted file mode 100644 index 8779590e04a66e4287cabe801aee9c8d2d793892..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 211 zcmWHE%1kq2zyQoZ5fBCe7@K#}vxXF*w88>mwR;JSOpFW+d@>+;J^=<61_l`gMh+j} m5QcC^5DpFj$pAqJ3FiL?0+1abeIR>4G%0p*0qxc`vCL));UB04$6hfB*mh diff --git a/lib/pytz/zoneinfo/Africa/Timbuktu b/lib/pytz/zoneinfo/Africa/Timbuktu deleted file mode 100644 index da18d7137740abeff3e856eefd86ff70d104ee09..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmWHE%1kq2zyK^j5fBCeW*`Q!c_uxZ#;|A7j)r%F?E;KUjQ{`tXaEX>0L%aXA3rc~ pK-fOMAq?(79PStb761_;Bv|tw2tZbWXpnUvnhYzsfNn700szD1FH%piB-tcL?a=QhecxH`5q>d#B+J>bN4KFzi+U-x#5dntI3|QSxLKj?mT$C$lRV) z-MjRWte3Cd`op?zj83V>VNE}kE=||&jP#n{l=q&~-H*d2ezPijYR9Jc{9YzbwoP*1 z(|vobs(L7)XN=PZB7E%nUhLl6|{}+zg+#`PM6Bikt AG5`Po diff --git a/lib/pytz/zoneinfo/Africa/Tunis b/lib/pytz/zoneinfo/Africa/Tunis deleted file mode 100644 index dd559ee763401a47ae9a68883bc254b628aa1b30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcmZvZJxfAS7{|}`B~s8%1V-Udn%Pi;QHwZbD$$$J9jeJ80yhaiKx0CK^#K}cDhm1v z6(p7Rwl*jQxy2n?qn_Udi>&A2IlptyJ;UMmH&^rPgQmcMjd z=sH@nbg{n>I*420#E3OC+GjpJuH zs%M;M+G#ipr|Y}rtF4uC#CUaZz;G$$*UHmcImynODw$ehF_kh5Zc3T|Tj-Eq3>A`L z-~B1IlJ0qj7=c)Un6W8#Aci28Af_O;Y>F|PVhv&rVh>^vVi96e-k`7vF$%E?F$=K^ zF$}Q`F%7W|F%Gc~F;8J1k^m$HND?+B4M-w}%i(mm+}|x=GrNpG`;-Kty4C9GZL)gMsGw9x@WBqXCX^*>uLe|E-wauIY@sT@ zlBp}UO;ziUPScfv6jN2}(i>7Hn~jBU^ri{l%;vbedh_R(rh43KseamPwhrBqn%)-mV&(OQb1dgK93T(K}-D)XwxGy~|x`c1OqS-EVWu zo?(w}xjW0WzWAi~UUZv%H=pRX!|%-g^B?6vL%2HF(J$@30p$vFjdF*N%tvI>RQ}wU z>Eafdo9MDndynMl@`!kpxctGKfcSI#0m-wMAeTQE__sQv?K>P+VGs8yKke$g)rIKm&?*ek7@{&nXNb}ets!bd^oA%7(Hx>WM0bYr5bYW2L-coO z6M$sk(53*%fsq6x3q~4{JRpfcGJ&K5$pw-OBpXONkbE54gdiC?v?)PyVk8C0ijfv1 zFGgaJ%owRba$_V1$qtepBtJ-kkPIE#6d^f6l7wUlNfVMMBvDAFj8q}Hvfs&$3JZ^L zkIY9zjp2uEx#3Q&W1VvC)0S(SwdIa?%5|6cY`FigS0vKDFfWO$<9%rfNePMZz7!Do E3+5nPNdN!< diff --git a/lib/pytz/zoneinfo/America/Adak b/lib/pytz/zoneinfo/America/Adak deleted file mode 100644 index 391ec98ec0f31cd595ed05a9b91a41c4cdb25d31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 zcmciCUrd%&0LSr%zb~K|6%ZndLdHwdwv5!Hz6D=S$_GwO zxKVG9$_M+-x)1GrPd?l_=tghaCu2%`-Prs_`ABMm8<*6h7ls$Q@qt@({K}-I@xQuy z(NEbbVLVGO{yIi2`8--DzJFUS?JSYY_D`y$npBy*{SWbI?mW4?Y(hL1Gc8kAoE0hl zaGe@4C{m|>(JOxL6)VRs>a@%6sPv)FbjC=xTGe|@i-CHT+48B(>X0hCu}0^hF$-_Z~dY`^WRlkE{(@oYkxjSsvQ;abbZR zvqE5r$QqGFBCAA}iL4V@sMV|#S*q2n68Wq-;ptkisFALrRC#&T5K>RL^S4 zht$t%3W!t?DIrorq=-lrkuoB6L<)&i5-BB8OQe`cHLa$cNIk8lph!inrld$sk)k41 zMaqiQ6)7xIS){Z`ZIR+4)wP=PBK5VJ0wWc+ni3;5Mv9D787VVTXQa?LSLvYOz>v^; zJ)ZEe`}jD{CqL5Zx~+Uov;V2JDYvP$`Nh^cz|^{&s2A|4+C7E;j## cxpqfT^h`nA)5^0mvNA+kd1hutW`>CP3w~*NkN^Mx diff --git a/lib/pytz/zoneinfo/America/Anchorage b/lib/pytz/zoneinfo/America/Anchorage deleted file mode 100644 index d14735026a09cff0104e479fa6543301d482deed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2358 zcmciCeN2^A0LSr%*9!zjf`LeMd;#Ru0}4V>-YX!W5+Jvm7%3#iuo4W$@Qu=R=2lX+ zIh>7-b8NLqJJYRnExKi`P0TUedKt^qt(h!c>unar?R*dGubS&G&$H+GoZayk+wbdL z*Y;Gt^RE+Oe&OZxnU{Oo$bmxt*!*8Q#+sMQKgKH5)ai}xz*{S%(_iimdTF5y?n!rt zY%SBF&87aZx-=c`N%gz(BDCw34gSd32^~2!?vDELyuR!5h(G%4>oUea7=aq*rcD9 z>p53bRr1&Zec#6}m2xs%-+%1765Yje?(Pva&o@WT-~7E;Q1F*bU3pHV&H7fRXPyx0 zQY&KD^o`D(=nz@MAL{IjFRPq^V>iRe7yS=6B|+#T9$xlKOa6 zklrE-^M6xIT`Oc!a-1l-won#N{wf~$EJ{8&{-r3f==Ri_5!${USh)f*q_)nD|e>Yc~+ zBk!(LHI4gp?cowtSJJB2bf>8L+FY?!(t)(u9> z$1j}~jeBp(Cx!>b`j%0-VPL;#s{TPY??0}d%(wU3I=A`Hf zBZtDfO;z3tW^wSC|Nz2mDcwX^q4z3a43^{(HopYJbHLBUQ)=>cLasnZ>0TYhP}t}brJ)Cz88X$?R{>k$Lo}O9^+H%bv%{ze9F8| z1D93i;#p;GjuT{F&a~eD9#@q4176N+=H;FlFlU+nas=+$@2Nxvhm6i@hKGy~?Etwj zLXH_CFh*pM$S9FvBI85`ij351hKh{UY6gpp78x!wUSz;;9V@3vzj2am>GHztx z$jFhQBV$JfkBr`GhHo|FM*@IE00{vS10)DY6p%0=aX}O(dLF6Hg?dRufSqq*fDCB&bMK zk+33hMFNXN76~m9TO_zhbdm5{O?;66TTO(K5L-=*ksu>cM#7B583{BJX`BvqNN8|a z`0XB7WW*hO9Osi;q`I@mew&=>V4F~yc*odm&$Rahn`#qmlWk$|sjI6g_Ww)wKhfqN cF`e%yqFzkiv#S^9=I6@n>b$(%yj&UeH}EZKga7~l diff --git a/lib/pytz/zoneinfo/America/Anguilla b/lib/pytz/zoneinfo/America/Anguilla deleted file mode 100644 index 20bc9464b8dc49f9e814f26dafca1e779f763b6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVPK%Dlq>4f8+rJ!~g%s4=}L!_=Yez28RIU7#KoG QFz7!J;5Cd3XsQVp052#U=>Px# diff --git a/lib/pytz/zoneinfo/America/Antigua b/lib/pytz/zoneinfo/America/Antigua deleted file mode 100644 index 608b635977bde87ab1e17875905d25b8fe1245a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_y11f4JjxCxDUZ|NmnG3=IGO@7%z^^8f$w0}LEK hz99^*!66KeKnwvPB$)gk2tcNTXyR?)0$OIm1pv^6E<*qS diff --git a/lib/pytz/zoneinfo/America/Araguaina b/lib/pytz/zoneinfo/America/Araguaina deleted file mode 100644 index 34d9caf5a79c3953f47e1609b64f12b06d7926ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 854 zcmcK2JxH5D9LMp;S_4LET{<|Zry-leUz2LAR*IWY1?>ZU89IrmOFLxHLD0cTP`W7S za$|9j8)GMhw(4XEmV#(Z>sSXBUqZB;_r2B0!3$45A=~r&Uie{jxHY(Q%H2OaoEG=+ z`^myeS~5?23z`3~^xA1szU9+uFSROr|4Oo7`^W6By;ld<&m_N`SBD2nQV0|3e9@YV zijV4YeMqjV>veIUS&ExKR4JM>rLRSOeH@XS*-2fuJty_!zjcFtZd77NH%^aAQ`MG^ zy{j>?zn@jS{mjI7H2-@Dt0K!H>w4Y7$jV-~G_p3bII=pjJhDDg0I7hKKx%kh5u}ROl|kwtg?LXY zA*GO7NHL@uQVyx-bp?@%URM&Si4;YuB4v@fURM~Y>~*D)+DLJvI#M2~kK6#{7U09( Kgs8g|iRdjgKReL? diff --git a/lib/pytz/zoneinfo/America/Argentina/Buenos_Aires b/lib/pytz/zoneinfo/America/Argentina/Buenos_Aires deleted file mode 100644 index 5a52a51fc85a32108cca83676a4a78404568288b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1061 zcma*lPe{{Y9LMqB{?!^qMu#FI7AfMoJeX@y2|wAv3ccu{@Kg{%5ELCUh>9+qf7j`qj^Seg5)L zQrR0F{@Sr4I@)|TzbiMco11d^med#B^65gpb>~LaT0WL<^FFIKy+5C*R@Cm>N8_pb z3%zeTp}Pmy>FzgIy&|!k)1L$GBz@}Q$|OIcgpxk07wK#2u_Is2?B}2DPbUS zI3*Ay5+oEP79#b}ST_@5pY` zL1<~TtI*?6ElssYV~utwfwYL=5K!C{l^Ehzum9&{5(RrN_x=u-OnINo@aa=M-d|Un zeBt3bA`jS30ta8su$OCdLebkEPT9f7gN4kG#_jw z)@zoMCvB}SqH5!H`!#$<)qC1?{r$LUY);xnsiMBsM)dc}0rR8SYk$rTs$cigdS$d% z`8W3Kwuz%A(s?$&J2z!I+jIG@#23@`=|aAH*9O&HKAw+xzK)qg`FORW_S_!oNYtO3 zgL84C3!jx-^~CUSus~F=RDlIj5|LEa;RK zktLBekwuYJk!6u}k%f_!k)@Hfk;R>|It6 zr8uP)q!_1EgOr2RgA{~Rgp`D?CJs`R{I?!eA!Q+TA%!88Ii)nDHm4MaROgiPkou4U zkqVI#ks6&+BvPf*l^G1I?hZ?h+^xKW;Z}LeRMMCWv>Bp{vSpnMRNfM(e33vmHqXZ- O(Emm1c~L2MU-UO#U-2OT diff --git a/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia b/lib/pytz/zoneinfo/America/Argentina/ComodRivadavia deleted file mode 100644 index b9c987bb56894c23ca7a74d02d792585e3f4fe00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lJ!n%=9ES1Re6%qtRs|Iisn}8y9S+qRQ46PJD2Q3oK&6v|2!fzESV2@=oP>Y` zL1<~TtI*?6ElssYV~utwfwYL=5K!C{l^Ehzum9&{5(RrN_x=u-OnINo@aa=M-d|Un zeBt3bA`jS30ta8su$OCdLebkEPT9f7gN4kG#_jw z)@zoMCvB}SqH5!H`!#$<)qC1?{r$LUY);xnsiMBsM)dc}0rR8SYk$rTs$cigdS$d% z`8W3Kwuz%A(s?$&J2z!I+jIG@#23@`=|aAH*9O&HKAw+xzK)qg`FORW_S_!oNYtO3 zgL84C3!jx-^~CUSus~F=RDlIj5|LEa;RK zktLBekwuYJk!6u}k%f_!k)@Hfk;R>|It6 zr8uP)q!_1EgOr2RgA{~Rgp`D?CJs`R{I?!eA!Q+TA%!88Ii)nDHm4MaROgiPkou4U zkqVI#ks6&+BvPf*l^G1I?hZ?h+^xKW;Z}LeRMMCWv>Bp{vSpnMRNfM(e33vmHqXZ- O(Emm1c~L2MU-UO#U-2OT diff --git a/lib/pytz/zoneinfo/America/Argentina/Cordoba b/lib/pytz/zoneinfo/America/Argentina/Cordoba deleted file mode 100644 index a703e957d5ebe02e0651d77ddfff4d3f7b8b851b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lPe{{Y9LMqB{^c4)R!|WUixk|*%7YB1M9^VSbSom(SXTb}zMs({3iA2!+w0+nCqM7(;OSG{&R?fZ zzVLDm%FBJj*v*`JcqyYFZGB}Xx99Za!Z|gy`La7TF>a=t4|MU?YxVfed-uu3h?$w* zqTRuqc{(zppB*Tv(v^z)d|SiJ9uMl-<+v*MCf#!FzIu5rujkTt%-pBz?tI!)^X8*l zjU~)N>ZDum39I^O!~GgMqZ-}qy76JuG&iQ)X1S`q)ra&_b+7qeO1M9Y{p#o4j9wm2 zDDTD|-8O#2gged_cIGEcM|-}|nfzipKVK+x?O3O}D#r>j$I~&hzYwog)vntE(PZO= z**6n6eM75F-`lIvLrY`kaPdUc=U?Fy478pQ`t9BGN)^ZPyt3;AJ#Vq%3wz$X8o!Gb zzR35rt$Qk+b$TL>5I>MV3X@MHWU@MwUj_Mi#fq>d5j|Ssy6?slX~FAT?N}2&4+645SXL6oOQO zlwy@ykYcP-4N?wL4^j|P5mFM`nz%?&^1pSc3MmVz3n>h#%qpcJwOOS&q&lmVht!7@ zh*XG_h}3A6B9SVwRc64yvL_U5J*zNa@4wTOKwBZ&D1B>epz9*9A{fL7 z0>zcrsHcN9)bgoiGY>MD5>bay(JhHsWBv2(_kFqucG&aqyq|}Mo%Z{tN6(z@ceboH zdEu}Iiz9*{qvM=>`ItMsiJ<=#@(NlBl=e{W`56)s6Y2p?#4t+ zc{dNct<%SKxcgjwe{M#1x99Rb@o&24>sY=wnlZf}-suDDH{3owkdIa?>foJBSG@j8 zA6wxC+}Fy!u;+cO@?9(QBJbPn`_9ep ziDcRtN^wTgPKKL&?W@GCgF1$P}$INo1Nf5Lw+@9Nl_8}ewIRh>r8=ZMtJH@Sh*XG_h}4J_ ziByS{X|;6*{LSr9kloVSf&n=)m?iR*NdLuX!}M*lG0ImWl^2P0hmCai=Jyj4Y4f2< JgVOP#$X|a10A&CG diff --git a/lib/pytz/zoneinfo/America/Argentina/La_Rioja b/lib/pytz/zoneinfo/America/Argentina/La_Rioja deleted file mode 100644 index 333819a15f79909ac5163a69b136f60b4591e2a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1117 zcma*lPe{{Y9LMqBoXfR}te_$yjQrD9hX-pJh4IJ^LbS^q2%b7b5Clbs45Fe-r(h5x z2ozUdgPsm6ah6XlTM5ZvjtDvoif%=Q4g2S>@B7&)3iA2!+w0+nCqM7>(5aK%-e0Fh zzVLE-<>kKd&W((Ea51GHZhL7ac4YL#{8=@*<&vGukDJ2MeLZ#awR-gCy?uNkVx|jQ zwH?ZsC!?eK>EWU(UM|~b+v{fLc(a~aj;T^#k1f^isTWtXdNz66%znCN=aRmfGaqdw z8aMNa6LzsTtQN=W_G{?0s&}{Q`iC*Iv?*biN)`2Oaaez^956qMar<*>K>fO#(#s=p z=0{dYBf zt7X2(_jQeXBANF3QoI9cZ;;!cC;ji4!tz(VoFnpb-|WjdH)8f8lOeMq(;@RYWkO^| zr%Z{=iA;*jicE{li%g8nj7*KpjZBWr?v&|~`JIvgk^z!}Q*uC(a7q?P8b}^UB2LK! zNd?KpDajz&I3*nyZ|c7m^r~8Iqb)azm1HN_I$kNPbR9 z5Xlfp5y=rr63NmjX(D+#U82FJl|3P;l4q487(&@jVsoW7iga}b*1A&VS4x#HQtF1r R{g{;czgj&nA_?z{{048w^9%q0 diff --git a/lib/pytz/zoneinfo/America/Argentina/Mendoza b/lib/pytz/zoneinfo/America/Argentina/Mendoza deleted file mode 100644 index 76afd5909e0ed14e11c249473b34744ef58170c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1147 zcma*lPe@cj9Ki9nyYKmr0!t_h2_eO_%V3&886$fzqP?t3f~O8q1VPaugZ|N_Q?L*c z1d3Z;gQma|wVc{)OGp+}BIvMDbSomZWwY}2`%V|Z4$d&|I}U>2?~@uhb)wx{v#RBV z!#W^`d;Q&;Y4zx0Qa|4Q+Dz<7>xsp)YI5skJ2^gPrpgcW^sTq*$-7VX>4h3IGgYtc zK-xST8PU)8XI1t}-o9uknb~8$o?U5Ext=bYE8JJFt_|tA#2qvD^}3x;glgV=u?wx8 zW-)%;7Q3rdakONA1gBN0y;he#kD78_+?I0->Su9KFE8vhzp|b7_jI57b1$h^hC5Yw zqeEAY9X3@>XEHm7#!XZ0P^P)-yJ`M*KGU+TL$|!inqA8$ZL2wC+6o`^?%Vy1U8R?1 z-%Oj)rq1*nJ!pFet4;6wtBsN9I=3HV2Nkkoe$)@-r!dUsJueJ%)|2~EK2jBi9}9e! z^1R6VM)$sX^?N*#@_Le-zLeL`O+Ip6yHfw3TaElCht(~IdqXJe-0(yBt6|6tDRZRE zk}^+MnJHzit}MN1}F|(#RA2HtC*m;pxAH~9~2|5 z;)G&_;)P8M6F dIG*wqw(=ruH#xRjR=*z+w(F-WDn<65n!okH1)cx^ diff --git a/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/lib/pytz/zoneinfo/America/Argentina/Rio_Gallegos deleted file mode 100644 index 65d0230a2d06ca8b94cfeb60aee0ba3b1a3faf0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lPe{{Y9LMqB=9bHfte_$!j1<|rJXp4z}{A?`IH2LH>UH_ImbXr+wb(fs-dXy}zzT zdBekXSRT%sZ(Yl%`{z^o!HySZYG+1IEuL1>+b-DY$qAFI-PJSKU#f?%-r7g!n#^o& zyS4)v^LT7bKRJ|F`HMySw54k1j)(NzN=y}c;|J**tJo06pv-2-ja%%gV|W6r1sqCZ;e-< znFF&iqjO72m)F_e;kBms^`+K8aFutc;kP>&3d=X&&lf$<_Y2mObGaCZ`2L#;pXDNN z~PwAat+&nx}!g(C7R9QWLacgWMO1wWNBn=WO1jgjx6t#^^pRQ3Y<~`QiD^9K&n8>Kmj-*1M6L&@+pDJ8wqq%{d`mc O{a>V>*CgfcZTbmWsqo_f diff --git a/lib/pytz/zoneinfo/America/Argentina/Salta b/lib/pytz/zoneinfo/America/Argentina/Salta deleted file mode 100644 index 963917a01a2639bd782d7f3580647153dc4edc5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1075 zcma*lPe{{Y9LMqB{^gP)E2xMFBSp3@57t^J!6Q2e(Jpgfc9+qfYQ-qiSyFWji-BW#*d?^un#z>hYWR_Q}O|vpBy? z+mW1kIx(T2^%qs~O4&Z&(=baX!+L2gu1W(*TdLhxFR$hGa{7*0{&d~0qXQxoHF8!pdOLLE!=!0$PuXUvqQ2F~^!LhP^P`xsKNp77uj!0l8&4?z z#v$D{b<9M&&K36OXG~W|zR;cgV!A(HDD>>xqI$|F3Ng>uG1FIw*DC73?cvU3GGFBT=GHxx&UynG z&QR7H=Jw~4{r4_W`6~`jzZ~v6e0k1~->V`UAv+;kA$vJxGh{cXY=`WJY>4cLY>DiN zY>MoPY>VuRY>e#el&z7yow7NyJF>k~_D33UN(V>_NDoL8PU!+^1L?yljUb&kr4^(X zq#2|eq#dLmbPaKlj^uyq(Gt=V(iGAa(w0;DLK<^QXGm*K=?!TP=?-ZR=?`hp={gJr x*Y`%kt#<>4JR_` diff --git a/lib/pytz/zoneinfo/America/Argentina/San_Juan b/lib/pytz/zoneinfo/America/Argentina/San_Juan deleted file mode 100644 index fe7007b85ca4a22659c2c3093d078893fa2f466d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1117 zcma*lJ!n%=9ES0mFB^kmRZtO;iv2KgIaFgrshp6ZAa+Rug-#A42nEH#3ZmlTBm|@g zLQA4u1y6@)Nu#}*)@Z>JNQ(##1;tHKi6MUV`hQL)QLyK7^E+HR^?fqKXHNGzf1Nh@ z!prHCm;08xH?!)&rL=yy^M#q-oz>Gz=Tvd~Ww%(EG&9X9UApy3J$n7leS9%uW@mP2 zcQ|XFOibvfN6V^wrRvV@YMA+xK|Q}3Q{ z#?4adlw0o$t9q{CehrPNMsK@ryw92D)|A_<)YP~7sQz9%WPX(6?$6So`gJd@SI6VZ zyKzvrO&&Ml&a?TwV+GUMK9=uFd@)_0F64XmY*IZh3;BKB-8$-gR#9^#A6u!Z{kMlY z5{+l(@NCTJV$LK3O81YhH~nv}cKG~je1d`26SDY&=y~O;<9J@hb>zNW^@Tm}?Fzrk zRldmgjjelXAmb#{yn`8Mh})kh^Y59$@>jf^WAbv}=E*rfK2<^{LuNy!L*}!}gvg9m znG%^3nG~57nHHHBnHZTFnHrfJnH-tjD$^tLTO|P`10)5jafXp`b1S;_y_AuS{?Brzm2BsHt#h9qZ|?2z=3{H&57 zk|B~Jk|UBNk|mNRlBd-s8t|{}2}zYa>nwo~%9e99Dy6oHv~~J6*iz+JN|i5C>gLw{ Qgp~TfS{)}M2_K031`~$z4FCWD diff --git a/lib/pytz/zoneinfo/America/Argentina/San_Luis b/lib/pytz/zoneinfo/America/Argentina/San_Luis deleted file mode 100644 index fa30a68397d231324df70d2d7833a95c68228fe9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1125 zcma*lK}eHf9LMoj_ipbR1y)d2(j~?6^dOo+7|-yqlDy18;i*FeK~QwaAPTy43WSnQ z%2v`X@QJcyT0XUGB_)d~(M>426%=c%Qs4gH$5Yh7_vL**4=+3I_stBPKGp91a|QB+ zhpSs2&W(3&45>$#()#hv*Jg6}ke*yPr}En`+x*0snX28_)3@HMCm%l9rxz1uW~x!! zfg$s3bW}e-SWty4CHtbOYGzOPdUmx<6_Z`IxHPU_T^-hQeYefr*K2mZFI4m9i!JZ# zGz&c^ZKXS|D%q<25j~@-?G3v6IcsWLdu**(RzE9)`d4|s`CaI=%hUa8JWdfy$_b@l7K{Rnq77WHF()Q`mE6br*b$@9XnXgxm+7fW^V zF#Nd0d$Gh9`M$}0-_p~U@seqt{)~5wlf2~k_m%noSaJCk57!}iI5&lIogW#0hzy5} zhYW~}=#(LmF`Y6fGAc4GGA=SOGBPqWGBz?eGCDFmGQLv+Kq7ET2uKV_5Kf5#3BxII zAb}u}AfY%V79Adx7Y5~fq)L;^)3#kEi)_3OK%(x+4!#G(PY2675yyEl|7y{>iX d8m-&tdX=~IDqp16&92vNN2S;GHS2ka#2*rw`nLc8 diff --git a/lib/pytz/zoneinfo/America/Argentina/Tucuman b/lib/pytz/zoneinfo/America/Argentina/Tucuman deleted file mode 100644 index be7bd271639a551eff3b1bedb3b0646beab4e9b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1131 zcma*lK}eHf9LMoj-E>Kj6;wpTB1LAG2Wu^g>JblCw96bAo(d!gf}%qPQPHJSFo+QZ zic332Jsm93l}{~O8OUNv1Re%Ox1wSVv-0i#eRhh1d|%%8^X$cwzi+blnZi%LP9^>^wNxNN$IiKGirRpMLRw^VkQ>u>+Fp;>e1Wx_VM{fGdZzQ z+uoFUGB~K8?#-#(rGkC7xnib{1@zQXo62{@Y`%0)y||Lr)A3to`qNcA6Zh4O`Dlxg zsG05Tv*mpuRUWF?Z^2Wl(%z&iABN1rx=y>0FRJh5e!W=SWq#zM_Gh+R{koITO9N5m zU)!l0Mh=@$^XbgC^r&fWN@rSPUro#BbD7qyt5s{^XeQ$MI%4)@+Db*W{bo-%R(WoA zPqrC7@kQxZuXR`d3ez=zIec(&*c{3p57*Q#^A6Ni?;zF&g6@~^=L(+Z`+4gHe1EP` z6Y~9cCEjxdzR34g)pKV&>2)M{x|3cHr$4Xczqbm>U-57qkcabnU#_zQcW)!RA=@GQ zAsaenM`TNLzgoYDc(0@8z1nn1d6N*hQY zNFzumPH6?{1!=}9-5~8ar5~grq$8vyq$i{)bX{?fw&Z{7(HGJf(izek(wkG7L%MTH zdq{syX%OiUX%XoWX%gwuDQzNsI;ByhQ>?aHSG&ABD1CC*^R5flyI(TiJh4i$)ihnE eH7i}R@|I-fizK_IdOjk_{x4h4Ym}CEH2wy7l=|QR diff --git a/lib/pytz/zoneinfo/America/Argentina/Ushuaia b/lib/pytz/zoneinfo/America/Argentina/Ushuaia deleted file mode 100644 index 18590effb093a4429c23fbcedaadf5ec0fae774e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lPe{{Y9LMqB=9X&}SwTfa7%8%Kd9c=^5+2z>i0q&P!&8R{grMkjq5&d|7PUS8X?31lkGj}wk=a%9s-4>PxXw`lWpHS8ICS83yYHAx&ww5odFO@<4wYbN8%O&jhnO^ndc8^{f zPALECZrwO`&_r5JW_M&JOiNQH+nW4jT0fl0wryXl+6qUqG4G>_nSI%Kxu|yD=xa_^ zpPIe1aii}aR=Tvxb`7pHU9T=S2ZGDILk+*(!BAMf`F^h8dA^^wo}5dCK*aZ7m-#Fe zcq8xE)X%BzwAb0g)0_7CIQ@C0|GiK|e#OJpArI$`zFen=$FCr3A&ViaAsJ!CKTovzG=;PURU)cEUe2(OT{OjsjL3A7%fi!!j<1uCBssJxLt*VWI5 PB+&mw>UmKqcUSZ$aBT3H diff --git a/lib/pytz/zoneinfo/America/Aruba b/lib/pytz/zoneinfo/America/Aruba deleted file mode 100644 index 73bb7eaa81662d3d6a36c187d6be8a4dce232161..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_z#0TYQ`G#)FaR|Nng+3=IGOAK1ab^8f$w0}LEK iz99^ben1=?0@4EnAtadm9|%CEgJ|My-~w7^!UX`SuPyZe diff --git a/lib/pytz/zoneinfo/America/Asuncion b/lib/pytz/zoneinfo/America/Asuncion deleted file mode 100644 index d4014a6b78933fad9650ee005632696ff923d074..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2036 zcmc)KYfRO39LMnkcnQP=O##VnRw&}(ckl!lU4DcYGzf%)2;DRcfs789^3n~P<TpjM_dHT_m%bk-Kowrl3j!D8`yH0!Wj3gfZQ>SmeW^V3UY-iMl zB&mJ9CT}c~nN{!FSu4JjTk_NF?2M~sPFjhk#Ai#&c!y2BSZC5M^y%EMelqD_#OYyZlmAR?a=AD~BtjcwBTXCB)%qGcVPDUV*W zYnsxfqWlM2x$19;n3J|@;rFsO>0?_R-!Ii;Z`pM}eHfO+zR zdVOl&PV@A(VqM=_Z#L9q>N6F^rfzAXZp_Iv&!&!QefkR76g$ms`fGtSjQnOBFC<7) z|Db*D_^-0L`>=if!*kNSqs#pbk!Vwow$z<9t*iHHTTzc`&ur5d=kGNyB~alcw8G<(ZfJa_uXJD&^I#RQuZQ`{ec3aT^mG6L%v&o;NTS2zcIU4NUU9 zZ-yqmV{V#wQ&<`al-F=qM%-z=entNKfKPG1b93!*H_yqQyBc>TcOr+KA35;Ip+^or za`=$}AR|DAfQ$hd1TqR_7|1w~fgmG6hJuX6*9`_44Kf^LJjj5M5g|iD#)J$C85J@t zWL(I=kdYxnL&k;-&ex3&86Gk|WPr#Bks%^uLw2~ zhKr0B889+pWXQ;vkwGJ)Muv@y8yPq}uVBnU_p zkT4)|Kmvh80tp2Y3nUmwG>~v0@$hv4K_Y^L1c?a}6eKE0Sdh3Nfk7gJga(NX5*#Et zNO+L=AOZ4q5kf+Q#0Uuz5+x)|NSu&BA(28tg~SR877{HaTu8i-fFTj{bsRvr0oI Q7z&zflT{iH=J1g44=b$^3;+NC diff --git a/lib/pytz/zoneinfo/America/Atikokan b/lib/pytz/zoneinfo/America/Atikokan deleted file mode 100644 index 1b49e37c943b55e971162900aa3c7ed4d2d6698f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319 zcmWHE%1kq2zyPd35fBCeHXsJEMds~T*f4+B&w>*_!V^w+{A;+R{H5ShBIgGNMg}Hk zmjC~EZeV2i|9|xY1_+x2EW!gK83deNLKvKbfjAt9140;FfovdPgb*RvT>-Kggh7BE zh(T{t;WU!WtgI~d|(Ajt*vfhiXN%5QKt diff --git a/lib/pytz/zoneinfo/America/Atka b/lib/pytz/zoneinfo/America/Atka deleted file mode 100644 index 391ec98ec0f31cd595ed05a9b91a41c4cdb25d31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 zcmciCUrd%&0LSr%zb~K|6%ZndLdHwdwv5!Hz6D=S$_GwO zxKVG9$_M+-x)1GrPd?l_=tghaCu2%`-Prs_`ABMm8<*6h7ls$Q@qt@({K}-I@xQuy z(NEbbVLVGO{yIi2`8--DzJFUS?JSYY_D`y$npBy*{SWbI?mW4?Y(hL1Gc8kAoE0hl zaGe@4C{m|>(JOxL6)VRs>a@%6sPv)FbjC=xTGe|@i-CHT+48B(>X0hCu}0^hF$-_Z~dY`^WRlkE{(@oYkxjSsvQ;abbZR zvqE5r$QqGFBCAA}iL4V@sMV|#S*q2n68Wq-;ptkisFALrRC#&T5K>RL^S4 zht$t%3W!t?DIrorq=-lrkuoB6L<)&i5-BB8OQe`cHLa$cNIk8lph!inrld$sk)k41 zMaqiQ6)7xIS){Z`ZIR+4)wP=PBK5VJ0wWc+ni3;5Mv9D787VVTXQa?LSLvYOz>v^; zJ)ZEe`}jD{CqL5Zx~+Uov;V2JDYvP$`Nh^cz|^{&s2A|4+C7E;j## cxpqfT^h`nA)5^0mvNA+kd1hutW`>CP3w~*NkN^Mx diff --git a/lib/pytz/zoneinfo/America/Bahia b/lib/pytz/zoneinfo/America/Bahia deleted file mode 100644 index 9735a14a6eabe19b22a55eca67ebd9b649884bf7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1777 zcmciCYe?019LMpaTR}#(pv79ZZ%K%GvacR9Yi-1$8)esjW!AcxrP;-tv~DgdfU&IXt$#b#oO_m|Kekj#Q{E5S)Sl4hKEK)KbMxiF zn~$~SV2eC_P^YayOkUK6_U}%MrklR-zZBP$QJKtu~BhNH_e~k=% z(#>X+Wt(WjSsk|GqGXy{9X{chX!Rz|>Ys12=ZTGVUL`qsf#$@2mRuRAxs4@e<0XR*$dQD#=rM4cV!Yl3m< z8a&RExv5=s?zK;)Ao(vXINl-iA2n*>?iN{az1=P>X^^i@-mr@%9g)Q~r|gof3ubBA zKD(@^F-23pwnd5aQk*fz7T;WMR`#mUm8U0|k{5xN))mRB+qqh{dAzJX^NFr0Op~?W zCv@HDE>d3A+ph1^E)@&ow&L{-sT|W}EAO3>4gG$y8-BTNzUeq@H=g`MHZ@n<%{%s* zEtd}I)@AEW)zNMG?UX&TZP!vwPI|wuFuebJBoc;gtw|q-;hkS2U8d#-kuPV>=1;)1 z+!Orw04vmE(#taTN_PVH%u)QvBByc2h zBy=QpBzPoxBzz=( diff --git a/lib/pytz/zoneinfo/America/Bahia_Banderas b/lib/pytz/zoneinfo/America/Bahia_Banderas deleted file mode 100644 index cd531078d0e8a4752bc242e83836dfdf0ae307ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1574 zcmdUuOGp(_0EUldSSC2wgD3*2APl>y>CLPxyOx>WG`p2q>b30JP18{;tb80u1R-(^ zf=GlQdQq4`nLQS5auXF5kqUtep{SsfAW0$9`NmZQLGAhvXTD)Jv-v(>VK9&=ep|Ty z!evGJ@;>)+?+5eNXw`6UV5k3{=as)N((Uh?XjM-?*7yfH?kFKlnNZ$hB-YK5D>4H{ zQvSG1Ub5M6Cl1M#;Y*E_`QJp!`$%Kek3o?-7HzHWeJR%TL|AJdc8Rq1&(^xmX0g8d zxs~41DL3TySe~**nX&w=wK1baZi+f$WiC#and2QsR@fq$HBe`48JQ}x`*s*P&t@v` z`B<^_=9tQ@pCR&2zg62xm&p9e`)Ygobm`0KR6Alm$(?bHYL|E>3ua$13x;pW-D3@A z;o}au=S{J>_jbEbrZ z{ozav{kLP=T|Oc7(-L8}edD5-X4~yjMDiYD*!KONkXe)8bG$y`-R=_}ee?A7X6Sc) zf1U3yWU}=T3L+ImEQnkX!5nJIAfmxZ+4#39c_JM|JcxV{0U;7XM1;r)5z?WS5+Wu; zPKclkNg<*#WQ7RJkQO2?L|%x%5Q!loLu7^s?NCb%5!<1b8zMMFa){^<*%`t^q-Tf^ zkslHOBmzhXkQg9AK%#(z;ZVl`2?P=eBos(2j9?(qFv5Yv!w3ix5hEl>OpKr)Q9;6T zsN;eJ28j$38YDJIaFFOA;X&eq1PFB3W=2wEF@Y; gxR7|^e;06s?%S=qj`JqD5?t|d-h_BpvMWB~Cwj`Z5C8xG diff --git a/lib/pytz/zoneinfo/America/Barbados b/lib/pytz/zoneinfo/America/Barbados deleted file mode 100644 index 63ca138ee46998bf4ee62b00024430ea16c7b060..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 330 zcmWHE%1kq2zyK^j5fBCeE+7W61y)w7JlWBj{DhC;(*wRKJs0?=GdvI|$-5v}_UM67 zNWcZ*`2Pta26h3A%uG=D|NjXY1_m(6^8f$U3yd89{~tfVz~kc^!r%nNjxInP90IZh z3_?h7&3_;Oxd=pqTm>=!g2O diff --git a/lib/pytz/zoneinfo/America/Belem b/lib/pytz/zoneinfo/America/Belem deleted file mode 100644 index 9c37b6a5c49329a57f19a067050dabcc64349773..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmb`@El31G0EXc?|G*VB84P!hX2akr7{w-NP^V}xiEw>`#b8#93R)(LK{no*EQgwu z0}+n9b;YPf@Mqam#(Ad-g5WH>&$4O1SFe^gCd7}^>ArAtitgsUfBz(kDuZ)r)eM)gDsGQ6leKhbq;fd_A!7TlboLKVMfL10|C!j;rjV zCi9>k=f|08KliB5oh?(m+Eb;?J2PUYVi{hW(e1Jt>$@}^g$^f&`Uf)*)RL^4?&igaiN!3-*NP@z3st2r%C?d zaysSmd;3t&Vx>?xU`LJ|H}?j1+WT!6)Po*pN4G|5?BJ3eTWMGE?lm2M+M$XmtBd7T z^>}$smu@$kCyh~EzWm!fjj!wRQ(sNx#(6!_Q8knOgZ5d=T{9K++NsrRW_n+jo&G+o zs@wM3>daMD`?c9VFPv5{7We3v13C4own@J}lT|Z!e(E>5q?*0*ST%w)XhS8%Pz#RdAD@QzP~xIKFpr9ANwDw)VXguRr?ZU&R*1+QfHJ1 z*ZoN*k_qR^Q4lyc`6z61t~3&Cbgotjw;Vl|4-R!5mah|X#lI)Nj`wzQcyr|4k+(f8`2KxhcrYwA}x`gUTKPS^-5c$uU8r) zosrf^Z=^ZW9chpBM>c@$0NDbv2V@h-F1)f0WFKDH2(lBeYz5g1vKeGI$aZMSe!Q|F PWJlirxTUm=t0VmfZ6N8? diff --git a/lib/pytz/zoneinfo/America/Blanc-Sablon b/lib/pytz/zoneinfo/America/Blanc-Sablon deleted file mode 100644 index 8a33789afcbb422ff086f021a0716992e463eb11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 281 zcmWHE%1kq2zyK^j5fBCeRv-qk1?KH&O_;yyZouh|M+ujdzZ6_bczc0?k%^h{|NpBO z7#aTmKYoCL1F4RQpC1~~*ogB$~#r-s`k~Br>&z%seMl zSL~N3ib_exiK2(wSdY1DXJ9GkIoaGQFVC#Ocz@VBGQ;M`_Eu8>seqI~YFJGXq>9y) zLFyodkV;4?q!v;PsfLt8>RC-eq@vZ7L~0^M*^{bBS)?vf7^#euMrtF)k?PieEAN`0 HFzbE;7gY-W diff --git a/lib/pytz/zoneinfo/America/Bogota b/lib/pytz/zoneinfo/America/Bogota deleted file mode 100644 index 9df037ee3c442c8b0a1cab29b0c5e45c30864826..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 231 zcmWHE%1kq2zyQoZ5fBCe7@K!SL}-Z?b8&$7zE}q)MyCJ&cl9tZ{QrOa03*x)|2sD@ za60*hFgW`MgNP7_UWO3t=Cc5$K^O#JY{CCP5I4u<3y22U1(F2W2ckiCGBPtU!z=|_ a4YU+!H3!&gULT;Q?sc|U9YQ~mGv?04S3o%8qSu2kbib)k(FrmXTM^)IsJRL5F zRruj!(mnQ?y6($<9dYrLh#YR$QSbMQ=(qc%e5qYr-}S7#VMn95(bphj))tG{k`;1R zUW&LWb>bo>qGxr-&GZH1&PLGInZ;Z(YM-PhHj(~h1>Vmg+(jh;e5UE`(M?jo@)8nxhV0tKTke!WK1+y zCCHZUfY_WfCAT!65L;s}$!+C5V%zkD_U8^L|L7Nbd)!{Nedv_lG45AS_x9^&F4U;j zwsyVqWWH*vYt*~;B`V<(uHc{hj;UvITv4id;fc3Vdh^R?nU$Pp6HmX3yvSAtc|ib%IYY~qpXjzK*|bj z%@QeVq%4xMO3E^+T_-Orlrt+OER|!el*Lk3OIa>uy_5ypniW%)Y-`p`Su|zUlx1_Q zo3e0@l~b0^v3APhIaW_uKF9hg0&plmk$|EBMFd-;0!0Rj4iq6MN>HSrXh9K!q6S3{ z4m~J>a415N#MWp+5yjT1LXm|-7m6?xWhl~6w4sPYQHLTAMIVYl6on`fQ8c26WNTES z$i$%&MJNuXC{l4~MG=cbEs9(ey(ofF6r)IHYc!*XW@}WV$YyJFqX@^L97Q^cb`QUsQ=tmKdq98>=TcaUGL|daGMMhhrBSlCKB`H#JXh{*1LrsdD9C}g&r6@{~l%gp` zR9mAeMOIs*D@9maqbx;QinbJSIn<@d%b_ntU=D>T5_4!w5!u$LOp)2v=u8pX)+kMp znxZvDY>L_xxhZ;61P^kVPlypb^qTrO&YoyturrVw!VTpA5N9+qf7j`qj^Seg5)L zQrR0F{@Sr4I@)|TzbiMco11d^med#B^65gpb>~LaT0WL<^FFIKy+5C*R@Cm>N8_pb z3%zeTp}Pmy>FzgIy&|!k)1L$GBz@}Q$|OIcgpxk07wK#2u_Is2?B}2DPbUS zI3*Ay5+oEP79#b}ST_@5p2K@Js8qoc26|1xqr0AHmA$Oy!zJB1^Y*)Mw-;q8v>G6 zu~JPd$(Cob7pU|(<$C%AkD8I_)iWNJu8}}X1{+% z&si5&bGLmZ&lUZs=B@ff=BItGyg5d^V>e8;XNP1DUokm%Lh}5;Nt1iMRr`AP8~?c) zo!1dI`G*$if^erQ+&N7z3~W`4YDRUD_f_>m;dgp*N{%YdcqqlU#-!xY7bB&~x2sF9 z-cv7re@T|~d(2Chj?2;mznNu6_sQ~>ug%MyNA)XJ{boheUR{=V(3F>L)aAbqs(`Ou z0@qKgib;)9ajsjfy1QH|k9}xXf776Y?Oo=z3rlrXL&Q|~%+hO?RGOM-qF$TnGof|A z=+K{2Ol{FsU3)WE)y@1_>INsP4P%2+e`-X%K73jlI%DdMfo^GRI(yJ=Cd=E=67|lR z5oxK-P^|}I@@~;zYDdd?*_n1j?W*dLU1N_-wD_!!4*y_wryth42QHiUMx(l|x6kbP zwobQqd|>uoEY%&2&1T<`Or4aFn3SCK#Q6SFo=i;{=SRo!h5XNn#N!{GNJw_i)Oh^3 zk%{s6XZ;Dvy-9QT>D(oYyUhOQJ)dlAYm?ymkOZskS!+*O8IO>x;Mf=C_J}07A99a> zuc62AA#R5g5HBEZI9fj-jzB!&mv9B*3&Rr{>Aznhovq}hTjm!8JAe_CWdrX%M7CkQO=G9zmMqXuAYylcVhuq*0JgL0ZM=6{J~=Zb90`=oh46jE+HC z=4g8cX_}+$8l-KGwr`NeK{^L%9i(@V=0Um#|Ih97*j6sKnam9?^cVW`bAts1{sMo# F=WpJ+5FY>l diff --git a/lib/pytz/zoneinfo/America/Campo_Grande b/lib/pytz/zoneinfo/America/Campo_Grande deleted file mode 100644 index 46840981043ea98f2af981e7e24e1f085ac0a4fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2001 zcmc)KZA{f=7{~Dg6*G#Oo10^aVPs0+@!}yRvbvBI4Gu}1kT6SOh=xTHL!#6J&e_JY z&6uXqq%}8<*6ud9(8YGIhdGj^6}E{W%+1XjTd^7Ppq=jT?aN-&JO5{g&)L~|!*+dt z;fgJrG6Vm5?r`7m=83pBpA!yz)|}ma|JpyhZx)-AW6Sl_rB)fp`C11?XXs$!A9nC$ zjSNkv=%tTFWq9bAj)e2%+J_1Due-L&xUJXg_obVOl3blQ{fkV+kJzc>ab|jSmfmP< zGfBN2I=AVHd9X9zCT9(qc`e)Zp?iKcDdlr*%H^FhKPO=4_n(&q^OAHy&zMOKL^ZYj zkUaYP12(NzO}hP77j61kf}KZo@yZh-k-eIcw9aI%4ce@@CdtmJ)a;3~vLtztE;-w1 zmX7z^obC_g@!>JeeLvSc(VJkG)y*+aes@HlD*oF%z5ia-;E2iF8>h=>-<154bDDpB zSXP8K+7%P}g+`%NuL zE-=qmy`ZImR1?l$s^Q;ON?A&xmh~=_^4MuDKOQeHULMklcSmL2nMwQ7<{xE!*G2pC zDkHD7_1Fy=eP(0r5nDO)3sY6tVymXkNOfA3t^TRr)Xa)#&6i=b`C6rJIlN6??SDpV zn@eTuiAVIcipS*j_8D52J6qn^@vz;NI4Sk(<81xpMQK=e)izw{k;XYc*v4-znC&+{ zw@qE+^48!!+uZuGdHee=eW!Al*>Ute-C5WnyY|#+Y|QO_MWcOvfj~5R{#?wR(dcO# zxVtD64&;SO`4e^*$`k(YgKl*{^9LPu4@Zq0w$~jua^T33BZuyF$BrDl*Bw1__{i}i z0U!||As{gzK_F2eVR&5}NFZJp2@(nt3;!p@gV^s5h5WXF(N^FU6e?eUKb}4C=w|WDiSLaED|jeE)p*i zFcL8mG7>WqwAV$Agza^4BY}He`3rP^ho$f{KxeQG9<{DAcKO83NkESH!jG)c-_b#L*sR0gA5Kb zI>_)KL7hD(^_eFG!`QifsolrmJOLVz)QsE0Wtc9mDzqwuFpTGoRzgQE4E!_XBEht zFu!swOO&q3HsQ91OZT%XvEj`ZnS0YE@ZJ$iHG2el=pSr>~@RT6$$mb~s)TPK=i>2SB&HdZFLU+xn-Ze+-^&J&{iO5QcH(tgsu#{bAco!x+3K=J08o z`|I~Sk5@R0ydpcxd`+FEzn}Ln5;4pp6aG&sNG?b+NH$11NIsTkLP$nPN*p;^nn`hF zg`|b#g(QY#hNOn%h9rk%hopz(ha`w(h@^<*XlW+Nk)@@XCP$t~q8ynbsdD6sB+HR4 zk}i@jk}#4nk}{Grk~EUFrI|L8Hj1JBXgkD44zTS&5@Y` zL1<~TtI*?6ElssYV~utwfwYL=5K!C{l^Ehzum9&{5(RrN_x=u-OnINo@aa=M-d|Un zeBt3bA`jS30ta8su$OCdLebkEPT9f7gN4kG#_jw z)@zoMCvB}SqH5!H`!#$<)qC1?{r$LUY);xnsiMBsM)dc}0rR8SYk$rTs$cigdS$d% z`8W3Kwuz%A(s?$&J2z!I+jIG@#23@`=|aAH*9O&HKAw+xzK)qg`FORW_S_!oNYtO3 zgL84C3!jx-^~CUSus~F=RDlIj5|LEa;RK zktLBekwuYJk!6u}k%f_!k)@Hfk;R>|It6 zr8uP)q!_1EgOr2RgA{~Rgp`D?CJs`R{I?!eA!Q+TA%!88Ii)nDHm4MaROgiPkou4U zkqVI#ks6&+BvPf*l^G1I?hZ?h+^xKW;Z}LeRMMCWv>Bp{vSpnMRNfM(e33vmHqXZ- O(Emm1c~L2MU-UO#U-2OT diff --git a/lib/pytz/zoneinfo/America/Cayenne b/lib/pytz/zoneinfo/America/Cayenne deleted file mode 100644 index 7109a98ec5cecf1c930240d6d67aedc82548a9cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zyQoZ5fBCeCLji}IVOJ5p78sy=>bNj|NqZ@U|{(F|M&q0mjC~+USMGH g@eN^ccMAcj2Z9h1O#Kf8Ad^8fai((tEi&c;0G{hG1poj5 diff --git a/lib/pytz/zoneinfo/America/Cayman b/lib/pytz/zoneinfo/America/Cayman deleted file mode 100644 index a4095d38633409baf9fb0cdafddffde48851d554..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIVSUOWnldOe+Q8L|NqVn3@qNhAq=j;AwWI@LkM<* zn1NCt3<4lSKy04>K#O(?YL!=cxMNs}%Y0#a~T!Sz17cKZ3}Cpw>NgF9qmu+9aR--XCrsnSyZ4tJ6R>Wa>`9!VX^F9kZxMSt1yQB&M?k}ke9UhVblr}rL-QeVC7(g!Pxwhz|`BTjI<%{*PHLt7kymbA; zyysO#)(Bmh6t9kFgzFR0J=DojzWUUVFjEy3CZ~J)m@|Gp^5bn{sy#%ie>rZ>Rvnk0 zN()U*QK6jMU8!nwDzsU)N1b0#pfAi?sp^um^~KS1)z5Kr^e+!3sb9NI(3kFe$^6zb zMqh4{Xf9t$lq+YV&DA5(@_TU?Q{RjS>h>fb8Ah5skPE@a&zTA<|f^!|2fsT zPmT5n{6=}q_tQ;VZB|V;d??M#o9d>DMY?&}M&p^Es$1+>Xj-mWD6N*Jn49ON$Svs! zrgc(+v>6s^yrM(p)?V$*ZJpXl+YUX|?M<#qy9T$bb{E>}_LWzZ_kqj$j?a%NpH1Iu z-xa&nooOxQuGuS8hr#EiCuW(s*K3RTb)IefTnBWgW@AmK@?71yI?{B> zdrSM5Jf*s3P1OOpeO0%NVLEWpy(%a%O@gO1QQf14%KZbYRfu12=@I<3>gnMvq3zF@ z&?=Yoy0X{wE~=0Rj;=RhIahV~&ezO?3(ECF?<&(LIbT1VIbS^z_koTWm#q4B%hZv5 z2dK!pZ4%Y>Srb*VRH8lOOmyxHiKz)PkG;28KVI5T#m-FE{k8_GxRE1t|F>^Z1H!`f zz|@OskhianA6%;9ue#}kknJkrl#dMcIb?=@Au`Oh)eO%*E+fj9n30)<@^z&7T`(kvGhnq^;;IAiEolwub z9W9gg*PCb4y2x`ml_ojCQ`CYzW^zcaJfFPMOz}D(DRFa6imOJag=VX?^8I>R+c|1l z-X@)XX@Z)bwMfr65~F5jr0N&8`>TvmL-edAEtI(Z_g91KKGV?sx*z`gSN~6+sIT9# z(M{^>*DV)!UP}|_o#xK>R@dH-=o>E)gW@I9J`qFg(?6coX8(+9-{b#z4cdQV;bDHV z53k$S+Zol+wH#TA$XY~JBeEWm6^X1#WK|;T5?PtZ+C)~Tqg|iK3U#z=6j`OnIz?70 zvR0ARimX>;#Ug7KS+&TzMOH4dc9GSKtY2gWJK8mjtYSyIj**p&tYu_1BkLJi(a4%c zRyDG&k(G_CZDe&L>l<0&j&_YBtK8A9b7Z9>Yu(YVc4WOHD;`<%$f`%yJ+ktVweM(G zKeGOj1RxneQh?+DNdl4uBn?O&kVGJvKvIF^0!apv4I~{%J{)aAkc=QHL2`m51<4AM z79=l7Vvx)rsX=msBnQb3k{%>KNP-+~hL98?IYN?zPL_B*_NEwndBxy+2khCFrV@Mp5Ifm3BxnoEkl0Am>A^BrSAd*3b6gt`* zB1uHDh@=t8Ba%oYlMJaua>LnS!PHxl4m5*NT!igBe_PBjbs~1HNIs8w@80a&|DB9?1E@aDpIb2*WAjXwMPkByqH7338e^+VccCQIInQIaQEz1vy!e zvjsU_8o1rSSHtT*3kNL-T4+stj^p6b+3J3}aZ1x9(^>6(E diff --git a/lib/pytz/zoneinfo/America/Chihuahua b/lib/pytz/zoneinfo/America/Chihuahua deleted file mode 100644 index b2687241cd05b6904a7d95bae697642becbe5b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1508 zcmd6mZD`F=9LIl`d1$R1A|Vn=wC*142{UHbX6$Y@cQbd`-OOgpHpaRhcZyat97@y- zCGwEAl$odUN+^UBlUkB3DI$4Ff9Lb}MtP;Y@I9SAr~jM(o6jc@tgeigKQ_>Q;j*B; zyoaCa?5l78P}|d4SrodQ@hH?4l@#jw(fmHHs!`$_2G>u^Dwc$TH}#2==c}anZk;@6 zs!AF2SyFnV)b#JqWX7jqW@hI@N$rRg=ZtYQd`kdSO?g%DFc|{6~^i?u7`+3y)HZT3$^`PS55?+GwN_<2{8FA>u2!yyk%}okwJL3>R1OQ7s<9uX>cd>K`o|Ngel*Ffd2w0R zUL0s@ZavoP4)mGY)0cGJ`n#sS`LJFe>{S~oH|vHOchttr61{2kdDR#bmd0;;Rd`5H z!rgUh^Se~pay4IVeK1b8om^+Ow~Or9nP-~zy%bMBPJeqMJpcAM&e0YT$7wSX;W+0{ z$Y960(&35X?NPtJ=lBESUmTDOuFt;h{e6MIFvhXN8i+X%dmsiuEOKd0;y>8LFbZN7 z!z_qh5W^srK}>ULZG#xcunuA#!#;?C3=1J9GHiqx39%AlCd5vNp%6*_!V^w+{A;+R{H5ShBIgGNMg}Hk zmjC~EZeV2i|9|xY1_+x2EW!gK83deNLKvKbfjAt9140;FfovdPgb*RvT>-Kggh7BE zh(T{t;WU!WtgI~d|(Ajt*vfhiXN%5QKt diff --git a/lib/pytz/zoneinfo/America/Cordoba b/lib/pytz/zoneinfo/America/Cordoba deleted file mode 100644 index a703e957d5ebe02e0651d77ddfff4d3f7b8b851b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lPe{{Y9LMqB{^c4)R!|WUixk|*%7YB1M9^VSbSom(SXTb}zMs({3iA2!+w0+nCqM7(;OSG{&R?fZ zzVLDm%FBJj*v*`JcqyYFZGB}Xx99Za!Z|gy`La7TF>a=t4|MU?YxVfed-uu3h?$w* zqTRuqc{(zppB*Tv(v^z)d|SiJ9uMl-<+v*MCf#!FzIu5rujkTt%-pBz?tI!)^X8*l zjU~)N>ZDum39I^O!~GgMqZ-}qy76JuG&iQ)X1S`q)ra&_b+7qeO1M9Y{p#o4j9wm2 zDDTD|-8O#2gged_cIGEcM|-}|nfzipKVK+x?O3O}D#r>j$I~&hzYwog)vntE(PZO= z**6n6eM75F-`lIvLrY`kaPdUc=U?Fy478pQ`t9BGN)^ZPyt3;AJ#Vq%3wz$X8o!Gb zzR35rt$Qk+b$TL>5I>MV3X@MHWU@MwUj_Mi#fq>d5j|Ssy6?slX~FAT?N}2&4+645SXL6oOQO zlwy@ykYcP-4N?wL4^j|P5mFM`nz%?&^1pSc3MmVz3n>h#%qpcJwOOS&q&lmVht!7@ zh*XG_h}3A6B9SVwRc64yvL_U5J*zNa@4wTOKwBZ&D1B>epzAdD@c;kL4UDY+|F2%az!~i28^Yl10>r@~Aaj8r1iS4lKq(Lg z0WKg0u?7DFL1w#F2#5x`1SAP^4VVVH2tfLBMrI}` dggF)HU>2~0Il&I*^#QsUi=%;V0{Xy=3jpwLNhJUP diff --git a/lib/pytz/zoneinfo/America/Creston b/lib/pytz/zoneinfo/America/Creston deleted file mode 100644 index 1cf719ae837475e9dfe22e1b7513a80906d5f789..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 207 zcmWHE%1kq2zyQoZ5fBCeCLji}Ic8t;E|~Yznt_qw|NprY7=UDd0|N_$?He4z5CFsw z5Q5!Q7N9H$g8;}x5S!;e5X9LQ>;cgr8$dMJ7AD63|0f**Sp&2TXbsRZ4hY-FH-rJz MLIwsdpny3S0OcGtc>n+a diff --git a/lib/pytz/zoneinfo/America/Cuiaba b/lib/pytz/zoneinfo/America/Cuiaba deleted file mode 100644 index 232ef670ff53dd575954275d367e9fa30129e73d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1973 zcmc)KZA{f=7{~DgDl;55H#f%;!^n(4ym&~7%w33zh6f`~NSLKCM1vxUA!_15=WJu? zR;&lJNpo%)&fRWqqKoaG)f~~%65T`)=GIn?t=J5C&`$UF_N6cCo&U4L=j`mfVY|M+ zP}$ba8G#3$N$wloJWcM+=eUo*-qqUi=(@i;?iHGI!^`yi&Arl_{f+hxP1U~mKW*Q+ zD(Rm{(wmCIvC28+n>hSzo*p5h^^B*(^Ji8QI3vYydvYVgLeExjF}jksdrmi zOhVTYozwWMdAu#pCT8}Vxy{@4iD}nNQt2F2V!*Dtb3AIbXoK649JS$Cc9#A z!sO3r)%>%^WYxH_t3TNPw%jh)t%tYCn?1|5dS|iJoOw#$ zDtlJmZk?*NIkV)Q-A~$W@ncfAA;#8?-H`evzuEfhozgJ-2itJry4imBq-|^;ksW;p z?asYlm|fqu>wD#U%YmVlpK;jz%%5?@J)AOf&R%!Y$XO$&jhwgFoj7vlUU%xqxg#f!oIP^-$oV4) zAQ>PjAUSwl5=a(amj;ptk_i7NnINekxgg0P*&yj4`FLGINJd_l5|WeGC52?=b!j1a zA&DWGA*ms`A;}@xA?YFcAqgTGdR>Z0j$W4}k|mNRk|&ZVk|~lZk}Hxdk}Z-hlCRe# zjAZO}DI+<1UD8O_NZLr=Na9H5Na{%LNb*SbNcu?r$OIrW;B`}g%z@WU0x}C;Hx0-< zAQOSi1Tq!KTp*Ky%my+Y$b29Zg3O55O$jn5UN-ILtZyU$Q*gyBq6ipb<>2*6EacAOd(T+%oQ?O$ZR3gh0GU*Q|{k?b7j#( gp0ntv|21f_ZridLxzu2~q-CbbLP-r~-2V{!FU^EtE&u=k diff --git a/lib/pytz/zoneinfo/America/Curacao b/lib/pytz/zoneinfo/America/Curacao deleted file mode 100644 index 6733d2413e3ba3e802c3a720ff09f30a5383a802..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_z#0DSVsp#)FaR|Ns373=IGOAK1ab^8f$w0}LEK iz99^ben1=?0#phDAtadm9|%CEgJ|My-~w7^!UX`QS1t7b diff --git a/lib/pytz/zoneinfo/America/Danmarkshavn b/lib/pytz/zoneinfo/America/Danmarkshavn deleted file mode 100644 index 9feacfb1c9fffe62128c678397cac470dcd40f91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 700 zcmci9ODIH97{Kv!%?z5TqhV$+UNgq^7~GJRoiwQ#DYumDNGU5>&SI3M#i#5j7M30x z%V8rcDW%!SLQRsCjg)Mz^PjR(%Eq~!^Sh7L{eSM<^3ss{u`10QHY;v6_jNn@NfpZG zrt614r6KVm;n2NAeAg0rJC|tbL>h1RrRicznhR$-c6h8?cK3Aars%fZx^7=t)gAK- zI-YTLVr)Wprbcx#X6vq+sI~*+V!w|__hV9eiec%!tdhRd4@n(7OaJzr3~XG<;95bP z#UpW^rX0&(;rsOpc;0JXDbFk3DF63ada$ZJkJJ2%Qni_^t7g;e8CRvvgHo2o7f$yN zSv<2y!y*ro2+4$`LUNTg$&hSFIwT*G5Xp$7L~YgP4 diff --git a/lib/pytz/zoneinfo/America/Dawson b/lib/pytz/zoneinfo/America/Dawson deleted file mode 100644 index fab060999850a62ccd916fc80d216c94daad8d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2067 zcmc)Ke@xVM9LMoH1Wrk|&z2|2YWx_aK|-gNp0Kf6 zwc=AwZL6-2%zs*I;>hM^F>|Y}IhR3eEgN%fWvf`r+M;q?@8_r0Kehh#d;8quv+r&E z#p@Z_+}U2``PbuGLD6pDDEV;@pvA!{hzupIJIGUieGT`1Wf3YkAyE zFCA9CiXY64oxAnC*hZDp5Yh8ju22h#Yjy787Lzw8SLdhInEb2N_NK2En1b>7*8l!* zX5qXuAXQxw&;Ro|KwzMu{k zWT@bke7*9ID{9q;*L2;bkJRdsTzlJ@H`VP!zuP-rd0ySw{iVHY@C~!3Y0Tc;`kbjR zw{~s)F0=OM2^}hXR)r=`>4xl`s$uk~UO%-#-Sg_GZTzgug!dn|8{TO&O+Ji5b7?0QEO`GLS_hw{XhfgXs)bI7A zQUg7nba$WazUQV=uNkl6?#XfYyjXq26Kj!kzno?{_41-wUNnpHc=`H^$bbLa&z7G# zJO|})UzC#Pz*8^0jZ6TU0Wt+-4#*^sSvX}H$UKmV@W+`6G8JSl$YhY&Ak#tSgG>mS zkyECG%n6wkGAm?S$h?q=Au~g!hRh9_95Op(ddU2oGC^d9PMIPyM`V)7ERks<^F$_! z%oLd_GFN1>$ZV16BJ)KijLg_6Q%2^DOd6RrGHqnu$i$JEBU4A_j!YhzJu-b{{!U2% zk^!fr0Lg(ErFrEuD?KeEEz@@$J`$Zqk91G! zC*2$9@%+<0d81tM=DGUixx2qHO!4IWPXYf*FW4 diff --git a/lib/pytz/zoneinfo/America/Dawson_Creek b/lib/pytz/zoneinfo/America/Dawson_Creek deleted file mode 100644 index c3fb166b0887753eb80b078c47bf4c5876774662..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1033 zcmb7?OGs2v7=X_mXG%=yCme`qaUe)-6ZD`mqD`Pd(o_>Y7KV!kT%{1ys)7u1lcz<{ zCOg=sAc}}Ukis?*)TW8b=`l?&8>W|59{*KHl^WP-& z4a;oMOMG_OL}#{rxjflDW}n)UJX`zN4x5LPOWv}%!Zmqbe&k;a zIeD4C>0e#B>hgEa`PV&XT%qrXf78+F-X7cM-)-IL-nVV^9~#%Vk>tZ%Z# z@zqkAztonpN%=HVwx4fI%9ncu`}J&2zFnX3qg{hC)|>a^$M3rDhlc#bflKbk_J03! z^C>sEvfEEJ^vkb>89!a!Ez?sc?eAhnW`+;iKlfXtJkV^z%PYj3Z?wVbT8SN9V5_>2x=KjRP@PZ3W81|kpm3wvcrk2x4YD?OrcIocXO{Gn%-gSb?k)B<` zJpIZtO}g9{hdOPW4zGs@fk=Uffyjxdf*_J0q9C#$!XVNjsyK)|h(L%$h)9S`h){@B zh**eRh+v3hh-ipxh;WGXh$PP_Z3 axIq6)yQ|yQs=dwLUL`&~Yc$4nHGcsaWcAYk diff --git a/lib/pytz/zoneinfo/America/Denver b/lib/pytz/zoneinfo/America/Denver deleted file mode 100644 index f8908febf220f27b3efa68bcc119633c8efee299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmd7TeN5F=9LMp)g90~@Q;8vb6-07=JX* ziZRO|P|{j6@nOxzhPsApE1ScuX)UzpvTXFQNdotF-Y4uI`@g<-KVHAx`}gOKYqe)> zhPdW}%{M$;r+IjnU3+u%8~q`w`^7lj^V*MUca2Z)X`U*2^DpS$w!P}3)^I&E?~nSS zs%UXJ)vHGrw2MC@-TF$XS6mr=T8{nT7UO5j<-~_M!gn-V`rnEZVrQ%jXz_`_XC`FO zh8PuGHB(P18CO$t$8<>AunKu8Q-{gpDs2Bj=@{9quDj5q!_OTP5yzYKwD)^N|R~3k;!u#cn>;!RB!U7pRH($*RbI6#$cop;8d>#8$n2H+; z)w53gq-GzysBi8$rRI2N$y;_DP;*!M<-Bzti(50ll(#K=SIm$4K*lF(5$`*%6C4{w z!te>5c+n+pAK0Ul&eW^qt`~I5;Zl{_SgX@sS)|fyn`OqP8ERp{TDhonRAt6LAn(Zd zOf3#clv%NtMb`J>GJEWt$T|6oyz}#Zv82zT@9OUqOWS_dckkLRa_c_P_cZTP_ZIi* z`>MC8ywsO0D|NEdUNNx}XXZFd$h)Pj-xK%E@lq-r}e^W32v_d%>TJ(eOEmg%8 z9$nHgM?JKpNSAs8)rz=e?OOSba*apovdojJ?As*ip8d6O4^ES-e1l?j?}&VOc%P_f z9+Hm?w2I2=BXUjGdhw|9w61DtQI91b(vR1ARCPqVt|=%|HJ7})Ha=O^o^oqXNTl-Y z&(Z6?`&F&)D3?#1o+h63X3M7zjEK6jSXtjTBsOGD$c=SJ#HOh8a&vKq*z6nA-mF8) zJN$*-65X!03>?#2N4@IVt{(l|S+{CvY|`6~=BUQX8ohmIoDu$$7L${i-BZIe^(Idl0#*YMmBLYYWIAVYVfg=h?7&zj91cD>vwq2Y)P5*(|E4iX-#i4PJWjtC(kLSlpj z35gOCCL~TsppZx*p+aJX1Ph545-zKW7ZNazh#?{4h#3+zj;JAFp%{_#pwbng}8xL?ntx7?C(4fkYySgc6A*5=^U!CK67oi6;_JtBEKQ zQjVA+LFI@l5>}45B7xN?B<@Jyk;o&V4-A<61O@-|diAUS zUeow?VVY-pZ%S`^KUsSFja=?DoxisEHu@sKVg3~?Ha{mh7p7#Sq$N4i(^Jw@(j0#Q DJ6nx# diff --git a/lib/pytz/zoneinfo/America/Detroit b/lib/pytz/zoneinfo/America/Detroit deleted file mode 100644 index da53d46df347ac70897f4f5c51feb83b6a878627..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2202 zcmdtiZ%oxy9LMn=L|_+4C@EB;f{b0{KV3z=6$b2vdd2i&il#>c?+}V_Y7EM-7G&C- zb2`k`Sf(}lH&V0ZDyHVFt(7UO?9cGj7Hci)7(HmQaXas`p7p3_t>4`_uec2+ zV&x@CDmkr^c1@M5(he)1cSwBZDV3~yB;~6Yb?V8eTz#TjPk!Y|lXhT(PT$dFuIap6 zU)vlqQdj9S0BZcd86-k)qTbNp)Rq){_1K3Prs%_q~p8&z57f0i3gom1IIK9w5} z9#J>7d* z=8V6m=bk-p=6%zrg9E?F?e9LW@7VpB-1*#kUDXGyy0~3xs;gAZ zSicDsuGOKTou)Q*zOFsiY8H&<>V?nmkVRiqs_@npS^Rd6s#_hFCA|sio?x*oeRxDI z%Sx9>{YNS?J|@cpud3xgOg1aB&*~LtE}NAT{kq}skXbdnQ?KqmZtfdw)oU8}o3(w5 zwF$bP3^@Y81e>AKbQ#+(7RIHjt8zh>SuA-j=r8#j-HNTN98%I7@ExmJ1>$%JN zf%Yu(;J}b>tDi8k`?!86pv|VX{d#l8X|tuSQ*W8LB<&Tws(tvBbYym@j=@9H`A36# zq_0OFy%gJK3shO|5Ku)>CouS0uz=`Jed2Vn=6qUM%+73tmDjcH&KMQY`l2 z$+#4Er@4E|qHx5kS{CtYIQQDK#GdL1e}6CT?>q7@rV_Icb3rD9%m$f`)6NH(5HcfV zN=`c`Ud^PCSvl>rka-~!bK039Q$yy4Ob(eHGCgE|$OMrYB2z@>h)fchB{EH9p2$Rz znL6!Mk+~w1MP`dk7nv_IVPwY0l#w|jlSXEZOdFZE(@q?jxzkP^nL9FhWcJAPk@+JD zKr(=&0LcN81SAVc8jw67i9j;pw5dRHfg}UT29gdWA4o!wj36mNa)KlU$qJGdBri^z z7$h@Jn;IlHPMaJgJ4kwv{2&QJGK8cE$q|wyBuhw|kUTkUqL55EZK{x5Ic>6#Y$54F z@`WS}$rzF{Bxgv{kgOqTL-K|s4#}L;rVh!S(NxNFMR1+=$cy=Ax diff --git a/lib/pytz/zoneinfo/America/Edmonton b/lib/pytz/zoneinfo/America/Edmonton deleted file mode 100644 index 3fa0579891a9762b7c131ec5ece5d6d02495bfc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmdtiZ%oxy9LMnkp}>tlrxHU!BP|I6Mi>RMixs4Hr-gV79MKa` zWy~@ORD#wDQ`cy0pgG+7qjT5gvJx#Ton@mxTP*C}&ig!K>rs!|`riHS>v!St=j~eM zUXw2VansCSc(~Wi!~2XE#!j5?8XVAX4h5_3oiFKb?>4pP#Y=i`+jOz7;S=4Pc~res zc2V|4^{W1ik7d8_Bk^fRnD);9y~$e>Ej};5AWz4AE&iN%MowO;6u!Z1>F@KdQO! zU)DGE99MCkIr8SM18QEmU(Rp%Ox%+Bjl6Z)dtyP4dFNL{V#$7ozH4Z=Si1cuefO>{BDe8`zNc-My0>`0zOQz(%3Jud z&d*z|@_!qZ18x9bN#SgMMv+`6PQPCc}w zNSAs7RatDZc9nmpTvsD?MdmS8@qLo4oO?l3jz-9pzEQDi-?)5utWQ+6dF3O+9iqDS zkX+rhRy^uFscYKX)nmyA^yBqzRU5uT*A*10x+@-CAD^u1k5_7UaHMj-o1+_k_(iSl zTp^!086lqZWXq=p#zkXAjBMKO6;EgWCD%0`66>SR$qmJwVuNo|d$JBF&)8YLF?xsE zI6R^^O?cF^T|N4_FDg}YORL^In4?;%>-3hLu_`cN%IBJ(DLpT6eGjwWa=FtboO$LcGtUb1l(@`ngb1)-u79yKzd6>1EDl*6vOKFsS#2nq)JGc zkUAlSvYJXErQ)a+QY?;YA?4zz7g8{eiXkOKYK9aIsTxu?tEn4OIIF1~QaY=t9a21w z>LKMr>W35%sUT89q=rZlkt!l(w3<31g|wPVBBivNS|Y{ds3uZQj(Q>m<)|o9QjVG; zMMbKLlohEfQdq00EK*vlsV!1mtEnzhUZlQAfjKISl$fK&NRc_JjFg$9&PbuHrqW2M zt)|vUv8|@sNV$=EBLzn)j+7j!IsSi(?l7TWY=WQU%t%R3NlkL5rKO~$q&ofvy_=8y diff --git a/lib/pytz/zoneinfo/America/Eirunepe b/lib/pytz/zoneinfo/America/Eirunepe deleted file mode 100644 index 4e586a341f3a652bc6db845aff22bb3f9d8b9be4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 640 zcmcK1txJPJ9Ki9L&fp^|f(Rn&T-M-A5YvfeLGd?yk{C<_{{TTO&L9XDlPDIeOG~mD z;BVDR^F&-b2d_j&x)jntI-F;REIVq$Kw?>oxur*pk2 zm20h;{IkeqKV06r0f2%K)^PGL8ZWQS8yr76l4lC1)Bm+L8rjef5G?M IpP2E!0B?Q}`Tzg` diff --git a/lib/pytz/zoneinfo/America/El_Salvador b/lib/pytz/zoneinfo/America/El_Salvador deleted file mode 100644 index ac774e83f46bb2967f587ea3175d6d2d95a15387..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmWHE%1kq2zyQoZ5fBCeRv-qkc@|$?rl2tE&I84m*#Syb`yMFU)CMpy0^$GvYZ4e3 z{{P>(fsy6^|J4f^IDC9V7@S>zI5-5T69hs?u;@P!fGh*)16c^7L6(AOki{UHB+I#g I?l9v508!&K$p8QV diff --git a/lib/pytz/zoneinfo/America/Ensenada b/lib/pytz/zoneinfo/America/Ensenada deleted file mode 100644 index fffdc24bfc4c076584787843a5a6b457a23c5bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 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 I+rEAO1p%4dkN^Mx diff --git a/lib/pytz/zoneinfo/America/Goose_Bay b/lib/pytz/zoneinfo/America/Goose_Bay deleted file mode 100644 index 83e5a9b398fd1b600e8f0a72995855dc274d0bd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3193 zcmb8we@v8h0LSq=Q9u+0f1+ZFnxG;AN}j(04C6qMCj~vsACHO=c%~VO<`d55CTwkP z&L3$GZ8^a|nkgm!B!TZ>gG8 zQGRwwu;bi-o#oDiyN+)<9g8?Ww9aw<+Kz||rW1~u;rCY8$j#2$;w0CPsXo@a*GIZ8 zj%u?0Wc7Esx}LLM3U6^;`u(u=anipfe zRy5Gon9|$&>q6bu6mj3$oE+l%tyi$~`p8GF>$mSZTYT$XE!B0-Kbk9D?xQE1H_je# z-TboBdh5s+w$}XzthcxAx82$FuJ!J!&9-}sbFB9>mf0S}zij<;+zeY=#8PM5&ns*X zdq&BR{Aa3<+ETU0*T<^5D^h#n?5VapdT5@q+p1}It7hI>t9B}^(R^07N}c6fau=ya z@=d6g{i2Uc{zEI|u0gw`0Mkx6pmn{}O)HeUU)rGtp30Vce6~*Qd3dcBw8y3fm(0_8 zZJ4a~&YPt5$qrTfrVP^hS=!b95l^&`VS}Ur{#Uet<|op?+qyjH>J=%px9ePtA3Y?5pVEqf^}B?R%6_0b|^w8a67U zTLRrd+;&Kb|G?r-SXHbfZppGw&&XF^ z%9&_S8keTbNE%?DakofM9vkOQu9fwa!2a%(is^c)`=NX0zQsz~#eVj5B~h96X&)(L zLA)&Od?39tHB6qp)+Nme^^r5PPD+`No8-B1`=q%|X3h4TL$#f0)Uw<6s`C$4X|FaY z>Vhq0+QQ03>Y|(yZE`(2cr z=i4OZeHU&%($XKBk zv{%dPEXC5gh6;IoNWQeba;LnZElqm6v{2sYijtI~Z228WkW{p2io9v}9m#C!k~nagjrV^}ng6{<-NX~zTo=U6 zIm{!jMboB^K(-0lCuF0LokF$>*(+qTkljMI3)wGZ!;l?AwhY-bL$PVdt|8lIDE1B6 zIArILtwZ(>**s+TknJ-R`-g0xq1ZuW3z0oUHWArHWE+uvL^cxHNn|ULy+k$>*-d0S z4aI&U8)_(a6xmW_PmxVUb`{xHWM7euMRpe1T4ZmL%|&(>*tm; diff --git a/lib/pytz/zoneinfo/America/Grand_Turk b/lib/pytz/zoneinfo/America/Grand_Turk deleted file mode 100644 index 733c17984b411c5a7bfdd87bd550a1db2d34388f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1871 zcmc)Ke@xVM9LMnknK6VJ7D3CAJKFc^VhV0N*%McYV@fs{%BDj!zxu!5+jo!K-M{bW zE7q9UQt5l<8DoFp<=JarzGruh@AKszZ8j6y-_x%o!sgYr#X2t%Ft5$c))NEcOnzZN zUe6phlhVh@q=#8*@}I*}aPMC=<=P$bpZ`g{@!5Hqn)I1B4|hpn!(V3F)?WQq=%$&z z^b`Gd-WgL=yh|62-cW(81|1muQWgI*N6+Z*R3!s3DeXz9;KkWe)={U*yYi(X9ygUc zAIr>e#LQaxyM&5nnAw&6GUufnQ#JWlT{ZN-nfv5BJ@3{%Gyk_9UETYiT5#nfz3}*5 z_0FlydQsa2wfM*(dAI&kwWMj2)RZMvZOsy?9XV^lr5km4;FyWzEY^{Wt!C-)G+lT4 zs9N^(B8eVoQOmzAl=}5iwW2#i-mflGEB6e^s)Ae)oS&sAN^QBnPjlRDMcQ{hzD$M~$+t=VP`1muflC5myH<`K4n+L>)Tmlk~I~ z^6|V&_Od+h_SLiu&%1oimsuB$`D$zIyDDb?;fX!}L^JGPygVuU^8IDcK8a3$IdZN% zoGfy-$mt^Ii<~fW#>gon=Zu^*a@J0J+Q@k$Cytysa_Y#rBPWlXJ#zZU`6CG+86YVj zIXG<+NES|;29gJo2$Bhs3X%(w43Z6!4w4U&5Rws+5|R^=6q1$GriJ8%B!*;$q=w{% zB!^^&q=)2(B#2~)q=@9`v`HdaI&GRro=%%6k|~lZk}Hxdk}Z-hk}r}lk};AplC#q$ zjb!b#X(M?%ZQ@AgNa{%LNb*SbNcu?r$OIrWfJ^~02goEKv*5JTfXsu_P6RR&PCFII zTp*Ky%my+Y$b29Zg3JgqCCHp0lY-2O(@qOAFHSo#$jmtH)F5+%Ob#+T$n+rdgG>-I zLuq5uU&zPvzF)x(*)_5|WY;Lutx@(eyGGA0lFyfA=P6`osw6rySQ#uYiB?nuD}v=& FPXWmk_~HNn diff --git a/lib/pytz/zoneinfo/America/Grenada b/lib/pytz/zoneinfo/America/Grenada deleted file mode 100644 index df1b6895f9c1f38580293eddad9f74af2e87751e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOHFNn!l||CkH|!~g%s4=}L!_=Yez28VzYF@%s{ P(0?GnYZw>MR1+=$TCyEs diff --git a/lib/pytz/zoneinfo/America/Guadeloupe b/lib/pytz/zoneinfo/America/Guadeloupe deleted file mode 100644 index 15c0f1f7450c27dcc5971c9769455758f1606817..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVN6xxPkHi|6>6R4FCThKfu7^;~T=@7#spp#1KM) PLH~gOuVGw3Q%$%4?mi!V diff --git a/lib/pytz/zoneinfo/America/Guatemala b/lib/pytz/zoneinfo/America/Guatemala deleted file mode 100644 index 6118b5ce2d95b66dc88cc40c7470a53105dbd6c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 292 zcmWHE%1kq2zyQoZ5fBCeP9O%cdFIc3b%#B4O#=JbX%{4QDiS2mKM7EO_3nYjiI@v6 zAwdbQ^4- A_5c6? diff --git a/lib/pytz/zoneinfo/America/Guyana b/lib/pytz/zoneinfo/America/Guyana deleted file mode 100644 index 5f98c4a0e88b3bdfa80996461f4662dd4d0adfce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 zcmWHE%1kq2zyPd35fBCe79a+(d1u_L?D%PEw}-2Ci;a5yZv#dqW|sf|PgXE6{QrO2 zg#pM0lAQnlU%db#j~`&*^zjX0aCdSC5|JSwqo5#!1WW$|0mxzy4YC|$1jqp(nj%MV J0o`Q61pxc|L;U~% diff --git a/lib/pytz/zoneinfo/America/Halifax b/lib/pytz/zoneinfo/America/Halifax deleted file mode 100644 index 756099abe6cee44295a5566ad6cd0c352fb82e64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3424 zcmeI!dvwor9LMqB+*&Iv3>mrB(9CyZS}yHNw1bTgHVm6jB5jH#bIBT=h@DgD2<0+F zE){-jXvqBB9lCtBp(*Ag*F>2l*ZulDKmYbe$2tAkcjvpu@9b=6|Gl2?#35-fM|uA7 zR5d^0TczsIIfqlj81N7U?a# zzS-S1??=a1a?!UtHO|@d{v3C&$aVI;mf`MqraK45cXkg3k8lok80$N9JKKA>uJ9c` zA-zXt|167}-^eJIS5-;oaedVNUL8v+(8rtPsUM;j>r&5rbs{87pU|1=WZ6`CYW)OJ zR+u7B=L{4&H&&iWixEF(HZ?m(0s2z;9d)_dS$(~(uefLrub+0sB z-#=7SRTR|F{m$@^@KP6pLzZk$lM6ECQS4%ZGy(iXhJd z8FX#3ctlTyF#ttlNnl0@Z>TP?fJcwKbs`>uR`M_Zr|Mo;LsajjQ)T?|D3OqrBKvHuBl-@Dm14n7(XVq;**~*X3}{$cCMInciFeP- zfzeCF!1Dom@Dl}U@V>J;xni*zvU}2^?L9ob9?Ifoyx-KdOJm6R5Di8Pv5Bd-O```Eb_eqb(??0vjs`&i}eV#!3 z`BD2lI6fiK)3v*K2bgz|c}1cbDvu|?eoK6SZS$LleM2@5**RqEkiA1T57|9r`;h%Z zHqdHz5ZOYj*+XO#t!5XIZAA7F*+^t3k*!4b64^{-H<9f`_7mAqWJi%LMfMcgRIAxl zWLvFfUy+Tqnw>?q7TH^5bCKOewinr7WP_0%Mz$E)V`P)9W|xs|wwirLHX7M!tJ!K~ zuaV70b{pAlWWSLOM|Rw5wj9}WWYdvdN46c=cVy#{okzAF*?VO3k=?hN?ML?CY8rra z0BHfz1EdK^7mzj}eLxz4bOLDw(hH;+R?`in9Y{ZrhM?^TA7}}W=?Tyjq$@~UkiH;| zK{|u92I&pb9Hcu|(;lQhNQ00LAuU3Bgft2164EB5Pe`MXP9d#AdWAF#=@!y1tLYcg zFr;Hh%aEQSO+&hdv<>MS(m14ZNb8W^AY>O_7W+Qc^1Z({&c0XQ`;cg)eb41vE7Ir;=t42ohT>nZ>dP zr8&q4l`>kXnGT)J&Ju|^s&5cujdBK#2W_r4#uyRYe(%%VT=h(Uzn$|syZ7D)#2c4Yciy*Ff|JufOt=M68n z@0*CzsPBud`v<}_`s6ZeeqDh)a4^P-DfGyLI|Hl*EAn+=?sY46VVXXa*l8__cvBZg z4%&;SS|x6*M<2d=KpyEoqmN$PF7fS$G~uXM5)apEQbUp?*A!|>dA6oLo1tl|6ZA1_ zgLtC*WJ&5NSu)u!OQX7V>2R+;K5;^y=sc_G1Mg_Y$sWnPuv?cMJR{4SeQNDIB&$|> zWYtKMu8xhA)jzk%+Q4yH`-SLJLj#iCQYAUvW9oh5faZRct9dooRGKbme#UHhddCM^ z5H%{koPFw>=$Cczn|0mw5nUhAAnQB&bi-(g6n@;UMSV|7@#{x)GlRNof0exG>CoL}dGb=kaov-ZB73GTNp+G}tFIoD+8Ie&d$Cbo{(Y9# z9j%o5??&{MhHTk;qE8z(CCI+F+cm&_yEo8%%MA*=bJy=bZM$54|2MWf$nQUY$`yL^ z%`a=bKG%ws<|*)*&A8ld-Y(z&&n(3J#lvYa58pHW=2SMuokJ#v%nq3zGCxN%L1c!G zW{Suh9nB<>St8R!=7~%cnW>|hDl%6`Gg)M|$aInUA`?bu#(Xekj+rwsX=K*Ow2^ru z6Gvu_OdXlKqnSK1dq*>UWd2A3kPILxKyrX20m%ZA1|$ziB9KfVsX%gpBm>EYqe%yn z4WDZH4qsbkTJV%o~ zBz;K!kOU$bL{f<45J@7EMI?<#9+5;knoJ_8bTqj{lIdu&iKG+BCz4Pkqex1ToFYj@ zvWlb?$t#jrB(q3r9ZhbL<$4HWqEF)<~@{A-J$uyE`N0VzL z*^VaLNV*+OzLA6@8Ano%Ag_XGkas~e$jcy_M&9NE IhKV^B0F_3Lv;Y7A diff --git a/lib/pytz/zoneinfo/America/Indiana/Indianapolis b/lib/pytz/zoneinfo/America/Indiana/Indianapolis deleted file mode 100644 index aa3dfc43730ed25bde9c967039951f5c2fc15cc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1649 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 diff --git a/lib/pytz/zoneinfo/America/Indiana/Vevay b/lib/pytz/zoneinfo/America/Indiana/Vevay deleted file mode 100644 index de6167c08291f6cc510f655f2e7dc178d62b0119..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1397 zcmb``Pe@cj0LSt7+|^356bw8p9`evd*FPad7#O;U<@zUAGcz4aTTIKT%(TorRF;=+ z8WCm`B}EjJVI8C*Du@V_A_!~>@+OSfp@{Z1-=RZL-JHj~&tv!c{YC2A_U1W%odoj> zms4pj-)W=QGY2j|`Yy-LtQxp-@q>JIHa0Mw@l{SYuh5_SHx0xl1KPXcDQ6_6-N8>P z?x@l}854f-Q^r>+QJmc^L&ZfRv^cIyvYJ%M%#bck+N?_Nb?7bg8EWgLbF%DRp$PZ2 z%kl?nMMXncRu20`RYA7gc4SUe2U29D=B0@ISd_K-H%0B2)w(YIxvG1%pm)T^RsFRY zy>oU*HJqBzyQVr+W6Owc8ZB2Md|x&Xwu{|a!*WkFELxI!WNS&bXq~T@(RC>z`no{2 zB`k`z+v#%O+*{E;yis?&Sy21C1Ny+78P!=6)AIa;I+(BYq0SL?c+FGYRne=uVjpGq zhGEe?`$YDn^@yIStFrf7y*M^{S{{F2Ao}{F^2B7i=x;2QCoed{aUD0#=lbK9=<&RV zcU{NxZjCv9`@P)0SMqj}J@3V1H?^oZ;uKYzyWQN%h!Zm3A@iF#E-&7Ze>bqq{LAH3 znag*;GpErP8$)_Pnn1ch+Cch18nK#AkXF$4!UxT8OgBI~NIytJNJmIZNKZ&pR?`*I zmeuryG-frOA*~_3A$ zi}Z^$jC72&jP#5&jdYE)Z8d!(jayCUNb6S9JJLMTJ<>kXKe7R22gnwXJs_Jvc7bfe zYW9I_#AW?wG r$#znyc2a3&VKb%w&+7NCAknNX->fY&ygry0%*hPr<_2?vIf=gj@u$3K diff --git a/lib/pytz/zoneinfo/America/Indiana/Vincennes b/lib/pytz/zoneinfo/America/Indiana/Vincennes deleted file mode 100644 index b79f6725b62a3c16ef4abecf92a92b67b33d5579..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1677 zcmbW%Urg0y9LMqJ$dS@zX;XJD7#Dfr+W2eHn#0W|j8PtuIQ~O~#{$m?h{qC!M)uf*4l{{{aKEoGxE;`nse6HT1%?A+US7JSC{+U0`(2<9O58nO7eDhW&xU}YuxwLnQo9IZZ zA2!}_HnlsLYEGExo(;iol~0)~$qjbq@tB#dC{pA16%&1~a@jMs@l+7MLu!lF@z2fP-WL5r{(yNg8P|==x=d3=p>CS1HOaLrbn@F$)0~~w%_F(y zrP&{K%fNcq`rW*3>&$U4k51V3Z5e0!$L#(R>t1Oew6Cr@?+#QQv2k+MEL#a2-YnMxPcTdv1ekxb@)K{9r?s!T)TSDFcF40ep~~gETz-=)!i#s}{yUQu zC?2jRdHBu=<*Luh3?Z9Cc86>a*&nh&WQShaBC&V{GZ=Mf!&n4Rj_K!4xbl{a1xah$v zO(0!(r46JHq!FYOq!pwWq#2|eq#dLmq#>juue5~pcN|UcMJ{hvCRPQwH1L&DOF=9zHerdqX>WqBk-o2GcY%u}qW>M%-B4s}5!&)@HR;zGi9;eYZ!pMRd)=lA_3 z%PNXzf%?+dxc$+}++v-97)*-Rruc?*DSdb)P(; z9_;wTJ#4XI>QJ_e_C;1Trd+W3x-HDBF-3(lOi|B4RXlQmEpFfDO8QT*CBIg?N!`Qk z)y;3Kw&hD2-GZj6RwsTl3pZEkMI#%`;);Y`(!bU$ zEzZ+RyUR?)h(WsIY}{04_UOv}F|)j@LsvC?-Vv6KBdh zTi)qORV3d<@|!#X7kBc_Qz-wr;^nE5m+$OIp7QimGcu9LR3ej!OeZp-$dr0zQjuvz zCKj1mWO9+|MJ5=TVy{dxGR??DBU6n`HZtAFgd zhSY`>hg64@ht%hl0+9;6QX*2LSBgZcM9M_!L<&VJMM_0#MT$kLMao6$MG8hL_Dab} z&0Z-QsoE=LBXuK%Bb6hiBef&NBh@42BlRO20NDaw*#yWo@XAI&wt`nS1F{{E4S{S4 zWK$s90@)bI)<_HFq-S{eeDmp*DJMwde)|(e2hK6TvOHvM$ntn)Z3F}T@)+!wN7j^t kERFwOATKuv^pm|(AbTYz@j>qB+)+7+{QTVf+)@2r02@NJQUCw| diff --git a/lib/pytz/zoneinfo/America/Indianapolis b/lib/pytz/zoneinfo/America/Indianapolis deleted file mode 100644 index aa3dfc43730ed25bde9c967039951f5c2fc15cc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1649 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 JgVOP#$X|a10A&CG diff --git a/lib/pytz/zoneinfo/America/Juneau b/lib/pytz/zoneinfo/America/Juneau deleted file mode 100644 index 48bd37e88e273741eb5b7df37417932f670a5e00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2336 zcmciCZA{fw0LSq^j~A{`w}eDQJEDR-dcb%p%213D35?rKh%6Gj!%9#XLs1fwkz2{t zHixt5ILB67>X~k(YoX;_TP7pedYFsStyxZ8>uEKL+xZ^Wo8m>U{Qr0E=j=aTvHiZ@ zx~6Ayo&P*h<_m{suQ}Y4FYHNFqYHj%8Er`MOr9ze!MD;qPJfyRc{#=t+A%|fZC)G* zZ%9=UYutgzl4#|U*8{FsSEy*ua3K2V8R7m>2WEVGT*Z8K(Gz=ipStbzanJ2<9}}K~ z`#g8-35Ywlwt8kZZ4q&`>qUIISKL)p;F*<{FA|b#0<)tNL}F-OATcA(llaqeJ?F|I zl{C6g&;7`y=ADStcOU*iiS{Bnzx#qp_RWzCHhwP_=KUoXt@=cy#D61G)87%PlM_14 zy;r1-f34H6wTO(NGdgqZ6_qt`SZANyq?UBOq~&YXD#x#6ZfmYuTDD8xQxm81QX6G{ z?r*BV^^hz~nkfpeE|x_TzlwW5cFX%NeIbfo?2e@ zsb0}|P?at@rdO7Bs+B)qmStJ}qHOG(ERWqL%1;i;RX6HI#p@sH)t`5$%I!z=Bk$I! zs`?&XeV|yaDfa6}+vlm8q;l=`Im-KIhW6!MQNHgUmTTt)#oF`fvUc*as2hxtPmG@v z^}BD%Cx-^by2cUt)IhIzy7Ibi=slvI$r{${{XMENR_hIAezoDoe(g^!SN@A_y2+KH znvVMP#;dXFxdW~8`H^(-Li=NKla3M1z5?0OcT;T6pDnjEkBHXz3E5V4LbL^E>Gr~5 z)js}*?nuz8W9X9J`ul#hZQujl`DL5h-u0&5amuH<)^+O_`wLY_s1r8r8$R_l!WDT7 z-(awBr{e^JZv;ZZ?QfL*jp2KUCm8H*apLSf!QSUq*La=k$IYoWr_}4za?H1q3Ueu` zFgM2uF^6YL@AR8;n?K<21kB-{5;V`Uv!C_gj^5n!$j*?hS9V1&t_Ka*A*)_6lWZ%ff zk)2!3)~#mm$mWsVBil#zk2C=30MY`a2S^i;E+B0{`hYaTYC3_m!fJYfGy~}d(hj5_ zNJEg0AT2?9f;0u`3epy&FGypM&LFL^n%*GILAryq2k8&eAf!V`i;x~6O+vbav+NQ;pkBTYuSj8kn63lEK$_KlqS>WYrK zg|Fj`byDZ<34Z%_I{#|4skUjMDYa>|DYa>|xhL8C{MD7F(Ep>>|8$!F!Bnx`bi9b7 UXI3uF&drvYl{q=tIoZgjntSqTbVMQh2aAwm5DxP>&?8k=li7YZq>h@vvWSr&j088^A(lM z&368EMVl`?TszIfIjLrATHy5${*W72+!ENdp;2xw{mt3ZHBlak9~U@s$|FB}As9H` z_ZNA5W~@HmSS=bh$I26hC!EIprTTPJb>N%rYh_biMc~Y;MN-vF3pAJbWJ~4nz_$g1 z~vDwQFUwig-%tNEsAS;;L*nL5b)QXJky~K@sy}cNv?o zOUCY4ujBLz(LpVj9lv@*#qamaTlOteowh%(6JD9C5?9U9w^lr;ZY%NV&QtrTE(NK& z>(Gv>TWSZL)F)MRZ{MbSM05~6evXqpo7+V4vGcOmfuq8`^9$K~(@t@FnWOJ`Zk^~; z*rNN+t5tXA)a$!OzohQ&vQ?+_D^)4MPh@Ibp-OGqBKw^itoqljlxYnw@@^s$lm5J-V&08uQvJIriiT;axIcj(fk47(d-BCsaj=hjKII#3x(Dq~t{DD?BWG zS1!xRId6-}XFKUB?n7!y{Utp$xJ?ypZqU=3R;%gD_UK3I7O3Lc)p|zFI3>LA$(bwX zi&+Dzpj(=Xf&2oVFtAPe~O1&vRu-^kq@9!!75vo)Gh^hUo=IFR91MlJ(=Y z4QgRwP|G!Y)Dt;MFIrfwO1m7?i^o@}#lbVOY)F+TYdRpylgdST-J7!F_agCh&2st7 zsa&z7(l4Lg>lT&81#;=jj&NN6+!2x24%a_~8PzWAcEZl#-*47A6x#Q$%L#?v+2};s zb9?*l$lFN>g+ATy>YO*q=j2T?&%@@K;B)fLIp2IUmx~u~-+%w;=J#@VxOSO`b8^UB z#gV~{$WM>__{h(X1OSNu5&|R!Rucpy3P>2NCJt5;2qY3nD3Dkn!9b#cgae5O5)dRJ zNJx;FAVEQ*f`kQ$3lbP4GDv8wCN@ZLkmw-cLE?i12#F99A|ys=gT#R-ahWgyaY6!x zL<$KN5-TKFNVKdbTu8jECSXX!kdPrULxP4x4G9|(HzaUK zNCd4Wgh&jLARUP)5@#gPNTiWaBe6z;jYJy>Hxh5F z2{;mQs|h(0bE^qD5_Kf(NZgUYBauf!kHj7cJ`#N-{7C$*W&n^8u$m!2#=vR@0T~5k z7?5#51_BugWGIlaKn4RD4P-cw@jwOy84;@)5@bxQW>An(v6^8)#swJ|WMq(`LB<9d z9AtEm;X%d+86aeYtY(OiF|wLLLPp7Ih6x!bWT23dLWT+%D`c>c(TZ?gyCb7+9It=6 zVY}$C+ZA>W|9-R1p-}AxdTO@Itd`lXu+?%U*zM|Uw<~F^*KF4R@7J{fgE%v5IcC<< UyaUs-(=*e&Sy|~>>6vkV13*u>o&W#< diff --git a/lib/pytz/zoneinfo/America/Kentucky/Monticello b/lib/pytz/zoneinfo/America/Kentucky/Monticello deleted file mode 100644 index fc2f1b0df86ece6228927ba6062f03ad43bac2cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2335 zcmb`{Z%kEn9LMqBHg(hC6@9uQ*)#m_{9GCXdY>DJtY z(EbczwnjB4Ni?lR+M2okERof07M&i%nj88fdQf5a_Iv-_SCgJ zmMi{tLHb{KxnBM99XIe=x_#u`U*+Jl3+-Le;g4<>L2qY07&t zP56c*lsFtATzju7zwK9r|CVqW(6GP`th^$Fie~KK?DI1C`4l@e>VynEc2tC^KDof@ zwZp$2Q4y!N*$Yn{RFSVA6j3jBsOWti;)d>Obz@7lh^ft2vE}*VrWNt(=G1r*m$Y0i z3b`iY{T9jipW^Jr-_Og0iQnv7&U`Bq-}=VBb?5_mTW6%WebVv%<=)XM*SwQtRjhZ*%KiZBp~5V=cH6YIE+JZas?J%S`8ipg_l8ydL!_!n zJnPhaG^=X8!%p3+lj@PF{m%N`W9rfIHmAPnklHY?#|zd*HpG3z|unV_CHKIybqd6hgc=4{Dx z)RXOpoUO4Rs*Z|or^EZ5?9A`CI;YOauDC9%Yy7C}{-w@(YG99i`eLEAqo-Lub28ED zsV|p14+~4Ugv-xg|NPGS9s`R7Rm>;L8D`t-|pf=^$)zjqLs7cwzqX2{f#xgnD?>e(UF zL*|EOf_yMTPEV0zj>sfAW{FG_nI|$)WTr+vRb;M4Jz0*~BGX0Yi%b}qF*0S2IU|$i zm^CtOj(H;!=a@M%b&k0sljoSdQBNP4Kav0>14s&x93V;H$O4iEjyxcV;K&4$3XWVD zbuy4_7{!yGJ>Q8$qAAaBr8Z-IP!udh9fgbYB+L(B!?qAMx7px{2&QJGK8cE z$q|wyBuhw|kUSxYLNbM<3dxmGCkx4zQKt*Zmr*AS$rzF{Bxgv{kgOqTL-K|s4#^yn zIwW^SojfFaMx8z+e@2}^B!fr_ksKmPM6!sa5y>NxNFY19ct zGHTQ*MRJNH70D`+RwS=TVv)=usYP;&Bp1o9QKuKluTdu$$*@tU7|Ah`WF*T-nvpys ziAFN*=hBaVfPv5d`~(GFx5wuj(E%}S)}7Y1{;Siv-%+O4F{ajWtKGWN|6c4rlMP`y Z;(0pe>F#BjxtZDN?wp*=oXqU7KLARimL32A diff --git a/lib/pytz/zoneinfo/America/Knox_IN b/lib/pytz/zoneinfo/America/Knox_IN deleted file mode 100644 index 33169f4596381b700b3598dabf7706dce25f65ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2411 zcmb8wZ%oxy7{Kx80*W9gnHZ9RX~hgAu%Wc!)~1eK62ZKH3Sp*(SmsfYM2(JHlYG%M zZ3?a-EONPKXideo(9~M1IYW~ml>pP6g&d6+q;_xTd+bG9Qmj7Q}re9Wc5>V zyuMtJVXkCm$j?*a%+-WAxq5SyxfUvNt)<`ma-~~-Z9QpvzC0<{k9Miv#!hW^pHMfp z9M^pds?@Fi61jcVYwomp<&UotjlU^T0v|*gsg4v+Rj&zpwO4{yMyQa5L-nBC>uT`R zJvubyTNV0Nf)0!NScUC-Pr}VRYG~(n9nrquL>^nChaK5whVR`bQ8i`ezRhJaq9Whi zUz#r?=cSuyZ@P?nD%LzOAy#6>O;MwV+>zLz(JJ<4jDE1|wi?rNOF#7aMHP48f{w30 zs>YTNmxnjjt8sZZWc;$v%p+-M<MpQg*tb~2sJxns(yA&pPDl! zUirC;ytq%5b(l=*vfd3u8??>Md3#%xk+n-A!U{-tVN z?RLGsElX{vT%%uWN>Y`@1^V^sVM;vW2@1Bid%Z&L`R;(<3>on0|M;Ci;K+WD1Ogw{ zNr*cSarX%B5_R|awCO&XHpgBC_R96i412cY;l|xJ@Uq!Iap7Wi*^6^bz)o?nzmBqa zl;xu=AY}c-9uz<*h)^JLwU|&qakZ#0z(T==0t^Ki3N#dK7{H;R!vGHj9|nLZ z2r)oJ!H5AQ3Q7zxxmuhkKv9sQKt;id0u}`=2Dm7AF#twEi~%wVW(=UYTGS}8QE;OG z=W3B-fX>xo#{izIMUMeK3Vsv-DF{*^q+mz^k%A%xMhcD;AYCnz6ewLSmJDFJS~MBp zq~OT_C|fG08EnQy`~cP63^QItBJ1k9`G)xNsc!HRxZS z5BzEObkIHC`%k|X2z>N4?pWWg?AG_c$?l1AzK^{7d}g+FePHANLY{=%e*u&2$C9$2 SOrDgSl9ZjAnw*-P68%bdh%NXZ2r}EHQ$RGx8ZZsEiWz1X&_O diff --git a/lib/pytz/zoneinfo/America/Lima b/lib/pytz/zoneinfo/America/Lima deleted file mode 100644 index a37eeff7de59cabb56b583eec024d09e7ee6e2c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 395 zcma)%FAKsz7{+gZii0tWVA=$k$sq{#D=S0cz$L*d*bGLyMbNJJ2@Ez73xppJWA43QS!1@5{yxuIwS^3PLj>C$*R|48>U3aCsZ?sFQs*P9^an8$;Siq~uTtXQ z-AuZ|AXOUdZAFs0L39Pt7er?ey+L#@Nd4&_3=Rd!1B43*9}rF;yg;}WBtOm2 RON#^(2>zkTm_^P#>jTuEeU|_L diff --git a/lib/pytz/zoneinfo/America/Los_Angeles b/lib/pytz/zoneinfo/America/Los_Angeles deleted file mode 100644 index 3b7ce1dceebf9fa9db859068da1fa7eba6df1cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2819 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 UyaUs-(=*e&Sy|~>>6vkV13*u>o&W#< diff --git a/lib/pytz/zoneinfo/America/Lower_Princes b/lib/pytz/zoneinfo/America/Lower_Princes deleted file mode 100644 index 6733d2413e3ba3e802c3a720ff09f30a5383a802..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_z#0DSVsp#)FaR|Ns373=IGOAK1ab^8f$w0}LEK iz99^ben1=?0#phDAtadm9|%CEgJ|My-~w7^!UX`QS1t7b diff --git a/lib/pytz/zoneinfo/America/Maceio b/lib/pytz/zoneinfo/America/Maceio deleted file mode 100644 index b5201e81d42f9256adcb7125469509a08d77ba41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 742 zcmb`^KP&@L0LSsGe~F4ei@~5CO$UkLQPK*7*a!n|z+e(#Vla@9kT6M%BrIeK7+Ew_Q{;KyTP-Bs`f*Cl7j90gxp}YNIhdW}rW)>@RD43DKkB8s?}|)%PiF0~c-_^`Tltj8pG?d5nt&>d zw8=u^R22Q!PVu0iKAtP&=hmufyx5k3r90K6x*QR{RL$#ivZd-=1;^{0;KPClMRHE) zCL!e7vTSc0R+0Rf6OC<(?#!d?&JBv5bM5rb*QgTTFE6d#4a?H{G3zVS`u57I92&N* z{?RcWHveso{f9c*9102Px=3N9vZpDH z)b=#Rk?Kf!{*(I10>}!;6380JBFHM9W*KB1PqPrR60#Js7P1(!nx|O~Sr7kzLBAO@ G?EeOOlO$IF diff --git a/lib/pytz/zoneinfo/America/Managua b/lib/pytz/zoneinfo/America/Managua deleted file mode 100644 index f1c35040ce46c190d6def6984a7391616ce93a28..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 437 zcmZ{gy-EW?6h`mv#t?(xhFGK!wDqqrg{6XBdUi3IzTI@K;djw` zJ9q8%_oDqcbW6wAi_0&&ZYBFDy02eu`(RvTTe<7`v&;U%;V6ouL={gM!hOdqgu5H7 zh4A!X4bEt$nhXZsvVCuTb=LDNF^T_s-MXG>lB&7S1tq^)J%OywBkMyHAQ~m50?{cc zC5RS84Wb88glIxkA-b?qPU4y>Q9(J+<1BMI%e-_pIm8yquK0+>;0Ay9)#t+3 zk}bZ>nTy)KuFRB7CG0lU!6#QOuIr#RZfZxNeh5xY-OuRP!=!ub+|=)G%Y5{uZDV=X zG|IQS>D68Htjo5-0rQ#9+o7vtGraR?Qz!FoWGb+ud)sEL_ui)6rJ2ax=(fbKPZX6) zN=4D#b)rM=PW3EieU-_s@bOt8$N$6DNDh0E&9Sl@*^cZ-8pKKmq(!XsK$;+3kTysk uq!H2yX@&Gcn#D>tq+P7^LmDC-*-1;JC(;z@inK-gB8~CCI(w3Q+WQ7f-vFcl diff --git a/lib/pytz/zoneinfo/America/Marigot b/lib/pytz/zoneinfo/America/Marigot deleted file mode 100644 index 15c0f1f7450c27dcc5971c9769455758f1606817..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVN6xxPkHi|6>6R4FCThKfu7^;~T=@7#spp#1KM) PLH~gOuVGw3Q%$%4?mi!V diff --git a/lib/pytz/zoneinfo/America/Martinique b/lib/pytz/zoneinfo/America/Martinique deleted file mode 100644 index c223ef5c2011dfe531514dba8262ba3be5552625..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 231 zcmWHE%1kq2zyQoZ5fBCe7@K$E;u9{yzIhHJCSn^HnHc~7KemT~;s5{R2N+oY|G#>H zk<-o1H-y147>Hd$AbJ@>u$#{Ulm=lCfUyPt13_lH$Po|?vI`^$vJXT<>||zwSqik8 Y1#C4Z*lJ!Mpv_pUXJFt0y2peI0E@6U5C8xG diff --git a/lib/pytz/zoneinfo/America/Matamoros b/lib/pytz/zoneinfo/America/Matamoros deleted file mode 100644 index 5c59984def290712e183eea0655eaf8dc7a133b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1402 zcmc)JPe{{Y9LMozB`A^wfe<7L6?kYZH`C0tELTHwnmYfaW>)Id{_H7rI5T@7(NlQ{ zOeiEoyM$PmVMG#Emnb9%kq$yh5`pvtMMC1Q=l#2O>JWX$kJlLN^m~5-HLcAa@yD$< zzwmHX=HdH>@#y=8Z57|d_O_?m9SjRkdz?)7Rf|1kUt~sVw#f9nmV0B9MAp{NI%{c7 z?ECdfXa9&%`=c{DXL42LKDnt63@)gHccjh>JyVDJZpgzWqbk2KB)z-))Ddr~Ji4h_ z`F5mB-^z7S5R)hi=9@&};!k<(?rl{xS1kQK5mg*blO=Vv>iE!RS(=lp$~wQx@}v|M zsF;(1Rfnp~n39#Bl0|j$J6-)!h!bm3T{HGk)GiF`y1p0ULZ@e!~jnwG||BO04 z5Rqqgjj6N2TG^P;ubOo@Z6t3baU^pjbtHFNlRT2Wtw|rr-_}e3nE^5djyWKc;Ftw64UTyr z6XBQ%G8K-w*qX^8v#~YPLFQv?CWOognG!N5WKzhikZIw6o>#nCTc%l?)1U70xYC?{ Lx7+1*rN#dSVcugw diff --git a/lib/pytz/zoneinfo/America/Mazatlan b/lib/pytz/zoneinfo/America/Mazatlan deleted file mode 100644 index 43ee12d84a7c7e47aaa92406d01a539ccf93079d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1550 zcmdUuNk~>v97q3_4T#_^8mK6uf+)l(hX%78(kws6PcyCjEc?u|)HKlsy-)~+a7pLC(?eR=!Pu7NIZj;A}m*VE%4>FF767<~Al!qeY;eNd!ahZY}FVU<(#q9m^h z&-|t%=C4+fVJ~#lxP@x*jIXlzoxfW0^SLbjGSMvSdMeQ!erEa2R*7l)XjZh;%gVCH zCiYN^j!Ww>@kIx8Lhy03Dxp9p22`1(d9ga_TeC{`ovV}kE7h7eWAxgdY?bn8j<`-m zsnn~!l2$WKr8mBnjKT<$S$a>hVy7B+$`#3;{oUjQHp)7AX>uoD(zye-&H67#bl#n_ zCcm##Z@7F*ZR||dn+~5*1t&tZr$np5I+tut-mJE43YMY;32JN11o2MvnBtkArFbaL zY#Z*AlHPe{`>Sr*ac!(Az57h>Y<_QcUF_6l6%R~#!%1C{_fGBh*6PZo_f=J5zTPvv zO;rciNcE4SswN;$YF?D7+E3B4_eO@=_hgprKflu)XcwtFm}csay%wKQ&Kd3F`wxy~ zosJfgC7JuG-)X4V~ms?y}Zi%;Vx_w;TA(Apg zg~$pK79uS~T!_37fgut*v_*!W2?~@uhb)wx{v#RBV z!#W^`d;Q&;Y4zx0Qa|4Q+Dz<7>xsp)YI5skJ2^gPrpgcW^sTq*$-7VX>4h3IGgYtc zK-xST8PU)8XI1t}-o9uknb~8$o?U5Ext=bYE8JJFt_|tA#2qvD^}3x;glgV=u?wx8 zW-)%;7Q3rdakONA1gBN0y;he#kD78_+?I0->Su9KFE8vhzp|b7_jI57b1$h^hC5Yw zqeEAY9X3@>XEHm7#!XZ0P^P)-yJ`M*KGU+TL$|!inqA8$ZL2wC+6o`^?%Vy1U8R?1 z-%Oj)rq1*nJ!pFet4;6wtBsN9I=3HV2Nkkoe$)@-r!dUsJueJ%)|2~EK2jBi9}9e! z^1R6VM)$sX^?N*#@_Le-zLeL`O+Ip6yHfw3TaElCht(~IdqXJe-0(yBt6|6tDRZRE zk}^+MnJHzit}MN1}F|(#RA2HtC*m;pxAH~9~2|5 z;)G&_;)P8M6F dIG*wqw(=ruH#xRjR=*z+w(F-WDn<65n!okH1)cx^ diff --git a/lib/pytz/zoneinfo/America/Menominee b/lib/pytz/zoneinfo/America/Menominee deleted file mode 100644 index 438f5ff0b846447eab7ef45c8ef19d49db69f12f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2257 zcmc)KUrg0y9LMqRL6Seop9~6-ptNMj0RcnNq$pqv67kOwLC8Wd#4?@|j-p178^gL# zHYw9;C`E3qm>SEl7TMp6{>%{PY9?td*KDk(^dgm=)AN4pqAlO&o69j} z`bv1C2@Iyo#DbqxSk`wcY)7h&h<#T@^uHmI=0$b$*={}QheIanSgVdcy3548wM%06 zwwPO9XpzZnmFCu_N{Oq^Gx4Q)a@)K_b9-8%ButyDri716V#pMg_*a6SdhV)98or|M z_~eXAKK!Fj>HS#U>5q}Sw)LuM%m0+=>pn7f=Z?rdW&6yG`1d4r<~EZW7}jZ#^(Jj} zK+n8TY|@8b(%zBPDx+tk&KxLGv)Ze5R`(2*-RPH`4dH5bNtN8Y^n%JwoiB58zEN|- zk|b~HZzk`2K;~Wj%FO@rtlW3{9kbxzxX%A@r@6mtR6p>lG6l`Y^n)Ec)I$}o>%xX+ zRWz$Z7Z)v2#TVa~l8p7HWMr?DMpc;7fh|%tmTew>?Pb02)FM^BwM{QNlBFtYYxLsX zlhu+1`Fd&VCABOmMf;YYQoeDIuFM@&mA@uSRq{zw^@T`v;D}k-_p{WD?lH9;pUWdd zo6V|*1M+B3t$D2cQ(d>cO|8!8)Afxtsv)XVuPMn_YsS{<#?%zm_-&bP3iGI@ey?74 z{ulMc?oxU3c+jl(r^{0Z&za`RC{bOXnWuCAkY}3TG#lcFrKMuKX$g#Je_o&Rj~>^X z5<1nUp~JfE@3m@kPq*IkeVN+Y-m0G+^s4q%EA(@FqLp~W6EeZR#1qQv#(sjqqlY{a z48FZzLf!Xp_nyRCVz2#PSmcw!W%gNNpT#~Yw%_e}c=7gKe>GwDuRL6refXXbv{$#W zv>sUyvLa+j$eNHvA**uQWg+WA7KW@0SsJo7j>RFXbK2!0>vP%#a;y+pBCXGGhtlw!1fKDFRXjqzp(MkU}7pKuW<;3#1qv)j-O@Q4gdb92Ifel5o@n zDGEnbkg_0kK?;LZ1}P0v8>Bc$b&&EP^>Nw)aa71@OT&*(xNE;JEVt3U get`ciFhtru&$0jJEuWp4lbPi$&(6-w&diGZ2fbEx+W-In diff --git a/lib/pytz/zoneinfo/America/Merida b/lib/pytz/zoneinfo/America/Merida deleted file mode 100644 index b46298e1f202ee4ec22ba3cf9f8079c83ebd6c7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1442 zcmd6mOGs2<97q3}ky&6AO7sAUKm;4#W>%(+I+!#0n$oO%l#WeWerk!8j}H_yp{!$fBdN_sEpKwbt9%IW4?Af z`^~n94|;oan<O;6 z&Fsl>%igjGQx%mg)oFpov$#;#tbAi?J}2sZ-^Y#jak$?9;)4=$hY+N_9mKQBQ(-^dLK<{q%{*BhtHE%qX}WLd|a z>E>tup8GGf@L59*K1C0RA`nd&sz7vMC78~t~i?t=$VncocWl?nK diff --git a/lib/pytz/zoneinfo/America/Metlakatla b/lib/pytz/zoneinfo/America/Metlakatla deleted file mode 100644 index 4145b9a58164680ce931c1db83eaf92f713bcf74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 717 zcmaKpJugF17=TZ|RI4~B+D->asYxWhCJ_>mkW_j_*gBBdd@KwSg9L*(-54Zy5(Xb5 z6T2{UkTCfH27}r4K9`Bcd-I;>uJZ*)CDlZmyeB88 Qq*LW)Kh=E1={Okw0*}wEApigX diff --git a/lib/pytz/zoneinfo/America/Mexico_City b/lib/pytz/zoneinfo/America/Mexico_City deleted file mode 100644 index 1434ab08804dac08e4f595967d8c325691f08aef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1604 zcmd6mU1*JA0LLG5WLQm@3m+vZt>*0OI2dMg#+vQehhv*zJDWLk7<=a9Gz?EoN-^7o ze5{o$U(q%fX3T|@Q)Eq(FwrTJxbRSme7&CEn>$y^h5ys@{@&iJ_u}{Sl?4MS;*X6o zU%0HwT;3<0>v=1?K5dKi1d9FFJ%j$<7`MOo$02?9Ww$?k!c}l@^~cD)cP|PCqQa4Z z>%|2_r{W^dLro8pYeFJrN3=}ME)}k#cXICRG~rHpAm@#qCgx9ltLMM@DHeRYuhWJd zYGKbEy{PNETHM#H(~rGWOWLH)sJpE)4<40E^Uo?zb)C#gJgAms70TtY0hK)~Rc3!_ z5;=}Ine%j`Sn=w!%YYI!*}J@)*-d+`~_K8 ze@n?jhh=@)GqF9eMea!J6FZlC<*q61B9s`^p|1x-Lu{^Y7^)PzKg`j4ZhFMtfmq$x zQK9yAe$@M$GSz|RM|wmQXQVj}`^nqCJ(krGBZOtOw+M%2T|OhCE$c@2h#31hKF{kD z-c>%~;bxgz;=_~Q^ZkWUmKjz-%!1ejF$`jvO=B9wHi&T$>uehHAokfb20|=^n8+_; zBg06Dl?*c>b}|fwSjsTfrm>Y_EW}!fxe$9H216`{m<+KQVl>2Rh}jUkA%;UNhnQ~D z*v>HCrm>!3KE!@T0gwt9B|vIm6alFMQU;_BNFk6)Af-TRffQrYR0AmoQV*mcNJWg2 zAT=?Hf>gyQ3sM)OFi2&L(jc`#inD2|gOmrU4^kkcLP&{_8X-kOs)UpYsgqGCq*6wy zkXjkV+BDTN%C%|gWfTmlm{BsMW=PSHs^R}%_E;0V+XSEBbvcurNeSNMBWv}aA7_aD zhljJtKKveW@_x82sis1w*7ch)2luG4#ocDy=F@t7PMevqs7_BDdDNt(FV|@UH)K-6 zbUmr>h@^i`){{H8NJdXs`CB6rxHDR1HfKuKsb4BsRcJyx`&4#;-%MGiRZiM)Gc|NY zO^g3(!pWUF{ISPO|9M%@=)PxWzCEO8wZD|vk1BQUiMulA;sUK|&&u4E3N6EGE^5{+9r!%jaQL01rl>A*{#kW-K=W8j+Ij&0jznRjMo4T~C*Q^*grpvB&n3a7sy1eCrS=A|e zb!C%T(;CuiBj;t^;iy{gZiE~H`gWXb{`gRB zIh$g(zUbB4>V2lBy+hX)zc<@YT+lmmy3EenCcSIqb+bFVO79+cEcM|=Ro{0_8b+0? zhR(yX_eZX3Y^|22H>ql0bD`{i5T}|~`{ls7el;j=@IU!@-m_Al&-0#W-w@C1HNIh< z_u<{3#Kn=AZ*Eb{ClU9R7h^r{#QtJso;@s$7g-y!IAnFm@{si*3q)3kED>3w(=HNO zrPD4GStqhkWTnVbk+mX=MOKR}7g;Z|U}VL}l94qdi$+%Mw97`;jVv5lIkI$Q?a1Ph z)g#MC){hi`RDhI#)Zny5AXPYR8Au&YTL@AKQVLQFQVdcJQVvoNQV>!RQW8>=(-wtP z<+NoXbvbQeNM%TANNq@QNOeegNPS3wNQFp=NR3F5NR>`oCQ_%<7K&8rw51}oBE=%r zBIP3WA_XHABPAm>BSj-sJ8juW-A-FLQn}NXj?|76k5rG8kJOLc0Qi630ts9U*%HZ% UWkj+Ap+HtfBp3_?16c{b0R`)=fB*mh diff --git a/lib/pytz/zoneinfo/America/Moncton b/lib/pytz/zoneinfo/America/Moncton deleted file mode 100644 index b51125ebf1121965254ac60b6ef3afc0bf05913e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3137 zcmd7TYfzL`0Eh8ixr~u0DHwvOXoVV}fF#~xEgeE3jtbrqJe9_PTab#E+^8lU;X~t$ zdCAM*SdHW~4VvblBw_)Yj(G$n%*3Mznt_6vk*?5r-uf1O_uV=Bd*|$a{y!;mGvAD| z{payAHyoay%;DYtgSG>ruw;$gap+gq zwQNx}xwZPNeu>J^5X8LqP{Fm zUMiR=bYYyloEa;w-9t7Gb&IC>f%;nSKy^LTu7B%$Ro(Dz&^PW?so$F_ zb#v{Ps->z(-#k(&ZWUL^)*VHnZQU+;`~3oOCp%x>oxe!@k(?#(#U+V9M$s_o?cB`xO1)dbo1eh3SXKd#R3+p1QNBP1!cLYWvz6)oppT_Q+`!p7NIT64j#n zpndW&zfHo&wo&@Dt`Lvw<+8{54a&ECj_i4Gnd-GWSNm<5t)3{DrF*X&tNLV)(f)J# ztAK=H-8Z&FJvsED4jddT`gOmggX|AQP@7u@U%n*zpQ)Em9X%=r>@AlAcYZDg<=)mI zAFdIDQ_t!lSv%F!F$eTBQ$AA927IbRhc8s29pB1fKJjW;{bo7*#xV6KGX_Uom|i`3GNGjdsMzF1bjPp$~e5-Z9! z%9ZVj;@!gKa#dY~aOKUB@0Iw8y!3JM{mr*UH+vT!56>o?>($93Rx*+sgSio77JM|WVw*_vNQ{ZteB-)GGxt= zMYA-khAbPhZpgwRD~Bu{vUbSgS(?>DmJeA!WC4*CM3xX)Lu3(=RYaB%Sx00ck(ET2 z5?M=RF_G0omebO#C$gZ(iXuyjtSPdn$f_dCimWTLu*k|HON*>6vbf0VBFl@cuccXF zWQCC>M%EauMdpQ7<}u3*tTVFE$VwwijjT1Y*vM)l%WY}a8(DB<#gQdP)*M-MWYv*n zN7fx#cx2^~rAO8tS$t&mk>y9$-_jHSsQ^*}qy|V4kSZW$K*sR>dPq$)^Rkh&m+K`Mik2B{5F9Hcr(d64>8ngSseLP~_x2q_X$ zC8SJ9osdEyl|o8|)CwsUQY}kUE~H+TreH|LEKSLfnju9)s)m#esT)!_q;g2prt7xQbVMONEMMXB6UOxiBu9PB~nYIm`F8|aw7G#GzCQ}YH3P} z)YQ@x6{#vxR-~>-VUfxrrA2Cs6c?#3QeLFKmZrc+g)L2qks4c?A|q8s%8b+*DKt`P zq|`{Q?H=8__;`ACaoN=$AGJFZw@KvMMBC)rMBC)rMEl=dTQ~lRNh!Af3->?ew%L75 Z(MOrGhb2WvL`94YONxw)h>RHN^EWgsxVQiS diff --git a/lib/pytz/zoneinfo/America/Monterrey b/lib/pytz/zoneinfo/America/Monterrey deleted file mode 100644 index 7dc50577749baded06400fbe5d2e8dbf2579253e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1402 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 diff --git a/lib/pytz/zoneinfo/America/New_York b/lib/pytz/zoneinfo/America/New_York deleted file mode 100644 index b2c2377f4e87960bb2adafda2a4ac6385cadceea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3519 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 NC{k7yEDM(U{{__FS0DfY diff --git a/lib/pytz/zoneinfo/America/Nome b/lib/pytz/zoneinfo/America/Nome deleted file mode 100644 index b682bfd9cd899e670ed89de3fbe79a0d06e14911..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2350 zcmciCeN2^A0LSr%*9!zi3BDlG;~T`Q2M~p#ybwl+z=K?GLZna-!%{F9!xu12M{X6R zo5N{zoMWpk+nH{rvFMg-ZCUOPw~}0xZq0PbTCbMn?R*cbe`>D3JkOr{IeW%mY`?Fk zuJy?r>t82Af8pf}=$HGv)4NOjWAlG%A8T~nzmKg}H%@GF0) zvT2nsw6WSBR=wC4UX<&1Wl#6HUfkf1jJ@WIJaXBI`u+>wZC{W3qsM=B$M{D4x1St$ z-|@ydCwBjc`_A3(ICpJ+)jh5Cpc7ZS-5p=n>r5|bbk9g_aAwZy@y&`Xb`pZu`4ZCO zViSHSRt)SM4oGU;fzy8F;&X?GQfxqYYQJnw8VfBm=ig1kS)!WAFe$?;!_ zl(aYPlpEJoYSc@1>cp2S?Ml0yKKh=@IQxRk96F@3j%}2SdY@BbuOqWtq{!*Wk-4Qi z#NwJbnU~TemgM{*m%1Jj`H9o){7d(Ug6luq_kI*5?mPdvU8s`P{Uays2VRa)%MKi{ z-ECJ?(ayJJan&d4!KVGPWYJq{dC69}{KpHTG;`1{J$p)&#cZ+5jtz?ySL^NagYT=A zpLNTMZHHCm@j6*mze_p$3T1U+i(1u{Bx@4Ol*emH&mZZ^n|D!qzj;`!Neb9&K1>s} zH!j$9!_nf=iBop{&Pnmu=&-%E$uHIo_1g^<->Js_!}9UWGwO+!U9u@gspira*?e`6 zYDp=REuVI(R#&=gJ>pgCFU82G_H~G-{b}}wuGM0riniOlOGW#@q`hg$Eb&a6-|mRN zE;_4@+MR(Jsw@AD?3(yZbwQi2obbxtwS8*)V7?3r zwn9R0_Jp~@Z{ZUNG&`0R2y`?Ag__?8^CjBcV*`P{b}KFr7*ovf`dfIsKbNA2MG`oAtXdd zjF2E9Q9{Cm#0d!$5-B89NUV%HSV**tI$TJ+j5=UQ#E_67F++leL=6cW5;r7pNaT>v zA+a;+;33g7>hK})GwJ{$5kx|W#1IK05=A78NF0$sB9TNwiNq2KCK64f4kr>%qYfw% zQKJqi5>q6oNK}!qB5_3mi$oR)EfQNKxJY!3I=o1HjXJSnDr3*7~kvt&^=|t&^Q-?sHdG m=v@DgZ2ui>{s~j*jw0v*z%nZ-O!0?RXA8_qNBB5Io zEKT3MEYzS0)wJY1-&-vtp3B|ma@&1>_VPw5YW+AJ<_k9`Vs761_D|N=oPlKC`HHGc zeN1M{DN%@PS*X3p;^4I|W~M}`-7U+9c~L3t$*LU|ZwGb#-Zdv0XN&TqU#RAMP&O}5 zMJsTjTgT6;U2DqE-Lx9YZOhxs0b{JvjZu6uW6S*}}u^>w=LL)Ge;p0TaT*##ape`}8YhbFE$ zbV1s9nm$M)q!ZH0)AT}`d75rWJER}d5b21tM0z4kk*-KvPtzA^>}fh9t&!gRC(V)W pNPDC|vH`LKvW2JF1KGsW?1F5A?1OCNX?8-k!vEeYV5W-(z5&G687cq( diff --git a/lib/pytz/zoneinfo/America/North_Dakota/Beulah b/lib/pytz/zoneinfo/America/North_Dakota/Beulah deleted file mode 100644 index c1e3b025b916172bb8464c3de234656e12551c06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2363 zcmcK6ZA_JA9LMqN@O0z^c4c4)2&E-~fPi8^QWOwDo*+B|3Skt8*aNo@kQm}s5{wtk zd$|~85)@jknJ_npV*kH3Nd}I zTweJgOUw*sO5YpNLi9vQN9T<2d-96(-xR3=YUbI2CDSS>XUcY_j4S7J>2|O@rh*R+ zNtgFkbqbTCiR&E1gv7aresQX`iXvoCz``>Nk<`ZHUaAIxn)`|4H8d`G{CC z=(4j%_K7=o|7hR2cc;i{{Mf#$eXqK^c+k$R-J$Z9Ja6actyB5Go|FYit)k$}>#{Jk zS`;4cl0_3a;=Y&n+bhpjDR*m&y8lRuRa{l6O1kG*53I;mrA?QuRnf7^v-+&%nRckM z^kJ*)>ljfH^QpJuq!4Rnj(FD&Toje#J>IJJ_r!yv+r8Db2gJJGD(^$?cU4Vii}i5Q zfO@39(y9&ZP;~{_R^7w~RUa2?)t@R-4NiyEa4=DA{N^j`(e6U=*lC~l@#e+ii9;8> zjb)+2+I_;iDg9@$xpBXDOZX>ZYjLM{>&%2|&KR(o$4{$m5gpdH(IM3`xxw1ryGK2B zuE=U_Yf?Lg6Ro!Da<#K(wj~_G;peZv{+CZ+z*T*GzPI`u!spv(ivaUJ%Y29Ud`AZz zl6Mj2&hrTOD*cq}r^F+2_0PHbXMGO7`1btsxSaa0JY2Vac#rn!s}2YmqzsKRHp<{A zqoWLuGCos1K*|UyL!^w6GDvDh$qU2e^f(CvJd|h zOc^s}&>W+t44Y%zl!0@MoHBHdu~P=mF?!1IImS-`fPw%80#l6v1q2ET6c{KtP=KHy zL4ksT1qBQaG$?Rz;6VYzR3k!x#8hKK0fhq<3M>>{D8NvVp+G~yh5`-+9SS@Yd?)}> z5TZb2sxhK~#DNk8CJvk^Kye^NfrEcWI3RvV9Nn61ziq!Dfn^#OhK3fVpEMV1!Pl= zG6iN+jWY#k3eps)DOgj$rl3uM+s~mt{sAVu{>Pu7z^nRbEA_uCMr$p%_WLinwdmSH q?RS{*J7T3(9%( zrs;)D@vjTfzwmGe^uv2>@8Mkg-IJlJuhVV!zxj*$W>2I&Ht)I|tBVzX-e|F=u2qWZ zixt+*uX2TNILGq8?-rsb-g0&MM8MXYR^Y}s6;wCN4lbKkAxo$1(DZQ?x;M)Xw?Ii&8m)Ne z$>QGRhpgDSg=$uKgcTQ%q~d;0wBxUYEB9EKJ^R$JYR=GvozQ<)-PbzXx_{T8n!DO> z&0Bv)JdkzSda&eUkr;E@N}6wrB;SvAa>OQ)JbucaKj9S%Mh>Wy^J`^l?^cy|tUxYo zuTtsz6J*kH00IrOl)2iH^PU$aTe9Z6B^ul^)o>@F5Bo%1^zS{I0y2QNF# zCphS~ef<6p`&`2Bf5#R<<~_`ONBaFIj=C(~ zMYN~DD?F?8Q=y+SugKSb=j*@qx%lGS``_aV)&J$;y7j}m+pn)SDDo&}Xq2&021gkk zWq6eFnd$*jMo1YVWsHvF#GI);BQ-;qmehL5-1Sk-gY78hKP*9-2K*50m1O*8S z6cj8dU~r&8frA4N3LvH$5eg)x8WRdA9H>xWq2NLRhJp+Q8VWWX;84)vfQNz)2S5~r zI3P0B7;%6^L5Tw<3QiQDC`eJDqF_YK40-&izkOHBp#*hOfTSSF0VM@X4lpTbQsAWE zNdc6CCcnF2HgX$sU7tSMkq(5Ap0;L@MKAQN71;S&;k+dkUJFrlr}ervh4-~Y(1f6*3d pzoU)cvCBN#?f*CYZ^TK2W__{dJ;k#qEi)}W#gmbdmXVeo@fZ2$ct-#L diff --git a/lib/pytz/zoneinfo/America/North_Dakota/New_Salem b/lib/pytz/zoneinfo/America/North_Dakota/New_Salem deleted file mode 100644 index 3488e466d5225d7f5185e7c910bab0f1bfd62eba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2363 zcmb`{ZA_JA9LMqN@E~#myD~5Ygwm2gKtM4dDGP`ok02fag(wO{EaUP45;eR^g89OE zZ!W@00wY&zCd|!nY=l{@t(*&+)7mI)Jz3Pfa*G9Wy1w^XZ>m@EKfBNO=J5LW@vg7m zkS6|dGt4hM+zaO6J)-Mqmi6jjknV1awt8OrL4Uk2#2Q&}O^sAXh(E>~<;3^pV)9~{ zy#7&^m>S5GzBi(U=!}xC_9@}_^mXaKB~k}e&$R-JC-saK6IM{ls1DknZUxI>9ek`` zy6q$ShOc_8kW251(BZw-tW!PW#y7jAJhWHbwC_1NySY}}Twf!@*5!-vf(PWB%y@B2 z{GBplex9Bi?3R&!aXRwXg;vy+U>!X&)0%hsM;+6D)r##ot8Z93jwpbW`M#d#rB5vwSE8e|T#E+h~60Um1qM_HU#PdogbvFA{pjh7L zwz3Bgi+c|IWZnDn9S!<2AJ=I#zqvUQpgimo7~o zP^I6*i1L`v?D7wUST}XjUf+8~RE&1om96iKhlh6BRW(P&BVCpDqn`J4b$hdVEU8yN zURR-NLfdq0ezvL|+ovXR!?*kh$qka?9EM!#8byF+YP0m zLLE3`Z%O|}Y;Abm-WL9;*k06bZ=V{|O&PtaY4n`l5z(f04E5{g@r`O{*FnAOVxijI z(x{&qNK`FVWqMENEG1mR<>zm{rs)$HFbyA{@2zf^@c9l~BEWf{>3oOye5d+cl6Mj2 z$@L1)8uOHyr`RiU%-=cYZ*wlb`1bz$xPr`odAJVq@E+|mR}~P_M;RJrY?Q%KMn@SQ zWqeM}04XD+43RQM${?vTN?sTyXU0hwD91=CL#2$BGFZxJDZ_PY#!DHnQ!`@9kSSxP z44Pxqlwos>n=){YkyD1wF?Pz}IYv(zKF9be08kL1K;YD1Kmmb*0tE&N4iq3LNKl}l zU_k+c0}Tos9C%OwacU5uK;qP3LIH&X6$&gATqwX$kfA_B!G;131sw`J6nrQEQ4pd) zebGN%SJ4$zz$)HqBvQgGw|l7b`$loTvEz@(r_fs=wK z1yBm26iA&KOevr`HK>082rZ16m5U9N<#W<$#xhF9*OBggGE~YA~jN?9`x4 zf!V3SnF2HgX$sU7tSMkq(5Arc=Q1Dv04Kcu@6U|DY4{i`$Aq!Y_-*7ie*Z1E`Nddh p{0?*cj#%k2ZvVI8e<4oXhV^BJ_e9T<jI?hgq^V^lEJ=@nZ_KL*nh_ZaDp z7cwJqlaU$!U1YwGF|rn(i|lW!)Yj3bB4;RCZF|rsa=SjM?Y-?{N5d19*U>9?mJF%< z>Q-5>`KsDgP$hTAH7V!DJn5XjViZPfkcHEY#@^ZGvgrDNDt=ZWT`iqz-)OEZsR*e3 zJ?rIxoFY{k3YTRG$;y3jR=R)0DNouX>3N%Ec-OrV-icV_@X~}RzcptZnYk@0I;M=H zv3lY<2S8 z7g^VH$T&3_D^7>9jQYVj(cpcX^FwzOSTtz+4;t+Gb7UrUf-;XKRq6A|`rAJgnl5W+P3l!!3R zJ2ym>Y2F_Si{U%W`1O0S%Pm}GZjsMhpuhF|`?>$37*ikBAmt$SAO#^6S?ZGbA8O(# z3aN^tETk@^Fr+f1G)r9@QXEHhNO>IfAq8?&h?K}tBT^(%B~m6*CsHUXGs}>PHs9u>xcX9BV)p z!LbTt8OS=2g&-?ImSU;bf-J^TuLfC;rCtxRAY?_zk~r3cEQ(`Q$g()rg)EF?WysPj z_1cidS?bjx%d^z$Ll%gv5LqI!Mr4u5D)IkcX0)DdhMsGZE7j((r6jrRcAMRn68#fq Cu8G0` diff --git a/lib/pytz/zoneinfo/America/Panama b/lib/pytz/zoneinfo/America/Panama deleted file mode 100644 index 3a4ff2aecf898647d8f22a8c9021bd83ce5d0003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIl8|jzF_?Sf2#xo!~g#~H!!d``-U*M28VzYF@#_@ zh#4pa!XN-L1jOd~4+NR*Y62h{Y$y}Z)B=#HK(krEW^?!e%|G~uppqfXFa*$!xT)92E8E^CsPJ5Lt8q_ zfBd5cZaS8uKU}R@8LrmGpfzi?)>WdlYH+H>A8oWlwB<72?R-zQ+S=OM`m_6X?&t3Q z^R~D5`^H;399Y&!7aGhd4fg+Iy*V%Ga9R9jy3AK zEqPvcG*?|;mGW*VzN~Tza@{2v(`sqpvb%Kd7m@qbw3~N+N-P^6ck^Ex6E~h5c5mAI zgIfO7A-ACU6IHnDq<3@ptXi@DY44WoW2$InyH}JN5ha-suViXato*LTTQ%AzN+<4d z%Z6G-@Jz8A>R%_ypUV*yiG;4){j*pdiRxRMz7*l2Rr*&Ydr_SqJhC|WEMA63ha1@ofgm3+BtW>Rzxtkqo~ax z^7NypCscQHO3R}o>anoWySoR~8Pik8BR1Jupsd3qx(<^#Mhh^Wz7Lgn} zB%k=KTI}mj$S2>-7ya9!a{n<$qy?@>OHaGW`=YK>luyMXOZuJqXO61H`%-iEb;xfUUioF{>v{o%Xtp0`0M**GU?Pl5O-=_b2ge&U(YS> zG;qv|I*xgEoPhnx-)?_C$N$AFd~-1kWFE*wtY#+2RFJvwT}%d<4Kf{MKFEZS86i_b z=43UKLS}_b3z-)(F=S@Q)R4I$lS5{QOb?kKGC^d9Rx?Fpj#e{CWR}P@k$EB$MP`aj z6`3nCS!A}zbdmWY6Gmo?Oc|N8)l8a;StHX%=8a4onK?3bWbVl1k=Y~DN9KBIl?$FJaInns3AD@$XmgO$PZ N(pW`Bup(HV`73F&WV-+W diff --git a/lib/pytz/zoneinfo/America/Paramaribo b/lib/pytz/zoneinfo/America/Paramaribo deleted file mode 100644 index 6f889ccaf1ffc6caac36d024ea0be15df86bbb77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 294 zcmWHE%1kq2zyNGO5fBCeRv-qk1t+rh?bxT~edJP-&K7RLh#k`V40kXxF|)A#|9{4V zfdNR`Ft7kg9}s!&1Oo?{IDW~AKws$03h~rbq`?(4hjL832*w299}QO_2Qxi(odolC$CgU;VF)XBR%uq5pac5yzoP~&mJQmm}E9=Q~A>}Xd zic%6QTVg34TMM$4T<05+jC1epys=7C+e0f{SADC1A zk7HTmiL082O&NGcvH`(0Nu384}WoQ3_ z=o*b$kzhhZBYvxYBsMKJTr$J_xtXr?`?YnPvxs3h&eetKcAV3FBm4JTh?s3eBYFmH zzSlJQHSGV*Wa$;d@#*26>*zDFQYs*pSYirdD@AP#Vhv&rVh>^vVi95zViRH%VijT* zVi#f3QU+27QV3EBQVLQFQVdef%*^d&cC zd(8yTB3JdiuFT#@r7|E6Y$|1K z*(8$I21V7)UG*+5`D%V)g_k?-<9qx+tZdz|Hf8m=ZhZ;?g@Hm5*Ktrt;yM-z4TXn7 vL}8*(QMf2%6gCQ7T*pTtjO!RFloU>Og_Ocdp{4Lrh$+nUAE-U&KI44>AeRYn diff --git a/lib/pytz/zoneinfo/America/Porto_Velho b/lib/pytz/zoneinfo/America/Porto_Velho deleted file mode 100644 index 12774792326b5bb730494e6d2139c30d98eafb71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 574 zcmb`@y-Ncz0EY3@FZ86kIOtG6SBIbu;*{!Y1u-D_2PlG*i>`LXfk+hYUh- z6GVs7t6c<#0~P!ztrGKO6$HT?cfaGNdmp{FxjrR+oOb_(o0IW3@9F)s{A00y^||=9 zWJ)jd>b#bhmDvkbNxD^a=*d<~8!~Q9sM=v7@8c6y*ID^`khX7~Tk_p*tB<}((^#HU zjq;6bMs?df?J})oKz$YpCUbS9hIb##$nk<5osP}e-i{jYy)$j8UoPh^2ZeC%_Bz$! zT-l1A#hez|+zJoPzx$*Au+aI#N@Qu!uSFIktC8hFzaA+N^c9d2NDZV2QUxi4)Ika% km5@?FUkfP~^wp4ZNIiB^5UGfiL~0^M@qemDKJZNR4I&`k diff --git a/lib/pytz/zoneinfo/America/Puerto_Rico b/lib/pytz/zoneinfo/America/Puerto_Rico deleted file mode 100644 index eada37a111c074859e5d8b5600fb1d98e8df4df1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 229 zcmWHE%1kq2zyQoZ5fBCe7@OzxH=_fWl)n^QN_cyLiIL&||KkT3faKK+j4WW1!!bC7 z!7%`c!$TMt7(plmyYVbQV?h`MU~GZ^Kv4B;>P`?1vI<0ltOL_PD;b%Y82|r2#166( aXfxDKu+2O^zCc@%Z3kHo#9Tl@6D|Pv-9}9S diff --git a/lib/pytz/zoneinfo/America/Rainy_River b/lib/pytz/zoneinfo/America/Rainy_River deleted file mode 100644 index e006a30dbf358cc4bfa9bd2d9cd780697a9c5ca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2105 zcmc(fe@xV69LJwSns|wlNg)!LnuH!FhoPrQKLo}=PyBHnAY}f)5X<ZRN&hoVPrqNMDlzj0p3}bJ&63;oxc2uI%ly`Ao!2=> z0`*aqzbi==lvb&`)?AW;>?LYp{#UYSe1-~6|J4L9#?<1gUzjDIomY2%|E5`bd`uU< z|BSik;E2BW1u^$Ep4Rub9gt-eFYBVZMk$`(rb~)fOUYmFs?yvYrgZqIDod^~Wqo^9 z`Dnl_fAM*};@nCJ?Q791Pv%KQZH-=ac#5oETBz4FUzW8QSvtJ#oP@_bI#SRtkzX=Z zRpvLQ>Wos=v6E(f&rhmmkKR&WBX!B` zdTVK+Y#rUE>$9_@{_AqxFy12#Z~650i$BZ5hs)F>gK@JXI!`@%{DNtWBr7@iiFvHx zceS(e6|*aKNHtY-n5NjMjs|-qIx?ttr?t!OfnMEmWt;5j>ePF`Eth?*&H9OcpR{hM z)K4CnB+8=_#(C`hx?b`4sS_R*kH7JfN_5Xj?mn@oIIN1++EZ!IsxWV~hZFw)H~$9v z8;5n+!}HX*-Ok@S?u1wXF#%!�ZELj@AtR1Un#xKrC^zra)|g7z42eVh+R}hCvXE z7$!k%Vi*OnieVPSE{0(c%NV9PTH7GTL9BzA2eA)gAjCq3i4YqZMnbG)m|4oE#91%XrqQW8i_AVq;x1yUAB zT_A;Vw3UIB#?jV>Q5?rJ?xQOYPt=D|AV`H6C4$t5Q6xx}AZ3Eo2~sFXr68qpw6%g1 z%h6T~QZ7eZFG#^46=RePQZq);AXQ_O4N^Bo;UJY`l+MxC4pKZvTRlkm9Bus|1%y-( zQbI@#Aw`5#5mLqkPl9J$BKPZh#pAD8CtMC~8f_r|OQZWHWktw_@!CkbN-B@nwsWEV U*%w;i&-dr~LV9EP4IS#gX(B0ii5g60E;Xv(M5Lr%r78`FO* z|8PF7hUw6M%Bf>Mtwm-&Y%S*)&bd|0hiT1?_0`&P$~eETU;nuENA_p$+wWet+wK1P zyk3z7^&jNPKlXzAhKDt}htJ8s?pPy#<;+<8Xk6pXA@vn9v?^qiOF}YiN~(P&D^*fP zPS)WAdnGktxTZc#F(Yn0(X`IT=GE_h(ex8Pn~a0s>TA)LzGUGHT^Fc65H1 zj43@}$0nbY%<)@oW?!etN?c~My4%h8`$cv_$8O{ATB_NtjV90@)|}=lle=rI2J51d zw|1aTEUuI{=G@o(%&9Ud??;_HAWcFeezT!_eKO_A4|eLMoATyQU)gELdQHLCpW3%} zcAM#+seQZQoO!3^6MeV*kSVNf&~Q$RDGJZlqCZYcarSCk+_hgylFDsK`$j443EKBQ z-)m-EpQ&Y=n#{~oxmsRRZD#FxS!YixFmu-bsdLjZOl015jr96VMgAGBxSKAO>DO%K zMUkq$Q+7eyZK>|wXKPw6$ij}8T~vES-fyk3i_6ZNCEJ^HX?B}gR#&aHN!!fw;sRaX zv%=J6W@z1&Qd2*`r}anuX63y*x@u2}e0Vi(S4Stvnq#+YLq(G4&hPC<`M=A@4TtU8 zoL(#n?}2@nhh!2bVJ7p)AVSC##(oojWyKk_2^t>`0CL)%kb8tbC=;S#9@fX z5SJl7L!5?q4RIUdH^gy>=N_Hw5Z^sI=NaC6bnY|!hctlE0Z0oNJ%BWU(FI5wAbo%| z0@4XcD*J#mrV@h1#dGg0+kJJrLAsy#Q!&+QG>d9fn{>vyV44LTxxsk%4gvZp1jg0pQ-@L^SiBCk&9 zCM6=}b0?bE60t%_#vc7@D6O606`!i}{OZ!WFlJd=mx`VSt#7Za=7~w$8l9fuVe_}< z*neoE&7lj@#?|ye8X=vKR<5QO(#+L#L)szzkcLP{q$Sc5X^M13+Pa#)NMl#i8EK95 u=09nUbVu4F{gDlj9grA5;gMUCATqHt^7hF5K z5s4sImBW-o-ctz1OIfDJyk9wlE5VNMb9AR0SH8o0K8Ime^L)c~(HBK>;#@M{a5=^1 z@}BkTp#6HRuUB^_((Lz*Rqls^2hPW`Lbp%db>g{K-MAZa5?2bW#P?n2({6_KIet0v zwK?4#sNZr1Yc}1X`|Xk8!U=ceX0J1vy6h7SJ!;nJl3)J^^zSb%GB@9?|GbIW^Zl)Qq0P3PSX3`Y zpWA<5KGsVQOYP-n`FiEfEqk^6ky^_rk@eeoYW-iXY^}O#duCF0hLh?-;M7k_>ZxBJ z{rIBibu5c`-rKG~s(IIv?!Slpr{XD@6_sJBEH$^*+^6PNho!{4a{|ZD@EQJm&m00E z5s(l_3?v8=1qp-1@il>vNWLZ%5(^22L_@+M@sNN>L?k2<6A9{Tq9S3DxJY1M6B!AO z#72T6(UI^-d}IK=W(3F(kTD>GKt_QK0~rT05M(6CP>``8gF!}v3O6*LRG7d!-P)%6Mh diff --git a/lib/pytz/zoneinfo/America/Resolute b/lib/pytz/zoneinfo/America/Resolute deleted file mode 100644 index 7713f5bead4314819aa3feefaaecc9f0ab2a5ebe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmdUvZ%ov69LGOLE{%;^8HGqtrV@G_9EzTQ(28RW5=lG>1j!UbH04w3A*a%pjp-xv zfy;C{)J8tBW{yR+7ODN)TFo((xur~NIp@awrfxc6oZr{aCu}{jhrMqEm7rrjvA(|bNP{=QY3-O+3UU17~>tv0!Pr)sbvDtVj6 z>5SqknOSi|^E2nlti0cJ_SiHDO}uVH*G6Q{(64sx&sSvLAD`R#Cx%VIw;$OBdj`zH zgKA%GI&EHS->t8ge`*Trn>3u$Zi>Q7wCMKNQk=cP7WW;HlB9B5(zQ)W2ZQ#FL!X#M z{fo71dy84zovY=wHRjEI&*+l*1*T%l9bKB1VIs@=H8SiomHDT%^6zx1N9)%||CE}6{kFFKM_JJmvvu{yU-RmNId?_Y2TQ5{P+=hA|C(dOJ5Ry<>`l?#9}ci42L69xYRw4 zMUJBv`42Z7cjJyBw+y*wevg}G+%@F38TSpjamJlPZk=)O9^K7D?jCacko$)?0Pz6g z0>cN06AUjPZZQ0SIKuG6qjLq~i$~`S#2bh^5Pu*JK|F%E1n~*t6vHcsTMWM-jxjug zxW@3!qjQeo9mG9`e-H;D9ztA%_y}(RN(@E77R z#AArd5T7AVL%fE#4e=Y|IK*?0&UJ|I9-Z?H?>##A8U8~Wz~}&^1&kg*n!xA+qz#Zh zKpFw*1f&&^UU+oPfONy7YX_ts9$iBq9f7oj(Gy5h7+rz1h0zyCV;G%*w1&|ekFGh8 z?s#&XBB diff --git a/lib/pytz/zoneinfo/America/Rio_Branco b/lib/pytz/zoneinfo/America/Rio_Branco deleted file mode 100644 index 7be212b1e6510bea50ec61997a9bc880d0b5aa1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 zcmcK0uS)}A7{Kv&I)f)Ff(Rl`-GAVZAf{I=3yRP1k{C<_n?(?d8njrJM6p<1T9TdV zZ9~)Lu}uY=LlA$Bo8$HU9+(8d;B&n9eec@y@mDu;Q|iYg-5(Bd&cC zd(8yTB3JdiuFT#@r7|E6Y$|1K z*(8$I21V7)UG*+5`D%V)g_k?-<9qx+tZdz|Hf8m=ZhZ;?g@Hm5*Ktrt;yM-z4TXn7 vL}8*(QMf2%6gCQ7T*pTtjO!RFloU>Og_Ocdp{4Lrh$+nUAE-U&KI44>AeRYn diff --git a/lib/pytz/zoneinfo/America/Rosario b/lib/pytz/zoneinfo/America/Rosario deleted file mode 100644 index a703e957d5ebe02e0651d77ddfff4d3f7b8b851b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1103 zcma*lPe{{Y9LMqB{^c4)R!|WUixk|*%7YB1M9^VSbSom(SXTb}zMs({3iA2!+w0+nCqM7(;OSG{&R?fZ zzVLDm%FBJj*v*`JcqyYFZGB}Xx99Za!Z|gy`La7TF>a=t4|MU?YxVfed-uu3h?$w* zqTRuqc{(zppB*Tv(v^z)d|SiJ9uMl-<+v*MCf#!FzIu5rujkTt%-pBz?tI!)^X8*l zjU~)N>ZDum39I^O!~GgMqZ-}qy76JuG&iQ)X1S`q)ra&_b+7qeO1M9Y{p#o4j9wm2 zDDTD|-8O#2gged_cIGEcM|-}|nfzipKVK+x?O3O}D#r>j$I~&hzYwog)vntE(PZO= z**6n6eM75F-`lIvLrY`kaPdUc=U?Fy478pQ`t9BGN)^ZPyt3;AJ#Vq%3wz$X8o!Gb zzR35rt$Qk+b$TL>5I>MV3X@MHWU@MwUj_Mi#fq>d5j|Ssy6?slX~FAT?N}2&4+645SXL6oOQO zlwy@ykYcP-4N?wL4^j|P5mFM`nz%?&^1pSc3MmVz3n>h#%qpcJwOOS&q&lmVht!7@ zh*XG_h}3A6B9SVwRc64yvL_U5J*zNa@4wTOKwBZ&D1B>epzo6`u&ie7K4-@PV+J&6Rpc z-F#SfTCKsmEM?i)jKdr`U0a=UuT&7bmflvx%F4M z+R?3kX*wtOcDI-z=T6JelTBvWu@(t#epAVTCb@5iRw4B@GQ4`d3N4){Vc8xvV(Jtb z89P~pk1f*o-xIDP{8M$rK#GaHI8sM-jxY~={F@%tddrM{<$_kV6V;e)AL+5hL)EyI z=OsGzni`+;p*$G&g^HPQSYqy6HL*dB68qg5Gof#pOgzzQ;=XLq4;|iP;@?@K6B;&} z#62^0Qq_wpxh7gq%G#h(iU#Y{m|`_KxmQmKOjBu5gCwmdLQVa>N76g~P}44aCJ(Z#v4y=yUZICXo}+w z%6#WXQxevuOS(^)(i{7A*~z13!B?B~!sgG_qW2c+@*Que#rrb!lImS*X~P0pmhDx` z%co04Y@vE0W3*I;tT9!i{G@82z^wT5l2mslo0Z>wDo?&0YF2f8uU9wSG;3b_M6X@f zWxU&u=yhc`)cVTjbWQqMwP8-R-WYLA)h2A0+S`XzUGNI2JHJ)cU(1nA#}}*3XX0eb ztDDW%mSNKH%p&vDu72_J_w&EYKVXo3{yQI^Z*PI)_barx|FV93ajp&?^K28WCe86Gk|S35vtgvbz) zF(QLRMu`j)87DGOWTdWksK{7d?O>77BEv<-iwu~5&WMpABV$Gejf@%@HZpEx;K<04 zp(A5Q29Jy$89p+8Bmk~90!Rpu7$8AFqJV?}i31V{Boas{kXRtWK%#+!!_~$E35ctW z2oe$`CP+|_s32iM;(`PQi3}1NBsNHJkmw-cLE?i1$kj#&2@w(_BuGe}O(dL1JduDR5k*4kYGaB76^SYmRwS-S zV3Eiop+#bg1Q&@e5?&;}NPv+DBO!LRF-C&yYNL#V8HqCzXe81|sF7IX|3273w&rQJ W=5cu`@k#NCad}CJ@u~5NL4N_`Dx8r3 diff --git a/lib/pytz/zoneinfo/America/Santarem b/lib/pytz/zoneinfo/America/Santarem deleted file mode 100644 index 45419528f9df01abda7f9c98663ea1d69e5ea920..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 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%0D-JUHu8U_7nCwL!B?@ z$aT+Ta^CLIBTdlP)!VU^Y_FXmJ1ks4uD@*;xj``doT1_TCFDju+2;(6M~o*sI*n8X zeV-=YQ3}+_oPEyF)RBG8(DZc!`pwMP=M2rRlq0*mbmF{xxIUlP{E`K^#Rm2{L(9bX zWY=jg=(mb7*93ikw*i;Qt*5fj8QfbYliT#WPQR_~MHO@HnzPRt+Lf@+89c1m=L{bA zR?+Y9aXRNao|sHl?!+iq*J(5RoWb*Wm?BF0|BE$}{{3TYVr(d9`p?fle}RAg0{;hp zfq#AfK>rqk{`~{J#{B&~1HOtC{&NTK^=~2QuNO4Iw3q%Zg#Y>`g8uK}e}5H$Z_1bd EAL$j&X#fBK diff --git a/lib/pytz/zoneinfo/America/Santo_Domingo b/lib/pytz/zoneinfo/America/Santo_Domingo deleted file mode 100644 index 23ace9adc3e21ee0fc2b64f87f4f5c578d135b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 463 zcmaiwy-EW?6ov2X?wB74Bo--zJV3f2Hd;lEu%N;~wzAqPkj_%DunfL{wOv{Z3zZN9 z7D>67I;d};?ONQNGes;SxYu7kj?%n%n&rc{whn(X zIli8m!8|khO&nf+yKoW3*1bFXdK(v7kFIb(nw6?|ZvS`mdC>ey0~3U+69tj#I2BQy zPK;H3evp#tSyR-QyC&FTfeN-w=u_v3*T^rXjUdeAUF&8W=Li#f*}4R@>h|krE6o; zk(C?H_L*DF<(8i|Tj;Wp)6_XfI$Db%lKfMVE1T(gQrGAC@z4IK|NP#L$L)6iu)UwJ zpr)}tFZ8eH4)+ajo|t>{dDI7=G#~05Q#R1~*GzNxO1>WHZ;{@@PqlX_p?%|iw0(!? z%Y~cwYX6>oxp<*N2ZD%Ptx3~A?^-C=x|Zto(GyI(GOY2FCnS-6-X`|P&COp&=x|%B z8Gm|*PT26hnP?uj66rRRwlwM^BTt!(>bq^mr8P2n>K}G;&q>LgG)6Oz4w|gc70r6D zO&*|YG(Y~e6v#v^=x#7m zuYF?+JGaTSi-S6SXV^S(Drsk|9&MgH-mXv0`Q1F-{TC} znP%qJmS|PzArlm3Y4CHQ%*z<5^G-h~)v1@YdjGJ@ztpWY@AS({XNK&8hAw&ez*)Pn zbf3J^cF-=${mLwEYPUTs;x~NmAdQ~Y~8t~X4yT>y6m&rrr~O!jUBbJyr)2$ zHWkZ?Ll5Z6noL=>E1|2Wr^%Yu`|R3rL(;q;ZkunMm6jR3w&jO|vhLw8?Yd)U%=+OE z?S=zC$;Q5z-L!S5dHuv*ePhX5)B4e7eY1RrY~Hq5Q&Vp5E1B%62!)c#!GV-JlgaPC z4W(5?gV3zGRs0Fuh4KXdeb8Io&-_6r-NR8MhwXL8jT|^~Gq4$Z#R!g$x)nV#tso tV}=YG#-< zn2a?u;*ao0?zb^Cn>BMA)7*YPGlu!uZ|(Rzzy9!tzx?A5-*$R@*X6(W^W~qlq%g($ z;c0Jv!iQ(A`S2dGXQMZ&tFL5Kx70ot!sEZxMs$6ok-@h$^20feYB{dm@78LM%R4ms z%vp&!S}(DC_e;-emALhr%;F!Ad?n_E(gAC4Wl+>v^B`tQJq^Fci zdTXT&jjqw5kLSy<|I2jvS+|UMn5!9e`I^}{T>q>Ztt0ou=%~VY9ld3kjL8a7cR{p_ zO?asucdKND+|ca!CzAd4g^UZnDC3&0%lMXqGNJy6cyFCo-}Y*mc=UiyDk+i4)thz7 zjBPr#c#-A|DOSHXTc<@%)aj1?I{mX#bHlSF_g)vB`Kh1GI`vU!H;2lc+Azs$cq4Nw zKS+K}lg!I+miZh0(FG$<%fh@{S`fEe7G>6JVTY5tI97G>t6f^uTB=K~SLo8meqDBW zwiaJoCCj&FYDry=tSE}pl~rl7YD$Kb7DmcyS5H~v`66q>EGbJ4*Rprdq`dQIEx&U` zD&F4LbtmfNuck&_zx$GIsNbi5R~*vH?UfqTCb(VOkYD^22>e@QS%E;yQ>$$t@cvy; zhwtxJCvGk%?Av#*&u_W2`Q-R5k9qO%Vt#KP{=&Ri{+~GEfO$A${*_Zk&KWsrfY=Z_?SWPqfA9LUKZqLb5{ALh`aTi6NQUn$(cokmQi;ko1uJkOYwokra^}ktC5Uku;G! zkwlS9ZB433uC^vwBwHk1Bwr+9Bx59HBxfXPBx@vXByS{fBy(GnI+DAsNgl}_Ngv4{ znE+%4kSRds0GR}27LaK`<^h=qWG0ZQK<2{MOa?L=$aEm{flLT8Bgm8>bAn6?GAqcm zAoGGu3^Fsw)F5+XYbFPo9a}R!$owD^gv<~!MaUc>lZ3y?EQOl6axqs9-{7RQBxkbI L;d43dH&^Ia1&_b8 diff --git a/lib/pytz/zoneinfo/America/Shiprock b/lib/pytz/zoneinfo/America/Shiprock deleted file mode 100644 index f8908febf220f27b3efa68bcc119633c8efee299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmd7TeN5F=9LMp)g90~@Q;8vb6-07=JX* ziZRO|P|{j6@nOxzhPsApE1ScuX)UzpvTXFQNdotF-Y4uI`@g<-KVHAx`}gOKYqe)> zhPdW}%{M$;r+IjnU3+u%8~q`w`^7lj^V*MUca2Z)X`U*2^DpS$w!P}3)^I&E?~nSS zs%UXJ)vHGrw2MC@-TF$XS6mr=T8{nT7UO5j<-~_M!gn-V`rnEZVrQ%jXz_`_XC`FO zh8PuGHB(P18CO$t$8<>AunKu8Q-{gpDs2Bj=@{9quDj5q!_OTP5yzYKwD)^N|R~3k;!u#cn>;!RB!U7pRH($*RbI6#$cop;8d>#8$n2H+; z)w53gq-GzysBi8$rRI2N$y;_DP;*!M<-Bzti(50ll(#K=SIm$4K*lF(5$`*%6C4{w z!te>5c+n+pAK0Ul&eW^qt`~I5;Zl{_SgX@sS)|fyn`OqP8ERp{TDhonRAt6LAn(Zd zOf3#clv%NtMb`J>GJEWt$T|6oyz}#Zv82zT@9OUqOWS_dckkLRa_c_P_cZTP_ZIi* z`>MC8ywsO0D|NEdUNNx}XXZFd$h)Pj-xK%E@lq-r}e^W32v_d%>TJ(eOEmg%8 z9$nHgM?JKpNSAs8)rz=e?OOSba*apovdojJ?As*ip8d6O4^ES-e1l?j?}&VOc%P_f z9+Hm?w2I2=BXUjGdhw|9w61DtQI91b(vR1ARCPqVt|=%|HJ7})Ha=O^o^oqXNTl-Y z&(Z6?`&F&)D3?#1o+h63X3M7zjEK6jSXtjTBsOGD$c=SJ#HOh8a&vKq*z6nA-mF8) zJN$*-65X!03>?#2N4@IVt{(l|S+{CvY|`6~=BUQX8ohmIoDu$$7L${i-BZIe^(Idl0#*YMmBLYYWIAVYVfg=h?7&zj91cD>vwq2Y)P5*(|E4iX-#i4PJWjtC(kLSlpj z35gOCCL~TsppZx*p+aJX1Ph545-zKW7ZNazh#?{4h#3+zj;JAFp%{_#pwbng}8xL?ntx7?C(4fkYySgc6A*5=^U!CK67oi6;_JtBEKQ zQjVA+LFI@l5>}45B7xN?B<@Jyk;o&V4-A<61O@-|diAUS zUeow?VVY-pZ%S`^KUsSFja=?DoxisEHu@sKVg3~?Ha{mh7p7#Sq$N4i(^Jw@(j0#Q DJ6nx# diff --git a/lib/pytz/zoneinfo/America/Sitka b/lib/pytz/zoneinfo/America/Sitka deleted file mode 100644 index f2ae47a323e7ae30dc82ab37bb67ef6ca0464b54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2324 zcmciCeN2^A0LSr%*9%vur-TF~I=+FtdVqK<%213D35@Gah%5?YSP2Sa_(oDXax1yo z=3o{b=UBC+p6OP)7Fw>gWip0aFLP14HOr}My{$%ZJKy7~t(<@QJUh?lx%d8ex8K*- z(E3!K^S{euzTt4~G>7+;Q#+E>_?(~H$D2~!siPGl_-2Od45W*Y7h~Me?r9=y-TXj! zQ<{oc?hQniMJtcI6!5&fSVg;|f#?Irh4%*?nD)&f74zk3H}=FXb;0VRl_0F*-pcg%$*oGUME&9~bGF=jW;9 z@wxi;4?Qa7aHPIt-}g#%mB?AWr_^l!OgU%GcVceApK{*PPef|`*D@{RZIL!LsnfkX zMf${7I^$xy$Q(JYv(CJvvWNERoFi-1f}R(&e5F?9wkVm`k*D%2o|kvl#i@d{W?7i` zt19x`FN>3>i{cCOWy$0(;;xUq^6s;ri&CAc?|JW-xHk}`7w+9F?rXcK%eK9%7S(*J z7dH>8@&yO=lJZSz$xr8GMfQNGICD}~#%>gqM~3Cn%Z;My)erQt&$?Ch=KcD?cN$bp z<91!Ur&KL3ZP5>PrKq~(O6~JI%J)a6_7|L2{%;?UD^r4E<#TOq>*r z+pfq*M~20!<}vx$P@j0b`jT$y+pnI;9@S5_Y*)>(TCc8XQL8WS)-7q3s^xU2ZuMlU z)&qXM=0dD`dQXRZW-LQI+qFWj)iI*YUnJZ6uZVSpiE@40nCOU~l$|w)MQ3n^?kXNt zT@%0S?gXv6N6zXEzwK5Vhu+tlzUWk&dtTRDj`~&4s$TuvK(Pu5b;7Q9het--z&jZ1 z-|9HQ;A?@9aQlq1&zNAax7~61H6+fyC)U>aoZ5%YsWqqE=hU0eWmV>-tjfGOPKY^w z|Ske(q;L%L=)ZA1EIHH||$XEm)udWSR*=^oNP zq<=^Qkq#m)M0$uc5$Ph*Mx>8c(@3O~R?|wPmsZnEq?<@Pk$xf#MLLSK6zM6_RHUm& zTamt6O=FSHT1{(_-das_k?tbxMf!_080j$5V!Ybpu<+1`>)nyjQ8(~*obfj(a&H>X z{;ke`x@<~qT4?HQx@_v4V4unMn_0`MO`EUL>3W;#e_Q=et<8UMwcB1QUP8~as`GR5 Pa%5I@Zf;I)j`aQoFr7}n diff --git a/lib/pytz/zoneinfo/America/St_Barthelemy b/lib/pytz/zoneinfo/America/St_Barthelemy deleted file mode 100644 index 15c0f1f7450c27dcc5971c9769455758f1606817..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVN6xxPkHi|6>6R4FCThKfu7^;~T=@7#spp#1KM) PLH~gOuVGw3Q%$%4?mi!V diff --git a/lib/pytz/zoneinfo/America/St_Johns b/lib/pytz/zoneinfo/America/St_Johns deleted file mode 100644 index e7a18d601d0255c26885313540cbe755e009a77d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3638 zcmcK6dr*{B9EWjGquWM^7MY6~lG}NXO*2$8HO;s?>*p01#_^Be^Ub@a zXij?A-(J!BD|~qUs6RZ%t=wMF^Z8ZHo#o!rM=Lh$SzNjHA^!`mko(0I13fP-?R2lQ zk9l6Un%u9WHQ8)xS0P*97LcYrd%PzrJlrV{Jp3 z|BV`}vF?>}&zs98HP%0Hzvr!a$&GK%De$b#iEUgrDbwQ}ajB!KuzQ=^SDtgLZ+m3byKmRVZ}O(O-dogG_5L&cT_4QcQT5@%cGpK^>#H{3 z(AWF%z!g=_gu~uXy1kjaW$Z?feV)$>G?FJFH7aIW~O+$Fy*N)z9dCdh9m z_ZNZdI^}oC?V>q5UVY!MuhWv)p;`_dc3LC-s&&V1=RmVh9jsgD{II!F{rIj=wAD7q zpDHTFq2(3w=lhn3!^LGXc)casa|`8>ODBn6MrFyP$py}@y^~}|bf(jB^m28qCDG|r z!_;q1v~%1Wr9!W^I$=-mSK$vfI^7m-RozSWi-_4Rvd6ToB67kO8I@Wiq6e>$F@2Vc z*s#ZB>`%9gQ@$#ZJ@+nidTp96PhDT^^sc^5^?CM6r|-klRKG~CI*s@KW-0?9U2(kWZUPpMh4FJ<=Z264Y5X+ zyX=(u9@ePR1UvQd@2#}C7X;Jq_{7S{jt`EWzSAfEU&OHeJ(99p}5SxZ0S^MVs4>*xs_^Vj>@vLGW%Is zhZhF3N2Ua_cg+k=?$swSx&ETyl!HG9u2?B;_nzKX&f;iY7r&g`5DdBcPGqF`j1ES&2SRF;ikwsAq#|b( zIjzWfMNTYoW|32ioLi$lxyac?PA_tPkrRxZVdNAe=NLK3$XP~CGjg7h6OEi{NxNFi6j)sD3Venr$|zftRiVe@`@xD$t;puB)3MLTqL_j zon9orNP>|JBPm95j3gP!GLmK_&q$(?Oe3jAa*ZS#$+l6a8_744a3teM%8{HSNk_7d zq#emSl6WNZNa~T?8+G!L>>G9Zk^CF=1VCm0G6j%1fJ_2p79i6AnFq*3KxP6m6_B}L z)RO_34Msg3kojQL69SnL$do|l1Tra*S%FLoWL_W>1DP4f)IjD2GC7dhVbs$DnIA?y zL68|@)KdhRBgiB{W(hJ)ka>bk6lA6#Qw5nT$Yeogi&0M(WWE^ngh6JEQBN6U&LEQp znKj6?LFNrIagdqQE&M;cBf58aN9v(-65dfK;dlP^-)R<(-Z^^h=$)h2PPExGJUf3p z_cUM8J4dgb0Vlre&SBx`&p$1mKPQiQh}A!nF)kxj|M-ZUjFj}0)DbypX(?$bsjMR1+=$HP#&I diff --git a/lib/pytz/zoneinfo/America/St_Lucia b/lib/pytz/zoneinfo/America/St_Lucia deleted file mode 100644 index b37a1cf7e807d05d1797d3e3fe6a783ead623244..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL?jzJc-o|6>;z82^K wLCioY5C#E|As{x-e;~+g7uf)!!Go&W#< diff --git a/lib/pytz/zoneinfo/America/St_Thomas b/lib/pytz/zoneinfo/America/St_Thomas deleted file mode 100644 index 482f0b549fb8e2bb7e8ce74c8b51798a45662a38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOHFPhkB2|F8lB!~g%s4=}L!_=Yez28RIU7#KoG QFz7!J;5Cd3XsQVp09vRWVE_OC diff --git a/lib/pytz/zoneinfo/America/St_Vincent b/lib/pytz/zoneinfo/America/St_Vincent deleted file mode 100644 index e553af77b5349c15371947e1d874e33009f556bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIVL?j{(|xU|6?;482^K wLCioY5C#E|As{x-e;~+g7kL4q!GPnf?;Jz(0@Rq17TML+sa@`EoPIj_O2KNba#TXX#lUSMSY}+(~!w(sW;H($D71TY6sJU&m(9Y0B^+ zGNWokKI$VoKDZXYn6U{jG3D#}{idBe?Ta{fRr7r3&aBMEcPie7Eeo6ZQ1Tl(1)Uw8 ztx(qWCf?5u|54Lvs0yhIsSK$NsUB17Lli(XKvY0UA>oEWT diff --git a/lib/pytz/zoneinfo/America/Tegucigalpa b/lib/pytz/zoneinfo/America/Tegucigalpa deleted file mode 100644 index 477e93950c2f09b8c338033c07a53d4ef5c01912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmWHE%1kq2zyQoZ5fBCeb|40^d6xKiyC}@M^FT3Xc7RgVz6Z)SwE-@%Jr7*2ow&fn z2!{Xvud`ub`2TbwKsmI@lw7BhhkMq9R8xhj!TVJX4OHmp<#V0!@rKHr&@$_Bi#jmyOuB}B zD!XY+=JYm;g9X>*q1qymn{-Cz<)(?eZ$sLhSg71{0i7R}qVgxJ^^uhrb#$a#dOkRX zH&7*yJ=`n`DqT_x{t$(kvGVw(1yQsuT>6S13Eyf^mZXh{l3m!1q{%*8vSe_M)w-WT(w@d0=+a`T}Vn#I;f6*5P##M9Ld)?C1uP(+s(5(fHs&(z1 zY)kJGZHtq#V@reRm>!g!KRu#rv|V;D*hQeHOkSRf7CqG&^2+V6VqMrjeL|rpy*67Y zG_S(eheESYZ5upZpDicX+#(+lnB)74R6^#E3;&S}k`0m$k`Iy)k`a;;k`s~?k`8PROK?Ss~Lx=7mfQnHe%QWNyghkl9(9 z=^^v8G!sN-XlbU1%n_L+GD~Ed$UKpW;(s#JNVC{fv)lx4irr~XPVhP$c85JV@;7N6 BlW70| diff --git a/lib/pytz/zoneinfo/America/Thunder_Bay b/lib/pytz/zoneinfo/America/Thunder_Bay deleted file mode 100644 index 34f750b4df72db9977cdcef0921cdd5eff95b799..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2185 zcmd7SZ%oxy9LMn=2u2r3C@4}Q1B-$DHx!LZ14gJC@>Fp?gy zW`kOdRa&!uBQsmB#-yCJwK8S3{*8`p@t}nrqX#Y4y`A^5C#`z!`R)8(clSQMpLd`s zw6)Cp*NL~^a5;VU@;R-4-cJ3=<3>*B{3fT>wDtxgCZ_j{j=f)-84^)(>Q9Mp&?;f> zs9c57=;xmt_M7>9nzJ5_B9}CJQM|D(lc^a`g*`)ZDOVu6cN$ z%5MC@SU96l>IzW0#6ssD4i`PnUcY5QBUtY^2nrT!_YYTm4>i^Eb=U8QQK4w~A+O}cih z&(tL^({+d2%<{<`z2dpOvhvHN%D<~sR=tz0>NohMVIWT3R#_~o@0(C-GE*hc_^}F1 zPs!TySJm1dXPI?bC-l1G=gj)ZLEUs<%-k{Fr#JK*F?Wu%>5a{UX4B9rt^9Ax=H6Dd zrEoy*3i?%Za;LP^7OR%YCJE-Is^F)U5}G-sLT_ZrwuvuP>%bDzcJiFQJDh3m86MN^ zjS(aLNA$hr+H|xJ>h0+tm>u<9dPn4Y30DlL@c5{7W^}5~k^R#3dy{%#Xpijts#5Lh z4$6b?W~uItb+Y?uPsPN}h>5!(o@n&7=RGePJ^H2>7ma>&EGEIdliWL{YE8ha;ofd< zgT2)O`#1Mu&c6cxy^NXmS1#uXd->< zRAjBlVv*G%%SG0UEEriavSeh<$fBKg)yT4)cHPLrk(DD$N7jxk9$7uId}RGd0gwtH zB|vI`6alFMQU<5315ya25=beKS|G(hs)3XPsRvRJq#{U3keVPxaoVaNWpUcNAcb+- z${?jdYJ(I9sSZ*eq&`T2kP0CsLTZE*$!V*El*wu9gcQnYD}|H_sTEQzq*_S1ka{5n zLn?-p45=AXG^A=s*_^g+Na38ea!Bc%wsuJIkm@1jL+XbV5UC(iLZpUB5s@k)Wpvs) zB87C?N+P9n+FByTM5>9D6R9UsP^6;xcS+-7<1dIO8hzc?(FN6})CTn*DRn_jTj>vY h{}a{oRkd%QEpE9jZGnG5QCU$*fxoo0sI;iW_ZPOwXY~L8 diff --git a/lib/pytz/zoneinfo/America/Tijuana b/lib/pytz/zoneinfo/America/Tijuana deleted file mode 100644 index fffdc24bfc4c076584787843a5a6b457a23c5bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 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 PsH3w}r+`iYK_34C{Ai2_ diff --git a/lib/pytz/zoneinfo/America/Tortola b/lib/pytz/zoneinfo/America/Tortola deleted file mode 100644 index 6f9d9323858c42dfe192bcf61fadf5e76b0e4540..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOHF7h(MW|8Nci!~g%s4=}L!_=Yez28VzYF@%s{ P(0?GnYZw>MR1+=$SFjyn diff --git a/lib/pytz/zoneinfo/America/Vancouver b/lib/pytz/zoneinfo/America/Vancouver deleted file mode 100644 index 0c1fa52690498b3cd087a90ba9ba4d4f0467d532..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2875 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 F{Ry)=ETsSd diff --git a/lib/pytz/zoneinfo/America/Winnipeg b/lib/pytz/zoneinfo/America/Winnipeg deleted file mode 100644 index 2d22791686e86b2f17a0f7fa53ad71f03a3384fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2865 zcmb`IeN0t#9EZObQ4mGR#0UvYD~2Khis1`op<|E;>J?GQ)G)*{j&CTw;J3v@|5CGj z8Aa--bL0cyEa($RfYP;x`kFl zS(aYRb6br?33@4cxOI6(m|lqpvYL`c%b&f5*;m6uPEE{N zrHT9V8^#VP)^TGeTH|i-m!!e-?WCG*lI)*mC+}S$Da|qV8=r2`@wF4I)Rl!gVPCYB zmYt>Pn|oOkMTk(6j&{b(@N~cZOvK` zUv3rDpVDPPYpi8ed$h1+uC=^uldd?IVy!G%qN^$+t)dxIb@kRBmbf^)Iyrdoq2sG} z=O=qS_6Ixu8~;D`cn<7#iO2KxcJX%ZeVuFf_RkZ?x+QV4Ij5R4-OU^Ba=EyQxI4Ci zdFRY)`(TG2-uL#Hm<3`NhsH1v%Ro#6u?@sH5bHq91F;XpKoAQ-Oa!qJ#7Gb;IW%U1*vX+W6vR>x zQ$cJ6F&4yH5OYE71u>XIV=;)yAU1;-4LVli2D33^H-_ODmSdO>VmpZOAl8GJ4`M%v z0U;K2XiNyPA;gFbD?-f3up`5e3`;Uh$*?8Em<($&%*n7P!=Mn0GEC~w*c4(^h*cqG zh1eBhScqjAriIv+VO)lF8Rli!mtkOs#=;O2J2WYP?yF(1musp={4BJDD53xSP{0@!%Aq9X`z@aGt zqXrI55g1i)Xv)B-1Edg;NP9Y}c~^??)!QXxo*AT@GmiUg^WLsKS5ogA7%K`I3)6{A*=Vlk=( zDHo$&kb*HP1}Pb%W)4l!AXRf{$_A;MLsK|Nz7m-_ SG%7YKIx;mTCMqT>+V4Ls5UTkDs?ln@t*PF_H+9#C#Y84A%W5)iL%LS&)XJFEnQF}#3MI&#a) zY;!mp9Ou|-%XX$)=?b)5Ys+K|H>**UZq0J(TDMgcZ|8ehf93eo=h=Ba&z|S+-`CsF z@?4(tzbo8);c)FYhxeoldl&2R1;4h9H!Ty>r`O29n?=IuFO)&ACW+v#L>aQBK!rBt z>#*7c6=snH0QIC1u9OB>lWX&%3%vC66!E z_kQG3DJR4AeaC)KqO(}u-+MvL_sx?FHhnJ^=KmuXt@>1?#(g8xGTs(x(^ER#y#Ma$P~RIXpiy!Je`wBlvCtS(mNr!~uhyx&!! z>rq*hJXaK5TP%yGeiILT;+79id@f3Ks($GGGveWc5qkO2qvDa)>$-IJdum1XXL@Dx z5mmP29bI0wU6ucGMOI|@i;7Fc%~~ z=5UFsE%ECoI#X0#vPXM;j`IGUseSoZmG8U95(C^u6ay8GteiVt@=?n^&MC1vq$v?{~pyGt@XwVzuI`?koKo}l>cIfZgFL*mJ>d` z=~}dU{&2f|VJt(u*tte-)={F>S18*K+!R|166H&+W1>B7N_JGA6di$h-B~oMIw$|s zT?txsjZEmRe;iWV28Q+aFFMqYoy%d7hxzI_LFUXny|>;@g!#?kI%p2>DFJgW zKX-X2cJ~#YMfQYj%4&9nc3Zr#FD|n&U}wnIki8+BLw1L3580p9Y!KO@)oc;jBeF?k zm&i7eeIgr0c8Y8j*(MMF4A74zc|z2kkH_;S#MYPZM+?4w3iBZo1EI_-m=A}(XsY#;_50>;#sQv fUzcZemsZw!i>Y>2)zX~29GO*>o12rHBi;W3*T_f$ diff --git a/lib/pytz/zoneinfo/America/Yellowknife b/lib/pytz/zoneinfo/America/Yellowknife deleted file mode 100644 index 947bec914be3721c864580ae1ad150aebafcc957..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1966 zcmdtiZ%h<)9LMn=V5v9M-&QCJ{z=Uf;*LK`0;yR+7t)2{iAaQ5;O#Vn)ZO$%{I+n6 zM}Ak1wW%yu%?GU{b*<(`a}A%A&7E7zTDbmimW}>wvRPce_wQ+sder9E-Mt(e>Tum?evpc;l-`p&1?VebEc>JzJhrN4C#N^dK zYG+p$nK?zvZT{jqnL9mT=Vb?F-tWt_;M?g^n4YHdFZ?VE-n*^~PhOHm$@%u4mrl## zO&Pmn$ERj#wD@|=+&A)umR#wU(9mHGpKX%T z-nf>%x>CyHeYRrHY*`W6ZdW!3dAhQUSh&a{lqv|A=eP3xQE_NlQ`rmZh+pB@=7?H%Xr)}fu|ndoKR*55DBhR*17 z@q~2DII5kI2I;(!)Oau?@k=e5m^w=m@6_myAAggbgPZO1muH$?$!hz;>2cH5TwuG8 zq|J+!f7{(%=ggkGYj$trpxHZlOOsV+BsuoA?#n+a`$j&}{S!$^4V}~jU$jV1@5_4d zgBs~=@6pGIi5c9{5cXp zGC)#5a`3t&kSvfikUWq?kW7$NkX(>tkZd^8LGs~92+7FnQbKa_x}=b-IMPD$LJ~tV zLsCO>Ly|+XL()U?LlQ(XL{da@^tvRGEIHCd^5jSq$&@2iBv+1Pk!+E4k$jPak&L}A zWh7^>OB%`A>(WN@=13gL97!F?9Z4R^9!Vd`ADIAT2E1+xkU8+WNkC@7>!tyj2abtA zW`biXkh$QP3}iMqrURJ|WI~V`L8b(m6R(>TWLCUxT9A41x`{z%2ALXUZa5|fnH`Sl zLFR{Jf{+>Fm?C73yl#?^S@ODRLgvZqCJLD;WU7$4LM98DEo8dzHkq%08@5$$(@LT% R!WH4Nl4yB(xIA1I_y;nR-WUJ? diff --git a/lib/pytz/zoneinfo/Antarctica/Casey b/lib/pytz/zoneinfo/Antarctica/Casey deleted file mode 100644 index 8ebf0598ff90ab24c884305f36947b002058691a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmWHE%1kq2zyK^j5fBCeRv-qkdH>0sY4Ezmrr_Ow>Vx0PIST&HXD2W+F)}fORDnQ2 z14!Yl4GbI*c2!jsLwIlqgR>)$00Kr34k5wD|3Cn;6{HztGl&M+4x&LW0MX>Rf(z&_ HT?;M%FIg&< diff --git a/lib/pytz/zoneinfo/Antarctica/Davis b/lib/pytz/zoneinfo/Antarctica/Davis deleted file mode 100644 index cd7acad690b66f1ea56ce556858988a73135109b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 276 zcmWHE%1kq2zyK^j5fBCeb|40^IiJsQVEE>KU*MnnY6h=cA_m^me>wQATxHL-A{C7x1{6UR)mno69 zB8~JN(5UewjrO`UX3(LrhZA+#rCy1v^k}?}X+mL}EU)`0D-ur0%F5aF>CIlvIPR1+N9#0mf0brcoRzf&`MNIqh^&u^ z)$H&x$(|P7Fp(-bFW+je?}Kjaf1r5-DVpCkE(Ptu>O3?R&^Pw);QvFy9U0&Jh z?A2}Q*VGl;qDA&{DGt0L#os%n!9eg%uL4*sN!x+ diff --git a/lib/pytz/zoneinfo/Antarctica/Mawson b/lib/pytz/zoneinfo/Antarctica/Mawson deleted file mode 100644 index 48e24e1e5ef8db1b70ab5233744037522bd06209..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 190 zcmWHE%1kq2zyQoZ5fBCeCLji}IUgw)HF(`pa$p3BfI&zC0}BI#TL1$~RaF&(uVZ)! YOo9Ys{{sQYXpmMSjpqVcrEAIs0EkZ)o&W#< diff --git a/lib/pytz/zoneinfo/Antarctica/McMurdo b/lib/pytz/zoneinfo/Antarctica/McMurdo deleted file mode 100644 index 62ac42f078d52d6c24f5e0b0acd243cd1bfbb8cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2001 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 diff --git a/lib/pytz/zoneinfo/Antarctica/Rothera b/lib/pytz/zoneinfo/Antarctica/Rothera deleted file mode 100644 index b5dc735639dfd75c1cb177a8f12464585cbff9fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 zcmWHE%1kq2zyM4@5fBCeMj!^UIeD3M!5kp_|NpBO7+9*Rsu+U&LqdQ83=AP8m;_Rf L-!v|exyD=o$)FNN diff --git a/lib/pytz/zoneinfo/Antarctica/South_Pole b/lib/pytz/zoneinfo/Antarctica/South_Pole deleted file mode 100644 index 62ac42f078d52d6c24f5e0b0acd243cd1bfbb8cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2001 zcmdVaT};(=9LMo<%-nd+hcQG$4Igar_prW1xOvX*sGkXyAbRH`*~PW@&}*BY9u^<-hc_rJ@ox@!K|IWNYz{JuY-+J;D; z?_Y1I`wJi5PWR#W#P7Pk_r;|AWidw&TkQ42itG5(;?I6;32hfG@%=X}sjkoNdbQn# z7az0{Em0ep_MDAcT4|#OBbHo{X~|cgRmy}4rF^zlss0S59+|H(-^6R|3)6IW-!-L0 z<23H|evL05(1e}GbWbqG(i=|M#H1f=QoygtL+06(gl{$F@~|V%PH&=$_SM+E9Y3mgbFR&8`%)##t94)9yP8)N)cwV;sC4WIm8G?)?B>rZ zAFS2$cRqwd0n&t#s6dAM!m7#~q%@&u$D>V6p zEg5%B;bDg?e5+p%UwPh^UOJ{_pVnJ#?|wbO|fEx$i)%~qh6b8BpCU#eO^D6?%{`L_Mw zYVFvSVr|cq>Z$ra><<5s|Mkb+p!eSE_q%)S?DNI^^WECo>Z`6T4Y{wyA)n9h_x>yN zA1?crdt5h<3-@$aj$Ar&?a0L=SC3pia{WjFNCijmdYr6RQ=#Uj-rMI%)sWg~SXg?qZnkZi+ zk@AuHkp)0j09gWL4Uk1ZRsmTCWF3%&Kvn`-3QxBd$YLO?fh-5I9>{_qD}pQuvL?u) zAgh8b3$iZA!XPVyEDf?Yo^ElF)j^gASs!G9kQG9f2w5X!k&snFmI+xWWTB9iLY4|y zD`c@e-D)Arg{&8{V91IgONOi&vS`Sv;qA9Xt06D`HxBvhE diff --git a/lib/pytz/zoneinfo/Arctic/Longyearbyen b/lib/pytz/zoneinfo/Arctic/Longyearbyen deleted file mode 100644 index 6326961453f404a4a886362ee8b684b56fd5b4f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2225 zcmciCe@xVM9LMqR0SC#-z5M}a0YV|2*2!=1M_gv-!OS~Lxr|f-6%p&Ayo^C=ta8pZ zV(%Ku9J#CAC#@`Sm5Q4DHO7- z#!l$u=&sn5;3An?^tYyDpVibU->NJAn7W4F(`kbT_4+UO>J1+~uW5&mNcw?p$$0q{ znck+7x%DZ@3P(IHU z*T}qonsojVpWOCMm6mnYsJC~%-o9g@F6d0xJLzz1Y;TjL2VT{?8yn@Gwr6zNeb4Ih@OrJB z6V_0mLhp4g)fJvux?(h6t5V9P>Z{3m|Hw>P`R)Z>HIOW;_fC@Po^$d*>#)>xM5VT7 zK-O&gMb|DkBzm!eIv@1=R-s5T$}SXzco=@V~v z$(CrZZr%N%ZtLEoPqysS*7jDl99CTXIF}>AdG#;LO3!kb|Ky2cIWK))d~@Z!&tDm` zeEyL6F^4$@V`%)9B$+R{Iql}=`MQ72i44sMBa5*$t3j57tOr>TvLa+j$eNHvA*(`` zg{%u%7_u^CX~^1;#UZOhmWQklSs=1PWQn$Bjr>t85?Lj(Ok|zNLXnl)nx!IZMHY*! z7FjN`USz?@ijgHFYep80tQuK1vTkJI$jXtW+nTi_i$_+EEFW1vQUIg^NC}V{AVol` zfRq8L15ya25=bd*O)ZdO*qUk}lnAL2QY55GNSTm2A%#LJg_H`Z6;do)Q!S)iwx(W4!H|j}B|~b4 z6b-2wQZ}S+Na2vmA*DlVhZGN~9#TGAQ$M7DNClA+A~i&ch*S|NBT`4CkVqwwQX;iP ziiuPcDW|QeCsI&bQ&FU(NKKKVB2`7oiqsV;Y@8#`5uY&573WO6`j=%TPvti=K~1m| sJK@sj#Wz>p2ZD6=a%?Zx);uJe{?0DoOHZ&UwLH~gO MuVGw3Q+18G0A4B)cK`qY diff --git a/lib/pytz/zoneinfo/Asia/Almaty b/lib/pytz/zoneinfo/Asia/Almaty deleted file mode 100644 index 52f941e266a97069cc0c5ffba74808ee2acfa560..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 922 zcmc)IL1Vf^zEI+_I!>rLKw7tiK(i!B$a^h$x7tL?{?Tyli8K+9BvL zhNrQ^gN+?xm!w^Whu>kxU4+=hgdNtQ(;&Kpxq9E{4nn6+{l)irKE=cD`!gODUMAFE z=ZN)$H;1peKk>mg^<{l|FLo+2W1jA=c)UkHhP*$&&Ub&?HGOrT$G=rD1J#oBtmP%R z^iX==k4oQkT0*a)(*L+e2FAMNOlDug(LFgE*pYL`YZ7s_bYyngJpXysb7AwHihio- ziz~}|uw2%c-p=XE#gdLa&+GV;1xZZ4mZ5A>uH3sL!@&oVOvEMGN=YhkTc;X+8EM9J zy825p^^^MQs!wM(e&}m+O?`cFTk97MoqO|LZVcB#4(Flv%XPTpWj*Tr*m>_%>Q!Re_0kcOEj2t{{aG~$=m<{ diff --git a/lib/pytz/zoneinfo/Asia/Amman b/lib/pytz/zoneinfo/Asia/Amman deleted file mode 100644 index b62664e6755a36e215583afc59183302a762ed60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8504 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 Ck_DCk diff --git a/lib/pytz/zoneinfo/Asia/Anadyr b/lib/pytz/zoneinfo/Asia/Anadyr deleted file mode 100644 index 2841a6376d9f9694ab79586449398d15a57d20a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1183 zcmdVYPe_wt9KiACb?P!2?OqC3dKT71;BAB@pV;vFGJ|KM&8l?XcfBbMW}F zxcX!H%?UTlF*o~?i9l%d*@NMkvT!iEu44aKxi6h7U%VNu_?jsz%m7 zE|t)zEgPQhn%^)FhuvZQF!wYP>6T!C|Rib6&!BR)@dd(VG`;7aGnw zg@!i+xh?tTvBsx^dh5fqj@;_hO_!s3+nH(|9a^hngB=n-9gywqRnk20Lw1CUq$T!2 zT7E7_YvrPDeg9H+et)NTO=YERep>H-l-KPq?(2>#uu7#wcXPDB`JNLdg*%|k$oS1l6+Dkso8j;|N7D?%TwgBEpvH`S6r)n zUfWuE@b|s>m{Q|I=6_V#8D%S#*VbyKCg<2s&aq!U|GnpAB*$CMQ~ep0NGIIKfegQ* zl*L-!^343hD3{D)oXAM|K4V2ji;UORj2Ia+GHPVp$jFhgBcn&gk0gL(fTV!rfFyxr zfuw=tfh6K;GC@*7a&a}uAlV@4Ao(B(AsHblAvqyQAz2}5A$cK*A(^?F)R5d#(f zNP0+qNP`VDf>x15{vtP E0Wz==iU0rr diff --git a/lib/pytz/zoneinfo/Asia/Aqtau b/lib/pytz/zoneinfo/Asia/Aqtau deleted file mode 100644 index 27a3d50d373900078a7088e74e08ce25e002eda7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1128 zcmdtgPe_wt9KiACZCY+K*&*88GT*WqYU-M9%+i{ILvYfYJ`hB~b10!dCn>rF9U6ks zAxH?KLsWQ(kO_9GphL%q=ip7k=i0#z>m)Ji`94NPp1StDywB(1VZ4IBuRM2oCM&kB zn7!d;_1l+o`-|2E^Xgf>SX*7n>`i>k#G97=_~zFqiO;oa>ss1Rez;jpy{YJZFK_6! z$1{5Wy|cRg*0}bs4eA5uyY#_wN_Px3>qFgjeK_?+ABnE(bYnC~-@aSzoLJ0suCDl9 z?;pmxSKb9jpDzbJ3r~aI%7dWqdL_tQyrYg?STfn!dDB09-waG$HMzD~lh00?d|jGC z>WV6S%A3J&Wp(^*!kk#^RYQw8HT*iJPR_;EsYf+cytJuCDlKL-w^8(Vgc=${_Sw1X zk0%sv3P+-mX!GvvPgsaP-~Jm!p(q-JCMsJCB^jknA@hM7&#-icFAA1%ky~I|6cMRCi&eirin}xnJV98vdDCu zcEZS%kx3)dMkbC-9hp2beWU=S0;B|_2BZk23Zx9A4x|vLtpq8>X=_1>L8?K@LFz#Y zLMlQ^vIuHIibASF%0lWw3Uk`ZkkXvCHl#SDI;1?LKBPdTLZn2bMx;pmKdX$`f@M!G F@&l>+?gan< diff --git a/lib/pytz/zoneinfo/Asia/Aqtobe b/lib/pytz/zoneinfo/Asia/Aqtobe deleted file mode 100644 index 3683be2db87b36a072090d2a32622182d23c9b5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1038 zcmdUtPe>F|9Dv{KuC;%Hx|pl$>X_-Io3*X3tp8UJBB=1Pfglt**iz6bk`4tyEFCJk zC=}vBR6K--73`#f2ag_p2X7)?yok_2Pa%uFZ?;2VmyW&1`+YORFo*d*_tCRlN?lkH z^Mu1{HHYh}Z(MQ{BDiW-{5+kH9-R~__Z+)w=T#xLk(cU~DT&YJ zq~_B@seLmf_VW&@8*i2yBQdG(z9KghMQMorkjBV?IAsy-y!}vU8eUE|?XKC)+h49F z*0%KRrB&TBv!L(fr}f>Jd7Ye`()T9jCH3O9wD!D{wy_CG$0wyd)hF%6LCM6%b!PvT zbe#3-&dsoN?b*6}+0i}gKHd91r2A$Mb@s`z?$0Y3NFO9EpFiODnO%12kL?Ry4u-;i z-$A9)U-=)ItO_VKsG06#E5y9`#JcLeQ|`U<`+8*5RsF-RHy)UI-z`m-&njhErBk{y z)BOiI=Vl=YB8iV63L*<4%%hP85eJb65eSh85ebnA5ektC5etzE5e$(G5e<Ad$iUCbY0g(QQeGe*tW;*x>*G diff --git a/lib/pytz/zoneinfo/Asia/Ashgabat b/lib/pytz/zoneinfo/Asia/Ashgabat deleted file mode 100644 index 589dbc18ea2d733aa736b32ab888abda675118ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 657 zcmc)Hy-UMD7=ZDMw%Vpb2ho1SkN6p@2qGv74iQ8;R0uR6h(o7>;3_&ex~czxgV0SJ zvbYs=6&&8(!NtYJL0v?P-g8k9oSb|^?zvt|2)~9KTlHD>YixbO%@p;`zWc0jymHZK z`90oY)SJI@bE(Uj-0Smc{^2Pq+DW;b%02hw-GBmF0J88}*(!Tqwh+lw-^IVr;x zM@E*qWOS+}W6qK3NUe$LseA=kag!nl;~MD{G-zu9nSG4OOT=GL{~*`C7t1fPClyg#yDPz@Y$9 zkW4ic1&abkL8HJ?@F;*3L<%GYlLAUXrNB~fDZmtD3bd)lrhrq>P5&F-*8j-#oc#%Z C>3_BW diff --git a/lib/pytz/zoneinfo/Asia/Ashkhabad b/lib/pytz/zoneinfo/Asia/Ashkhabad deleted file mode 100644 index 589dbc18ea2d733aa736b32ab888abda675118ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 657 zcmc)Hy-UMD7=ZDMw%Vpb2ho1SkN6p@2qGv74iQ8;R0uR6h(o7>;3_&ex~czxgV0SJ zvbYs=6&&8(!NtYJL0v?P-g8k9oSb|^?zvt|2)~9KTlHD>YixbO%@p;`zWc0jymHZK z`90oY)SJI@bE(Uj-0Smc{^2Pq+DW;b%02hw-GBmF0J88}*(!Tqwh+lw-^IVr;x zM@E*qWOS+}W6qK3NUe$LseA=kag!nl;~MD{G-zu9nSG4OOT=GL{~*`C7t1fPClyg#yDPz@Y$9 zkW4ic1&abkL8HJ?@F;*3L<%GYlLAUXrNB~fDZmtD3bd)lrhrq>P5&F-*8j-#oc#%Z C>3_BW diff --git a/lib/pytz/zoneinfo/Asia/Baghdad b/lib/pytz/zoneinfo/Asia/Baghdad deleted file mode 100644 index 3ad361495ce53b051219d0043eba265ef81130ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 962 zcmb7?KS-2u9EZPm-i4@SwCJg2+8;gh>Qz(EI`#EmE*HGu;ZTANDM?C04G|Jw5Trp6 zY$!-1C~Am?S_DCe28(FOMWPyhi|EoM2#I0e=OmD7@$>S#=jD_ee$SJ+JThD_|14_X za9E=q-V5fulq>SC2SrW#ct5mb8<~9l9dhaRopAA4 z+T}w8KqNp!Kx9CKK%_v#K;%FKK_o#$L1aOML8L*%LF8p=0vQq^A{jCvLLpKaVi|HF zf+3O_q9L*w!Wq&b;vw=G0c2?rKtf=|00{yT1tSbb9FRaDkuXAm#KH)M5e+09NIZ;y t*lt8Q;p`KM?&GmLd&VzVOIDG!WEELU1$*Dq*3w@+{Rv9)EV4vH-fxKV!%qMJ diff --git a/lib/pytz/zoneinfo/Asia/Bahrain b/lib/pytz/zoneinfo/Asia/Bahrain deleted file mode 100644 index d87b7ce73915d8135e07945eec99d84d3d706880..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmWHE%1kq2zyQoZ5fBCeCLji}c@}<}C&JP-=>Q{8L_Y^4W#PcU!oZ+qz`)_-8^Yio e9KzrT#1Ifdg314Z0AxByC-F9L0WH%t<^lk%D;cc- diff --git a/lib/pytz/zoneinfo/Asia/Baku b/lib/pytz/zoneinfo/Asia/Baku deleted file mode 100644 index 72ae96e9cc952d2aad5ffdf5284b9a62c24f2154..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1942 zcmd^NfU!H`I3oQ2s4>PB!loiZzCbDB<}paobUP0cbZhA|++PR}ra^r#qcW;*IXZGogkDLAYo;zgUMMT-dud}!x-^w#$jUmmtjda))rF5`P5ghdHnW?q{kKEb#r>`8Ze5b~ zPk+`8=MTxo_Osf2xJ@^m+oPM;AJi?oo75H2rSpo6dgtmI-7VT36YK8&$uE(Ns~n)= zUWpVbDs{O<`~jXj?{DAm-uz8Z-n)9+U(K`m^}XkkU`QqwOtZI&kQ7w$F%QgT#@&AD zyqPbdk2u?}%{bqXGtNKZoI}n!iUkh2dt{}2Zt9za}x_yBPN;swMFh#wF~ zAf7;6f%pP(#?p8LamUj5191rA5yT~kPnO0hh*u1^7=AGvvoxMDT(dO3F`R>V$8Zng zAH+e3hY%MbK0=&icnNWn;U~mVhNlo$Esd`XXDyAl40jp+G8~3@%y1dvGs9_!*ATZM zenT9Gcn)#h()bQ>-qLsvai8HoqydZ$Fj~Oq0iy|wE-=~v=>ww?kWMgK0qFJ4CS zkaj@&0ci-NBaoIbdID(*qbrcMF#5u145KrQ)-Za*XpW`n4x>Gmraz1ZK{~`}5u`_u iCPBIcKgTx3n0}4SC19RlPKGbTo0;ngW_j(CFXjzafS}m` diff --git a/lib/pytz/zoneinfo/Asia/Bangkok b/lib/pytz/zoneinfo/Asia/Bangkok deleted file mode 100644 index 44a1018ef6385dea4a0fbc4fc6a9cc0726ad067c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmWHE%1kq2zyM4@5fBCeMj!^UITmH59|3aWY(Sz(1q>`sz99^r&LJQ!LkM<*n1NCt t3<4lSKy04>KoGXA^$3Ut8w!+xmp$g z*E6`Lep9~dKS!*6!^P2QFYXiG3)Py#?JvraWiP0srTsdRnPuM3>d@WyTs7U7`y`sZ z+e9Zka%swE>e7(Xmq$j-$Us=GoZDhXyY7&&-lJ-~twK+VtW)lsXZ7T=ICIm~k0d^$ zNX1{ds1w}{Ch^=YGUb;sGxhjENjj6RrtLqgr+?s9Gn$X-ac8_-DE-~t+FZpRaKW-C3Vq8_2l&hQh$26Y8XzDr@Hgh z=5LC1bq*T`M=aHGlop7cUW4-Pnhk~zL4#@ z%j_6^SK4~pP5a`E`zKCGbGiNgl|h%^AGD7y zSMdJ_5NChl;@E31?vwtqN9Dj*pCV&G27!zM83r;AWFW{$9PLn$u{henAfs`#!$HP_ z3c{jL0C7Q6j@c z#)%9R87VSUWUR}X_)X1=raU%mqMve>}89Op~Wc0}J zk?|t|aI_IXLf~j)fCK@F0ulx!4oD!7NFbp=Vu1t$i3So5BpygWkcc25akMc(g5qeS zf`kQ$3lbP4GDv8U*dW0{qJxA7i4PJWBtl4t9Bqt{AUWD7Az?z|gaitS6cQ>VR!Fdr zXd&T3;)MhZi5Llknkb#Ljs6I5D6g?LnMff z<0qVF!pJjmL;{IK5(y;|OC*>`G?8$|#@s-so$MognC<5zr=JNG0rL5;hT59goO<$k VnH!kzE%5s0`Emn!zJKl#{|4X}d;df!Yq@V!=hUeS=^I7s2761RNA`u_9ecsP%m>SVSkszQ?`q@$PZMeV=o=FrE9H#h-XE5SrhBA$GcFHbX_QAs_R6EZKjpFbsyrV3C{NVBmofiFI=1#L-Mlm>TfTHz zC*RDQ@wbN6`sA+JwotL!?-b0A*|KF_&zh&km#su@qIkORp4XYbR65gi!%HSorQ}A= zOGQWRRJp_Ju5{TwulISqD~5e`q229!S+Vzs5nMrhL7ZtSZxDA7e-MWdj}Vs-pAe@I zuMoEozYxa|&k)xT-w@{z@0!Xz#6P3~NC%J>AU!~ufOG+A1JVbi5lAPHRv^7Vnt^nq rsoH_`qp2E#bOdP$(i5a9NLP@yAbmj^gLDRIO>>*{7R(MgZOPy-caz>; diff --git a/lib/pytz/zoneinfo/Asia/Brunei b/lib/pytz/zoneinfo/Asia/Brunei deleted file mode 100644 index d6e713d436fb05ccf2112eecda9943acfb86ccf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmWHE%1kq2zyQoZ5fBCeCLji}Io5VDx$H`J?_dOqWbXk0CgIbS=05(J~!e diff --git a/lib/pytz/zoneinfo/Asia/Calcutta b/lib/pytz/zoneinfo/Asia/Calcutta deleted file mode 100644 index bc909c92c14d0e35a1733204663dda841d768b19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zyK^j5fBCe7@POh?Y0ePSPLc2Of_0@sYGZ7BNHn!V7i_uMf~ISlz?Gzy)-kuBnx=0T%%MvO7fp diff --git a/lib/pytz/zoneinfo/Asia/Choibalsan b/lib/pytz/zoneinfo/Asia/Choibalsan deleted file mode 100644 index 043b7ed5c2d721900d8f45f7a7ab122096d7ccb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 890 zcmc)IJ1hfn9Ki8^wIoWsVnEgVO_h2?ylI6*%ittJB!40jso_7^B;3$Q(BTFnVjvzd z8jTVL8a+rXx5&Et-AdY)3X(_>LU%Ncgbrt%w?I4(?R76d1X^q zy=wMk$`*HqYE6BY?JoyL$JwslxxZs{ZRvV&fW{f^9p!Wy-hQGN&50sS~ z18%< zk|EiUbVxoVA(9bEiR46*B3Y5NNM0l{k{L;jY?bOu$S_z!C8o(yWA96xBVYcptEQvSfm%!C9P7?R(Bj7=&4nOZl2k&}U;pn-wc z$2Ww*$KNl6!Py0fgF`@Sz#xPKC;kTlkTXFVK~4qHAm@Sr$jKlY-T(oRS3oq#J75~RNCC0F}}}iU0rr diff --git a/lib/pytz/zoneinfo/Asia/Chungking b/lib/pytz/zoneinfo/Asia/Chungking deleted file mode 100644 index 8a7a28a480a405b75fd1684d757b0db5646b8eb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmWHE%1kq2zyK^j5fBCeJ|G6M1vmU#F-17{q=4KmGY0w0`T~Wzj0Q!|!~&%_uLfmJ z=K>Y?bOu$S_z!C8o(yWA96xBVYcptEQvSfm%!C9P7?R(Bj7=&4nOZl2k&}U;pn-wc z$2Ww*$KNl6!Py0fgF`@Sz#xPKC;kTlkTXFVK~4qHAm@Sr$jKlY-T(oRS3oq#J75~RNCC0F}}}iU0rr diff --git a/lib/pytz/zoneinfo/Asia/Colombo b/lib/pytz/zoneinfo/Asia/Colombo deleted file mode 100644 index c71c0503d9998b579b22417f416c00672902e9c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 363 zcmWHE%1kq2zyRz(5fBCe7+bJ??p~SGQ8F55rfM&^RN7!+xQs!=sE|Ry#r~BBBNHK)R4X z2zGY?jbi{|5P-2o{{unTwwWp*8stV04RR-l2DuePgWLEuSx diff --git a/lib/pytz/zoneinfo/Asia/Dacca b/lib/pytz/zoneinfo/Asia/Dacca deleted file mode 100644 index 52e98ffc2c14d438032e6c2af40fd88433424eb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 364 zcmWHE%1kq2zyNGO5fBCeb|40^rBB^%+i-@pP~yx~qZM~oT$;h;KUcxa`iOwH&5aO7 zCPro!Ru%?^pbH>9(HRUtwr>OjCj&!B0s}9Y6k=dVDqs}z@C{*b3JnTj@C*)NaB*}7 z@?1a|$U_Dp*j)y44G4n(2M~kU^8bM#v#o6phz7Y5M1x!krh%>n(I6LtG=W?VqCqYP z(Gb@&GqJF;u>zfW1SAIZ1km|FPXKKIdII8nL9i#pz@Cuu0eXT+k1#NB0X?W|#svUC C*iQTa diff --git a/lib/pytz/zoneinfo/Asia/Damascus b/lib/pytz/zoneinfo/Asia/Damascus deleted file mode 100644 index 4b610b5a0836df1e06033c1b28afd4152e2493eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2306 zcmdVaeN0t#9LMn=AVP>}q$?i=q$0+{1+IVv2o@4y7yAVl$Aij`CKx>?zg1nZXG!*i-XjL`e8&M(CmvGxYZfJ1lso z2s`gFrdT4^o$>3MnA#d#|J>};8EG(jbH zSLvj#0?V_vT_(4;sg#EIbZV7QUYVws=3G>1sgKL_s83Z!WS3qR_^P#RcgkyL(PLq?mi?R_V=sex;?Ta z?RDiZ?$xEUwyQPXU3$%EjVg=WsLQ_Vw91Elx}v|@s{GQU*B;2T)*YRx*LTEPRb5F^ ztqZZL+h)i|vVXQ}Dz3;!7f)4>Wqu_$1Yc6MbC1i~p|h$k=nGwU>K(Q5hhw_FXPE9U)sn_JnK-*%h)aWM9a}kewl0L-vMj4%r>DJ!F5#23?&UB3pEI z_K0i}*(I_~WS{76loxi&Ia}q}E3#Q+x5##p{URIY*fFwYS7*=2rd^#~BirWKH?nbL z=g8JM_Ks|xWB17RIrfh^gZq#H;(kbWQy zK{|r81nCLV6r?LiTadmWjX^qtw8qux4bmK>J4kzw{vZuPI)tp}Lpq1F4(Xk%(>$bmu1@=q z{vi!SI*7Co=^@fYq>D%!kv<}gL^_GI66qz9(HRUtwr>OjCj&!B0s}9Y6k=dVDqs}z@C{*b3JnTj@C*)NaB*}7 z@?1a|$U_Dp*j)y44G4n(2M~kU^8bM#v#o6phz7Y5M1x!krh%>n(I6LtG=W?VqCqYP z(Gb@&GqJF;u>zfW1SAIZ1km|FPXKKIdII8nL9i#pz@Cuu0eXT+k1#NB0X?W|#svUC C*iQTa diff --git a/lib/pytz/zoneinfo/Asia/Dili b/lib/pytz/zoneinfo/Asia/Dili deleted file mode 100644 index 37bfc4b2786b53487a2507e39dd077d50eef6e70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 293 zcmWHE%1kq2zyNGO5fBCeRv-qk1tvX{IC6TX(T7W6?+UnI85CF^p2@(-#LU9Xz)-pe zq_UuafrWvgZUO@bm;|zcB0Lbbk8cP=h))QES8xb}vu6lMIUIzL;E4Y~0CEV31~~>q WgB%1h4CE*fO*Myc0bQ(X$prwJB|29C diff --git a/lib/pytz/zoneinfo/Asia/Dubai b/lib/pytz/zoneinfo/Asia/Dubai deleted file mode 100644 index 53f70d57a15a664efcc942a4e1644b0fd0b31c9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UITn7JxdO;Bz5x=oaA08Z@eN^c4-Nrw8A3=f=sytP MHH-^rs;&ta0B1oJN&o-= diff --git a/lib/pytz/zoneinfo/Asia/Dushanbe b/lib/pytz/zoneinfo/Asia/Dushanbe deleted file mode 100644 index c65ff2a7b3e5020f2427309c65caa2e950565690..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 597 zcmchTzbi#?6u{5r;(3x+;@#^#JU_2`DJcuf9i-@~SFVx_GSDl7$wa-fD*gb&Et@Qq z&2VN}%oYQK#ak=}KhEdAlrmYIZ{PDdoxVRhpJ=tRIVry)WgRx**{1G1^AD<5r?rW$ zU_b8mE;HHGMIrn4bnHDp#{RvZ>A9`Mx$9lcpKodJ$%^(J&TIePv=+9DIp z&3x!^v8E%r2OVv@)4+WXgV&dE?B=NKG&a%9*81{ lCWtDCE{HOSHi$ZiK8QkyMuXS*2 z!XjCmG*k9p7O5rInYJN?z$S&*wu2(~@PJx0 zsaoVYeP&*`K`rhTa>=_YmETz;m)8kVsES}+_X;>Ren+{3tK}z z&w1gW@Y5_F|5_Dy?Fg>wt5mC7-LmB2s46{M8eDU6?&-4XHd%gr;O*Ll9p<`SZ-iOX zZW^{fSBx#n<*<)=*j@ITqwW1?KKjxnzoyOS&0xBfoUW3YZ?q+VTeq~Un0 bM|M>JrfI*;=CG^HJuAo+|wCUh2lS`se3Z0eRBMu!LH4qaY^|DBNH1VFw9(IB6LX`t^x SG$;hXG)+Q*3m7!I7F+-vLSpU! diff --git a/lib/pytz/zoneinfo/Asia/Hebron b/lib/pytz/zoneinfo/Asia/Hebron deleted file mode 100644 index a073e06ef72e4127fdd0bb2262176bf0e26a4afd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1590 zcmZ|PTS!zv0Eh9jx~{fTU{F+8R+_1$nWkN=Omn@Jb|8CD%to>xB3h^ysc4G|tU!8* zhyo)b5Q?mjh_D+JT`Z?7L=R05rI_Y=Nz*W!Zzh1t$cMvsMp7zdf#ko^1a=uWJl&!(J_#0 zcShb8o$rMF)-~eqYTjjaw;l9Z=V#W)@N)mJ`MGw){u3%=f?H=`#B6Pc^fySI%l3 z6EWhfJ^S!=F{h|m&fQ!hVq+p@Tt%vwXJy;*k=-i({Z~2vTboL_A8IGQ?Gj0iF>=A3 zZE9hiLnfaqP$^p)?M3?%RchfQnc5z%7T4s9w48?`Jug8lnR7{G#JNSLvg=)P&A~90Q+Y_`R<*0OIk)_I z$(My^@~E9Z>4VDe*zGOotx|<|Tz1j(5mkJl*t_m(%K7!xEwbeF#mdr*hjwXYq$)k? z@@?4rQP?#dKFjg<3ULIvoT2}{93f#`!M-)_nPnxVI`khpdbWPyz0p$$7Lr2Dr3?3OhGJItGNB~F#NC-#_NDxLH1ri1l2NDPp2@(nt3la{Ga7c7Wcu0ImfJlT$h)9e`kVuqB zm`I#Rphg`j5-Jia5-bue5-t)i5-<|6QHN~QF(W}EQI88bG$hCs=KSv!66)d#_N{Tx o^gP=6VS%1?+kvVh%#%RXQKoI@`V!g>*0=t@6F6@Dd2*Wj4}jq$kpKVy diff --git a/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh b/lib/pytz/zoneinfo/Asia/Ho_Chi_Minh deleted file mode 100644 index 6401a10256bb3d7c420494dbcce37b3013522194..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmWHE%1kq2zyPd35fBCe79a+(c{=i)8YafSyD+(RGTcL%^yaL8jJ{nB7&fx zphc^{6%n=Qv~lSbqpM9*X*XxmGP|fbH9DQ=Ytf=rwCD_Heur7k`$QXKd)7FAoPhm> z%h_x%?}Fp8#%#}MgXvAKlfKB2wg=U_TOaPdtskAOlE)P{^uUEX@?=A~Nvv8fiAUCXAzd3YOyx3CZtAJZ3H5D7Tu(39r80q?Iy1RReIKsSKL(p5dv}MK=_r@k>t!Z)X_+{uml{tz zAl?Ih z$Lq8A-#(7B&(A*{KjX2swmBi*PX4cVbxqXS5~=4a>Qq^OpXgt#m$Qcjkrk08ku{M; zkyVjpk#&)Uk(H69UG3V);;wdeWO-zLqyVG>qy(e}qzI%6qzt4Eq!6SMq!d?M3sQ`$ ztp+IvsRten+EhdGRW?q&sHVX?>GKyn5p!k;_P0;d~7&#r61OhR;SPitN2PSL%%szQk=*%O&mVO^KK z?ttp6a>{|XTWc_PZ4RAYS&{6C8O lL?k2<6A6k$MZzL+k-$h~Bs3Bm364a^e-B^DKZD+1`2$+rrzQXZ diff --git a/lib/pytz/zoneinfo/Asia/Irkutsk b/lib/pytz/zoneinfo/Asia/Irkutsk deleted file mode 100644 index 7c38e7fd6b2863c2a7ec9fb0bc64705c88d49953..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1203 zcmZ|NO-R#W9Ki8sZd03tQJI!6J!Q6*t=25@wPt2x%^k84AsJX%2p&d67)XpvB8cda z9i+pLtXo8fj1Vt^hXRSph>#$AxpavI5ky%%-)9U4%jeJk`93`Rw+gZ6%ZrMG;38So8W2>4!K zO>LbSSg3t;OK-b-Mf-0K>g|{N^^SAhI&dngclMl@;Mqe`*LqZTb=Ar4$|k7~mPq|# zg*220b;G+q()eq&Zkk$<=J_AG<=&!hoqVhJjJ(%-$0l{CZ(6qvzma_%u~J6MM~s&;V#=6p&8R8kri`32cFO1}1BDGDnJEebCRF$yyZH3~OdLyp4E z*3hHyqY$Jpq)?=Aq>!Yrq|l`Bq!6VrrBJ1CrI4ktwKa4pd~FS33S$ao3TJ9b=eeBe z$DN<`6coChuI!7Y&PHn5wAqbgqt+-lj+a~0=4@nV-Eg1zCUf73>|EVByp;$4{zlI~ D_#Ftv diff --git a/lib/pytz/zoneinfo/Asia/Istanbul b/lib/pytz/zoneinfo/Asia/Istanbul deleted file mode 100644 index 864099556bc9875b7e9258af6c3b221d84c68eae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2721 zcmbu=eN0tl0LSrj?*%TGp*>oNB#Na7Dk`8T7>I?)RInpn%@p#ah?qpj*NHE2r_N=$ zd|WhjR3jyF>ZqmJ)KV*#7MeYsa;6 zFiz#T^_Kh&!LRx*vrhNF96aMIwp!gAjn)g<*4LM}8D~!v>E}*aM%%9S)-PA~8o!q8 zv)aqTjNjwZEvCM;{@Lpe}`C{s8eP@RU zBW$k~DVmMQ*4}!Dx(uUZ{RaJk)!huSW`W*$_NK-M3x;YBeUwLl2Ftb?Kv3e z>K)M-v$k4~Ial2nd*r0my(UWUv2LXnw|s%tv%Exmq-c`%X#QxeSLQIScT%Dj9~-0f ziHy(^Lel~X?On~p^FFihsXxqqhcBA_cb_wp>b@`sR39)0u71xPw6NApF4Q>WQOZ_KdMyDc%(+eXjbb*%kF?gcYv=AZVc_+w^nPSDQXlo}izdQ|51`bOkk`az8G91>%i zo5a}fw~BEM+eQBIgR)?Kn;gIMZTVzHh0xcnk`tbKSr(Shk`srOOMiZzoD@A?PEP78 zCtppLQ=&$TDW^Njr`r?7)IC?^w3Y}_RNF}u@BUdlQ}vseUfnE==`G^f6+g)t*&m6S z#m8ky+-5N=t3j5Ae<){nmvZ)x8)eyz`EpKErF^cv*`bbv? zzR^10`TgzRj4AMIxw#Yh$FKPd)r-H-&!5pWmpXsHsaOAhU+@U^13sLc>cjiPH`STE zr|ArG*^vwHs4hKn@sZ1q1OSNu5&|R!NDv%V6p%0=aXpVNLU z5>zCrNLU?JT#>*!s>mXtMPiEt7l|$sUL?LqfRP9zAx2`11R04k5@tsgXC%-_q#aeL zkytybU?b5+!i~fm2{;mQB;-iUk)R_{N5YQ89SJ-Vc}Ep`B=(Lf_(=4T@FVd@1^^iW zWC)NkKn4LB1!NeIaX`3Kj0!R=$haT_ zgNzI^G|1REs=+}<$59OrGCs%vAtQtg5i&-|AR(jV^0@Ei2?@RRxIJOsyL~+2zWaI9 zDmfQeZIfChwL9U?HmOxo+tkU~rY?7WfBQH2YMcINpZ+;e>ODd&*nm{FEU94dz_fwM Pg9axRq$E3ULn8hH9ONz6 diff --git a/lib/pytz/zoneinfo/Asia/Jakarta b/lib/pytz/zoneinfo/Asia/Jakarta deleted file mode 100644 index a4cbe0c576a103f280aa5982e95456a71c4c537e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmWHE%1kq2zyNGO5fBCeb|40^1y@$IKG-F8FX8n5=8j8Y?+UKl9OJn4Uyb3*)_om} zOw3FyOsotHDGETP4Cx9CEDQ{p6%3pV40RJ2co`T98bIu%0tQYm-w*~b$FLBFa8Dp3 zI0U2~4nnZI2jm721_2Hr2C+r|1A%>-X99=@xeY{v+y|mTZUoUFcYv;pXJpre6K7X&*U$Obx{*9YWue9mWJ-~#$e*PIIg!_8Xa diff --git a/lib/pytz/zoneinfo/Asia/Jayapura b/lib/pytz/zoneinfo/Asia/Jayapura deleted file mode 100644 index 0e79d3178813898789d7130d8e3fb8a40b927cfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 zcmWHE%1kq2zyK^j5fBCeW*`Q!d3K2%oN*yy=Z7y_7iBOqF)}bTzW~YCO#n%^&S2nx quzh?(7+gI=7@UJcK+<3kLV`8_fdFI`hz3~)qRFt53+M)2OD+Hp6)zzG diff --git a/lib/pytz/zoneinfo/Asia/Jerusalem b/lib/pytz/zoneinfo/Asia/Jerusalem deleted file mode 100644 index 4e6410f2b2d35afa6563a0963e069e48684551e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2213 zcmc)KdrXye9LMqBk(0yAO3KUD49E=flAs=xN)t&Dkjp8Km>BSsff<576UhtMZ`Ni+ z!C&T_P;RLk*3wWjbCI<~+en_&g_`EC3vf!ThgDquK>EEOH~FL1zkbi2y&lf^i}85} za#j`25dXS6%r`t-wRw0Cdnb0`>!+7B=;pRB{NH?VL!4>)%WkPD)OP(w``gznefEv7 z<+*}`>U@#5TXRNRtyd#XT!=X$FNP=SOQV9$rE7=u_lJGr^07#LMZYC}IDAH3-SfH9 zRb}GG>LZI5UhJJxP5J*PXu&Z=PafCvUN?a=Zn9om1;9@hPvHGJPp zdwgTBzOS;&4sRZ?BCMVM$gLk)_op1OC*-DE4@8WxC+5Uj4~lvIs1et7)OYQ6^tBfK z(1{TLr1PED&{%qj8DoPNmi-Fw51 z3)^nRb?x)d_J*q2Egl))ov$9b+@~M4ugk|iTyD*IZ?~MgyTN+=)va<~`MWw{-7GoZ zzsE{Us}WBmXUYXr*NTPV-A>ZTERoc?!dcWACz3n| z+ai|NRXfkrSt565q|B>G6!~jTIacmO@$6im^ITGbS`ptQpO2cL3hpX)3Ws{tO3zo$ z%C>g(!iCjx)ydQ9#RK;^MSJ(F)%*9#;_6ePWW(KZO-a3w8ONNp8CBw?)Wve$v|>>@ z?i0EG&P=iX_k5?Ur%1j0YnR;6nyxk;&6Ass#;DB=e>mkk!c;}&4!Nc5PxZ=DuN>mJ z^$8h#yv3Xk+Q%%S!iAcFYw<}8ESrmhpRCU z?_&ncWq>yG2_Z8=ri9E1nG`ZBWLn6)kcqjPnITg{=7vnp)yxi=9x^{< zg2)V!DI#-3CW*`vnII9E<47HnJ0y8X z_K@@;`9l)uYBGqV5Xm8uL?nwy8j(D5BofIaM=FtAawHSUCPzAve7c&1A{j+eisTeY zDw0(stw>&x#3GqRQtJsBa_i$Ae7#+7X0)cRZgEX(O>xanrnsiHrnsYSev@X3`#;q+ Hof!TPYgWv} diff --git a/lib/pytz/zoneinfo/Asia/Kabul b/lib/pytz/zoneinfo/Asia/Kabul deleted file mode 100644 index 7392c0497a75a943ee6ffeb9b3eb19b2fd17d22f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmWHE%1kq2zyM4@5fBCeMj!^USuXs%?f~RiH~={e_8trjj&30!CPN5zLzsb5APfQ^ v13+w!|3Hx0HfsTh1{(;Jad-ff0h!AJHkZZ6Hw11r0|OV(8eJ1BV*@S#M^+mc diff --git a/lib/pytz/zoneinfo/Asia/Kamchatka b/lib/pytz/zoneinfo/Asia/Kamchatka deleted file mode 100644 index 090bf488957b2fa56419a25c2b378ea9b5ce366c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1167 zcmd7QO-K}B7{Kw_57X=*6nm6o(FE2BfdH&A!{rjTU zA8VmG;bz(9W?y!H>*d^&+o`GYK+vwJN@glcc1~2zUJ6%zzGzoZ=Q1^u<#uhhQI*WBi#kbw7|5ZP%o^_Pn$#IxYc!S_5CNYU|9EeDJ89 z555`8tju-XYI~g2Rd=>%XuMC`Plt8&kp>O#S*(#{uS5@5%bK2g=@|PVYwNty8TlZc zKWC(?W>&l2zm#>~-|6~nTDqrS=!UyF?RkDvd(Yg{zSK#z_ny^_r*6om*a7X|eL@DB z6B_H^C4)unI@B~ELto-D>}!$X*CE;bu|(pJ$|Nxv&5vA|JLK_s3zxrW-nF3E@Ab_; z`1{_xW?AD|^B=8L#xnb-Qy%kI(-Z6q&)+AU7vAAKG2&RGF~@yubNJr!u-qLF=O0Em zXBJ~bM#=Y#6B#KoR#!7xWW30Tkuf8qM#hbd92q+@dSv`a0!Ri(3P=t}5=a(E8m=Y} zBoQPNSCa~o3z7_y4U!I$50Vg)5t0&;6Ot5?6_OT`m#aw($;{QHhUA7Mhh&GOhvbJO uh-8SQh~$VQiDZeSiR6hSie&0)QblrgHOV5`BIzRe;(wfQDS?L~(b8Xd4G`%7 diff --git a/lib/pytz/zoneinfo/Asia/Karachi b/lib/pytz/zoneinfo/Asia/Karachi deleted file mode 100644 index a8ff8cb769d1cb07cd1cae49d0120c074d812a63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmWHE%1kq2zyNGO5fBCeZXgD+#X9T$EIBjPXvL)xp&55qJXpcxzuLfNz3Us>`5JdT z92XdPa=S0^d~(;o>rJ%+BNHPtD+?GhFxcGznd2M5z{0=~oxuns-2xam7#Knl7T-Od>kAa>G8z;;6AP5$ zyc(1>oeNal(-~BS;yn1RAGB6Z0F!1{LhA?>y8tneMt~3!-1{F0KyC)nAa{dI0l6JSgWL}SAU}X; wkUu~)$S)uon!V7i_uMf~ISlz?Gzy)-kuBnx=0T%%MvO7fp diff --git a/lib/pytz/zoneinfo/Asia/Krasnoyarsk b/lib/pytz/zoneinfo/Asia/Krasnoyarsk deleted file mode 100644 index 580e8dd2f43ed3f49cba503c6397fa38348b08ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1182 zcmdVYU1-f=9KiAC?3^*@U~bqr4zpv9z43D}hhv;$X124rm?O4Gb9U3jiaOFBckXwOV7O^s_fKB|i=hqNsCT9*X+HRAgwk?$X6>F|d{`I$?J z@;A3k#j~@cm5;MhmAxs|H!jMup3}1YWQWM1Hd(Q^N2AC0>B`!6UDcY@)uF9g6Af$4 zuL_L?6B2trUDy6Bm34h18Xxq@`g;MXefn88T=*&*Z@-Yl;a8G8KdhVTA4%Q8=eoJ< zy42U**Dd*{q#=A+8%C~aqqkEVU!KsWPun#0aECSz9F>-$mo&rBMBfGASoa@AW0xuAZZ|ZAc;6_ zCP*qsE>4>ai)@f|kbIDYkc^O&keraDkgSljki3w@kj$JmH6%BuO%BNpNe{^nNf5~p uNfF5rNfOBtNfXHvNfgNxNfpV}X_G~=b=q{1e368ajPXB6*-z@#G5>FUbN{pe diff --git a/lib/pytz/zoneinfo/Asia/Kuala_Lumpur b/lib/pytz/zoneinfo/Asia/Kuala_Lumpur deleted file mode 100644 index 41bba37b0c5f62d76af6037ad86d42f7026383e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmWHE%1kq2zyRz(5fBCe7+bupxpncbbiWA)xSk}O+Wa)(^u&0MOCGrp{_U}R!u zVP#=sU`UJw=}9VJU}0cLS777>ksx+v1&FMhz`)PIP|(029PAsy;OpoECW1p4ynxs@ zG6bX-34~yG9S2Ye2!jBOE&U$|>dZn{foPCRK{Uv41Z=YZ?w-T@Y~C?g7K$ zZI>?`RS<4CI)gpnIHNnm@k*-;Cmx?+I2pbF!l@(w8&2DN4mdqAg5i=!?gz1n?-&@F znNT1LGb;l_dI8A3%nAk;28L1tMotEXf(8(~ZUTbL{gOy!B97`NOO}&h=>7`N#qy| zUb)GLNn$bD)aX1~Z}t6}m@Ewbm+yXGZoA(vJUB7dB!0}LzHnHBI^6v$iCWj~%!Tb( zee!N#-@c!3ln>3L=HqyYOjhmbsh&sqBu2z@{igHc9@bxy-SYLiOMknHTJPsW_Q!Fj z^|{+&r#EUWu~cnqakrHfbJ^LE8_N|uG~Mm%h9|IQ=F}ZHx#b7K>p7F&)T!=E?8v;! zZ9V^FQ5GC6=!IJ`S+v?FisvdF|8%7&nQApkqb+7xsKU@An#j_A`D6<*Im<7`mo@c= zhAF(6cR_D3EP|naUSZL#_`UESbfwi$2GIsl2hj&n2+;^p3DF5r3egHt3(=dQQVh`y zQ4P@zQ4TZOxuBjY{eT3J43HF%9FQcCERZyiJd8vcs!WhnkX(>tkZh22kbI1Ukc^C! RkeraD@Sn5#RO5i|`vL%a^V9$U diff --git a/lib/pytz/zoneinfo/Asia/Macau b/lib/pytz/zoneinfo/Asia/Macau deleted file mode 100644 index 7c937795787238ba47b51ad3cd4722f3a484074f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 781 zcmcJMJ1hfX0LQL{gOy!B97`NOO}&h=>7`N#qy| zUb)GLNn$bD)aX1~Z}t6}m@Ewbm+yXGZoA(vJUB7dB!0}LzHnHBI^6v$iCWj~%!Tb( zee!N#-@c!3ln>3L=HqyYOjhmbsh&sqBu2z@{igHc9@bxy-SYLiOMknHTJPsW_Q!Fj z^|{+&r#EUWu~cnqakrHfbJ^LE8_N|uG~Mm%h9|IQ=F}ZHx#b7K>p7F&)T!=E?8v;! zZ9V^FQ5GC6=!IJ`S+v?FisvdF|8%7&nQApkqb+7xsKU@An#j_A`D6<*Im<7`mo@c= zhAF(6cR_D3EP|naUSZL#_`UESbfwi$2GIsl2hj&n2+;^p3DF5r3egHt3(=dQQVh`y zQ4P@zQ4TZOxuBjY{eT3J43HF%9FQcCERZyiJd8vcs!WhnkX(>tkZh22kbI1Ukc^C! RkeraD@Sn5#RO5i|`vL%a^V9$U diff --git a/lib/pytz/zoneinfo/Asia/Magadan b/lib/pytz/zoneinfo/Asia/Magadan deleted file mode 100644 index e3c76b57f59f590e82cae053dafd15140a0c6322..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1183 zcmdVYOGs2v7{Ku}&X_taiXb0NQ`%&cnU9%lvV1gZHkdOcHk+&{=m9mGk7yyZtX64l zqQwv;RA^!0!X(1QEQA(Ggh&f%5mXBa;v?J?ft~-60U=tn>|E~s9S)bfxZgiLaPdOa z{IUG@gqsz&H~V!@D`F!r9*%w77~a=cTAs<36<>N+_TxdkeDQu?#ll=}(`=|OFx@Dd z$EzfGZ-ZPSj3jboZl^T6ZU<_1D|A;Yx!xo~zWzsiZ_NhhyJ(#_%@$+}J|-yM4UDg zBo!99IBhaWHb^>1K1f1HMo3CXPDoNnR!CY%UPxj{W=@+LlAF^ehh&GOhvbJOh-8SQ uh~$VQiDZeSiR6hSie!qUisb6F$s*Z0ZMsOlNWw_Q_#dR~C-u5W)c+g&O%v$= diff --git a/lib/pytz/zoneinfo/Asia/Makassar b/lib/pytz/zoneinfo/Asia/Makassar deleted file mode 100644 index f35823303bcd8ae8184f664127c6208e9509e033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 263 zcmWHE%1kq2zyPd35fBCe79a+(1r~maov=&n>V(rBvJIEQ-W4!1F*7kR7|E1Bj;79b7=C I=~{3B0K2C;L;wH) diff --git a/lib/pytz/zoneinfo/Asia/Manila b/lib/pytz/zoneinfo/Asia/Manila deleted file mode 100644 index 0e90ba6326a2e879f280184d6f481ab46fc80ab1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335 zcmWHE%1kq2zyK^j5fBCe4j=}xc@NI{(r`%3py2eU=L{ECsun!Tv1E93bqF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<Z91c0qO^C*L2;4Y=QCdH(?jq|NOB diff --git a/lib/pytz/zoneinfo/Asia/Novokuznetsk b/lib/pytz/zoneinfo/Asia/Novokuznetsk deleted file mode 100644 index f78c1f88bf659dc263bc62a3eccd1d77f1c9507f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1220 zcmdVYOGs2v7{Ku}&R9AVCB&pTO_`HTzUnlUS(9}qn@lGsvRhye3M(-X8hX%!7D84K z5fc?evF6b*No_N<&^5t!I?r=br4(-W?2D)V4 zgLVnuX_5I?;Ln~r|}sF#d>uqsbq zvMS%)QdQ5+j#od<>6+Y4U3=rAUfO#~FFVnt^`UmXd|$7`j_sEf4V|*GEg`GITcj=) zk-DE%QXjH({refR=0~|+J1{2kVV_=iFQ6OxKkM}uzUmFPUuf&_E1ft$DjSoJbmPJ2 zvZ>;_PBz|`&G{#FQ{=KVja`#wZ?`nRJT5Jt(vo_(Q??GBv0ASt2R+_A_wnUVd8SSG z<$0%G{QX=|=vQj{p!pw_eL(q?%Jg^&mFmcFcK6>m+`I2|WIVH+bI^Gwm~ORIsx9Gc zJ8YHSw#(gZKC3+La?b8%|HE`A&0@mHl=%XaMyAbT;*MtO$mEgfvnT+m04V{f0Vx8h z0x1Kj11SWl1Stin1t|up#?h36)Poe{Xewe+5>gXV6jBvZ7E%{d7*ZKh8d4il98w)p zo};M`DbUeWh?I!bh!lxbiIj=di4=-dij<1fiWG}fib4eT7M_1Hr!}X)ffG0W8X@(scT8qMCVm)a8A|vrqt%LS1RE85(+H54{iDQPS#($ zE$gSp#n#tD^TDUtQ1E9$G-NZfacoR(yEQ7e4_=j_)8}N<$$L6{<&xgfGN^YR>CwCV zy}CKvq?><4bi|jCk=ZJ}XE7xA=DzD_zFh8mea ztGL8fg5tPnpS!T6rOr z`RxraOYF;eY2Pz>@}hq-x;%U(x1wk;P+0J^tnmBiTSZ^SbHUMIpm?|=7aHo)l1J@Y zdjE*7yphyZmut1`Ohi|=mgt()5-qR$scR#XS`qrF>lVM)uy01fQxmd&{A;H2!ktXz z$UtDjo9ia>d{8z%?3b$EUfFc5M>cnMN%Um9R3E#ovGZqjOMRzqJ=mh#N)KyItXgYk z;u;SfkoZ`!?wF2B?a&Xc8(k(l2ZB=nYD#wXOv~YLT^5;DZ7W(qM^Dq8( zE-+V1}iSxpId diff --git a/lib/pytz/zoneinfo/Asia/Oral b/lib/pytz/zoneinfo/Asia/Oral deleted file mode 100644 index 8da2a1dee74d07f108a25abe650b669b3899624e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1086 zcmdVYPe>F|0LSq+{#{oyFWc_AsiRqonzpU&vXIw)F)kk~*^7KwC>c!zEpylV$9b`o9ceaDi>E*_g<-)9{B1OC45)$0>+ap0;p zZ}@O^nh(#luftC^mgfsjAo?hOEVOC|eQ)jH_V?M)x2=45J!;o}x|@%@%crks+ZWu_3`B(IMd>@!@|Tpx=b*wkP~Q0pmF1r2qf` diff --git a/lib/pytz/zoneinfo/Asia/Phnom_Penh b/lib/pytz/zoneinfo/Asia/Phnom_Penh deleted file mode 100644 index 5a52722a16123f192e06553a51c513d11605c67b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmWHE%1kq2zyPd35fBCe79a+(c{=i4R3^s1yD+(RGTcLqLk4AcO=v{{sQYUJwnk8$^Tb2ho(cfeYv)U2`q~ D#EUc~ diff --git a/lib/pytz/zoneinfo/Asia/Pontianak b/lib/pytz/zoneinfo/Asia/Pontianak deleted file mode 100644 index 3e882dc3570532a0afbbc73deb6fe15c38f37286..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 359 zcmWHE%1kq2zyRz(5fBCe4j=}xMY{j@G3*k%&v3eO3CE?dcLmpNj&a=jug36Y>%I=f zTO|#QOw3FyOss4S3~3EO^&pakfg!U3WJ28p1|9~6f(8&9ND448Bo#1l`1pn}1ORck zX9$B=a0r7lkVXX|B)IQC5P;kWqCxHi(IB^iXpnnBG|0^$8su&e4RSlkMq0U_3+Odn Gb1nb`ep$%? diff --git a/lib/pytz/zoneinfo/Asia/Pyongyang b/lib/pytz/zoneinfo/Asia/Pyongyang deleted file mode 100644 index 9dbd3c1ae0061fa6dfa04364b4ca65754eed71e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 258 zcmWHE%1kq2zyK^j5fBCeRv-rRTPN35Z1~svVMoiBibwvMA3m5?G%zwSGBGkRly`ts z)=dDB1q~n)#P$vj0WrZK1iM8b!$BAX*nk+s=J*c;nQf_aKs3lw5Dl^zM1w2`(I5wa tXs{!g7@3%v7#K>QfQ$jU1?XI${Xi1v7AV`tHw48!3=CXA=jmE<0RW|SLqz}p diff --git a/lib/pytz/zoneinfo/Asia/Qatar b/lib/pytz/zoneinfo/Asia/Qatar deleted file mode 100644 index 49668c2583c83ca4db7f304af8e4155711d39bfb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmWHE%1kq2zyQoZ5fBCeCLji}c@}<}YrxVq=>Q{8#2^49W#PcU!oZ+qz`)_-8^Yio e9KzrT#1Ifdg314Z0AxByC-F9L0WH%t<^lk(vl*=b diff --git a/lib/pytz/zoneinfo/Asia/Qyzylorda b/lib/pytz/zoneinfo/Asia/Qyzylorda deleted file mode 100644 index fc3bf46bccc52f5b437d94424b6a55446b65a961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1068 zcmdVYJ7`l;9LMo<(`S-`rBvG_R0K^&s!A|1})=x_vaDaF~vp>-)W=>L0Md@YXNOU~!^1~T;b4aP1^WYiy5 zgS_Fx)h8dG<4c+!D z>V2uP^UYn=_40+@@nl|i&(7+escF4)@|sScJFk1s%$UrTOJ-Mo()1l0HT`WTOg7VN zvXz|4B}Q~^DQ*VV(t7v8SF>laNe`A{I{*5M-aEaf_dWWc_4tzBe|y;+=zr&Xp{nYt zklZ!3Ki#3aaD6xu{reqODqocUh01AFt<=E+XHfLyeNg=UjeNUKsk4{8X7}wc&%;Lo zHFS8)9mfN8^prfxA&>6zJi#45{+2WNho!#B#ahT>{0OTd%OUGIWkF;`WJzRAWKm>Q zWLacgWMO1wWNBn=WN~D5WO-zLqyVQ>fRx~r8k|xDQUw=fAax*xAeA7cAhjUHAk`q{ tAoU;xAr(2LB%~&%6opiUl!erV6oyoWl!nxX6o*uY|6h3#>g>)&z5^$s;N$=R diff --git a/lib/pytz/zoneinfo/Asia/Rangoon b/lib/pytz/zoneinfo/Asia/Rangoon deleted file mode 100644 index efae2612a87ab4952a3932ca3dfb1bae2b9eb1fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 259 zcmWHE%1kq2zyK^j5fBCeW*`Q!1s8rQjye75kHp1U=^q%GfWlEKAo=JFkaXPy22L=W zH^?`H!6`H-guyE~guxfcfq@Y0cCiBGK^O!;_JG);|A8QETjvcB4YC(RgX{*;Q2T*u nqclL8fX)E2fzIFnJA)U@7W4tyjMFI$3|v5$>6%#?8*l*tM`Snk diff --git a/lib/pytz/zoneinfo/Asia/Riyadh b/lib/pytz/zoneinfo/Asia/Riyadh deleted file mode 100644 index 6ebe393d0b866580e22349b749152995c6ebcaa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 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 diff --git a/lib/pytz/zoneinfo/Asia/Riyadh89 b/lib/pytz/zoneinfo/Asia/Riyadh89 deleted file mode 100644 index a50ca48a91b9f37ae573a09c21bc208d8b0bbe60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8539 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 diff --git a/lib/pytz/zoneinfo/Asia/Shanghai b/lib/pytz/zoneinfo/Asia/Shanghai deleted file mode 100644 index 240c4c6f76dae5e2b0e4156805098a72034dd287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 405 zcmWHE%1kq2zyQoZ5fBCeK_CXPc{co;wctbyW5bDG>IEmS@->{g9rZzOml=b6W_^J| zT}FeVXJUa;oL7UgrgMRcdpd)vQ2Ylqbx#JhPmUin*tHonE-8OtVnl-s422JXhBMSn zU}RxnC}?2d@bL{{aCQOW;1G}m5QLE6$p1h9awv!fITlO<9SovDjt0>nhl9)oIUWQ+ z9stoGPk?BUM?f^lGawq|ArKAn6bOJk2BJZp1Jghcf@qK@!8ExZs51**45C5K2GJm=gJ_WRK{Ut_y7O^ diff --git a/lib/pytz/zoneinfo/Asia/Taipei b/lib/pytz/zoneinfo/Asia/Taipei deleted file mode 100644 index 70cfb27ca91f3e9dcacf7941b8432c7a10560c69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 724 zcma)(Pbh<79DsitG2_C?MUfH*k&`6K94WP>C zWAk_OZ^OnL2M&t&*-3HmdwYA{@B8}t`ku$vJ2coJzs70ru$gMRIlB&mVL9v{SK&aO zK5APvk=`abu1u(t<}Hcl4XRk#tBxfX&FNQ_obB$b^LUTGSP^qMJR(C{`)JlsU(F;b+Sb_#WRz13viKjnF0+q}f; zvA%x3w!%A&!QvE7hHZ+xyCOb#&u61_U zDE9a}QLl5FN?Rvh`t^R_d8kM3t((eR)uQbAmd+io>%N0!-M=@l2ezlRw^7i8D>*$> z>eRzC?|P)r(4*NqJ=Srpee*5wpPz#K<&BrGKbFU<7e%AFDLH1#kJD50G-MN2$;tfQu$OPT*c;tRE-i#AoL!8E%%ut~fik4x@HN6eSox5`48#t3NZ_@3o#6_3^5I{9aD@$tj84d@PF91`xXhgo*$F diff --git a/lib/pytz/zoneinfo/Asia/Tbilisi b/lib/pytz/zoneinfo/Asia/Tbilisi deleted file mode 100644 index d7e40548acec366bb1999324eeef7116a02788f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1116 zcmaKqJ!n%=7=};Uq)qOP;-EG^tv{`rCboL5O^Dj+X`n4ag^OMSib4ik5F9!bCpVkT zskl^}R2;-1g9u88D+mhyOinG4yQnA#E-p5r-*eJH#GmusbDodyoaw%gcka^Mi27q~ zk_nrYmrb9%pImNyT#dWiGRyw<#2cq4`dasV57iQ%m7iS8JE>PyKfSUP^gg&2^xawr zc3htgc3v$9yDm=$yU!Pc{+VnrFqR7T4B5fnbR*bje+e>?WF_;>stl@^{^0xAe73Uc zX5YSZbI+dY{SSS2=4{ptuk05_25N;L zMZcKVPO+ZykF57QM^_sDv9+)>b}y;NpL}qRSJ(B4n=c$aTi3e&yf(4e`?WOrX+G51 z(X4Q!t-7M!u_$F*wk2PCMZ0aKa$){V&QTGirreOFR8iA6&(?&wyxGD$w6)dCt@QG8 zWA2qsdCDuDG{+fFO;56=VTELw=C{N9dup5I5t~(zP2cxZR{7E61|&g9iaa7oNScsD z4JB1bvXFEk2}4qbBn?R$k~k!FNb->MAqGG!fS3TW0b&Hi3PUjiVuzs^0?!1ThL?6~rtoS}`ha$8GuAD;AB*KWHi$Rzi_3X2cW&L^SD}r>JKpobtwK7)rEy Zxs_gCZp>$lm;aITA9gBB6doS6egSQg=Ewj5 diff --git a/lib/pytz/zoneinfo/Asia/Tehran b/lib/pytz/zoneinfo/Asia/Tehran deleted file mode 100644 index 16149ed6bf5bc85657f6a684a70341d719df4f58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1638 zcmdVZNk~;u0EhAGP>N`p8blkVC@p6#J!$I8QjfFg^I2+{=A1)0Rhp%Xj3QkWEtF<3 zkZe&D9SNm{!4V5AED8&%O)eCJ3ZeqL-&+N(TD0gq?)_aZ+_(CF)}q>~NaK&=V!q+x zRG1gf-h=gB`uVK4Uh(jT^lS~Wc=cPty%u6ED+{W%cXGP&iJ8~FA*)oNf4dHxy{tA) zUDBJz*Q%hAX&HRgCPMn1bZGY(71k6Z!^_4*L~fmqO!}mvA{X`M^=)d4?>ZU1d{{(( zwdt6TZR&Jg260xJ6GVazzv28F($Dh+Gp|f2kHvANpl3~3)Crl+JhUy&=_f+bK zNhx3Ch_uJqGX24f$hg^~GY4E$*6I5)yCY8I)XeGJ;zqSAqe17ze^&Xy*QM1jKooe) zXq!=_Y>Te4@O{77{j5*!neY)scOU8Ep%hhe;fvhc+adO~1?bZ1+iHK|h%QTyRORBG zJP=eRD%SYuO7{U(`6E?UEj$&~Z=cAT={!+8zNG8!oKgp`MalZ}qoSdwN;kI5tETcn zd8oi&98UI=%`rowWka5BUHwY6x%A4m@9v^~Zd4zcO;ksx67;dL3Dq&uEIY4!6UY08 zbXRwfI??!Ao-8XB4vx-F&W_9e>CZ621tT!;&V~^o3|GTQ$#w8B3}N9pQS!|D%q**6 zHLtY1d~Q3feD>S1{>9Rk%){D{#ql?+4p|Ou-bDnm*` zYD0=cszb^{>O%@dDnv@OYu1PqiByS{iPVV{id2e}iqwh}i&Tr0i`0u0j8u%2jMQw` eEE=gADI2L9DIBRBDIKXDDITdF|G)Cx+BSsff<576UhtMZ`Ni+ z!C&T_P;RLk*3wWjbCI<~+en_&g_`EC3vf!ThgDquK>EEOH~FL1zkbi2y&lf^i}85} za#j`25dXS6%r`t-wRw0Cdnb0`>!+7B=;pRB{NH?VL!4>)%WkPD)OP(w``gznefEv7 z<+*}`>U@#5TXRNRtyd#XT!=X$FNP=SOQV9$rE7=u_lJGr^07#LMZYC}IDAH3-SfH9 zRb}GG>LZI5UhJJxP5J*PXu&Z=PafCvUN?a=Zn9om1;9@hPvHGJPp zdwgTBzOS;&4sRZ?BCMVM$gLk)_op1OC*-DE4@8WxC+5Uj4~lvIs1et7)OYQ6^tBfK z(1{TLr1PED&{%qj8DoPNmi-Fw51 z3)^nRb?x)d_J*q2Egl))ov$9b+@~M4ugk|iTyD*IZ?~MgyTN+=)va<~`MWw{-7GoZ zzsE{Us}WBmXUYXr*NTPV-A>ZTERoc?!dcWACz3n| z+ai|NRXfkrSt565q|B>G6!~jTIacmO@$6im^ITGbS`ptQpO2cL3hpX)3Ws{tO3zo$ z%C>g(!iCjx)ydQ9#RK;^MSJ(F)%*9#;_6ePWW(KZO-a3w8ONNp8CBw?)Wve$v|>>@ z?i0EG&P=iX_k5?Ur%1j0YnR;6nyxk;&6Ass#;DB=e>mkk!c;}&4!Nc5PxZ=DuN>mJ z^$8h#yv3Xk+Q%%S!iAcFYw<}8ESrmhpRCU z?_&ncWq>yG2_Z8=ri9E1nG`ZBWLn6)kcqjPnITg{=7vnp)yxi=9x^{< zg2)V!DI#-3CW*`vnII9E<47HnJ0y8X z_K@@;`9l)uYBGqV5Xm8uL?nwy8j(D5BofIaM=FtAawHSUCPzAve7c&1A{j+eisTeY zDw0(stw>&x#3GqRQtJsBa_i$Ae7#+7X0)cRZgEX(O>xanrnsiHrnsYSev@X3`#;q+ Hof!TPYgWv} diff --git a/lib/pytz/zoneinfo/Asia/Thimbu b/lib/pytz/zoneinfo/Asia/Thimbu deleted file mode 100644 index 90294aea202619ab9697a161be8a42753b9067a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmWHE%1kq2zyQoZ5fBCeCLji}d9FSaEm2JLUBL(x3E=@r`9?6X0NDu)96r7w44%Ou f3{D{-APFD{A;IMTKmalwq>p$TxPX@FnsEUDi!2#_ diff --git a/lib/pytz/zoneinfo/Asia/Thimphu b/lib/pytz/zoneinfo/Asia/Thimphu deleted file mode 100644 index 90294aea202619ab9697a161be8a42753b9067a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmWHE%1kq2zyQoZ5fBCeCLji}d9FSaEm2JLUBL(x3E=@r`9?6X0NDu)96r7w44%Ou f3{D{-APFD{A;IMTKmalwq>p$TxPX@FnsEUDi!2#_ diff --git a/lib/pytz/zoneinfo/Asia/Tokyo b/lib/pytz/zoneinfo/Asia/Tokyo deleted file mode 100644 index 058c1e99ba26b1ab7855b81895c8d577e2f582a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331 zcmWHE%1kq2zyQoZ5fBCeP9O%cc@CdzEx2wcH{tplv4$Hz#U|W5{iESFyR5+N)wde% zJo_(jw|h?m6C)HdFw{)|>F!y;$O2|_ID3UKc)0*^a0o~O2tu%1&I*(QVG!U3Vh~&4 zKMV(rBvJIEQ-W4!1F*7kR7|E1Bj;79b7=C I=~{3B0K2C;L;wH) diff --git a/lib/pytz/zoneinfo/Asia/Ulaanbaatar b/lib/pytz/zoneinfo/Asia/Ulaanbaatar deleted file mode 100644 index 39bdd89416a5998472dad71d0a19bf079279e711..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 834 zcmcK2J1j$C9ES0)bkRm!Cbznlx>ZXL5!$*>+Myf^wMZiogKy|WBHz%MkTVz%!x?P4 zY06+U7;G+s7%g4oBsxksPghe1f2m*7)NtO1zPhzJBL1Ay{)87dWWRV{bMW*Tt8u>@ z4TT5Q`1WlzJ;qh@T~M}U1IlwzFIx}mRNG!rwr_u_jy&tDm-}9;Hzu&b6a=T*iGHLlwl42+mwF2p=2&USt;q_HD5|7AGB&;-l zn;iADs17P~V;>{(hYX2~i42O2iVTa4 ziwum6j0}y8jSP;Ajtq~Cj|4y>AR$WHF*t%CQ8>aNaX11YkvKvju{eSu(U5RRJR~3z l5ebRJM1mqwk+4WyBrp;g35~=?f+NxK-^083XYh}^egXf)uLb}B diff --git a/lib/pytz/zoneinfo/Asia/Ulan_Bator b/lib/pytz/zoneinfo/Asia/Ulan_Bator deleted file mode 100644 index 39bdd89416a5998472dad71d0a19bf079279e711..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 834 zcmcK2J1j$C9ES0)bkRm!Cbznlx>ZXL5!$*>+Myf^wMZiogKy|WBHz%MkTVz%!x?P4 zY06+U7;G+s7%g4oBsxksPghe1f2m*7)NtO1zPhzJBL1Ay{)87dWWRV{bMW*Tt8u>@ z4TT5Q`1WlzJ;qh@T~M}U1IlwzFIx}mRNG!rwr_u_jy&tDm-}9;Hzu&b6a=T*iGHLlwl42+mwF2p=2&USt;q_HD5|7AGB&;-l zn;iADs17P~V;>{(hYX2~i42O2iVTa4 ziwum6j0}y8jSP;Ajtq~Cj|4y>AR$WHF*t%CQ8>aNaX11YkvKvju{eSu(U5RRJR~3z l5ebRJM1mqwk+4WyBrp;g35~=?f+NxK-^083XYh}^egXf)uLb}B diff --git a/lib/pytz/zoneinfo/Asia/Urumqi b/lib/pytz/zoneinfo/Asia/Urumqi deleted file mode 100644 index f46ff380a0558ed590f3e02b26bcd2d991de0119..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 389 zcmWHE%1kq2zyK^j5fBCeJ|G6M1vmWLl_H#bT|sV_8H0RgeStzG$} diff --git a/lib/pytz/zoneinfo/Asia/Vientiane b/lib/pytz/zoneinfo/Asia/Vientiane deleted file mode 100644 index 7d39589f19e8aade5581698bc41ef256984481ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmWHE%1kq2zyPd35fBCe79a+(c{=jl0w%`4yD+(RGTcLqLk4AcO=v{{sQYUJwnk8$^Tb2ho(cfeYv)U2`q~ D&EqsB diff --git a/lib/pytz/zoneinfo/Asia/Vladivostok b/lib/pytz/zoneinfo/Asia/Vladivostok deleted file mode 100644 index 1cae6d0fd9880e7de01c294cbecf820dde247f9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1197 zcmdUtJ7`l;7=Zsgsx>0k!K4~nt8I-n)|hHbwQcOf7-A9#8U(9_fG3yw&=SSK1JKu8sc3x^4Ac4Y*%Q;M zdUL+GV>bOF`0TRmd^jY{cTUQ#>nRCcjL7cOAqfxkYs-aJ-P6^ndyn|EwWe0v!i(DW zQ?%XhmG*ZZbl;EfvcE8^9i@_Vj=z_#>4HRV%*cVo?gTL)7 zMXuz{f0U8i;ugu}9jin}@3SwjODB%C_8s#ymtT4_naaqqWRG2rmRBQiSnSp=nSYq* zF9TD>OqLHYUCe|rQ?@pf#!MSCam>^)lgCUSQvjv{ObM78FhyXhz?6Zh15*g55=<%9 zrWT+WOf}Y~985i!f`E#El7O0kqJXM^vM_aF3d2-}DGgJbwJ8o$owX?sQy)+urb3`Z zphlobph}=jpiWGoK&6;cfm$)e0@YfZaxwKQ-9hdsXme-`&k diff --git a/lib/pytz/zoneinfo/Asia/Yakutsk b/lib/pytz/zoneinfo/Asia/Yakutsk deleted file mode 100644 index 461901f6f83bac90e1c1b4781469148325e6e6ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1183 zcmdVYOGs2v7{Ku}&iH78`ZlFCnNvDV<|Ca-G@H~W6P=MF2g0NXdeDowL{U;i&~q`w zx2R3DC@O-GHa!;RE`b#bOl%T9}i5BqdU-&b9loY3;-F|DW?(MaftE}MN%qk*>){WdJiKRgRpo;(z; z96Oa=F}(9t)uYQ&eWzb)t{#-y^L?`NSW4>l#HD`6evKVX=&E>^uHG8aHKoRqs`+VW!>E`5+8ga>o2^Pmg@u3y7!^9oqMhu+OJ7s_kG3}MMjH^*J($Lj2Rgt5BjZOBKr%p5KypBmK(av6K=MEmaoS9f zRFGVpHW?%vBpoClBq1atBqby#Bq<~-BrPN_Brzm2r%esX&1sWEvP05C@dI|K5iHGRy=6B4WZ9}Q%RejI)SU3pUW!6tkO@VXA}Od-j0%b( z3WDfh8J@Bh*r_599xZ+cZxTUyi9n*dgpGQ>&oG1z(Y5E{eLm0Ly=<`OJNL-(!HD`} zEHihw7;$s4ue`rpNqTSU&gxO=oEwww;w#eq=7#M5a6)<>pOVznW!-x{EuP|{!YuJFnoE`jN`3yo z-)EUpF)_cRip5olQf|iMQ!1(17uJP4-2eT|a{F%3KEG(Mf~j6tr4J_Tl6KYML{DLL z`3mJR!>;z#!s7nJY5z2X6Gu*+&*0>d(?<%hnhKB-kQ$I8kSdTekUEe;kV=qJkXn#p zkZO=}kb01UkczCPB%~&!D66RoDGR9!DGaF$DGjL&DGsR)DG#X+DG;d;DbZ?bM2fVU zDv>ggI*~$=N|92LT9IOrYLRl0dXa*Wijk6$nvtTdrfQ^YtEn3)9H|^B9siHo{pLU6 IHb(uw0GD+ZBme*a diff --git a/lib/pytz/zoneinfo/Asia/Yerevan b/lib/pytz/zoneinfo/Asia/Yerevan deleted file mode 100644 index c4ab2197f803986ebe700b1cddbda26008dbdcb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1263 zcmdthOK1~89Dwmz+t@s66-1LX)>o}*YFk5WLey3_)-+ZVDK!X+hY_vdrj*yYYq3 zi9LB_H$Au$Up74HG+!HcTF%{fS_f`9%lof7@!e;f#6zdFqT{r*_3oEs-9bqu3X=L- zlyqdDPCrY@%FlVdYBVIP%dNWodQx|c%+hO41ohg%ciQgzs51jKvMyWJox9%3`i4=R z?R+d&-3#WF<=AlE{s+cx4D?Pu=>E0@@ z&tGL`U`BP|Z&Rt*UGqDtrnst9s;kHHDV4U_Ppv;rI5+Ri?y{w*GUhQ;FdK$thP%2?KbPV^-1#>%xOe34`4;XUX#nZK)wF>0fHZ-0fwY12 zfi!}2g0zD4f;5A4gS3P6gEWM6gtX*pdP16VHC-WXA$=i@A)O(uA-y5ZA>ASEA^jl@ zA{`KyM U(mB#P(mVc7&HK$iqovLN9jTiZmjD0& diff --git a/lib/pytz/zoneinfo/Atlantic/Azores b/lib/pytz/zoneinfo/Atlantic/Azores deleted file mode 100644 index 19e40040672aca4a74011b89614eda7eff77e2e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3462 zcmcK6dvwor9LMqR&l=m@-qO+<`DKOGVwYSqzAhuN#HN;#(#(p)!axoT}Ri& zz9e-POQ@7-U%6y$=GH2qizU}IAtbHO^HZm@Qys@Y{eI{7d;HFC+dt0ndcM<#-IJB* z{Oi%ce8Y>!F7x7Z)U#`T%g7%vQ}chX@?M=Au5(KZbYAXkEhyYB-iYx!Kd-JX=y^h4 z8~3y>jER-k2bD-+-TGR1{4H5hx=xDTaOG`pj4pk$mAo_aDOonYyDraJs4H#?>idb= zy0Y>2y0WHHKlo{b7H|AaR`pettt)Gi9cHoIOp}W{i<_JucVvol|8) z*X8m_#zy^Q#~CdR4A9b}-SpEvxl;D-{Ze+=cgm+{JLS7dWYhD5Wz*Wx(<^dHoQm~3 zb@QYo*}Qm$vt`J9XUprWb?eYb*_xN-Y)gF1+4gvWZol?jxB4bW_7dJiVH4EA4H9J=BT~bxHG-`X1cj?*!FS@ua*nDwu zu*IuOf|upZ3$}ddnP712^x);UPYAXeI5HU1EiHIOT%X{T%{v5JH)tJf6FS&ybE22m zc5jjwTX}_d)%r;9>J_InZs7sFX3kgIZbq55pIEH%nM*Wb_zp?TSs_WutK`}tFGz~I=Y4G=>0Eh z_Sqc0XX8}8cXzsudGj_MyJ3Rd_f)cuTa+gEXSdYxPjrw8gS$yiRx^1Z;WC++a#|)e zab$A)NS$20N2WA7sZ+MBlc`5`=(MGa%&EJ^^vIyHFtKd)(O-Jx!^pX zq2~8$zs~FL!s^yL=QBK_{{Qu?soC4sacXLgRtGMqsj2$biKzXV*$FhZ@8+jRtN;9| z6Tvr5WbN;-Pfd4v4jYta-|d_E;+B+j`#S;iaCrUw2n5pqd+-{XU*W}Lw|VioMU8pf zksPha_#p#mH6w@&Au@)@AR?oP3?nj*$Uq_^i3}w&mdIdQ&1fRSiHs*QpvZ_KLyC+k zGN{O?BEyP|tJMrFGP20fB4djTE;72v@FL@j3@|dn$PgoAj0`d|%2qSX$T(ZgKqDiK z47JsaH8R*%Gup^-Tg`Z5g&A zCRj+ckZ>XKLIQ?F3<(($GbCt8)R3?taYF)!L=FiZ5<4V#RuerWd`SF|03s1YLWsl= z2_h0jB#cNLkw7AmL_&$g5(%c&L=y?8)x;ACC=yX5q)1GWpdwL4!ivNd2`my>B(z9u zk>DcHMZ#+}@kIh`H4#QajKmlTG7@DZ%t)M(KqHYxLXE^42{saKB-~aLZzSMW6LBQu zNX(I-BT+}fj>H`aJQ8^%^hoTH;3LsT!jHrsIRLEY2tW=20^}$_4g=&kKn?`t zNI(t+LnHJ& zpLNae)qb7V--Xu;JLfZ^euMw(X{NNAOT*k7_Lc~Q*?Xgry*K{)%s)h+seL!!n0v$i z)M>;wPE_sh2b%NZTsH^j#y^h^^Ie3wQPLCap%Ryx)UHFj`1bK}sR{A+Q$oZaMg1)% diff --git a/lib/pytz/zoneinfo/Atlantic/Bermuda b/lib/pytz/zoneinfo/Atlantic/Bermuda deleted file mode 100644 index 54dd33dbcbb30ae6ebf6aba4d3f46e1220d73d78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1990 zcmdVaUrg0y9LMoPI7cTjEGZK(u|J5x5e}Y0(9pzA7$?5U!8j`Ttsnv`k^muz=KPaf z*;Z(oV{^G&7iA4|RvW{}yy?$lR-?7y;~ZYJ+|0JtW^#Jo&uv#-wSH&6z0S^d?!NC& zd_(Kg;lMwhRQC%n&kpzUea7*zobj~z!+K-JehCH!HF%{*ZnE2S#!qjU^wEUQ{G{95 z{9c#Mc&pyb8hG5^(pzS3ZCz?-C$dduRhGT2bjsYm@VcF|AWQB@J8$QvT$j1O{iRtK z&P(>$3C%fmO6Gkus&^iKN9K23wYfWX%YwS^?Okn$&E1g`_MSC6&Apj#+Pp>0CU5Fv z%@0OR{=@-Y^h>_EZ=_cX&OI!JLmM?TyigYRFV~{igHqg*u;Gqhr6gKzm#q6nB6&IX z{_uzL!1Sao&HBoeUbi;FffbtaKKL!v{%L*hdML?T2&L}EmOM508(MB+pOMIuE)^}1M*V3BB%aFKYCfRTuikdc^? zppmGNu#vctz`ZVVBy_Kf9SPp+qDR6<;ztGm83AMnkTF080T~5k7?5#52Eyw`0vQUg z8w+GGylym*;XuX%84zSdkRd_F1Q`@$RFGjo#swJ|WMq(`@w%}=2FL402N@o(8y{qV zkP$+L2pJ<}kdRSAh6x!bWT23dLWaug#tIoMuNy67xV&z>kO4zR3>h+H%#cAtMh*Wr b!xnTqx5VvSL98Sc4iy!|ii<f8_SgIXiYx_`^-88JAN?Yx=!R53~SG-U7<#YX(9*azQh=#66< zcJZLz`f<17PMoy(qivS(#Q_`MEKA(9)kaj;+Q_mcHmWFWNjdp8+MjL7@hLXujiHtj z6;#Tj@fv$GS>w8f= zRuH9NWt>exeNxe7i#FfY;;G-+lJfJaOx$NnbK6w)+BaI3AT7JSSIc{Awc=cZ zR$dKj)t3uYeRhp~x+7OLttIx^@e6CV*L~gU z2lS}^!cW$4|B^NwZ?%n`9on?-v^KZx*OrDOYTVT*-zyQ3QUCc*U*F$y9QSv(6Umu5 zuRG2F^Y#Dddr>It1oMi+&b)j+C1Jkw`Ft-3|BKu0b06*(xnceTcg({rBlnElG;-IT z?rkIYjodhL=g6%i_m12=a`(vXBlnLqfOLSgfb@Vgfpmei;pz5)G=g-3w1V`4G=p@5 zw1f16G=y}7w1o78G=+49wB_mcg*4{rc80Wu^oBHtbceKu^oKNvbcnQw^oTTxbcwWy z^oca;>2`{=>go21G>deLw2SnMG>mkNw2btOG>vqPw2kzQH16qkjDAp3!A2(lx{mLPkAYznd~ z$hIK+f@}=3GsxC>x_g6cj;Fgj$o3%ngKQA8L&z2(dxZbzO^SAxD!@|tLz$^rse!a~ Ke<(e`Tl90%p0O(c diff --git a/lib/pytz/zoneinfo/Atlantic/Cape_Verde b/lib/pytz/zoneinfo/Atlantic/Cape_Verde deleted file mode 100644 index 5238ac8a6704a159bb67e0e19a674f62e2c6c9ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmWHE%1kq2zyK^j5fBCe7@N1VKCtJ^)Hw>5N@@hS#lJf+GBGm$|Nrs}1H=FSj~_6w z{Qv*)10x5BWMJ{}4PkH&1L5Ehh%rDigapg}0|CfF5Dl^vM1w2_8Ag`nTtMd-asdGF C$wV;# diff --git a/lib/pytz/zoneinfo/Atlantic/Faeroe b/lib/pytz/zoneinfo/Atlantic/Faeroe deleted file mode 100644 index 4dab7ef0859c244b916d61b7489d7371881e0ca2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1815 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 N{tMXT+N77~{sm<$Mv6e;~+g`+I=# a|NpxO7#P6Du=x0fK#gKx-~yUy#03EHLK!>& diff --git a/lib/pytz/zoneinfo/Atlantic/St_Helena b/lib/pytz/zoneinfo/Atlantic/St_Helena deleted file mode 100644 index d365e3ddf349472f852a9b437fa945a20df772c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIqo>kj$r)%|JMqTC=jrC`GzpK12G7MU^j>vC1BVaLTx9bZ7`T8|8E^prd)*@W diff --git a/lib/pytz/zoneinfo/Atlantic/Stanley b/lib/pytz/zoneinfo/Atlantic/Stanley deleted file mode 100644 index 34f9d022cd5aa2b03b601fbcb75f8897be6e50d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1220 zcma*mPe>F|9Ki7zUGqRKtTS&o`(x?0cNHd_t1+>3T-jR*}Q>ei`$P!a@L z_YM^j74+)TA(0{1Y`3JT5XvH!q(ebaw=!sY-xt9`5x&RF=f|+%;rBH@G>R~Rv9NyP4-9Ka}gSpmBLx=rn)dy>~WKhhyrhNP@BvS7dW%^aQcrrC3pWb)H zT=10T^ZpdRmy@#eYtmnK^MJMb`Gmjxe8j4_u~$|e3JU*Nr>u&Wh&3aXa&2Hqtm`pl zb>Ul4(^z5Ee4G-sUc;(=v0w+jytnG^P1@_7q*Z_EioHQjSR0R>v>PstS=OHYcH{Bu zvMF>zG!LGYo63eoOWTNS`Oz&}eNox^rdn+NUN74oZKKe27cQ7L0VN2Qj%8HgcOBTg_MQVg%pNV zhLncXh7^ZXhm?oZhZLw)6(S{SRgFlINR>#LNS#QbNTo=rNUcb*NVQ10NWDnGT2(Pp zvR2iM6s=WNBV{9XBZVWCo4GkzH_xMP_J`%oEB<7zV*j0UfsVac$F63Txti5m&t^fN Qiv2&q8%7cT3e82o0My}d^Z)<= diff --git a/lib/pytz/zoneinfo/Australia/ACT b/lib/pytz/zoneinfo/Australia/ACT deleted file mode 100644 index d95c245e5ee1cb22a2b88fa63bee6736a4d0a8ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 zcmd6p|4-C)9LHZLFyzumb9_}o%>+ZZQ_;IZGZlmsLpi>dMt~@4dT^;&dA?E`wfVgt zWOg&e8UA2lw5B;0vD{c8u==4dq&fPfVQtheB~#P)4b#OXrHUx7F+KYYs?%W1>II@73_J z6D6V`Q6v8HXk^AMjr=Y_qoS{B)TcMqIozcWy&o@Qe)w6&25-p2=f9BXHCN=3rWP5u zpi{;-?3G88PRNAP8kz9V9*ObfO6-_-G;VUW#&y4`36301Xsy!3!4#d?n5~n#oSL*F zq>mkKm*ldbPS!r1vgkdTTKk(kK4qs&%j=bC!`EbbYMV^&za*(qhb6V`BbhN2kSCkI z*0gUA>db~Sn%-Wg8Kno*b)-<;tIKs(eWuQypQUqF#cJlHB%SLX(Yd!oJ&7^mx%`WI zTZi5}x5n!PxvIT6cb z>C_5c`ge=u{`#)ueZN

)tBM&eh2B))L7-nky?Bz4H9_8B*Xc(v=lCx~gEF7A{Ot zpDSLAlAT%{eM5_H|E?v&SG4qMpO*D^YI)~bec}9NdGU0wtZw>T*1X*&FEunv#rnhY za_MfV%neADr&_90ieznEj?|2+({+wYUH509t{+^YwcljwhOQ@cBMM#<ph}o5e8HcqQ2xcVKW+<4kU} z(%OU)h$RqAAeulpfp}s9iis#Dq?nkFa@;$@!XJRc{4==7H#1EQw@o$I`}fQ9eR8*} d_rfYp^ElJ(GS{?xw=3P9?n=v_gED42?*R6K`>p^0 diff --git a/lib/pytz/zoneinfo/Australia/Adelaide b/lib/pytz/zoneinfo/Australia/Adelaide deleted file mode 100644 index b350cb6660a68969e89860ecefa57e708405ce71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2202 zcmd7U`%l$%9LMqR;Sz5wMT{}hATAkFTn=Ck4Dlq9k{lsC84!@Bf(N2bX!sQ^?Q+Ju zST}2W=G-ccz*axx8mMz?%q0~S)3n>#8f6(2={osWj8Sl+> zqeDK8nVu!FwV4|G(_)SD#%SC}85*DPjm8f}>$G!k>!r`9%VnQ@Ez`G0$&5pzlF)KS zW=0N3V)=2I<@U+tX@inf-ziCdJTA#4HIjVxWlhQG(3DZt*&e^n9%$D&69sx@Z?&e5 zBx>50{d(2z!;;<*){GseHFL>6$qN1;S7$ydbE{6tHBqgSoiila;~z>+d_;1_*6FpA zJ#t;-gyx>yrFnhxH2h$cQefd{Qdb?$?|0U(w2n zu-+V7Crh*1bm`9rWZBt0QuT44+%mdNmJfGI^+1dGch|^@UZ2!#E|l6(lis@8uXVNM zy3$vm0dKnAmY%4qW=83%sUP+Bb7!>vi__XLeq0;h9M(GyeI-qUr=&UZmbB=Q-02R; z>J1TDQ~#LUwX8?hmUPIvc}=oD#V@UiuC{rC+IGHCH%u(o;E6JAAIZ~>*VFXw7ZbGe z8AtEgabE8YeW{`L8FF94lyp^nFB?lIWK+&bx&Mk|(jEVXbpP5fnHW z!$H}4@HySKFRTyj?A8Y#Zqw~u_3C&ooKevi!Ra{94tmV5IUM14{m*^H%7A(9;Vmcd z|AV;1yv4=wl)1QOmB4kL&n5uCwVI(K zV?_pwj20O#GG1iB$cT|4BV$Gejf@%@HZpFj88|X>s~I{nc4Y9#=#k+g<3|F3L;wi^ z5(6X%NEDDTAaSsoKp>H@nouCIK!Slp0|^Hb485*H*eNMx)g zG)Qca;2_aK!h^&I2@nz?Bt%GzkRTyZLc)Z^2?-PuDXR$;5-TKFNVJe}A@M>2hC~br z84@!jXh_tMupx0n0*6En2^|tUs|g+wJtTZc{Ez@55kx|W#1IK05=A78NF0$sB9TNw ziNw-sf{8>E2`3UyB%nw{k&q%WMS_Y%)$?~uV`49Y({Ud9&VI$G`JZ62Y938u|8-yO k4>%Vx`&Vd9s>};{r3;I_#$11)H@`67o9mws1;x|;1RR|M*#H0l diff --git a/lib/pytz/zoneinfo/Australia/Brisbane b/lib/pytz/zoneinfo/Australia/Brisbane deleted file mode 100644 index 3e899a163f51980c2f92952b002d4cc672a35dda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 413 zcmWHE%1kq2zyK^j5fBCe0U!qR=lCs~GiQ&&htnaO8BQM$FF3P3tl{i(%Yt(YiW$zg zOBXN~ST?Zm$}p&Uo@G#d|B69fb3KFl`7;cfoD&%|*RNw>V1z&>W(Z_pn6-fsXn4;8 zAc4eo4GsbF89`DEA=ur=3X}q25D)}n5S!ya5EQ+g52itG1@S@d1<@ckgK4025m! diff --git a/lib/pytz/zoneinfo/Australia/Broken_Hill b/lib/pytz/zoneinfo/Australia/Broken_Hill deleted file mode 100644 index d8f3155c84dff3c25e1590a0c1aa086cc9d51a39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2237 zcmbW(e@xVM9LMqRaS(3^Ma&s#5I@#6q4?K{%u<%4vSKfG+ z&G{?6Ikrq=V5_;TK%HA-E~%)Pre&?IDEq-*L~Z@riayUTZLP&$e82nh_}<;VgFo)| z9Nt>r`aJ7@N4R;1i(`+u?AM*kUwgUpT>5W=-m@||&=B~buU5D zkhr1?GBdDSZb#yfzw!1=ZjM=O4$;}!+pgPCl(K+2sI(IlnZ|*49g#I{9 z+;UuRIebQvYJ!@)^NOY{J|?NYpXAn*U6NLIS<*(wBt4^7(uY2ljHr-goP0}eA8D66 zLKijj(jm{MDmLdzrN2(^U**xN z$|7A+oTFY>l0J|Wrz>ZK>B{k+^}*3=TK(k}tr@zYwQu+7L#Mxyx}M8YA9_a`v{xPu zbjzv@Az5AhtUR)`UDmjpW$kTsvM$~u>*E62=c*F1 zwPl~BkM11P$NXQbziGNWUNbJOWk1TMf?;_ghirK- zAnj*-vh~zK-F7UfPwj8h?N2xAj@D|m91~}lbBd=m)dweg&aw{lILuc%7~;$Q?|sP% zuX*j@Bg;GaDk9BCTpat%#eK}UIX2DKwb&Nk^%ZWN>GUIuu{EnfmSbzygDePH5wav? zP5crTg{%r$maSPAvM^h-GGuACW^Ksgkkui}L)M2Z5LqFzL}ZP~B9T=h%d|D?L>7vy z6j`dRSu3(wTeDhZxyX8v1tTj)mW-?!Sv0b0WZB5Nk%ilul_N{HHETx}Z);YMEFW1v zQUIg^NC}V{AVol`fRq8L15ya25=bd*O)ZdO*qUnCnsOlZKnj9X1Sttp6Qn3eRgkhE zbwLV)R0b&xQX8Z=NOf#Yd64=b1wtx>lnAL2QY55GNSTm2A%#LJg_H`Z6;dpuTDGQK zNWGAPAr(VPhSUrx8d5c+Y)IXZ!XcGIN{7@ADIQWiqe}-kxC+^L~4l?6R9RrPNbf;rl3egk&+@cMT&}46)7uHSER5=WgTJR&VSB`>!x@* zr~2Sz&so;4PX4&(kMi%s_Pv(axivpcdjE4@?(tfsCchI2HjhkH*xW>$x3UTr+ZZQ_;IZGZlmsLpi>dMt~@4dT^;&dA?E`wfVgt zWOg&e8UA2lw5B;0vD{c8u==4dq&fPfVQtheB~#P)4b#OXrHUx7F+KYYs?%W1>II@73_J z6D6V`Q6v8HXk^AMjr=Y_qoS{B)TcMqIozcWy&o@Qe)w6&25-p2=f9BXHCN=3rWP5u zpi{;-?3G88PRNAP8kz9V9*ObfO6-_-G;VUW#&y4`36301Xsy!3!4#d?n5~n#oSL*F zq>mkKm*ldbPS!r1vgkdTTKk(kK4qs&%j=bC!`EbbYMV^&za*(qhb6V`BbhN2kSCkI z*0gUA>db~Sn%-Wg8Kno*b)-<;tIKs(eWuQypQUqF#cJlHB%SLX(Yd!oJ&7^mx%`WI zTZi5}x5n!PxvIT6cb z>C_5c`ge=u{`#)ueZN

)tBM&eh2B))L7-nky?Bz4H9_8B*Xc(v=lCx~gEF7A{Ot zpDSLAlAT%{eM5_H|E?v&SG4qMpO*D^YI)~bec}9NdGU0wtZw>T*1X*&FEunv#rnhY za_MfV%neADr&_90ieznEj?|2+({+wYUH509t{+^YwcljwhOQ@cBMM#<ph}o5e8HcqQ2xcVKW+<4kU} z(%OU)h$RqAAeulpfp}s9iis#Dq?nkFa@;$@!XJRc{4==7H#1EQw@o$I`}fQ9eR8*} d_rfYp^ElJ(GS{?xw=3P9?n=v_gED42?*R6K`>p^0 diff --git a/lib/pytz/zoneinfo/Australia/Currie b/lib/pytz/zoneinfo/Australia/Currie deleted file mode 100644 index 43ca1e455803da69a06c0289048138fad5772e9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 zcmd6n>rd5n9LL{>%MjAYa>_*st>hAN@q$oFW`dxS7>8?$gviA*4}waT^qHFUAiBEA zvL(_OJ#i{sw2ei~HrEKOt$UhL4;tO9ty#{@zOSFoC-n#T`tA37o%220*?Dl@FMnlY z-E94b5O=~29q#tt@Bg&bUg?kjZOH$IhEA3RK0H=x!@b#ok*;Q)YL5*B2eK_>!c>J8 z#aih3EDKA!WMQAhSa{@F3xDfxi#RuEHynu8_%FWEgtm*i@%Vd+tU9BcI=eM7XFxZ% z?$#}F2Q{g@PLuxGrO8?Oni9NHQPXQJ>iZ1E`0^~Kcb&zKCfd~YT$?r+VR7{dcI&=A z#aFc1bQ`f5i}&lc#-DWij2*h8U|2JQ)+!#TY_yCul{UL{kLD~~U~@AYG;dm*WlmnE%uBNQ=Tnq*`a8?+9kaXo z-?zI5l5IiHs1_a=Z#hq$&^>Lx+M@M6y0_{hTb$dj`*QkhN$P8s8@Jc;LYHf4*ikM0 zvs?K;yrhE9cWc?nEn0r8PAhuLRJbo+_qS(j<+fxM1xjpHb)G#?G~bFBC7M4y+DhUh ztTghXm0teY%Fdm!^0OmWacaOS2aec-$4_hZ>%&^p`L3#-KCHE^U8-()K@XMhR84-f z)@9YIHnBwOqw-WYvB~OvHCF$7u{De?vBr<**@nTH_VCdu_Q=6;w(uf-yB`f2EeBA#I87*Vgbu+IrztZ5w+|tzViR`=CkN->K2#eI52hcbn~a zag(*}thOgNuQH#mTtUIt!6iM@#XtJxBfe`-PI8O=?!Avg`Tu_qq3$DYc-Gy#9(UQ% zk{S|^83$${n2~sPL&1y%GZ@ThFvHs6$3k(n$AT&U1fZzbp0m1{s z2M7=lAxwxcF~S516D3TTFmdwi0)>ebCRCVMVSQrhyfu3Vg>{ah#C+! zAZ|e5Fp=}@LWhYRCU}_WVZw)rA0~j92x3Bri6Ia~Ac{a3fj9zz1S09#g%XG*5KJJN zKsbSTVgibZC?=%Xi)oPW$`u@P9bD3$Z~0}epdnsUuRS?gQRu(g)vIAugv;!#jCA)* TDa=Su%}7m8DV&Sa=0yAp9G&vE diff --git a/lib/pytz/zoneinfo/Australia/Darwin b/lib/pytz/zoneinfo/Australia/Darwin deleted file mode 100644 index c44512fbb73ba306be6c2ad6cb6f2615a95d7695..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmWHE%1kq2zyM4@5fBCe4j=}xS?2hyT{35n`j68gyEslCkE=MdJ+|ZQa)*j@3#vHI zw<}dJFhU{2D z2H6d!f%b!FkQ=}>&>bKelTg0JwNuga7~l diff --git a/lib/pytz/zoneinfo/Australia/Eucla b/lib/pytz/zoneinfo/Australia/Eucla deleted file mode 100644 index e78c2d42514ef555ce0201bc22f0e7ba8200abde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmWHE%1kq2zyK^j5fBCeAs_~^S?BoeFqpH)sO5CXktwH-XR@5xo*{B}xidp3EU4p68-P7#Km2i5USI z7&>JbfmT%W00|_vb9itFP=FC6#}IK(B#lkoUke(2F1%%MjAYa>_lll1qr-1tAs91VJS+?xaYFTrBe-h-7*C%q&`qRc6Vu zCDIuE;zYV=n~TUc)(EYwdzz!#8r`g|Sq_n&*Q4{7`U8ADd!E;GzUPiTkyqbu2kBXY{7*jrJwoUGP+0Xt`i^H!oEaX)HSTd2PazQlP9&r_q#3K)TO&C zKCxw4t-2?(*On*0Zdoz=EIV+ORsMdcU821GIl8ws zLu+;0Jov~;Ml?gc$ix?5E_joO%At?Kw9Z3@d)&Ey8F^;B8yp9NMoyxi(P zoo}1_XWD~Dr`bb?CfJteFWSTQvu*W$Yu?R4YAE|h+j2+LnDLF85(c$B{Dhi=53Bj& zYuYjLoLas%J@Qe5cD`GsM|<1su}+`u+Pl?!yDRPSZEMY=E0>@Db#zJ3cJR-CrN?va z$w^j0q4U|pp$h+hIDyVr-0-q<^FCqRp($BEVn&1+5@t-Uok3wng&7uRT$q7jMur(0 zW^C9U950LxoZ%tH2MiDxA!dlc7+pJq#EjClGfd1lT{{ECj1)6eV64DkfzblP1;z^u z7#J}yWMIs$ok0Vm28Ioc+qE-rVC1fyp<~9589Zk6nBil_4+H=c0Za&h7yv;4q5y;e zh=Xe<5I`g_p#Wlm2?h`iOgMmeU;+X}1QQZWOn{(Zq5^~k6BpM`U@(yZLW7A7CODYr zV8R2$2NNJ5LYNQ%F~S51h!Q4Dm^fhq1w_iV6DlB9K(K&l0pSAT1q2L;7!WcbW|*L1 zqJ{|@CT^I(VIt?+2^}VOnBZZehY24hen0?$2m&DlVh98gh$0Y1AdWyFfk*cP=Cgr83B&Q~) MB<0ORv*(8V3!!2o8vp`Wp`=zNlV}T*d~q5 z)?yolCH+w;gfSS~T9l2}7Gua55lJkzqO$%7*&lrtgFb;|pXaw9|JdJtkGscl{^39G z=PSHARyoz__r%*@c=OcSH{ZR(o>$&a3g(%lM~9-x>E)8#SshLB2W8Z0w;KH>O69FZ|t%e|%eKWVV}(>p$yE@8>4- zyHk2%PnDU}a#>|{9hAv(Qu)qplPP75%6}vzf%1@=TI-W(IX*SLBvEFJOjI)iPh@8A z6BSH-*97m}RN3thWY*;iYW6=}X3m)|o%7RqGxyW;I`_meleguVp7+U*GCyDRf{JGO zz}Kwu7c|JiggJWA*oZ88dQ=xY`oa|6+N~FNZZ}IVuF|3QrKae3wk~c8n57M=dYLMg zs2d<{x2*0?y6Of|B|wMzpBXf4q5$6n_AOx)2uyvMVGf+ zFzXJU*6XFkY=|Dv8_V{ZO$D2EMR2XzJYk{Ul04T`zE`2Pde+F+|MFF|J4a$SGSs%K zX;SrrS5>!qWc%0us+z`!vO`@{D%NLqMtXE@VYjKv{!{PD{LSnh{;jU}o-y^$zS0dn zO-BCSsrUR5GkY(U>V4-vll^Tel1+EYi)-PN8va`wpSBj=AK zfMkHAfaHKAfnK+# q8T)BhW^kw|?DSh2#~H%%Ob+;GP4mC}7RV|J_QT#FzacC5vD!OIKsTA1%L>_(}F;R0SN>WN*D|)ii-+?blBzz a%f@EQ#@3&CW!0(3XBd!5wyiD9m%ah>UV+5` diff --git a/lib/pytz/zoneinfo/Australia/Lord_Howe b/lib/pytz/zoneinfo/Australia/Lord_Howe deleted file mode 100644 index 1f542d3700d59c575750e55470ea66114db86309..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1821 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 diff --git a/lib/pytz/zoneinfo/Australia/North b/lib/pytz/zoneinfo/Australia/North deleted file mode 100644 index c44512fbb73ba306be6c2ad6cb6f2615a95d7695..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmWHE%1kq2zyM4@5fBCe4j=}xS?2hyT{35n`j68gyEslCkE=MdJ+|ZQa)*j@3#vHI zw<}dJFhU{2D z2H6d!f%b!FkQ=}>&>bKelTg0JwNuga7~l diff --git a/lib/pytz/zoneinfo/Australia/Perth b/lib/pytz/zoneinfo/Australia/Perth deleted file mode 100644 index 1c7ebb795cb7b10a4153c9ba18802c741b43d313..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 440 zcmWHE%1kq2zyK^j5fBCeAs`0x=lC7kGiQ&j!0C|l3a5`3PdKx^Xu;X#p%Xaye=p$N zCb2+@F=>I+^7;jusxb>R*Pl{wE!?l*#+t6+u3WRg{ay0{Pv*Dj5@(q{<`UpgWdV1z&>W(Z_pn6-fsXn4;8 zAc4eo4GsbF89`DEA=ur=3X}q25D)}n5S!ya5EQ+g52itG1@S@d1<@ckgK4025m! diff --git a/lib/pytz/zoneinfo/Australia/South b/lib/pytz/zoneinfo/Australia/South deleted file mode 100644 index b350cb6660a68969e89860ecefa57e708405ce71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2202 zcmd7U`%l$%9LMqR;Sz5wMT{}hATAkFTn=Ck4Dlq9k{lsC84!@Bf(N2bX!sQ^?Q+Ju zST}2W=G-ccz*axx8mMz?%q0~S)3n>#8f6(2={osWj8Sl+> zqeDK8nVu!FwV4|G(_)SD#%SC}85*DPjm8f}>$G!k>!r`9%VnQ@Ez`G0$&5pzlF)KS zW=0N3V)=2I<@U+tX@inf-ziCdJTA#4HIjVxWlhQG(3DZt*&e^n9%$D&69sx@Z?&e5 zBx>50{d(2z!;;<*){GseHFL>6$qN1;S7$ydbE{6tHBqgSoiila;~z>+d_;1_*6FpA zJ#t;-gyx>yrFnhxH2h$cQefd{Qdb?$?|0U(w2n zu-+V7Crh*1bm`9rWZBt0QuT44+%mdNmJfGI^+1dGch|^@UZ2!#E|l6(lis@8uXVNM zy3$vm0dKnAmY%4qW=83%sUP+Bb7!>vi__XLeq0;h9M(GyeI-qUr=&UZmbB=Q-02R; z>J1TDQ~#LUwX8?hmUPIvc}=oD#V@UiuC{rC+IGHCH%u(o;E6JAAIZ~>*VFXw7ZbGe z8AtEgabE8YeW{`L8FF94lyp^nFB?lIWK+&bx&Mk|(jEVXbpP5fnHW z!$H}4@HySKFRTyj?A8Y#Zqw~u_3C&ooKevi!Ra{94tmV5IUM14{m*^H%7A(9;Vmcd z|AV;1yv4=wl)1QOmB4kL&n5uCwVI(K zV?_pwj20O#GG1iB$cT|4BV$Gejf@%@HZpFj88|X>s~I{nc4Y9#=#k+g<3|F3L;wi^ z5(6X%NEDDTAaSsoKp>H@nouCIK!Slp0|^Hb485*H*eNMx)g zG)Qca;2_aK!h^&I2@nz?Bt%GzkRTyZLc)Z^2?-PuDXR$;5-TKFNVJe}A@M>2hC~br z84@!jXh_tMupx0n0*6En2^|tUs|g+wJtTZc{Ez@55kx|W#1IK05=A78NF0$sB9TNw ziNw-sf{8>E2`3UyB%nw{k&q%WMS_Y%)$?~uV`49Y({Ud9&VI$G`JZ62Y938u|8-yO k4>%Vx`&Vd9s>};{r3;I_#$11)H@`67o9mws1;x|;1RR|M*#H0l diff --git a/lib/pytz/zoneinfo/Australia/Sydney b/lib/pytz/zoneinfo/Australia/Sydney deleted file mode 100644 index d95c245e5ee1cb22a2b88fa63bee6736a4d0a8ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 zcmd6p|4-C)9LHZLFyzumb9_}o%>+ZZQ_;IZGZlmsLpi>dMt~@4dT^;&dA?E`wfVgt zWOg&e8UA2lw5B;0vD{c8u==4dq&fPfVQtheB~#P)4b#OXrHUx7F+KYYs?%W1>II@73_J z6D6V`Q6v8HXk^AMjr=Y_qoS{B)TcMqIozcWy&o@Qe)w6&25-p2=f9BXHCN=3rWP5u zpi{;-?3G88PRNAP8kz9V9*ObfO6-_-G;VUW#&y4`36301Xsy!3!4#d?n5~n#oSL*F zq>mkKm*ldbPS!r1vgkdTTKk(kK4qs&%j=bC!`EbbYMV^&za*(qhb6V`BbhN2kSCkI z*0gUA>db~Sn%-Wg8Kno*b)-<;tIKs(eWuQypQUqF#cJlHB%SLX(Yd!oJ&7^mx%`WI zTZi5}x5n!PxvIT6cb z>C_5c`ge=u{`#)ueZN

. - - Call withAttribute with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in (class="Customer",align="right"), or - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - To verify that the attribute exists, but without specifying a value, pass - withAttribute.ANY_VALUE as the value. - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def operatorPrecedence( baseExpr, opList ): - """Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; each tuple is of the form - (opExpr, numTerms, rightLeftAssoc, parseAction), where: - - opExpr is the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants opAssoc.RIGHT and opAssoc.LEFT. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted) - """ - ret = Forward() - lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward()#.setName("expr%d" % i) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - matchExpr.setParseAction( pa ) - thisExpr << ( matchExpr | lastExpr ) - lastExpr = thisExpr - ret << lastExpr - return ret - -dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes") -sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes") -quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()) - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default="("); can also be a pyparsing expression - - closer - closing character for a nested list (default=")"); can also be a pyparsing expression - - content - expression for items within the nested lists (default=None) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the ignoreExpr argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an Or or MatchFirst. - The default is quotedString, but if no expressions are to be ignored, - then pass None for this argument. - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=True) - - A valid block must contain at least one blockStatement. - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") - - def checkSubIndent(s,l,t): - curCol = col(l,s) - if curCol > indentStack[-1]: - indentStack.append( curCol ) - else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = Empty() + Empty().setParseAction(checkSubIndent) - PEER = Empty().setParseAction(checkPeerIndent) - UNDENT = Empty().setParseAction(checkUnindent) - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:")) -commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline() -_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "')) -replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment") - -htmlComment = Regex(r"") -restOfLine = Regex(r".*").leaveWhitespace() -dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment") -cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?" + str(tokenlist)) - print ("tokens = " + str(tokens)) - print ("tokens.columns = " + str(tokens.columns)) - print ("tokens.tables = " + str(tokens.tables)) - print (tokens.asXML("SQL",True)) - except ParseBaseException: - err = sys.exc_info()[1] - print (teststring + "->") - print (err.line) - print (" "*(err.column-1) + "^") - print (err) - print() - - selectToken = CaselessLiteral( "select" ) - fromToken = CaselessLiteral( "from" ) - - ident = Word( alphas, alphanums + "_$" ) - columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - columnNameList = Group( delimitedList( columnName ) )#.setName("columns") - tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - tableNameList = Group( delimitedList( tableName ) )#.setName("tables") - simpleSQL = ( selectToken + \ - ( '*' | columnNameList ).setResultsName( "columns" ) + \ - fromToken + \ - tableNameList.setResultsName( "tables" ) ) - - test( "SELECT * from XYZZY, ABC" ) - test( "select * from SYS.XYZZY" ) - test( "Select A from Sys.dual" ) - test( "Select AA,BB,CC from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Xelect A, B, C from Sys.dual" ) - test( "Select A, B, C frox Sys.dual" ) - test( "Select" ) - test( "Select ^^^ frox Sys.dual" ) - test( "Select A, B, C from Sys.dual, Table2 " ) diff --git a/lib/matplotlib/pyparsing_py3.py b/lib/matplotlib/pyparsing_py3.py deleted file mode 100644 index c0e0af2e98bd..000000000000 --- a/lib/matplotlib/pyparsing_py3.py +++ /dev/null @@ -1,3682 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2010 Paul T. McGuire -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -#from __future__ import generators - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form C{", !"}):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word( alphas ) + "," + Word( alphas ) + "!" - - hello = "Hello, World!" - print hello, "->", greet.parseString( hello ) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments -""" - -__version__ = "1.5.5" -__versionTime__ = "12 Aug 2010 03:56" -__author__ = "Paul McGuire " - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -import collections -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums', -'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', -] - -""" -Detect if we are running version 3.X and make appropriate changes -Robert A. Clark -""" -_PY3K = sys.version_info[0] > 2 -if _PY3K: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - alphas = string.ascii_lowercase + string.ascii_uppercase -else: - _MAX_INT = sys.maxint - range = xrange - set = lambda s : dict( [(c,0) for c in s] ) - alphas = string.lowercase + string.uppercase - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # The Python docs (http://docs.python.org/ref/customization.html#l2h-182) - # state that "The return value must be a string object". However, does a - # unicode object (being a subclass of basestring) count as a "string - # object"? - # If so, then return a unicode object: - return unicode(obj) - # Else encode it... but how? There are many choices... :) - # Replace unprintables with escape codes? - #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors') - # Replace unprintables with question marks? - #return unicode(obj).encode(sys.getdefaultencoding(), 'replace') - # ... - - -# build list of single arg builtins, tolerant of Python version, that can be used as parse actions -singleArgBuiltins = [] -import builtins -for fname in "sum len enumerate sorted reversed list tuple set any all".split(): - try: - singleArgBuiltins.append(getattr(builtins,fname)) - except AttributeError: - continue - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - for from_,to_ in zip('&><"\'', "amp gt lt quot apos".split()): - data = data.replace(from_, '&'+to_+';') - return data - -class _Constants(object): - pass - -nums = string.digits -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join( [ c for c in string.printable if c not in string.whitespace ] ) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join( [line_str[:line_column], - markerString, line_str[line_column:]]) - return line_str.strip() - def __dir__(self): - return "loc msg pstr parserElement lineno col line " \ - "markInputLine __str__ __repr__".split() - -class ParseException(ParseBaseException): - """exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like C{ParseFatalException}, but thrown internally when an - C{ErrorStop} ('-' operator) indicates that parsing is to stop immediately because - an unbacktrackable syntax error has been found""" - def __init__(self, pe): - super(ParseSyntaxException, self).__init__( - pe.pstr, pe.loc, pe.msg, pe.parserElement) - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by C{validate()} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.}) - """ - #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" ) - def __new__(cls, toklist, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist, name=None, asList=True, modal=True ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - if isinstance(toklist, list): - self.__toklist = toklist[:] - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not toklist in (None,'',[]): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,int): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return len( self.__toklist ) > 0 - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( reversed(self.__toklist) ) - def keys( self ): - """Returns all named result keys.""" - return self.__tokdict.keys() - - def pop( self, index=-1 ): - """Removes and returns item at specified index (default=last). - Will work with either numeric indices or dict-key indicies.""" - ret = self[index] - del self[index] - return ret - - def get(self, key, defaultValue=None): - """Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified.""" - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """Inserts new element at location index in the list of parsed tokens.""" - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def items( self ): - """Returns all named result keys and values as a list of tuples.""" - return [(k,self[k]) for k in self.__tokdict] - - def values( self ): - """Returns all named result values.""" - return [ v[-1][0] for v in self.__tokdict.values() ] - - def __getattr__( self, name ): - if True: #name not in self.__slots__: - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - return None - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = ( lambda a: (a<0 and offset) or (a+offset) ) - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - return self.copy() - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - out = "[" - sep = "" - for i in self.__toklist: - if isinstance(i, ParseResults): - out += sep + _ustr(i) - else: - out += sep + repr(i) - sep = ", " - out += "]" - return out - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """Returns the parse results as a nested list of matching tokens, all converted to strings.""" - out = [] - for res in self.__toklist: - if isinstance(res,ParseResults): - out.append( res.asList() ) - else: - out.append( res ) - return out - - def asDict( self ): - """Returns the named parse results as dictionary.""" - return dict( self.items() ) - - def copy( self ): - """Returns a new copy of a C{ParseResults} object.""" - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.""" - nl = "\n" - out = [] - namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist ] ) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - worklist = self.__toklist - for i,res in enumerate(worklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - """Returns the results name for this token expression.""" - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - self.__tokdict.values()[0][0][1] in (0,-1)): - return self.__tokdict.keys()[0] - else: - return None - - def dump(self,indent='',depth=0): - """Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data.""" - out = [] - out.append( indent+_ustr(self.asList()) ) - keys = self.items() - keys.sort() - for k,v in keys: - if out: - out.append('\n') - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v.keys(): - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(_ustr(v)) - return "".join(out) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - self.__tokdict, \ - par, \ - inAccumNames, \ - self.__name = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __dir__(self): - return dir(super(ParseResults,self)) + self.keys() - -collections.MutableMapping.register(ParseResults) - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return (loc} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - def setDefaultWhitespaceChars( chars ): - """Overrides the default whitespace chars - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars) - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element.""" - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """Define name for this expression, for use in debugging.""" - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - """ - newself = self.copy() - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def _normalizeParseActionArgs( f ): - """Internal method used to decorate parse actions that take fewer than 3 arguments, - so that all parse actions can be called as C{f(s,l,t)}.""" - STAR_ARGS = 4 - - # special handling for single-argument builtins - if (f in singleArgBuiltins): - numargs = 1 - else: - try: - restore = None - if isinstance(f,type): - restore = f - f = f.__init__ - if not _PY3K: - codeObj = f.func_code - else: - codeObj = f.code - if codeObj.co_flags & STAR_ARGS: - return f - numargs = codeObj.co_argcount - if not _PY3K: - if hasattr(f,"im_self"): - numargs -= 1 - else: - if hasattr(f,"__self__"): - numargs -= 1 - if restore: - f = restore - except AttributeError: - try: - if not _PY3K: - call_im_func_code = f.__call__.im_func.func_code - else: - call_im_func_code = f.__code__ - - # not a function, must be a callable object, get info from the - # im_func binding of its bound __call__ method - if call_im_func_code.co_flags & STAR_ARGS: - return f - numargs = call_im_func_code.co_argcount - if not _PY3K: - if hasattr(f.__call__,"im_self"): - numargs -= 1 - else: - if hasattr(f.__call__,"__self__"): - numargs -= 0 - except AttributeError: - if not _PY3K: - call_func_code = f.__call__.func_code - else: - call_func_code = f.__call__.__code__ - # not a bound method, get info directly from __call__ method - if call_func_code.co_flags & STAR_ARGS: - return f - numargs = call_func_code.co_argcount - if not _PY3K: - if hasattr(f.__call__,"im_self"): - numargs -= 1 - else: - if hasattr(f.__call__,"__self__"): - numargs -= 1 - - - # print ("adding function %s with %d args" % (f.func_name,numargs)) - if numargs == 3: - return f - else: - if numargs > 3: - def tmp(s,l,t): - return f(s,l,t) - elif numargs == 2: - def tmp(s,l,t): - return f(l,t) - elif numargs == 1: - def tmp(s,l,t): - return f(t) - else: #~ numargs == 0: - def tmp(s,l,t): - return f() - try: - tmp.__name__ = f.__name__ - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - try: - tmp.__doc__ = f.__doc__ - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - try: - tmp.__dict__.update(f.__dict__) - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - return tmp - _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs) - - def setParseAction( self, *fns, **kwargs ): - """Define action to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a ParseResults object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - self.parseAction = list(map(self._normalizeParseActionArgs, list(fns))) - self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def addParseAction( self, *fns, **kwargs ): - """Add parse action to expression's list of parse actions. See L{I{setParseAction}}.""" - self.parseAction += list(map(self._normalizeParseActionArgs, list(fns))) - self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{ParseFatalException} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException as err: - #~ print ("Exception raised:", err) - if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or loc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - lookup = (self,instring,loc,callPreParse,doActions) - if lookup in ParserElement._exprArgCache: - value = ParserElement._exprArgCache[ lookup ] - if isinstance(value, Exception): - raise value - return value - else: - try: - value = self._parseNoCache( instring, loc, doActions, callPreParse ) - ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy()) - return value - except ParseBaseException as err: - err.__traceback__ = None - ParserElement._exprArgCache[ lookup ] = err - raise - - _parse = _parseNoCache - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - _exprArgCache = {} - def resetCache(): - ParserElement._exprArgCache.clear() - resetCache = staticmethod(resetCache) - - _packratEnabled = False - def enablePackrat(): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - ParserElement._parse = ParserElement._parseCache - enablePackrat = staticmethod(enablePackrat) - - def parseString( self, instring, parseAll=False ): - """Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{StringEnd()}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - #loc = self.preParse( instring, loc ) - se = StringEnd() - se._parse( instring, loc ) - except ParseBaseException as err: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise err - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT ): - """Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}} for more information on parsing - strings with embedded tabs.""" - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException as err: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise err - - def transformString( self, instring ): - """Extension to C{scanString}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string.""" - out = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - return "".join(map(_ustr,out)) - except ParseBaseException as err: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise err - - def searchString( self, instring, maxMatches=_MAX_INT ): - """Another extension to C{scanString}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException as err: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise err - - def __add__(self, other ): - """Implementation of + operator - returns And""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """Implementation of + operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """Implementation of - operator, returns C{And} with error stop""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, And._ErrorStop(), other ] ) - - def __rsub__(self, other ): - """Implementation of - operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + ZeroOrMore(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{ZeroOrMore(expr)} - - C{expr*(1,None)} is equivalent to C{OneOrMore(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """Implementation of | operator - returns C{MatchFirst}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """Implementation of | operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """Implementation of ^ operator - returns C{Or}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """Implementation of ^ operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """Implementation of & operator - returns C{Each}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """Implementation of & operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """Implementation of ~ operator - returns C{NotAny}""" - return NotAny( self ) - - def __call__(self, name): - """Shortcut for C{setResultsName}, with C{listAllMatches=default}:: - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - could be written as:: - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - """ - return self.setResultsName(name) - - def suppress( self ): - """Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """Overrides default behavior to expand s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match characters.""" - self.keepTabs = True - return self - - def ignore( self, other ): - """Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - """ - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append( other.copy() ) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """Enable display of debugging messages while doing pattern matching.""" - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable.""" - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """Check defined expressions for valid structure, check for infinite recursive definitions.""" - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - f = open(file_or_filename, "rb") - file_contents = f.read() - f.close() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException as err: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise err - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or self.__dict__ == other.__dict__ - elif isinstance(other, basestring): - try: - self.parseString(_ustr(other), parseAll=True) - return True - except ParseBaseException: - return False - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - -class Token(ParserElement): - """Abstract C{ParserElement} subclass, for defining atomic matching patterns.""" - def __init__( self ): - super(Token,self).__init__( savelist=False ) - #self.myException = ParseException("",0,"",self) - - def setName(self, name): - s = super(Token,self).setName(name) - self.errmsg = "Expected " + self.name - #s.myException.msg = self.errmsg - return s - - -class Empty(Token): - """An empty token, will always match.""" - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """A token that will never match.""" - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """Token to exactly match a specified string.""" - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - raise ParseException( instring, loc, self.errmsg, self ) -_L = Literal - -class Keyword(Token): - """Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{Literal}:: - Literal("if") will match the leading 'if' in 'ifAndOnlyIf'. - Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)' - Accepts two optional constructor arguments in addition to the keyword string: - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive - matching, default is False. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ): - super(Keyword,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException( instring, loc, self.errmsg, self ) - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - setDefaultKeywordChars = staticmethod(setDefaultKeywordChars) - -class CaselessLiteral(Literal): - """Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - raise ParseException( instring, loc, self.errmsg, self ) - -class CaselessKeyword(Keyword): - def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException( instring, loc, self.errmsg, self ) - -class Word(Token): - """Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ): - super(Word,self).__init__() - self.initCharsOrig = initChars - self.initChars = set(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.bodyCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc,result.group() - - if not(instring[ loc ] in self.initChars): - raise ParseException( instring, loc, self.errmsg, self ) - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - """Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if len(pattern) == 0: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - """Token for matching strings that are delimited by quoting characters. - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None): - """ - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=None) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None) - - multiline - boolean indicating whether quotes can span multiple lines (default=False) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar) - """ - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if len(quoteChar) == 0: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if len(endQuoteChar) == 0: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern,"\g<1>",ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """Token for matching words composed of characters *not* in a given set. - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - #self.myException.msg = self.errmsg - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - raise ParseException( instring, loc, self.errmsg, self ) - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - raise ParseException( instring, loc, self.errmsg, self ) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{Word} class.""" - whiteStrs = { - " " : "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) ) - #~ self.leaveWhitespace() - self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite])) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - raise ParseException( instring, loc, self.errmsg, self ) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException( instring, loc, self.errmsg, self ) - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """Token to advance to a specific column of input text; useful for tabular report scraping.""" - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - -class LineStart(_PositionToken): - """Matches if current position is at the beginning of a line within the parse string""" - def __init__( self ): - super(LineStart,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected start of line" - #self.myException.msg = self.errmsg - - def preParse( self, instring, loc ): - preloc = super(LineStart,self).preParse(instring,loc) - if instring[preloc] == "\n": - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - if not( loc==0 or - (loc == self.preParse( instring, 0 )) or - (instring[loc-1] == "\n") ): #col(loc, instring) != 1: - raise ParseException( instring, loc, self.errmsg, self ) - return loc, [] - -class LineEnd(_PositionToken): - """Matches if current position is at the end of a line within the parse string""" - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): - return loc, [] - else: - raise ParseException( instring, loc, self.errmsg, self ) - -class WordStart(_PositionToken): - """Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of wordChars - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - raise ParseException( instring, loc, self.errmsg, self ) - return loc, [] - -class WordEnd(_PositionToken): - """Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of wordChars - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - if loc2 > maxMatchLoc: - maxMatchLoc = loc2 - maxMatchExp = e - - if maxMatchLoc < 0: - if maxException is not None: - maxException.__traceback__ = None - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - return maxMatchExp._parse( instring, loc, doActions ) - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the '|' operator. - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if exprs: - self.mayReturnEmpty = False - for e in self.exprs: - if e.mayReturnEmpty: - self.mayReturnEmpty = True - break - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - maxException.__traceback__ = None - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """Requires all given C{ParseExpressions} to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the '&' operator. - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = True - for e in self.exprs: - if not e.mayReturnEmpty: - self.mayReturnEmpty = False - break - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(e) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join( [ _ustr(e) for e in tmpReqd ] ) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += list(e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt) - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = ParseResults([]) - for r in resultlist: - dups = {} - for k in r.keys(): - if k in finalResults.keys(): - tmp = ParseResults(finalResults[k]) - tmp += ParseResults(r[k]) - dups[k] = tmp - finalResults += ParseResults(r) - for k,v in dups.items(): - finalResults[k] = v - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.""" - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - expr = Literal(expr) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """Lookahead matching of the given parse expression. C{FollowedBy} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list.""" - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """Lookahead to disallow matching with the given parse expression. C{NotAny} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression does *not* match at the current - position. Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator.""" - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - try: - self.expr.tryParse( instring, loc ) - except (ParseException,IndexError): - pass - else: - raise ParseException( instring, loc, self.errmsg, self ) - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - - -class ZeroOrMore(ParseElementEnhance): - """Optional repetition of zero or more of the given expression.""" - def __init__( self, expr ): - super(ZeroOrMore,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - tokens = [] - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - - -class OneOrMore(ParseElementEnhance): - """Repetition of one or more of the given expression.""" - def parseImpl( self, instring, loc, doActions=True ): - # must be at least one - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(OneOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """Optional matching of the given expression. - A default return string can also be specified, if the optional expression - is not found. - """ - def __init__( self, exprs, default=_optionalNotMatched ): - super(Optional,self).__init__( exprs, savelist=False ) - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - - -class SkipTo(ParseElementEnhance): - """Token for skipping over all undefined text until the matched expression is found. - If C{include} is set to true, the matched expression is also parsed (the skipped text - and matched expression are returned as a 2-element list). The C{ignore} - argument is used to define grammars (typically quoted strings and comments) that - might contain false matches. - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if failOn is not None and isinstance(failOn, basestring): - self.failOn = Literal(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - startLoc = loc - instrlen = len(instring) - expr = self.expr - failParse = False - while loc <= instrlen: - try: - if self.failOn: - try: - self.failOn.tryParse(instring, loc) - except ParseBaseException: - pass - else: - failParse = True - raise ParseException(instring, loc, "Found expression " + str(self.failOn)) - failParse = False - if self.ignoreExpr is not None: - while 1: - try: - loc = self.ignoreExpr.tryParse(instring,loc) - # print("found ignoreExpr, advance to", loc) - except ParseBaseException: - break - expr._parse( instring, loc, doActions=False, callPreParse=False ) - skipText = instring[startLoc:loc] - if self.includeMatch: - loc,mat = expr._parse(instring,loc,doActions,callPreParse=False) - if mat: - skipRes = ParseResults( skipText ) - skipRes += mat - return loc, [ skipRes ] - else: - return loc, [ skipText ] - else: - return loc, [ skipText ] - except (ParseException,IndexError): - if failParse: - raise - else: - loc += 1 - raise ParseException( instring, loc, self.errmsg, self ) - -class Forward(ParseElementEnhance): - """Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = Literal(other) - self.expr = other - self.mayReturnEmpty = other.mayReturnEmpty - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return None - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret << self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """Abstract subclass of ParseExpression, for converting parsed results.""" - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Upcase(TokenConverter): - """Converter to upper case all matching tokens.""" - def __init__(self, *args): - super(Upcase,self).__init__(*args) - warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead", - DeprecationWarning,stacklevel=2) - - def postParse( self, instring, loc, tokenlist ): - return list(map( string.upper, tokenlist )) - - -class Combine(TokenConverter): - """Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and len(retToks.keys())>0: - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions.""" - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - """ - def __init__( self, exprs ): - super(Dict,self).__init__( exprs ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """Converter for ignoring the results of a parsed expression.""" - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """Wrapper for parse actions, to ensure they are only called once.""" - def __init__(self, methodCall): - self.callable = ParserElement._normalizeParseActionArgs(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """Decorator for debugging parse actions.""" - f = ParserElement._normalizeParseActionArgs(f) - def z(*paArgs): - thisFunc = f.func_name - s,l,t = paArgs[-3:] - if len(paArgs)>3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write( "<", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) ) - else: - return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) ) - except: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst( [ parseElementClass(sym) for sym in symbols ] ) - -def dictOf( key, value ): - """Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{Dict}, C{ZeroOrMore}, and C{Group} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. Simpler to use than the parse action C{keepOriginalText}, and does not - require the inspect module to chase up the call stack. By default, returns a - string containing the original parsed text. - - If the optional C{asString} argument is passed as False, then the return value is a - C{ParseResults} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{originalTextFor} contains expressions with defined - results names, you must set C{asString} to False if you want to preserve those - results name values.""" - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - del t[:] - t.insert(0, s[t._original_start:t._original_end]) - del t["_original_start"] - del t["_original_end"] - matchExpr.setParseAction(extractText) - return matchExpr - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ]) -_escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16))) -_escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p) - -def srange(s): - r"""Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be:: - a single character - an escaped character with a leading backslash (such as \- or \]) - an escaped hex character with a leading '\0x' (\0x21, which is a '!' character) - an escaped octal character with a leading '\0' (\041, which is a '!' character) - a range of any of the above, separated by a dash ('a-z', etc.) - any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.) - """ - try: - return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body]) - except: - return "" - -def matchOnlyAtCol(n): - """Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{transformString()}. - """ - def _replFunc(*args): - return [replStr] - return _replFunc - -def removeQuotes(s,l,t): - """Helper parse action for removing quotation marks from parsed quoted strings. - To use, add this parse action to quoted string using:: - quotedString.setParseAction( removeQuotes ) - """ - return t[0][1:-1] - -def upcaseTokens(s,l,t): - """Helper parse action to convert tokens to upper case.""" - return [ tt.upper() for tt in map(_ustr,t) ] - -def downcaseTokens(s,l,t): - """Helper parse action to convert tokens to lower case.""" - return [ tt.lower() for tt in map(_ustr,t) ] - -def keepOriginalText(s,startLoc,t): - """DEPRECATED - use new helper method C{originalTextFor}. - Helper parse action to preserve original parsed text, - overriding any nested parse actions.""" - try: - endloc = getTokensEndLoc() - except ParseException: - raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action") - del t[:] - t += ParseResults(s[startLoc:endloc]) - return t - -def getTokensEndLoc(): - """Method to be called from within a parse action to determine the end - location of the parsed tokens.""" - import inspect - fstack = inspect.stack() - try: - # search up the stack (through intervening argument normalizers) for correct calling routine - for f in fstack[2:]: - if f[3] == "_parseNoCache": - endloc = f[0].f_locals["loc"] - return endloc - else: - raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action") - finally: - del fstack - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] ) - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % tagStr) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """Helper to construct opening and closing tag expressions for HTML, given a tag name""" - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """Helper to construct opening and closing tag expressions for XML, given a tag name""" - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """Helper to create a validating parse action to be used with start tags created - with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - or
. - - Call withAttribute with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in (class="Customer",align="right"), or - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - To verify that the attribute exists, but without specifying a value, pass - withAttribute.ANY_VALUE as the value. - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def operatorPrecedence( baseExpr, opList ): - """Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; each tuple is of the form - (opExpr, numTerms, rightLeftAssoc, parseAction), where: - - opExpr is the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants opAssoc.RIGHT and opAssoc.LEFT. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted) - """ - ret = Forward() - lastExpr = baseExpr | ( Suppress('(') + ret + Suppress(')') ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward()#.setName("expr%d" % i) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - matchExpr.setParseAction( pa ) - thisExpr << ( matchExpr | lastExpr ) - lastExpr = thisExpr - ret << lastExpr - return ret - -dblQuotedString = Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*"').setName("string enclosed in double quotes") -sglQuotedString = Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*'").setName("string enclosed in single quotes") -quotedString = Regex(r'''(?:"(?:[^"\n\r\\]|(?:"")|(?:\\x[0-9a-fA-F]+)|(?:\\.))*")|(?:'(?:[^'\n\r\\]|(?:'')|(?:\\x[0-9a-fA-F]+)|(?:\\.))*')''').setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()) - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default="("); can also be a pyparsing expression - - closer - closing character for a nested list (default=")"); can also be a pyparsing expression - - content - expression for items within the nested lists (default=None) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=quotedString) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the ignoreExpr argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an Or or MatchFirst. - The default is quotedString, but if no expressions are to be ignored, - then pass None for this argument. - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret << Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret << Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=True) - - A valid block must contain at least one blockStatement. - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") - - def checkSubIndent(s,l,t): - curCol = col(l,s) - if curCol > indentStack[-1]: - indentStack.append( curCol ) - else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = Empty() + Empty().setParseAction(checkSubIndent) - PEER = Empty().setParseAction(checkPeerIndent) - UNDENT = Empty().setParseAction(checkUnindent) - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:")) -commonHTMLEntity = Combine(_L("&") + oneOf("gt lt amp nbsp quot").setResultsName("entity") +";").streamline() -_htmlEntityMap = dict(zip("gt lt amp nbsp quot".split(),'><& "')) -replaceHTMLEntity = lambda t : t.entity in _htmlEntityMap and _htmlEntityMap[t.entity] or None - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Regex(r"/\*(?:[^*]*\*+)+?/").setName("C style comment") - -htmlComment = Regex(r"") -restOfLine = Regex(r".*").leaveWhitespace() -dblSlashComment = Regex(r"\/\/(\\\n|.)*").setName("// comment") -cppStyleComment = Regex(r"/(?:\*(?:[^*]*\*+)+?/|/[^\n]*(?:\n[^\n]*)*?(?:(?" + str(tokenlist)) - print ("tokens = " + str(tokens)) - print ("tokens.columns = " + str(tokens.columns)) - print ("tokens.tables = " + str(tokens.tables)) - print (tokens.asXML("SQL",True)) - except ParseBaseException as err: - print (teststring + "->") - print (err.line) - print (" "*(err.column-1) + "^") - print (err) - print() - - selectToken = CaselessLiteral( "select" ) - fromToken = CaselessLiteral( "from" ) - - ident = Word( alphas, alphanums + "_$" ) - columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - columnNameList = Group( delimitedList( columnName ) )#.setName("columns") - tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens ) - tableNameList = Group( delimitedList( tableName ) )#.setName("tables") - simpleSQL = ( selectToken + \ - ( '*' | columnNameList ).setResultsName( "columns" ) + \ - fromToken + \ - tableNameList.setResultsName( "tables" ) ) - - test( "SELECT * from XYZZY, ABC" ) - test( "select * from SYS.XYZZY" ) - test( "Select A from Sys.dual" ) - test( "Select AA,BB,CC from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Select A, B, C from Sys.dual" ) - test( "Xelect A, B, C from Sys.dual" ) - test( "Select A, B, C frox Sys.dual" ) - test( "Select" ) - test( "Select ^^^ frox Sys.dual" ) - test( "Select A, B, C from Sys.dual, Table2 " ) diff --git a/setup.py b/setup.py index ac07dcb96369..21c9b571bc18 100644 --- a/setup.py +++ b/setup.py @@ -203,6 +203,9 @@ package_data=package_data, classifiers=classifiers, + # List third-party Python packages that we require + install_requires=['dateutils', 'pyparsing'], + # Automatically 2to3 source on Python 3.x use_2to3=True, diff --git a/setupext.py b/setupext.py index 8414d6f2c0a1..42d878ffa6c1 100644 --- a/setupext.py +++ b/setupext.py @@ -618,7 +618,7 @@ def check(self): except CheckFailed as e: self.__class__.found_external = False return str(e) + ' Using local copy.' - finally: + else: self.__class__.found_external = True def add_flags(self, ext): @@ -723,13 +723,14 @@ def check(self): def get_extension(self): sources = [ - 'src/_png.cpp' + 'src/_png.cpp', 'src/mplutils.cpp' ] ext = make_extension('matplotlib._png', sources) pkg_config.setup_extension( ext, 'libpng', default_libraries=['png', 'z']) Numpy().add_flags(ext) CXX().add_flags(ext) + return ext class TTConv(SetupPackage): From bae085994d9f7db2032eaa96eff1675e2222a643 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 9 Oct 2012 15:10:57 -0400 Subject: [PATCH 04/24] More fixes --- setup.py | 2 +- setupext.py | 206 ++++++++++++++++++---------------------------------- 2 files changed, 73 insertions(+), 135 deletions(-) diff --git a/setup.py b/setup.py index 21c9b571bc18..2b109f5c3de8 100644 --- a/setup.py +++ b/setup.py @@ -148,7 +148,7 @@ data = package.get_package_data() for key, val in data.items(): package_data.setdefault(key, []) - package_data[key].extend(val) + package_data[key] = list(set(val + package_data[key])) # Write the default matplotlibrc file if default_backend is None: diff --git a/setupext.py b/setupext.py index 42d878ffa6c1..4fefc6ade204 100644 --- a/setupext.py +++ b/setupext.py @@ -24,7 +24,47 @@ import configparser +# matplotlib build options, which can be altered using setup.cfg +options = { + 'display_status': True, + 'verbose': False, + 'backend': None, + 'basedirlist': None + } + + +setup_cfg = os.environ.get('MPLSETUPCFG', 'setup.cfg') +if os.path.exists(setup_cfg): + config = configparser.SafeConfigParser() + config.read(setup_cfg) + + try: + options['display_status'] = not config.getboolean("status", "suppress") + except: + pass + + try: + options['verbose'] = not config.getboolean("status", "verbose") + except: + pass + + try: + options['backend'] = config.get("rc_options", "backend") + except: + pass + + try: + options['basedirlist'] = config.get("directories", "basedirlist") + except: + pass +else: + config = None + + def get_win32_compiler(): + """ + Determine the compiler being used on win32. + """ # Used to determine mingw32 or msvc # This is pretty bad logic, someone know a better way? for v in sys.argv: @@ -107,42 +147,7 @@ def is_min_version(found, minversion): return found_version >= expected_version -# matplotlib build options, which can be altered using setup.cfg -options = { - 'display_status': True, - 'verbose': False, - 'backend': None, - 'basedirlist': None - } - -setup_cfg = os.environ.get('MPLSETUPCFG', 'setup.cfg') -if os.path.exists(setup_cfg): - config = configparser.SafeConfigParser() - config.read(setup_cfg) - - try: - options['display_status'] = not config.getboolean("status", "suppress") - except: - pass - - try: - options['verbose'] = not config.getboolean("status", "verbose") - except: - pass - - try: - options['backend'] = config.get("rc_options", "backend") - except: - pass - - try: - options['basedirlist'] = config.get("directories", "basedirlist") - except: - pass -else: - config = None - - +# Define the display functions only if display_status is True. if options['display_status']: def print_line(char='='): print(char * 76) @@ -189,7 +194,7 @@ def make_extension(name, files, *args, **kwargs): `name` is the name of the extension. - `files` is a list of source files + `files` is a list of source files. Any additional arguments are passed to the `distutils.core.Extension` constructor. @@ -213,6 +218,9 @@ class PkgConfig(object): This is a class for communicating with pkg-config. """ def __init__(self): + """ + Determines whether pkg-config exists on this machine. + """ if sys.platform == 'win32': self.has_pkgconfig = False else: @@ -236,6 +244,9 @@ def set_pkgconfig_path(self): def setup_extension(self, ext, package, default_include_dirs=[], default_library_dirs=[], default_libraries=[]): + """ + Add parameters to the given `ext` for the given `package`. + """ flag_map = { '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} command = "pkg-config --libs --cflags {0}".format(package) @@ -271,6 +282,9 @@ def setup_extension(self, ext, package, default_include_dirs=[], return False def get_version(self, package): + """ + Get the version of the package from pkg-config. + """ if not self.has_pkgconfig: return None @@ -437,9 +451,6 @@ def check(self): class Matplotlib(SetupPackage): - """ - This package handles the base requirements of matplotlib. - """ name = "matplotlib" def check(self): @@ -472,15 +483,13 @@ def get_package_data(self): 'mpl-data/fonts/ttf/COPYRIGHT.TXT', 'mpl-data/fonts/ttf/README.TXT', 'mpl-data/fonts/ttf/RELEASENOTES.TXT', - 'mpl-data/images/*.xpm', # TODO: Only with GUIs + 'mpl-data/images/*.xpm', 'mpl-data/images/*.svg', 'mpl-data/images/*.gif', 'mpl-data/images/*.png', 'mpl-data/images/*.ppm', 'mpl-data/example/*.npy', 'mpl-data/matplotlibrc', - 'mpl-data/*.glade', # TODO: Only with gtk backend - 'backends/Matplotlib.nib/*', # TODO: Only with macosx backend 'backends/web_backend/*.*', 'backends/web_backend/jquery/js/*', 'backends/web_backend/jquery/css/themes/base/*.*', @@ -506,10 +515,6 @@ def get_package_data(self): class Toolkits(OptionalPackage): - """ - This package handles the optional toolkits that ship with - matplotlib. - """ name = "toolkits" def get_packages(self): @@ -523,9 +528,6 @@ def get_packages(self): class Tests(OptionalPackage): - """ - This package contains the regression tests and data. - """ name = "tests" def check(self): @@ -565,10 +567,6 @@ def get_package_data(self): class Numpy(SetupPackage): - """ - Checks for the existence of Numpy. - """ - name = "numpy" def check(self): @@ -603,14 +601,8 @@ def add_flags(self, ext): class CXX(SetupPackage): - """ - This package handles PyCXX. - """ name = 'pycxx' - # TODO: Investigate what patches need to be added to PyCXX to get - # a minimum version - def check(self): try: return self._check_for_pkg_config( @@ -664,9 +656,6 @@ def add_flags(self, ext): class FreeType(SetupPackage): - """ - Handles the Freetype dependency. - """ name = "freetype" def check(self): @@ -692,9 +681,6 @@ def add_flags(self, ext): class FT2Font(SetupPackage): - """ - Handles the ft2font extension. - """ name = 'ft2font' def get_extension(self): @@ -710,16 +696,12 @@ def get_extension(self): class Png(SetupPackage): - """ - Handles the png extension. - """ name = "png" def check(self): return self._check_for_pkg_config( 'libpng', 'png.h', - # TODO: Determine minimum version - min_version='1.4') + min_version='1.2') def get_extension(self): sources = [ @@ -734,9 +716,6 @@ def get_extension(self): class TTConv(SetupPackage): - """ - Builds the ttconv extension. - """ name = "ttconv" def get_extension(self): @@ -753,9 +732,6 @@ def get_extension(self): class Path(SetupPackage): - """ - Builds the Path extension. - """ name = "path" def get_extension(self): @@ -773,9 +749,6 @@ def get_extension(self): class Image(SetupPackage): - """ - Builds the Image extension. - """ name = "image" def get_extension(self): @@ -790,9 +763,6 @@ def get_extension(self): class Contour(SetupPackage): - """ - Builds the contour extension. - """ name = "contour" def get_extension(self): @@ -805,9 +775,6 @@ def get_extension(self): class Delaunay(SetupPackage): - """ - Builds the delaunay extension. - """ name = "delaunay" def get_packages(self): @@ -823,9 +790,6 @@ def get_extension(self): class Tri(SetupPackage): - """ - Builds the tri extension. - """ name = "tri" def get_extension(self): @@ -840,9 +804,6 @@ def get_extension(self): class BackendAgg(OptionalBackendPackage): - """ - Builds the Agg backend. - """ name = "agg" force = False @@ -1161,9 +1122,6 @@ def add_flags(self, ext): class BackendGtk(OptionalBackendPackage): - """ - Handles the Gtk (regular Gdk) backend. - """ name = "gtk" def check(self): @@ -1196,6 +1154,9 @@ def check(self): ".".join(str(x) for x in gtk.gtk_version), ".".join(str(x) for x in gtk.pygtk_version)) + def get_package_data(self): + return {'matplotlib': ['mpl-data/*.glade']} + def get_extension(self): sources = [ 'src/_backend_gdk.c' @@ -1267,9 +1228,6 @@ def getoutput(s): class BackendGtkAgg(BackendGtk): - """ - Builds the GtkAgg extension. - """ name = "gtkagg" def check(self): @@ -1280,6 +1238,9 @@ def check(self): else: BackendAgg.force = True + def get_package_data(self): + return {'matplotlib': ['mpl-data/*.glade']} + def get_extension(self): sources = [ 'src/agg_py_transforms.cpp', @@ -1308,9 +1269,6 @@ def backend_gtk3agg_internal_check(x): class BackendGtk3Agg(OptionalBackendPackage): - """ - Builds the Gtk3Agg extension. - """ name = "gtk3agg" def check(self): @@ -1328,6 +1286,9 @@ def check(self): else: raise CheckFailed(msg) + def get_package_data(self): + return {'matplotlib': ['mpl-data/*.glade']} + def backend_gtk3cairo_internal_check(x): try: @@ -1347,9 +1308,6 @@ def backend_gtk3cairo_internal_check(x): class BackendGtk3Cairo(OptionalBackendPackage): - """ - Builds the Gtk3Cairo extension. - """ name = "gtk3cairo" def check(self): @@ -1367,11 +1325,11 @@ def check(self): else: raise CheckFailed(msg) + def get_package_data(self): + return {'matplotlib': ['mpl-data/*.glade']} + class BackendWxAgg(OptionalBackendPackage): - """ - Builds the WxAgg extension. - """ name = "wxagg" def check(self): @@ -1410,9 +1368,6 @@ def check(self): class BackendMacOSX(OptionalBackendPackage): - """ - Builds the OSX backend - """ name = 'macosx' def check(self): @@ -1422,6 +1377,9 @@ def check(self): if sys.platform != 'darwin': raise CheckFailed("Mac OS-X only") + def get_package_data(self): + return {'matplotlib': ['backends/Matplotlib.nib/*']} + def get_extension(self): sources = [ 'src/_macosx.m', @@ -1463,9 +1421,6 @@ def get_extension(self): class BackendQt(OptionalBackendPackage): - """ - Provides information about the installed PyQt. - """ name = "qtagg" def convert_qt_version(self, version): @@ -1496,9 +1451,6 @@ def check(self): class BackendQt4(OptionalBackendPackage): - """ - Provides information about the installed PyQt4. - """ name = "qt4agg" def convert_qt_version(self, version): @@ -1525,9 +1477,6 @@ def check(self): class BackendPySide(OptionalBackendPackage): - """ - Provides information about the installed PySide. - """ name = "pyside" def check(self): @@ -1544,9 +1493,6 @@ def check(self): class BackendCairo(OptionalBackendPackage): - """ - Provides information about the installed pycairo. - """ name = "cairo" def check(self): @@ -1559,10 +1505,8 @@ def check(self): class DviPng(SetupPackage): - """ - A simple check for the presence of dvipng. - """ name = "dvipng" + optional = True def check(self): try: @@ -1573,10 +1517,8 @@ def check(self): class Ghostscript(SetupPackage): - """ - A simple check for the presence of Ghostscript. - """ name = "ghostscript" + optional = True def check(self): try: @@ -1591,10 +1533,8 @@ def check(self): class LaTeX(SetupPackage): - """ - A simple check for the presence of LaTeX. - """ name = "latex" + optional = True def check(self): try: @@ -1608,10 +1548,8 @@ def check(self): class PdfToPs(SetupPackage): - """ - A simple check for the presence of pdftops. - """ name = "pdftops" + optional = True def check(self): try: From 9b408cd008a4c7eb7b6a2c0ef454d111513f6f86 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 12:13:33 -0500 Subject: [PATCH 05/24] setupegg.py is now redundant. --- doc/faq/installing_faq.rst | 2 +- setupegg.py | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 setupegg.py diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index 6374d94875cd..ab2c90c7c92d 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -139,7 +139,7 @@ If you want to be able to follow the development branch as it changes just replace the last step with (make sure you have **setuptools** installed):: - > python setupegg.py develop + > python setup.py develop This creates links in the right places and installs the command line script to the appropriate places. diff --git a/setupegg.py b/setupegg.py deleted file mode 100644 index 7552ed3787b6..000000000000 --- a/setupegg.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Poor man's setuptools script... -""" - -import os -import sys -from setuptools import setup - -# Setupegg assumes the install tree and source tree are exactly the same. Since -# this is not the case, symlink the correct dateutil dir depending on which -# version of python is used -if not os.path.isdir('lib/dateutil'): - if sys.version_info[0] >= 3: - os.symlink('dateutil_py3', 'lib/dateutil') - else: - os.symlink('dateutil_py2', 'lib/dateutil') - -execfile('setup.py', - {'additional_params' : - {'namespace_packages' : ['mpl_toolkits'], - #'entry_points': {'nose.plugins': ['KnownFailure = matplotlib.testing.noseclasses:KnownFailure', ] } - }}) From 6f649713dfd5b1645726d0b56d1f7ed8b7ec8bc0 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 13:26:10 -0500 Subject: [PATCH 06/24] Fix type in dates docs --- lib/matplotlib/dates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index ccceb4699182..c22c08e730f8 100755 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -83,7 +83,7 @@ * :class:`RRuleLocator`: locate using a :class:`matplotlib.dates.rrulewrapper`. The :class:`rrulewrapper` is a simple wrapper around a - :class:`dateutils.rrule` (`dateutil + :class:`dateutil.rrule` (`dateutil `_) which allow almost arbitrary date tick specifications. See `rrule example <../examples/pylab_examples/date_demo_rrule.html>`_. From 088a267face3c366e663187f1647ab0c8e9a9653 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 13:26:26 -0500 Subject: [PATCH 07/24] Update INSTALL document to reflect new reality --- INSTALL | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/INSTALL b/INSTALL index fa03255b5844..e43b117ebd0a 100644 --- a/INSTALL +++ b/INSTALL @@ -196,6 +196,16 @@ libpng 1.2 (or later) user, you can ignore this since we build support into the matplotlib single click installer. +:term:`dateutil` 1.1 or later + Provides extensions to python datetime handling. If using pip, + easy_install or installing from source, the installer will attempt + to download and install `python_dateutil` from PyPI. + +:term:`pyparsing` + Required for matplotlib's mathtext math rendering support. If + using pip, easy_install or installing from source, the installer + will attempt to download and install `pyparsing` from PyPI. + **Optional** These are optional packages which you may want to install to use @@ -230,17 +240,8 @@ backends and the capabilities they provide. agg template source statically, so it will not affect anything on your system outside of matplotlib. -:term:`pytz` 2007g or later - timezone handling for python datetime objects. By default, - matplotlib will install pytz if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force or - prevent installation of pytz. - -:term:`dateutil` 1.1 or later - provides extensions to python datetime handling. By default, matplotlib - will install dateutil if it isn't already installed on your - system. To override the default, use :file:`setup.cfg` to force - or prevent installation of dateutil. +:term:`PyCXX` 6.2.4 + A library for writing Python extensions in C++. .. _build_osx: From 7018842f04932ab37f8b6409d05934df335d9c14 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 13:27:01 -0500 Subject: [PATCH 08/24] Handle dateutil and pyparsing in the same manner as everything else. --- setup.cfg.template | 64 +++++++++++++++++++--------------------------- setup.py | 21 ++++++++------- setupext.py | 54 +++++++++++++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 52 deletions(-) diff --git a/setup.cfg.template b/setup.cfg.template index 9de2b6980965..4b56914b29dc 100644 --- a/setup.cfg.template +++ b/setup.cfg.template @@ -11,33 +11,16 @@ [status] # To suppress display of the dependencies and their versions # at the top of the build log, uncomment the following line: -#suppress = True -# -# Uncomment to insert lots of diagnostic prints in extension code -#verbose = True +#suppress = False [packages] # There are a number of subpackages of matplotlib that are considered # optional. They are all installed by default, but they may be turned # off here. # -#tests = False -#sample_data = False -#toolkits = False - -[provide_packages] -# By default, matplotlib checks for a few dependencies and -# installs them if missing. This feature can be turned off -# by uncommenting the following lines. Acceptible values are: -# True: install, overwrite an existing installation -# False: do not install -# auto: install only if the package is unavailable. This -# is the default behavior -# -## Date/timezone support: -#pytz = False -#dateutil = False -#six = False +#tests = True +#sample_data = True +#toolkits = True [gui_support] # Matplotlib supports multiple GUI toolkits, including Cocoa, @@ -46,17 +29,24 @@ # which is provided by matplotlib and built by default. # # Some backends are written in pure Python, and others require -# extension code to be compiled. By default, matplotlib checks -# for these GUI toolkits during installation and, if present, -# compiles the required extensions to support the toolkit. GTK -# support requires the GTK runtime environment and PyGTK. Wx -# support requires wxWidgets and wxPython. Tk support requires -# Tk and Tkinter. The other GUI toolkits do not require any -# extension code, and can be used as long as the libraries are -# installed on your system. +# extension code to be compiled. By default, matplotlib checks for +# these GUI toolkits during installation and, if present, compiles the +# required extensions to support the toolkit. +# +# - GTK 2.x support of any kind requires the GTK runtime environment +# headers and PyGTK. +# - Tk support requires Tk development headers and Tkinter. +# - Mac OSX backend requires the Cocoa headers included with XCode. +# - Windowing is MS-Windows specific, and requires the "windows.h" +# header. +# +# The other GUI toolkits do not require any extension code, and can be +# used as long as the libraries are installed on your system -- +# therefore they are installed unconditionally. +# +# You can uncomment any the following lines to change this +# behavior. Acceptible values are: # -# You can uncomment any the following lines if you know you do -# not want to use the GUI toolkit. Acceptible values are: # True: build the extension. Exits with a warning if the # required dependencies are not available # False: do not build the extension @@ -64,11 +54,11 @@ # otherwise skip silently. This is the default # behavior # -#gtk = False -#gtkagg = False -#tkagg = False -#macosx = False -#windowing = False +#gtk = auto +#gtkagg = auto +#tkagg = auto +#macosx = auto +#windowing = auto [rc_options] # User-configurable options @@ -77,7 +67,7 @@ # FltkAgg, MacOSX, Pdf, Ps, QtAgg, Qt4Agg, SVG, TkAgg, WX, WXAgg. # # The Agg, Ps, Pdf and SVG backends do not require external -# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, TkAgg or WXAgg +# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, or TkAgg # if you have disabled the relevent extension modules. Agg will be used # by default. # diff --git a/setup.py b/setup.py index 2b109f5c3de8..f55d6fe39b93 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ __version__ = setupext.Matplotlib().check() -# These are the packages in the order we want to build them. This +# These are the packages in the order we want to display them. This # list may contain strings to create section headers for the display. mpl_packages = [ 'Building Matplotlib', @@ -47,6 +47,8 @@ setupext.Platform(), 'Required dependencies and extensions', setupext.Numpy(), + setupext.Dateutil(), + setupext.Pyparsing(), setupext.CXX(), setupext.LibAgg(), setupext.FreeType(), @@ -92,6 +94,7 @@ ext_modules = [] package_data = {} package_dir = {'': 'lib'} +install_requires = [] default_backend = None @@ -149,6 +152,7 @@ for key, val in data.items(): package_data.setdefault(key, []) package_data[key] = list(set(val + package_data[key])) + install_requires.extend(package.get_install_requires()) # Write the default matplotlibrc file if default_backend is None: @@ -204,7 +208,7 @@ classifiers=classifiers, # List third-party Python packages that we require - install_requires=['dateutils', 'pyparsing'], + install_requires=install_requires, # Automatically 2to3 source on Python 3.x use_2to3=True, @@ -214,11 +218,10 @@ # check for zip safety. zip_safe=False, - # This option is important -- it reverts to the standard - # distutils installation method. Otherwise, the behavior is to - # build an egg and install that, which unfortunately, makes - # building and importing much slower. - options={ - 'install': {'old_and_unmanageable': 'True'} - } + # Install our nose plugin so it will always be found + entry_points={ + 'nose.plugins.0.10': [ + 'KnownFailure = matplotlib.testing.noseclasses:KnownFailure' + ] + }, ) diff --git a/setupext.py b/setupext.py index 4fefc6ade204..4155828c92e8 100644 --- a/setupext.py +++ b/setupext.py @@ -43,11 +43,6 @@ except: pass - try: - options['verbose'] = not config.getboolean("status", "verbose") - except: - pass - try: options['backend'] = config.get("rc_options", "backend") except: @@ -249,7 +244,7 @@ def setup_extension(self, ext, package, default_include_dirs=[], """ flag_map = { '-I': 'include_dirs', '-L': 'library_dirs', '-l': 'libraries'} - command = "pkg-config --libs --cflags {0}".format(package) + command = "pkg-config --libs --cflags " + package use_defaults = True if self.has_pkgconfig: @@ -349,6 +344,14 @@ def get_extension(self): """ return None + def get_install_requires(self): + """ + Get a list of Python packages that we require. + pip/easy_install will attempt to download and install this + package if it is not installed. + """ + return [] + def _check_for_pkg_config(self, package, include_file, min_version=None, version=None): """ @@ -803,6 +806,42 @@ def get_extension(self): return ext +class Dateutil(SetupPackage): + name = "dateutil" + + def check(self): + try: + import dateutil + except ImportError: + return ( + "dateutil was not found. It is required for date axis " + "support. pip/easy_install may attempt to install it " + "after matplotlib.") + + return "using dateutil version %s" % dateutil.__version__ + + def get_install_requires(self): + return ['python_dateutil'] + + +class Pyparsing(SetupPackage): + name = "pyparsing" + + def check(self): + try: + import pyparsing + except ImportError: + return ( + "pyparsing was not found. It is required for mathtext " + "support. pip/easy_install may attempt to install it " + "after matplotlib.") + + return "using pyparsing version %s" % pyparsing.__version__ + + def get_install_requires(self): + return ['pyparsing'] + + class BackendAgg(OptionalBackendPackage): name = "agg" force = False @@ -874,6 +913,7 @@ def get_extension(self): ext = make_extension('matplotlib.backends._tkagg', sources) self.add_flags(ext) + Numpy().add_flags(ext) LibAgg().add_flags(ext) CXX().add_flags(ext) return ext @@ -1250,6 +1290,8 @@ def get_extension(self): ext = make_extension('matplotlib.backends._gtkagg', sources) self.add_flags(ext) LibAgg().add_flags(ext) + CXX().add_flags(ext) + Numpy().add_flags(ext) return ext From 49bd70a6f1c5fee44413356a767c0f975e767171 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 13:38:35 -0500 Subject: [PATCH 09/24] Raise exception early if pyparsing and/or dateutil are not installed. --- lib/matplotlib/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 3f91b6194a67..e7a7a5e5919e 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -99,10 +99,27 @@ """ from __future__ import print_function +import sys + __version__ = '1.3.x' __version__numpy__ = '1.4' # minimum required numpy version -import os, re, shutil, subprocess, sys, warnings +try: + import dateutil +except ImportError: + raise ImportError("matplotlib requires dateutil") + +try: + import pyparsing +except ImportError: + raise ImportError("matplotlib requires pyparsing") +else: + if sys.version_info[0] >= 3: + if [int(x) for x in pyparsing.__version__.split('.')] <= (1, 5, 6): + raise ImportError( + "matplotlib requires pyparsing > 1.5.6 on Python 3.x") + +import os, re, shutil, subprocess, warnings import distutils.sysconfig import distutils.version From 4d8c846439a40bd489fc947976086cf7b2ffaac4 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 6 Nov 2012 14:08:54 -0500 Subject: [PATCH 10/24] Fix pyparsing on python 3 check --- lib/matplotlib/__init__.py | 2 +- setupext.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index e7a7a5e5919e..3018250deaac 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -115,7 +115,7 @@ raise ImportError("matplotlib requires pyparsing") else: if sys.version_info[0] >= 3: - if [int(x) for x in pyparsing.__version__.split('.')] <= (1, 5, 6): + if [int(x) for x in pyparsing.__version__.split('.')] <= [1, 5, 6]: raise ImportError( "matplotlib requires pyparsing > 1.5.6 on Python 3.x") diff --git a/setupext.py b/setupext.py index 4155828c92e8..f9057ba674cc 100644 --- a/setupext.py +++ b/setupext.py @@ -836,6 +836,11 @@ def check(self): "support. pip/easy_install may attempt to install it " "after matplotlib.") + if sys.version_info[0] >= 3: + if [int(x) for x in pyparsing.__version__.split('.')] <= [1, 5, 6]: + return ( + "matplotlib requires pyparsing > 1.5.6 on Python 3.x") + return "using pyparsing version %s" % pyparsing.__version__ def get_install_requires(self): From 7db8fe22902e1247d9db380fe848f1f3f5ea4986 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 16 Nov 2012 09:17:42 -0500 Subject: [PATCH 11/24] Fix build on Python 2.6 --- setupext.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index f9057ba674cc..055030f89751 100644 --- a/setupext.py +++ b/setupext.py @@ -12,12 +12,39 @@ from textwrap import fill +try: + from subprocess import check_output +except ImportError: + # check_output is not available in Python 2.6 + def check_output(*popenargs, **kwargs): + """ + Run command with arguments and return its output as a byte + string. + + Backported from Python 2.7 as it's implemented as pure python + on stdlib. + """ + process = subprocess.Popen( + stdout=subprocess.PIPE, *popenargs, **kwargs) + output, unused_err = process.communicate() + retcode = process.poll() + if retcode: + cmd = kwargs.get("args") + if cmd is None: + cmd = popenargs[0] + error = subprocess.CalledProcessError(retcode, cmd) + error.output = output + raise error + return output + + if sys.platform != 'win32': if sys.version_info[0] < 3: from commands import getstatusoutput else: from subprocess import getstatusoutput + if sys.version_info[0] < 3: import ConfigParser as configparser else: @@ -249,7 +276,7 @@ def setup_extension(self, ext, package, default_include_dirs=[], use_defaults = True if self.has_pkgconfig: try: - output = subprocess.check_output(command, shell=True) + output = check_output(command, shell=True) except subprocess.CalledProcessError: pass else: From b81c917dfb13287d9268c54ee78824a2192c788e Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 16 Nov 2012 09:18:29 -0500 Subject: [PATCH 12/24] Update Travis dependencies --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1c71092cc888..99a71d1d1c1d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ python: - 3.2 install: - - pip install --use-mirrors nose + - pip install --use-mirrors nose python-dateutil pyparsing # This is a workaround to install numpy with the version of # virtualenv in Travis. If that is updated in the future, this can # be simplified to 'pip install numpy' From 4301543c3df4990a9200d60ca94697f81205e863 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 19 Nov 2012 14:15:45 -0500 Subject: [PATCH 13/24] Implement a better way to handle overflow in the Agg backend. --- agg24/include/agg_rasterizer_cells_aa.h | 9 ++- src/_backend_agg.cpp | 79 +++++++++++++++++++++---- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/agg24/include/agg_rasterizer_cells_aa.h b/agg24/include/agg_rasterizer_cells_aa.h index c8f2cb80d49d..2be0efeca175 100755 --- a/agg24/include/agg_rasterizer_cells_aa.h +++ b/agg24/include/agg_rasterizer_cells_aa.h @@ -29,8 +29,7 @@ #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED #define AGG_RASTERIZER_CELLS_AA_INCLUDED -#include "CXX/Exception.hxx" -#include +#include #include #include #include "agg_math.h" @@ -183,9 +182,9 @@ namespace agg { if((m_num_cells & cell_block_mask) == 0) { - if(m_num_blocks >= cell_block_limit) { - throw Py::OverflowError( - "Agg rendering complexity exceeded. Consider downsampling or decimating your data."); + if (m_num_blocks >= cell_block_limit) + { + throw std::overflow_error("Allocated too many blocks"); } allocate_block(); } diff --git a/src/_backend_agg.cpp b/src/_backend_agg.cpp index 69ce4417d56c..7ebc34843eb2 100644 --- a/src/_backend_agg.cpp +++ b/src/_backend_agg.cpp @@ -619,7 +619,11 @@ RendererAgg::render_clippath(const Py::Object& clippath, rendererBaseAlphaMask.clear(agg::gray8(0, 0)); transformed_path_t transformed_clippath(clippath_iter, trans); agg::conv_curve curved_clippath(transformed_clippath); - theRasterizer.add_path(curved_clippath); + try { + theRasterizer.add_path(curved_clippath); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } rendererAlphaMask.color(agg::gray8(255, 255)); agg::render_scanlines(theRasterizer, scanlineAlphaMask, rendererAlphaMask); lastclippath = clippath; @@ -698,7 +702,11 @@ RendererAgg::draw_markers(const Py::Tuple& args) unsigned fillSize = 0; if (face.first) { - theRasterizer.add_path(marker_path_curve); + try { + theRasterizer.add_path(marker_path_curve); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, scanlines); fillSize = scanlines.byte_size(); if (fillSize >= MARKER_CACHE_SIZE) @@ -713,7 +721,11 @@ RendererAgg::draw_markers(const Py::Tuple& args) stroke.line_cap(gc.cap); stroke.line_join(gc.join); theRasterizer.reset(); - theRasterizer.add_path(stroke); + try { + theRasterizer.add_path(stroke); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, scanlines); unsigned strokeSize = scanlines.byte_size(); if (strokeSize >= MARKER_CACHE_SIZE) @@ -980,7 +992,11 @@ RendererAgg::draw_text_image(const Py::Tuple& args) span_gen_type output_span_generator(&image_span_generator, gc.color); renderer_type ri(rendererBase, sa, output_span_generator); - theRasterizer.add_path(rect2); + try { + theRasterizer.add_path(rect2); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, ri); return Py::Object(); @@ -1117,7 +1133,11 @@ RendererAgg::draw_image(const Py::Tuple& args) amask_ren_type r(pfa); renderer_type_alpha ri(r, sa, spans); - theRasterizer.add_path(rect2); + try { + theRasterizer.add_path(rect2); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, ri); } else @@ -1131,7 +1151,11 @@ RendererAgg::draw_image(const Py::Tuple& args) ren_type r(pixFmt); renderer_type ri(r, sa, spans); - theRasterizer.add_path(rect2); + try { + theRasterizer.add_path(rect2); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, ri); } @@ -1166,7 +1190,11 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath, // Render face if (face.first) { - theRasterizer.add_path(path); + try { + theRasterizer.add_path(path); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } if (gc.isaa) { @@ -1233,9 +1261,17 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath, rb.clear(agg::rgba(0.0, 0.0, 0.0, 0.0)); rs.color(gc.color); - theRasterizer.add_path(hatch_path_curve); + try { + theRasterizer.add_path(hatch_path_curve); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, rs); - theRasterizer.add_path(hatch_path_stroke); + try { + theRasterizer.add_path(hatch_path_stroke); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines(theRasterizer, slineP8, rs); // Put clipping back on, if originally set on entry to this @@ -1252,7 +1288,11 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath, agg::span_allocator sa; img_source_type img_src(hatch_img_pixf); span_gen_type sg(img_src, 0, 0); - theRasterizer.add_path(path); + try { + theRasterizer.add_path(path); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, sa, sg); } @@ -1270,7 +1310,11 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath, stroke.width(linewidth); stroke.line_cap(gc.cap); stroke.line_join(gc.join); - theRasterizer.add_path(stroke); + try { + theRasterizer.add_path(stroke); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } } else { @@ -1291,7 +1335,11 @@ void RendererAgg::_draw_path(path_t& path, bool has_clippath, stroke.line_cap(gc.cap); stroke.line_join(gc.join); stroke.width(linewidth); - theRasterizer.add_path(stroke); + try { + theRasterizer.add_path(stroke); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what()); + } } if (gc.isaa) @@ -1888,7 +1936,12 @@ RendererAgg::_draw_gouraud_triangle(const double* points, tpoints[4], tpoints[5], 0.5); - theRasterizer.add_path(span_gen); + try { + theRasterizer.add_path(span_gen); + } catch (std::overflow_error &e) { + throw Py::OverflowError(e.what() + ); + } if (has_clippath) { From d93226e7402a9f875d7449b8587372c0cbfb4236 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 19 Nov 2012 14:15:57 -0500 Subject: [PATCH 14/24] Fix agg overflow test --- lib/matplotlib/tests/test_simplification.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/tests/test_simplification.py b/lib/matplotlib/tests/test_simplification.py index 03a5d84597a7..50b025db01b5 100644 --- a/lib/matplotlib/tests/test_simplification.py +++ b/lib/matplotlib/tests/test_simplification.py @@ -168,7 +168,7 @@ def test_throw_rendering_complexity_exceeded(): ax = fig.add_subplot(111) ax.plot(xx, yy) try: - fig.savefig(io.StringIO()) + fig.savefig(io.BytesIO()) finally: rcParams['path.simplify'] = True From 5f41835a06ba2eddf4a988f9f87927749b0b568a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 19 Nov 2012 14:16:12 -0500 Subject: [PATCH 15/24] Make using an external PyCXX possible on != Python 2.7 --- setupext.py | 68 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/setupext.py b/setupext.py index 055030f89751..7fbe576dbeba 100644 --- a/setupext.py +++ b/setupext.py @@ -4,6 +4,7 @@ from distutils import version from distutils.core import Extension import glob +import io import multiprocessing import os import re @@ -634,17 +635,48 @@ class CXX(SetupPackage): name = 'pycxx' def check(self): + if sys.version_info[:2] == (2, 7): + # There is no version of PyCXX in the wild that will work + # with Python 2.7 + self.__class__.found_external = False + return ("Official version of PyCXX are not compatible with " + "Python 2.7. Using local copy") + + self.__class__.found_external = True + old_stdout = sys.stdout + sys.stdout = io.BytesIO() + try: + import CXX + except ImportError: + self.__class__.found_external = False + return "Couldn't import. Using local copy." + finally: + sys.stdout = old_stdout + try: return self._check_for_pkg_config( - 'PyCXX', 'CXX/Extensions.hxx', min_version='PATCH') + 'PyCXX', 'CXX/Extensions.hxx', min_version='6.2.4') except CheckFailed as e: self.__class__.found_external = False return str(e) + ' Using local copy.' - else: - self.__class__.found_external = True def add_flags(self, ext): if self.found_external: + support_dir = os.path.normpath( + os.path.join( + sys.prefix, + 'share', + 'python%d.%d' % ( + sys.version_info[0], sys.version_info[1]), + 'CXX')) + if not os.path.exists(support_dir): + # On Fedora 17, these files are installed in /usr/share/CXX + support_dir = '/usr/src/CXX' + ext.sources.extend([ + os.path.join(support_dir, x) for x in + ['cxxsupport.cxx', 'cxx_extensions.cxx', + 'IndirectPythonInterface.cxx', + 'cxxextensions.c']]) pkg_config.setup_extension(ext, 'PyCXX') else: ext.sources.extend(glob.glob('CXX/*.cxx')) @@ -661,28 +693,30 @@ class LibAgg(SetupPackage): name = 'libagg' def check(self): + self.__class__.found_external = True try: return self._check_for_pkg_config( 'libagg', 'agg2/agg_basics.h', min_version='PATCH') except CheckFailed as e: self.__class__.found_external = False return str(e) + ' Using local copy.' - finally: - self.__class__.found_external = True def add_flags(self, ext): - ext.include_dirs.append('agg24/include') - agg_sources = [ - 'agg_bezier_arc.cpp', - 'agg_curves.cpp', - 'agg_image_filters.cpp', - 'agg_trans_affine.cpp', - 'agg_vcgen_contour.cpp', - 'agg_vcgen_dash.cpp', - 'agg_vcgen_stroke.cpp', - ] - ext.sources.extend( - os.path.join('agg24', 'src', x) for x in agg_sources) + if self.found_external: + pkg_config.setup_extension(ext, 'libagg') + else: + ext.include_dirs.append('agg24/include') + agg_sources = [ + 'agg_bezier_arc.cpp', + 'agg_curves.cpp', + 'agg_image_filters.cpp', + 'agg_trans_affine.cpp', + 'agg_vcgen_contour.cpp', + 'agg_vcgen_dash.cpp', + 'agg_vcgen_stroke.cpp', + ] + ext.sources.extend( + os.path.join('agg24', 'src', x) for x in agg_sources) class FreeType(SetupPackage): From ce1da9b07c9f89f76622a823d92f85bd00f7b172 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 20 Nov 2012 13:23:08 -0500 Subject: [PATCH 16/24] Fix infinite process recursion on Windows --- setup.py | 270 ++++++++++++++++++++++++++-------------------------- setupext.py | 21 ++++ 2 files changed, 158 insertions(+), 133 deletions(-) diff --git a/setup.py b/setup.py index f55d6fe39b93..c0b37c7c0421 100644 --- a/setup.py +++ b/setup.py @@ -20,17 +20,19 @@ except AttributeError: pass -# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly -# update it when the contents of directories change. -if os.path.exists('MANIFEST'): - os.remove('MANIFEST') +# This 'if' statement is needed to prevent spawning infinite processes +# on Windows +if __name__ == '__main__': + # BEFORE importing distutils, remove MANIFEST. distutils doesn't properly + # update it when the contents of directories change. + if os.path.exists('MANIFEST'): + os.remove('MANIFEST') try: from setuptools.core import setup except ImportError: from distutils.core import setup - import setupext from setupext import print_line, print_raw, print_message, print_status @@ -48,6 +50,7 @@ 'Required dependencies and extensions', setupext.Numpy(), setupext.Dateutil(), + setupext.Tornado(), setupext.Pyparsing(), setupext.CXX(), setupext.LibAgg(), @@ -87,90 +90,6 @@ ] -# These are distutils.setup parameters that the various packages add -# things to. -packages = [] -py_modules = [] -ext_modules = [] -package_data = {} -package_dir = {'': 'lib'} -install_requires = [] -default_backend = None - - -# Go through all of the packages and figure out which ones we are -# going to build/install. -print_line() -print_raw("Edit setup.cfg to change the build options") - - -required_failed = [] -good_packages = [] -for package in mpl_packages: - if isinstance(package, str): - print_raw('') - print_raw(package.upper()) - else: - try: - result = package.check() - if result is not None: - message = 'yes [%s]' % result - print_status(package.name, message) - except setupext.CheckFailed as e: - print_status(package.name, 'no [%s]' % str(e)) - if not package.optional: - required_failed.append(package) - else: - good_packages.append(package) - if isinstance(package, setupext.OptionalBackendPackage): - if default_backend is None: - default_backend = package.name -print_raw('') - - -# Abort if any of the required packages can not be built. -if required_failed: - print_line() - print_message( - "The following required packages can not " - "be built: %s" % - ', '.join(x.name for x in required_failed)) - sys.exit(1) - - -# Now collect all of the information we need to build all of the -# packages. -for package in good_packages: - if isinstance(package, str): - continue - packages.extend(package.get_packages()) - py_modules.extend(package.get_py_modules()) - ext = package.get_extension() - if ext is not None: - ext_modules.append(ext) - data = package.get_package_data() - for key, val in data.items(): - package_data.setdefault(key, []) - package_data[key] = list(set(val + package_data[key])) - install_requires.extend(package.get_install_requires()) - -# Write the default matplotlibrc file -if default_backend is None: - default_backend = 'svg' -if setupext.options['backend']: - default_backend = setupext.options['backend'] -with open('matplotlibrc.template') as fd: - template = fd.read() -with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd: - fd.write(template % {'backend': default_backend}) - - -# Build in verbose mode if requested -if setupext.options['verbose']: - for mod in ext_modules: - mod.extra_compile_args.append('-DVERBOSE') - - classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Science/Research', @@ -181,47 +100,132 @@ 'Topic :: Scientific/Engineering :: Visualization', ] - -# Finally, pass this all along to distutils to do the heavy lifting. -distrib = setup(name="matplotlib", - version=__version__, - description="Python plotting package", - author="John D. Hunter, Michael Droettboom", - author_email="mdroe@stsci.edu", - url="http://matplotlib.org", - long_description=""" - matplotlib strives to produce publication quality 2D graphics - for interactive graphing, scientific publishing, user interface - development and web application servers targeting multiple user - interfaces and hardcopy output formats. There is a 'pylab' mode - which emulates matlab graphics. - """, - download_url="https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-{0}/matplotlib-{0}.tar.gz".format(__version__), - install_requires=['dateutils', 'tornado'], - license="BSD", - packages=packages, - platforms='any', - py_modules=py_modules, - ext_modules=ext_modules, - package_dir=package_dir, - package_data=package_data, - classifiers=classifiers, - - # List third-party Python packages that we require - install_requires=install_requires, - - # Automatically 2to3 source on Python 3.x - use_2to3=True, - - # matplotlib has C/C++ extensions, so it's not zip safe. - # Telling setuptools this prevents it from doing an automatic - # check for zip safety. - zip_safe=False, - - # Install our nose plugin so it will always be found - entry_points={ - 'nose.plugins.0.10': [ - 'KnownFailure = matplotlib.testing.noseclasses:KnownFailure' - ] - }, - ) +# One doesn't normally see `if __name__ == '__main__'` blocks in a setup.py, +# however, this is needed on Windows to avoid creating infinite subprocesses +# when using multiprocessing. +if __name__ == '__main__': + # These are distutils.setup parameters that the various packages add + # things to. + packages = [] + py_modules = [] + ext_modules = [] + package_data = {} + package_dir = {'': 'lib'} + install_requires = [] + default_backend = None + + + # Go through all of the packages and figure out which ones we are + # going to build/install. + print_line() + print_raw("Edit setup.cfg to change the build options") + + required_failed = [] + good_packages = [] + for package in mpl_packages: + if isinstance(package, str): + print_raw('') + print_raw(package.upper()) + else: + try: + result = package.check() + if result is not None: + message = 'yes [%s]' % result + print_status(package.name, message) + except setupext.CheckFailed as e: + print_status(package.name, 'no [%s]' % str(e)) + if not package.optional: + required_failed.append(package) + else: + good_packages.append(package) + if isinstance(package, setupext.OptionalBackendPackage): + if default_backend is None: + default_backend = package.name + print_raw('') + + + # Abort if any of the required packages can not be built. + if required_failed: + print_line() + print_message( + "The following required packages can not " + "be built: %s" % + ', '.join(x.name for x in required_failed)) + sys.exit(1) + + + # Now collect all of the information we need to build all of the + # packages. + for package in good_packages: + if isinstance(package, str): + continue + packages.extend(package.get_packages()) + py_modules.extend(package.get_py_modules()) + ext = package.get_extension() + if ext is not None: + ext_modules.append(ext) + data = package.get_package_data() + for key, val in data.items(): + package_data.setdefault(key, []) + package_data[key] = list(set(val + package_data[key])) + install_requires.extend(package.get_install_requires()) + + # Write the default matplotlibrc file + if default_backend is None: + default_backend = 'svg' + if setupext.options['backend']: + default_backend = setupext.options['backend'] + with open('matplotlibrc.template') as fd: + template = fd.read() + with open('lib/matplotlib/mpl-data/matplotlibrc', 'w') as fd: + fd.write(template % {'backend': default_backend}) + + + # Build in verbose mode if requested + if setupext.options['verbose']: + for mod in ext_modules: + mod.extra_compile_args.append('-DVERBOSE') + + + # Finally, pass this all along to distutils to do the heavy lifting. + distrib = setup(name="matplotlib", + version=__version__, + description="Python plotting package", + author="John D. Hunter, Michael Droettboom", + author_email="mdroe@stsci.edu", + url="http://matplotlib.org", + long_description=""" + matplotlib strives to produce publication quality 2D graphics + for interactive graphing, scientific publishing, user interface + development and web application servers targeting multiple user + interfaces and hardcopy output formats. There is a 'pylab' mode + which emulates matlab graphics. + """, + license="BSD", + packages=packages, + platforms='any', + py_modules=py_modules, + ext_modules=ext_modules, + package_dir=package_dir, + package_data=package_data, + classifiers=classifiers, + download_url="https://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-{0}/matplotlib-{0}.tar.gz".format(__version__), + + # List third-party Python packages that we require + install_requires=install_requires, + + # Automatically 2to3 source on Python 3.x + use_2to3=True, + + # matplotlib has C/C++ extensions, so it's not zip safe. + # Telling setuptools this prevents it from doing an automatic + # check for zip safety. + zip_safe=False, + + # Install our nose plugin so it will always be found + entry_points={ + 'nose.plugins.0.10': [ + 'KnownFailure = matplotlib.testing.noseclasses:KnownFailure' + ] + }, + ) diff --git a/setupext.py b/setupext.py index 7fbe576dbeba..f8c3b4d0d8e8 100644 --- a/setupext.py +++ b/setupext.py @@ -723,6 +723,9 @@ class FreeType(SetupPackage): name = "freetype" def check(self): + if sys.platform == 'win32': + return "Unknown version" + status, output = getstatusoutput("freetype-config --version") if status == 0: version = output @@ -885,6 +888,24 @@ def get_install_requires(self): return ['python_dateutil'] +class Tornado(SetupPackage): + name = "tornado" + + def check(self): + try: + import tornado + except ImportError: + return ( + "tornado was not found. It is required for the WebAgg " + "backend. pip/easy_install may attempt to install it " + "after matplotlib.") + + return "using tornado version %s" % tornado.__version__ + + def get_install_requires(self): + return ['tornado'] + + class Pyparsing(SetupPackage): name = "pyparsing" From e0735bf00489949baea5b35bae7e668111e7d502 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Nov 2012 17:28:44 -0500 Subject: [PATCH 17/24] Update to PyCXX 6.2.4 --- CXX/IndirectPythonInterface.cxx | 520 +++++++++++++++++++- CXX/Python2/ExtensionModule.hxx | 17 +- CXX/Python2/ExtensionOldType.hxx | 31 +- CXX/Python2/ExtensionTypeBase.hxx | 2 - CXX/Python2/IndirectPythonInterface.cxx | 607 ------------------------ CXX/Python2/IndirectPythonInterface.hxx | 2 - CXX/Python2/PythonType.hxx | 6 +- CXX/Python2/cxx_extensions.cxx | 59 +-- CXX/Python3/ExtensionModule.hxx | 4 +- CXX/Python3/IndirectPythonInterface.cxx | 518 -------------------- CXX/Python3/Objects.hxx | 11 +- CXX/Python3/cxx_extensions.cxx | 11 +- CXX/WrapPython.h | 11 + 13 files changed, 566 insertions(+), 1233 deletions(-) delete mode 100644 CXX/Python2/IndirectPythonInterface.cxx delete mode 100644 CXX/Python3/IndirectPythonInterface.cxx diff --git a/CXX/IndirectPythonInterface.cxx b/CXX/IndirectPythonInterface.cxx index 7286cdf65737..256bd7ebda80 100644 --- a/CXX/IndirectPythonInterface.cxx +++ b/CXX/IndirectPythonInterface.cxx @@ -34,10 +34,524 @@ // DAMAGE. // //----------------------------------------------------------------------------- -#include "CXX/WrapPython.h" +#include "CXX/IndirectPythonInterface.hxx" + +namespace Py +{ +bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } +bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } +bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } +bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } +bool _Function_Check( PyObject *op ) { return op->ob_type == _Function_Type(); } +bool _Boolean_Check( PyObject *op ) { return op->ob_type == _Bool_Type(); } +bool _List_Check( PyObject *op ) { return op->ob_type == _List_Type(); } +bool _Long_Check( PyObject *op ) { return op->ob_type == _Long_Type(); } +bool _Method_Check( PyObject *op ) { return op->ob_type == _Method_Type(); } +bool _Module_Check( PyObject *op ) { return op->ob_type == _Module_Type(); } +bool _Range_Check( PyObject *op ) { return op->ob_type == _Range_Type(); } +bool _Slice_Check( PyObject *op ) { return op->ob_type == _Slice_Type(); } +bool _TraceBack_Check( PyObject *op ) { return op->ob_type == _TraceBack_Type(); } +bool _Tuple_Check( PyObject *op ) { return op->ob_type == _Tuple_Type(); } +bool _Type_Check( PyObject *op ) { return op->ob_type == _Type_Type(); } +bool _Unicode_Check( PyObject *op ) { return op->ob_type == _Unicode_Type(); } #if PY_MAJOR_VERSION == 2 -#include "Python2/IndirectPythonInterface.cxx" +bool _String_Check( PyObject *op ) { return op->ob_type == _String_Type(); } +bool _Int_Check( PyObject *op ) { return op->ob_type == _Int_Type(); } +bool _CObject_Check( PyObject *op ) { return op->ob_type == _CObject_Type(); } +#endif +#if PY_MAJOR_VERSION >= 3 +bool _Bytes_Check( PyObject *op ) { return op->ob_type == _Bytes_Type(); } +#endif + +#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) + +#if defined(MS_WINDOWS) +#include + + +static HMODULE python_dll; + +static PyObject *ptr__Exc_ArithmeticError = NULL; +static PyObject *ptr__Exc_AssertionError = NULL; +static PyObject *ptr__Exc_AttributeError = NULL; +static PyObject *ptr__Exc_EnvironmentError = NULL; +static PyObject *ptr__Exc_EOFError = NULL; +static PyObject *ptr__Exc_Exception = NULL; +static PyObject *ptr__Exc_FloatingPointError = NULL; +static PyObject *ptr__Exc_ImportError = NULL; +static PyObject *ptr__Exc_IndexError = NULL; +static PyObject *ptr__Exc_IOError = NULL; +static PyObject *ptr__Exc_KeyboardInterrupt = NULL; +static PyObject *ptr__Exc_KeyError = NULL; +static PyObject *ptr__Exc_LookupError = NULL; +static PyObject *ptr__Exc_MemoryError = NULL; +static PyObject *ptr__Exc_NameError = NULL; +static PyObject *ptr__Exc_NotImplementedError = NULL; +static PyObject *ptr__Exc_OSError = NULL; +static PyObject *ptr__Exc_OverflowError = NULL; +static PyObject *ptr__Exc_RuntimeError = NULL; +static PyObject *ptr__Exc_StandardError = NULL; +static PyObject *ptr__Exc_SyntaxError = NULL; +static PyObject *ptr__Exc_SystemError = NULL; +static PyObject *ptr__Exc_SystemExit = NULL; +static PyObject *ptr__Exc_TypeError = NULL; +static PyObject *ptr__Exc_ValueError = NULL; +static PyObject *ptr__Exc_ZeroDivisionError = NULL; + +#ifdef MS_WINDOWS +static PyObject *ptr__Exc_WindowsError = NULL; +#endif + +static PyObject *ptr__Exc_IndentationError = NULL; +static PyObject *ptr__Exc_TabError = NULL; +static PyObject *ptr__Exc_UnboundLocalError = NULL; +static PyObject *ptr__Exc_UnicodeError = NULL; +static PyObject *ptr__PyNone = NULL; +static PyObject *ptr__PyFalse = NULL; +static PyObject *ptr__PyTrue = NULL; +static PyTypeObject *ptr__CFunction_Type = NULL; +static PyTypeObject *ptr__Complex_Type = NULL; +static PyTypeObject *ptr__Dict_Type = NULL; +static PyTypeObject *ptr__Float_Type = NULL; +static PyTypeObject *ptr__Function_Type = NULL; +static PyTypeObject *ptr__Bool_Type = NULL; +static PyTypeObject *ptr__List_Type = NULL; +static PyTypeObject *ptr__Long_Type = NULL; +static PyTypeObject *ptr__Method_Type = NULL; +static PyTypeObject *ptr__Module_Type = NULL; +static PyTypeObject *ptr__Range_Type = NULL; +static PyTypeObject *ptr__Slice_Type = NULL; +static PyTypeObject *ptr__TraceBack_Type = NULL; +static PyTypeObject *ptr__Tuple_Type = NULL; +static PyTypeObject *ptr__Type_Type = NULL; +#if PY_MAJOR_VERSION == 2 +static PyTypeObject *ptr__Int_Type = NULL; +static PyTypeObject *ptr__String_Type = NULL; +static PyTypeObject *ptr__CObject_Type = NULL; +#endif +#if PY_MAJOR_VERSION >= 3 +static PyTypeObject *ptr__Bytes_Type = NULL; +#endif + + +static int *ptr_Py_DebugFlag = NULL; +static int *ptr_Py_InteractiveFlag = NULL; +static int *ptr_Py_OptimizeFlag = NULL; +static int *ptr_Py_NoSiteFlag = NULL; +static int *ptr_Py_VerboseFlag = NULL; + +static char **ptr__Py_PackageContext = NULL; + +#ifdef Py_REF_DEBUG +int *ptr_Py_RefTotal; +#endif + + +//-------------------------------------------------------------------------------- +class GetAddressException +{ +public: + GetAddressException( const char *_name ) + : name( _name ) + {} + virtual ~GetAddressException() {} + const char *name; +}; + + +//-------------------------------------------------------------------------------- +static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyObject **)addr; +} + +static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyObject *)addr; +} + +static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return *(PyTypeObject **)addr; +} + +static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (PyTypeObject *)addr; +} + +static int *GetInt_as_IntPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (int *)addr; +} + +static char **GetCharPointer_as_CharPointerPointer( const char *name ) +{ + FARPROC addr = GetProcAddress( python_dll, name ); + if( addr == NULL ) + throw GetAddressException( name ); + + return (char **)addr; +} + + +#ifdef _DEBUG +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; #else -#include "Python3/IndirectPythonInterface.cxx" +static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; +#endif + +//-------------------------------------------------------------------------------- +bool InitialisePythonIndirectInterface() +{ + char python_dll_name[sizeof(python_dll_name_format)]; + + _snprintf( python_dll_name, sizeof(python_dll_name_format) / sizeof(char) - 1, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); + + python_dll = LoadLibraryA( python_dll_name ); + if( python_dll == NULL ) + return false; + + try + { +#ifdef Py_REF_DEBUG + ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); +#endif + ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); + ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); + ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); + ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); + ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); + ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); + + ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); + ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); + ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); + ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); + ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); + ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); + ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); + ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); + ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); + ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); + ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); + ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); + ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); + ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); + ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); + ptr__Exc_NotImplementedError= GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); + ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); + ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); + ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); + ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); + ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); + ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); + ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); + ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); + ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); +#ifdef MS_WINDOWS + ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); +#endif + ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); + ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); + ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); + ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); + ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); + ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); + + ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); + ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); + + ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); + ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); + ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); + ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); + ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); + ptr__Bool_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBool_Type" ); + ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); + ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); + ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); + ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); + ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); + ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); + ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); + ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); + ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); + ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); +#if PY_MAJOR_VERSION == 2 + ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); + ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); + ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); +#endif +#if PY_MAJOR_VERSION >= 3 + ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); +#endif + } + catch( GetAddressException &e ) + { + OutputDebugStringA( python_dll_name ); + OutputDebugStringA( " does not contain symbol " ); + OutputDebugStringA( e.name ); + OutputDebugStringA( "\n" ); + + return false; + } + + return true; +} + +// +// Wrap variables as function calls +// +PyObject *_Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } +PyObject *_Exc_AssertionError() { return ptr__Exc_AssertionError; } +PyObject *_Exc_AttributeError() { return ptr__Exc_AttributeError; } +PyObject *_Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } +PyObject *_Exc_EOFError() { return ptr__Exc_EOFError; } +PyObject *_Exc_Exception() { return ptr__Exc_Exception; } +PyObject *_Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } +PyObject *_Exc_ImportError() { return ptr__Exc_ImportError; } +PyObject *_Exc_IndexError() { return ptr__Exc_IndexError; } +PyObject *_Exc_IOError() { return ptr__Exc_IOError; } +PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } +PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } +PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } +PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } +PyObject *_Exc_NameError() { return ptr__Exc_NameError; } +PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } +PyObject *_Exc_OSError() { return ptr__Exc_OSError; } +PyObject *_Exc_OverflowError() { return ptr__Exc_OverflowError; } +PyObject *_Exc_RuntimeError() { return ptr__Exc_RuntimeError; } +PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } +PyObject *_Exc_SyntaxError() { return ptr__Exc_SyntaxError; } +PyObject *_Exc_SystemError() { return ptr__Exc_SystemError; } +PyObject *_Exc_SystemExit() { return ptr__Exc_SystemExit; } +PyObject *_Exc_TypeError() { return ptr__Exc_TypeError; } +PyObject *_Exc_ValueError() { return ptr__Exc_ValueError; } +#ifdef MS_WINDOWS +PyObject *_Exc_WindowsError() { return ptr__Exc_WindowsError; } +#endif +PyObject *_Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } +PyObject *_Exc_IndentationError() { return ptr__Exc_IndentationError; } +PyObject *_Exc_TabError() { return ptr__Exc_TabError; } +PyObject *_Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } +PyObject *_Exc_UnicodeError() { return ptr__Exc_UnicodeError; } + +// +// wrap items in Object.h +// +PyObject *_None() { return ptr__PyNone; } + +PyObject *_False() { return ptr__PyFalse; } +PyObject *_True() { return ptr__PyTrue; } + +PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } +PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } +PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } +PyTypeObject *_Float_Type() { return ptr__Float_Type; } +PyTypeObject *_Function_Type() { return ptr__Function_Type; } +PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } +PyTypeObject *_List_Type() { return ptr__List_Type; } +PyTypeObject *_Long_Type() { return ptr__Long_Type; } +PyTypeObject *_Method_Type() { return ptr__Method_Type; } +PyTypeObject *_Module_Type() { return ptr__Module_Type; } +PyTypeObject *_Range_Type() { return ptr__Range_Type; } +PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } +PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } +PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } +PyTypeObject *_Type_Type() { return ptr__Type_Type; } +PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } +#if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return ptr__String_Type; } +PyTypeObject *_Int_Type() { return ptr__Int_Type; } +PyTypeObject *_CObject_Type() { return ptr__CObject_Type; } +#endif +#if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } +#endif + +char *__Py_PackageContext() { return *ptr__Py_PackageContext; } + + +// +// wrap the Python Flag variables +// +int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } +int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } +int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } + +#if 0 +#define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + ((PyObject*)(op))->ob_refcnt++) + +#define Py_DECREF(op) \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --((PyObject*)(op))->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(op) \ + else \ + _Py_Dealloc((PyObject *)(op)) +#endif + +void _XINCREF( PyObject *op ) +{ + // This function must match the contents of Py_XINCREF(op) + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)++; +#endif + (op)->ob_refcnt++; + +} + +void _XDECREF( PyObject *op ) +{ + // This function must match the contents of Py_XDECREF(op); + if( op == NULL ) + return; + +#ifdef Py_REF_DEBUG + (*ptr_Py_RefTotal)--; +#endif + + if (--(op)->ob_refcnt == 0) + _Py_Dealloc((PyObject *)(op)); +} + + +#else +#error "Can only delay load under Win32" +#endif + +#else + +//================================================================================ +// +// Map onto Macros +// +//================================================================================ + +// +// Wrap variables as function calls +// + +PyObject *_Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } +PyObject *_Exc_AssertionError() { return ::PyExc_AssertionError; } +PyObject *_Exc_AttributeError() { return ::PyExc_AttributeError; } +PyObject *_Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } +PyObject *_Exc_EOFError() { return ::PyExc_EOFError; } +PyObject *_Exc_Exception() { return ::PyExc_Exception; } +PyObject *_Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } +PyObject *_Exc_ImportError() { return ::PyExc_ImportError; } +PyObject *_Exc_IndexError() { return ::PyExc_IndexError; } +PyObject *_Exc_IOError() { return ::PyExc_IOError; } +PyObject *_Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } +PyObject *_Exc_KeyError() { return ::PyExc_KeyError; } +PyObject *_Exc_LookupError() { return ::PyExc_LookupError; } +PyObject *_Exc_MemoryError() { return ::PyExc_MemoryError; } +PyObject *_Exc_NameError() { return ::PyExc_NameError; } +PyObject *_Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } +PyObject *_Exc_OSError() { return ::PyExc_OSError; } +PyObject *_Exc_OverflowError() { return ::PyExc_OverflowError; } +PyObject *_Exc_RuntimeError() { return ::PyExc_RuntimeError; } +PyObject *_Exc_SyntaxError() { return ::PyExc_SyntaxError; } +PyObject *_Exc_SystemError() { return ::PyExc_SystemError; } +PyObject *_Exc_SystemExit() { return ::PyExc_SystemExit; } +PyObject *_Exc_TypeError() { return ::PyExc_TypeError; } +PyObject *_Exc_ValueError() { return ::PyExc_ValueError; } +PyObject *_Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } +PyObject *_Exc_IndentationError() { return ::PyExc_IndentationError; } +PyObject *_Exc_TabError() { return ::PyExc_TabError; } +PyObject *_Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } +PyObject *_Exc_UnicodeError() { return ::PyExc_UnicodeError; } + +#ifdef MS_WINDOWS +PyObject *_Exc_WindowsError() { return ::PyExc_WindowsError; } +#endif + + + + +// +// wrap items in Object.h +// +PyObject *_None() { return &::_Py_NoneStruct; } + +PyObject *_False() { return Py_False; } +PyObject *_True() { return Py_True; } + +PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } +PyTypeObject *_Complex_Type() { return &PyComplex_Type; } +PyTypeObject *_Dict_Type() { return &PyDict_Type; } +PyTypeObject *_Float_Type() { return &PyFloat_Type; } +PyTypeObject *_Function_Type() { return &PyFunction_Type; } +PyTypeObject *_Bool_Type() { return &PyBool_Type; } +PyTypeObject *_List_Type() { return &PyList_Type; } +PyTypeObject *_Long_Type() { return &PyLong_Type; } +PyTypeObject *_Method_Type() { return &PyMethod_Type; } +PyTypeObject *_Module_Type() { return &PyModule_Type; } +PyTypeObject *_Range_Type() { return &PyRange_Type; } +PyTypeObject *_Slice_Type() { return &PySlice_Type; } +PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } +PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } +PyTypeObject *_Type_Type() { return &PyType_Type; } +PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } +#if PY_MAJOR_VERSION == 2 +PyTypeObject *_String_Type() { return &PyString_Type; } +PyTypeObject *_Int_Type() { return &PyInt_Type; } +PyTypeObject *_CObject_Type() { return &PyCObject_Type; } +#endif +#if PY_MAJOR_VERSION >= 3 +PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } +#endif + +// +// wrap flags +// +int &_Py_DebugFlag() { return Py_DebugFlag; } +int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } +int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } +int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } +int &_Py_VerboseFlag() { return Py_VerboseFlag; } +char *__Py_PackageContext() { return _Py_PackageContext; } + +// +// Needed to keep the abstactions for delayload interface +// +void _XINCREF( PyObject *op ) +{ + Py_XINCREF( op ); +} + +void _XDECREF( PyObject *op ) +{ + Py_XDECREF( op ); +} + #endif +} diff --git a/CXX/Python2/ExtensionModule.hxx b/CXX/Python2/ExtensionModule.hxx index dde3ec6f854b..3eb436d00048 100644 --- a/CXX/Python2/ExtensionModule.hxx +++ b/CXX/Python2/ExtensionModule.hxx @@ -66,9 +66,6 @@ namespace Py const std::string m_module_name; const std::string m_full_module_name; MethodTable m_method_table; -#if PY3 - PyModuleDef m_module_def; -#endif PyObject *m_module; private: @@ -136,19 +133,11 @@ namespace Py { MethodDefExt *method_def = (*i).second; - #if PY_VERSION_HEX < 0x02070000 - static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); - #else - static PyObject *self = PyCapsule_New( this, NULL, NULL ); - #endif + static PyObject *self = PyCObject_FromVoidPtr( this, do_not_dealloc ); Tuple args( 2 ); - args[0] = Object( self ); - #if PY_VERSION_HEX < 0x02070000 - args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ) ); - #else - args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); - #endif + args[0] = Object( self, true ); + args[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); PyObject *func = PyCFunction_New ( diff --git a/CXX/Python2/ExtensionOldType.hxx b/CXX/Python2/ExtensionOldType.hxx index 9702b00e7455..cfd2fbe6a578 100644 --- a/CXX/Python2/ExtensionOldType.hxx +++ b/CXX/Python2/ExtensionOldType.hxx @@ -178,11 +178,8 @@ namespace Py Tuple self( 2 ); self[0] = Object( this ); - #if PY_VERSION_HEX < 0x02070000 - self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); - #else - self[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); - #endif + self[1] = Object( PyCObject_FromVoidPtr( method_def, do_not_dealloc ), true ); + PyObject *func = PyCFunction_New( &method_def->ext_meth_def, self.ptr() ); return Object(func, true); @@ -238,12 +235,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Object result; // Adding try & catch in case of STL debug-mode exceptions. @@ -278,12 +271,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); Object result; @@ -319,12 +308,8 @@ namespace Py PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); T *self = static_cast( self_in_cobject ); - #if PY_VERSION_HEX < 0x02070000 - void *capsule = PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ); - #else - void *capsule = PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ); - #endif - MethodDefExt *meth_def = reinterpret_cast *>( capsule ); + MethodDefExt *meth_def = reinterpret_cast *>( + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ) ); Tuple args( _args ); diff --git a/CXX/Python2/ExtensionTypeBase.hxx b/CXX/Python2/ExtensionTypeBase.hxx index ad11029e71dc..1dfe4243619a 100644 --- a/CXX/Python2/ExtensionTypeBase.hxx +++ b/CXX/Python2/ExtensionTypeBase.hxx @@ -70,9 +70,7 @@ namespace Py virtual void reinit( Tuple &args, Dict &kwds ); // object basics -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) virtual int print( FILE *, int ); -#endif virtual Object getattr( const char * ); virtual int setattr( const char *, const Object & ); virtual Object getattro( const String & ); diff --git a/CXX/Python2/IndirectPythonInterface.cxx b/CXX/Python2/IndirectPythonInterface.cxx deleted file mode 100644 index 203f3f9170ff..000000000000 --- a/CXX/Python2/IndirectPythonInterface.cxx +++ /dev/null @@ -1,607 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#include "CXX/IndirectPythonInterface.hxx" - -namespace Py -{ -bool _Buffer_Check( PyObject *op ) { return (op)->ob_type == _Buffer_Type(); } -bool _CFunction_Check( PyObject *op ) { return (op)->ob_type == _CFunction_Type(); } -bool _Class_Check( PyObject *op ) { return (op)->ob_type == _Class_Type(); } -#if PY_VERSION_HEX < 0x02070000 -bool _CObject_Check( PyObject *op ) { return (op)->ob_type == _CObject_Type(); } -#endif -bool _Complex_Check( PyObject *op ) { return (op)->ob_type == _Complex_Type(); } -bool _Dict_Check( PyObject *op ) { return (op)->ob_type == _Dict_Type(); } -bool _File_Check( PyObject *op ) { return (op)->ob_type == _File_Type(); } -bool _Float_Check( PyObject *op ) { return (op)->ob_type == _Float_Type(); } -bool _Function_Check( PyObject *op ) { return (op)->ob_type == _Function_Type(); } -bool _Instance_Check( PyObject *op ) { return (op)->ob_type == _Instance_Type(); } -bool _Boolean_Check( PyObject *op ) { return (op)->ob_type == _Bool_Type(); } -bool _Int_Check( PyObject *op ) { return (op)->ob_type == _Int_Type(); } -bool _List_Check( PyObject *o ) { return o->ob_type == _List_Type(); } -bool _Long_Check( PyObject *op ) { return (op)->ob_type == _Long_Type(); } -bool _Method_Check( PyObject *op ) { return (op)->ob_type == _Method_Type(); } -bool _Module_Check( PyObject *op ) { return (op)->ob_type == _Module_Type(); } -bool _Range_Check( PyObject *op ) { return (op)->ob_type == _Range_Type(); } -bool _Slice_Check( PyObject *op ) { return (op)->ob_type == _Slice_Type(); } -bool _String_Check( PyObject *o ) { return o->ob_type == _String_Type(); } -bool _TraceBack_Check( PyObject *v ) { return (v)->ob_type == _TraceBack_Type(); } -bool _Tuple_Check( PyObject *op ) { return (op)->ob_type == _Tuple_Type(); } -bool _Type_Check( PyObject *op ) { return (op)->ob_type == _Type_Type(); } - -#if PY_MAJOR_VERSION >= 2 -bool _Unicode_Check( PyObject *op ) { return (op)->ob_type == _Unicode_Type(); } -#endif - - - -#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) - -#if defined(MS_WINDOWS) -#include - - -static HMODULE python_dll; - -static PyObject *ptr__Exc_ArithmeticError = NULL; -static PyObject *ptr__Exc_AssertionError = NULL; -static PyObject *ptr__Exc_AttributeError = NULL; -static PyObject *ptr__Exc_EnvironmentError = NULL; -static PyObject *ptr__Exc_EOFError = NULL; -static PyObject *ptr__Exc_Exception = NULL; -static PyObject *ptr__Exc_FloatingPointError = NULL; -static PyObject *ptr__Exc_ImportError = NULL; -static PyObject *ptr__Exc_IndexError = NULL; -static PyObject *ptr__Exc_IOError = NULL; -static PyObject *ptr__Exc_KeyboardInterrupt = NULL; -static PyObject *ptr__Exc_KeyError = NULL; -static PyObject *ptr__Exc_LookupError = NULL; -static PyObject *ptr__Exc_MemoryError = NULL; -static PyObject *ptr__Exc_MemoryErrorInst = NULL; -static PyObject *ptr__Exc_NameError = NULL; -static PyObject *ptr__Exc_NotImplementedError = NULL; -static PyObject *ptr__Exc_OSError = NULL; -static PyObject *ptr__Exc_OverflowError = NULL; -static PyObject *ptr__Exc_RuntimeError = NULL; -static PyObject *ptr__Exc_StandardError = NULL; -static PyObject *ptr__Exc_SyntaxError = NULL; -static PyObject *ptr__Exc_SystemError = NULL; -static PyObject *ptr__Exc_SystemExit = NULL; -static PyObject *ptr__Exc_TypeError = NULL; -static PyObject *ptr__Exc_ValueError = NULL; -static PyObject *ptr__Exc_ZeroDivisionError = NULL; - -#ifdef MS_WINDOWS -static PyObject *ptr__Exc_WindowsError = NULL; -#endif - -#if PY_MAJOR_VERSION >= 2 -static PyObject *ptr__Exc_IndentationError = NULL; -static PyObject *ptr__Exc_TabError = NULL; -static PyObject *ptr__Exc_UnboundLocalError = NULL; -static PyObject *ptr__Exc_UnicodeError = NULL; -#endif - -static PyObject *ptr__PyNone = NULL; - -static PyObject *ptr__PyFalse = NULL; -static PyObject *ptr__PyTrue = NULL; - -static PyTypeObject *ptr__Buffer_Type = NULL; -static PyTypeObject *ptr__CFunction_Type = NULL; -static PyTypeObject *ptr__Class_Type = NULL; -#if PY_VERSION_HEX < 0x02070000 -static PyTypeObject *ptr__CObject_Type = NULL; -#endif -static PyTypeObject *ptr__Complex_Type = NULL; -static PyTypeObject *ptr__Dict_Type = NULL; -static PyTypeObject *ptr__File_Type = NULL; -static PyTypeObject *ptr__Float_Type = NULL; -static PyTypeObject *ptr__Function_Type = NULL; -static PyTypeObject *ptr__Instance_Type = NULL; -static PyTypeObject *ptr__Int_Type = NULL; -static PyTypeObject *ptr__List_Type = NULL; -static PyTypeObject *ptr__Long_Type = NULL; -static PyTypeObject *ptr__Method_Type = NULL; -static PyTypeObject *ptr__Module_Type = NULL; -static PyTypeObject *ptr__Range_Type = NULL; -static PyTypeObject *ptr__Slice_Type = NULL; -static PyTypeObject *ptr__String_Type = NULL; -static PyTypeObject *ptr__TraceBack_Type = NULL; -static PyTypeObject *ptr__Tuple_Type = NULL; -static PyTypeObject *ptr__Type_Type = NULL; - -#if PY_MAJOR_VERSION >= 2 -static PyTypeObject *ptr__Unicode_Type = NULL; -#endif - -static int *ptr_Py_DebugFlag = NULL; -static int *ptr_Py_InteractiveFlag = NULL; -static int *ptr_Py_OptimizeFlag = NULL; -static int *ptr_Py_NoSiteFlag = NULL; -static int *ptr_Py_TabcheckFlag = NULL; -static int *ptr_Py_VerboseFlag = NULL; - -#if PY_MAJOR_VERSION >= 2 -static int *ptr_Py_UnicodeFlag = NULL; -#endif - -static char **ptr__Py_PackageContext = NULL; - -#ifdef Py_REF_DEBUG -int *ptr_Py_RefTotal; -#endif - - -//-------------------------------------------------------------------------------- -class GetAddressException -{ -public: - GetAddressException( const char *_name ) - : name( _name ) - {} - virtual ~GetAddressException() {} - const char *name; -}; - - -//-------------------------------------------------------------------------------- -static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyObject **)addr; -} - -static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyObject *)addr; -} - -static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyTypeObject **)addr; -} - -static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyTypeObject *)addr; -} - -static int *GetInt_as_IntPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (int *)addr; -} - -static char **GetCharPointer_as_CharPointerPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (char **)addr; -} - - -#ifdef _DEBUG -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; -#else -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; -#endif - -//-------------------------------------------------------------------------------- -bool InitialisePythonIndirectInterface() -{ - char python_dll_name[sizeof(python_dll_name_format)]; - - sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); - - python_dll = LoadLibrary( python_dll_name ); - if( python_dll == NULL ) - return false; - - try -{ -#ifdef Py_REF_DEBUG - ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); -#endif - ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); - ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); - ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); - ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); - ptr_Py_TabcheckFlag = GetInt_as_IntPointer( "Py_TabcheckFlag" ); - ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); -#if PY_MAJOR_VERSION >= 2 - ptr_Py_UnicodeFlag = GetInt_as_IntPointer( "Py_UnicodeFlag" ); -#endif - ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); - - ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); - ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); - ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); - ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); - ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); - ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); - ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); - ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); - ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); - ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); - ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); - ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); - ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); - ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); - ptr__Exc_MemoryErrorInst = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryErrorInst" ); - ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); - ptr__Exc_NotImplementedError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); - ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); - ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); - ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); - ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); - ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); - ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); - ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); - ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); - ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); -#ifdef MS_WINDOWS - ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); -#endif - ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); - -#if PY_MAJOR_VERSION >= 2 - ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); - ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); - ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); - ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); -#endif - ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); - - ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); - ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); - - ptr__Buffer_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBuffer_Type" ); - ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); - ptr__Class_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyClass_Type" ); -#if PY_VERSION_HEX < 0x02070000 - ptr__CObject_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCObject_Type" ); -#endif - ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); - ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); - ptr__File_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFile_Type" ); - ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); - ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); - ptr__Instance_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInstance_Type" ); - ptr__Int_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyInt_Type" ); - ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); - ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); - ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); - ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); - ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); - ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); - ptr__String_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyString_Type" ); - ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); - ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); - ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); - -#if PY_MAJOR_VERSION >= 2 - ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); -#endif -} - catch( GetAddressException &e ) - { - OutputDebugString( python_dll_name ); - OutputDebugString( " does not contain symbol "); - OutputDebugString( e.name ); - OutputDebugString( "\n" ); - - return false; - } - - return true; -} - -// -// Wrap variables as function calls -// -PyObject * _Exc_ArithmeticError(){ return ptr__Exc_ArithmeticError; } -PyObject * _Exc_AssertionError(){ return ptr__Exc_AssertionError; } -PyObject * _Exc_AttributeError(){ return ptr__Exc_AttributeError; } -PyObject * _Exc_EnvironmentError(){ return ptr__Exc_EnvironmentError; } -PyObject * _Exc_EOFError() { return ptr__Exc_EOFError; } -PyObject * _Exc_Exception() { return ptr__Exc_Exception; } -PyObject * _Exc_FloatingPointError(){ return ptr__Exc_FloatingPointError; } -PyObject * _Exc_ImportError() { return ptr__Exc_ImportError; } -PyObject * _Exc_IndexError() { return ptr__Exc_IndexError; } -PyObject * _Exc_IOError() { return ptr__Exc_IOError; } -PyObject * _Exc_KeyboardInterrupt(){ return ptr__Exc_KeyboardInterrupt; } -PyObject * _Exc_KeyError() { return ptr__Exc_KeyError; } -PyObject * _Exc_LookupError() { return ptr__Exc_LookupError; } -PyObject * _Exc_MemoryError() { return ptr__Exc_MemoryError; } -PyObject * _Exc_MemoryErrorInst(){ return ptr__Exc_MemoryErrorInst; } -PyObject * _Exc_NameError() { return ptr__Exc_NameError; } -PyObject * _Exc_NotImplementedError(){ return ptr__Exc_NotImplementedError; } -PyObject * _Exc_OSError() { return ptr__Exc_OSError; } -PyObject * _Exc_OverflowError() { return ptr__Exc_OverflowError; } -PyObject * _Exc_RuntimeError() { return ptr__Exc_RuntimeError; } -PyObject * _Exc_StandardError() { return ptr__Exc_StandardError; } -PyObject * _Exc_SyntaxError() { return ptr__Exc_SyntaxError; } -PyObject * _Exc_SystemError() { return ptr__Exc_SystemError; } -PyObject * _Exc_SystemExit() { return ptr__Exc_SystemExit; } -PyObject * _Exc_TypeError() { return ptr__Exc_TypeError; } -PyObject * _Exc_ValueError() { return ptr__Exc_ValueError; } -#ifdef MS_WINDOWS -PyObject * _Exc_WindowsError() { return ptr__Exc_WindowsError; } -#endif -PyObject * _Exc_ZeroDivisionError(){ return ptr__Exc_ZeroDivisionError; } - -#if PY_MAJOR_VERSION >= 2 -PyObject * _Exc_IndentationError(){ return ptr__Exc_IndentationError; } -PyObject * _Exc_TabError() { return ptr__Exc_TabError; } -PyObject * _Exc_UnboundLocalError(){ return ptr__Exc_UnboundLocalError; } -PyObject * _Exc_UnicodeError() { return ptr__Exc_UnicodeError; } -#endif - -// -// wrap items in Object.h -// -PyObject * _None() { return ptr__PyNone; } - -PyObject * _False() { return ptr__PyFalse; } -PyObject * _True() { return ptr__PyTrue; } - -PyTypeObject * _Buffer_Type() { return ptr__Buffer_Type; } -PyTypeObject * _CFunction_Type(){ return ptr__CFunction_Type; } -PyTypeObject * _Class_Type() { return ptr__Class_Type; } -#if PY_VERSION_HEX < 0x02070000 -PyTypeObject * _CObject_Type() { return ptr__CObject_Type; } -#endif -PyTypeObject * _Complex_Type() { return ptr__Complex_Type; } -PyTypeObject * _Dict_Type() { return ptr__Dict_Type; } -PyTypeObject * _File_Type() { return ptr__File_Type; } -PyTypeObject * _Float_Type() { return ptr__Float_Type; } -PyTypeObject * _Function_Type() { return ptr__Function_Type; } -PyTypeObject * _Instance_Type() { return ptr__Instance_Type; } -PyTypeObject * _Bool_Type() { return ptr__Bool_Type; } -PyTypeObject * _Int_Type() { return ptr__Int_Type; } -PyTypeObject * _List_Type() { return ptr__List_Type; } -PyTypeObject * _Long_Type() { return ptr__Long_Type; } -PyTypeObject * _Method_Type() { return ptr__Method_Type; } -PyTypeObject * _Module_Type() { return ptr__Module_Type; } -PyTypeObject * _Range_Type() { return ptr__Range_Type; } -PyTypeObject * _Slice_Type() { return ptr__Slice_Type; } -PyTypeObject * _String_Type() { return ptr__String_Type; } -PyTypeObject * _TraceBack_Type(){ return ptr__TraceBack_Type; } -PyTypeObject * _Tuple_Type() { return ptr__Tuple_Type; } -PyTypeObject * _Type_Type() { return ptr__Type_Type; } - -#if PY_MAJOR_VERSION >= 2 -PyTypeObject * _Unicode_Type() { return ptr__Unicode_Type; } -#endif - -char *__Py_PackageContext() { return *ptr__Py_PackageContext; } - - -// -// wrap the Python Flag variables -// -int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } -int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } -int &_Py_TabcheckFlag() { return *ptr_Py_TabcheckFlag; } -int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } -#if PY_MAJOR_VERSION >= 2 -int &_Py_UnicodeFlag() { return *ptr_Py_UnicodeFlag; } -#endif - -void _XINCREF( PyObject *op ) -{ - // This function must match the contents of Py_XINCREF(op) - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)++; -#endif - (op)->ob_refcnt++; - -} - -void _XDECREF( PyObject *op ) -{ - // This function must match the contents of Py_XDECREF(op); - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)--; -#endif - - if (--(op)->ob_refcnt == 0) - _Py_Dealloc((PyObject *)(op)); -} - - -#else -#error "Can only delay load under Win32" -#endif - -#else - -// -// Duplicated these declarations from rangeobject.h which is missing the -// extern "C". This has been reported as a bug upto and include 2.1 -// -extern "C" DL_IMPORT(PyTypeObject) PyRange_Type; -extern "C" DL_IMPORT(PyObject *) PyRange_New(long, long, long, int); - - -//================================================================================ -// -// Map onto Macros -// -//================================================================================ - -// -// Wrap variables as function calls -// - -PyObject * _Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } -PyObject * _Exc_AssertionError() { return ::PyExc_AssertionError; } -PyObject * _Exc_AttributeError() { return ::PyExc_AttributeError; } -PyObject * _Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } -PyObject * _Exc_EOFError() { return ::PyExc_EOFError; } -PyObject * _Exc_Exception() { return ::PyExc_Exception; } -PyObject * _Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } -PyObject * _Exc_ImportError() { return ::PyExc_ImportError; } -PyObject * _Exc_IndexError() { return ::PyExc_IndexError; } -PyObject * _Exc_IOError() { return ::PyExc_IOError; } -PyObject * _Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } -PyObject * _Exc_KeyError() { return ::PyExc_KeyError; } -PyObject * _Exc_LookupError() { return ::PyExc_LookupError; } -PyObject * _Exc_MemoryError() { return ::PyExc_MemoryError; } -PyObject * _Exc_MemoryErrorInst() { return ::PyExc_MemoryErrorInst; } -PyObject * _Exc_NameError() { return ::PyExc_NameError; } -PyObject * _Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } -PyObject * _Exc_OSError() { return ::PyExc_OSError; } -PyObject * _Exc_OverflowError() { return ::PyExc_OverflowError; } -PyObject * _Exc_RuntimeError() { return ::PyExc_RuntimeError; } -PyObject * _Exc_StandardError() { return ::PyExc_StandardError; } -PyObject * _Exc_SyntaxError() { return ::PyExc_SyntaxError; } -PyObject * _Exc_SystemError() { return ::PyExc_SystemError; } -PyObject * _Exc_SystemExit() { return ::PyExc_SystemExit; } -PyObject * _Exc_TypeError() { return ::PyExc_TypeError; } -PyObject * _Exc_ValueError() { return ::PyExc_ValueError; } -PyObject * _Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } - -#ifdef MS_WINDOWS -PyObject * _Exc_WindowsError() { return ::PyExc_WindowsError; } -#endif - - -#if PY_MAJOR_VERSION >= 2 -PyObject * _Exc_IndentationError() { return ::PyExc_IndentationError; } -PyObject * _Exc_TabError() { return ::PyExc_TabError; } -PyObject * _Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } -PyObject * _Exc_UnicodeError() { return ::PyExc_UnicodeError; } -#endif - - -// -// wrap items in Object.h -// -PyObject * _None() { return &::_Py_NoneStruct; } - -PyObject * _False() { return Py_False; } -PyObject * _True() { return Py_True; } - -PyTypeObject * _Buffer_Type() { return &PyBuffer_Type; } -PyTypeObject * _CFunction_Type() { return &PyCFunction_Type; } -PyTypeObject * _Class_Type() { return &PyClass_Type; } -#if PY_VERSION_HEX < 0x02070000 -PyTypeObject * _CObject_Type() { return &PyCObject_Type; } -#endif -PyTypeObject * _Complex_Type() { return &PyComplex_Type; } -PyTypeObject * _Dict_Type() { return &PyDict_Type; } -PyTypeObject * _File_Type() { return &PyFile_Type; } -PyTypeObject * _Float_Type() { return &PyFloat_Type; } -PyTypeObject * _Function_Type() { return &PyFunction_Type; } -PyTypeObject * _Instance_Type() { return &PyInstance_Type; } -PyTypeObject * _Bool_Type() { return &PyBool_Type; } -PyTypeObject * _Int_Type() { return &PyInt_Type; } -PyTypeObject * _List_Type() { return &PyList_Type; } -PyTypeObject * _Long_Type() { return &PyLong_Type; } -PyTypeObject * _Method_Type() { return &PyMethod_Type; } -PyTypeObject * _Module_Type() { return &PyModule_Type; } -PyTypeObject * _Range_Type() { return &PyRange_Type; } -PyTypeObject * _Slice_Type() { return &PySlice_Type; } -PyTypeObject * _String_Type() { return &PyString_Type; } -PyTypeObject * _TraceBack_Type() { return &PyTraceBack_Type; } -PyTypeObject * _Tuple_Type() { return &PyTuple_Type; } -PyTypeObject * _Type_Type() { return &PyType_Type; } - -#if PY_MAJOR_VERSION >= 2 -PyTypeObject * _Unicode_Type() { return &PyUnicode_Type; } -#endif - -// -// wrap flags -// -int &_Py_DebugFlag() { return Py_DebugFlag; } -int &_Py_InteractiveFlag(){ return Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } -int &_Py_TabcheckFlag() { return Py_TabcheckFlag; } -int &_Py_VerboseFlag() { return Py_VerboseFlag; } -#if PY_MAJOR_VERSION >= 2 -int &_Py_UnicodeFlag() { return Py_UnicodeFlag; } -#endif -char *__Py_PackageContext(){ return _Py_PackageContext; } - -// -// Needed to keep the abstactions for delayload interface -// -void _XINCREF( PyObject *op ) -{ - Py_XINCREF(op); -} - -void _XDECREF( PyObject *op ) -{ - Py_XDECREF(op); -} - -#endif -} diff --git a/CXX/Python2/IndirectPythonInterface.hxx b/CXX/Python2/IndirectPythonInterface.hxx index 33d4b83f34fc..a29a394c6c6a 100644 --- a/CXX/Python2/IndirectPythonInterface.hxx +++ b/CXX/Python2/IndirectPythonInterface.hxx @@ -113,10 +113,8 @@ bool _Instance_Check( PyObject *op ); PyTypeObject * _Method_Type(); bool _Method_Check( PyObject *op ); -#if PY_VERSION_HEX < 0x02070000 PyTypeObject * _CObject_Type(); bool _CObject_Check( PyObject *op ); -#endif PyTypeObject * _Complex_Type(); bool _Complex_Check( PyObject *op ); diff --git a/CXX/Python2/PythonType.hxx b/CXX/Python2/PythonType.hxx index a89a6c90481e..fc45a4bc6c5e 100644 --- a/CXX/Python2/PythonType.hxx +++ b/CXX/Python2/PythonType.hxx @@ -57,17 +57,15 @@ namespace Py PythonType &doc( const char *d ); PythonType &supportClass( void ); -#if !defined( PY3 ) PythonType &dealloc( void (*f)( PyObject* ) ); -#endif -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportPrint( void ); #endif PythonType &supportGetattr( void ); PythonType &supportSetattr( void ); PythonType &supportGetattro( void ); PythonType &supportSetattro( void ); -#if defined( PYCXX_PYTHON_2TO3 ) || !defined( PY3 ) +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &supportCompare( void ); #endif PythonType &supportRichCompare( void ); diff --git a/CXX/Python2/cxx_extensions.cxx b/CXX/Python2/cxx_extensions.cxx index 6ae62c7cfb05..b9bdcd136fac 100644 --- a/CXX/Python2/cxx_extensions.cxx +++ b/CXX/Python2/cxx_extensions.cxx @@ -254,7 +254,9 @@ extern "C" // All the following functions redirect the call from Python // onto the matching virtual function in PythonExtensionBase // +#if defined( PYCXX_PYTHON_2TO3 ) static int print_handler( PyObject *, FILE *, int ); +#endif static PyObject *getattr_handler( PyObject *, char * ); static int setattr_handler( PyObject *, char *, PyObject * ); static PyObject *getattro_handler( PyObject *, PyObject * ); @@ -290,9 +292,7 @@ extern "C" static PyObject *number_invert_handler( PyObject * ); static PyObject *number_int_handler( PyObject * ); static PyObject *number_float_handler( PyObject * ); -#if !defined( PY3 ) static PyObject *number_long_handler( PyObject * ); -#endif static PyObject *number_oct_handler( PyObject * ); static PyObject *number_hex_handler( PyObject * ); static PyObject *number_add_handler( PyObject *, PyObject * ); @@ -335,13 +335,9 @@ PythonType &PythonType::supportSequenceType() sequence_table->sq_concat = sequence_concat_handler; sequence_table->sq_repeat = sequence_repeat_handler; sequence_table->sq_item = sequence_item_handler; -#if !defined( PY3 ) sequence_table->sq_slice = sequence_slice_handler; -#endif sequence_table->sq_ass_item = sequence_ass_item_handler; // BAS setup seperately? -#if !defined( PY3 ) sequence_table->sq_ass_slice = sequence_ass_slice_handler; // BAS setup seperately? -#endif } return *this; } @@ -370,36 +366,26 @@ PythonType &PythonType::supportNumberType() number_table->nb_add = number_add_handler; number_table->nb_subtract = number_subtract_handler; number_table->nb_multiply = number_multiply_handler; -#if !defined( PY3 ) number_table->nb_divide = number_divide_handler; -#endif number_table->nb_remainder = number_remainder_handler; number_table->nb_divmod = number_divmod_handler; number_table->nb_power = number_power_handler; number_table->nb_negative = number_negative_handler; number_table->nb_positive = number_positive_handler; number_table->nb_absolute = number_absolute_handler; -#if !defined( PY3 ) number_table->nb_nonzero = number_nonzero_handler; -#endif number_table->nb_invert = number_invert_handler; number_table->nb_lshift = number_lshift_handler; number_table->nb_rshift = number_rshift_handler; number_table->nb_and = number_and_handler; number_table->nb_xor = number_xor_handler; number_table->nb_or = number_or_handler; -#if !defined( PY3 ) number_table->nb_coerce = 0; -#endif number_table->nb_int = number_int_handler; -#if !defined( PY3 ) number_table->nb_long = number_long_handler; -#endif number_table->nb_float = number_float_handler; -#if !defined( PY3 ) number_table->nb_oct = number_oct_handler; number_table->nb_hex = number_hex_handler; -#endif } return *this; } @@ -411,11 +397,9 @@ PythonType &PythonType::supportBufferType() buffer_table = new PyBufferProcs; memset( buffer_table, 0, sizeof( PyBufferProcs ) ); // ensure new fields are 0 table->tp_as_buffer = buffer_table; -#if !defined( PY3 ) buffer_table->bf_getreadbuffer = buffer_getreadbuffer_handler; buffer_table->bf_getwritebuffer = buffer_getwritebuffer_handler; buffer_table->bf_getsegcount = buffer_getsegcount_handler; -#endif } return *this; } @@ -434,10 +418,9 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; -#if !defined( PY3 ) table->ob_type = _Type_Type(); table->ob_size = 0; -#endif + table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; table->tp_itemsize = itemsize; @@ -575,11 +558,13 @@ PythonType &PythonType::dealloc( void( *f )( PyObject * )) return *this; } +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportPrint() { table->tp_print = print_handler; return *this; } +#endif PythonType &PythonType::supportGetattr() { @@ -605,11 +590,13 @@ PythonType &PythonType::supportSetattro() return *this; } +#if defined( PYCXX_PYTHON_2TO3 ) PythonType &PythonType::supportCompare() { table->tp_compare = compare_handler; return *this; } +#endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) PythonType &PythonType::supportRichCompare() @@ -669,6 +656,7 @@ PythonExtensionBase *getPythonExtensionBase( PyObject *self ) } +#if defined( PYCXX_PYTHON_2TO3 ) extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) { try @@ -681,6 +669,7 @@ extern "C" int print_handler( PyObject *self, FILE *fp, int flags ) return -1; // indicate error } } +#endif extern "C" PyObject *getattr_handler( PyObject *self, char *name ) { @@ -1719,11 +1708,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - #if PY_VERSION_HEX < 0x02070000 - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); - #else - void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); - #endif + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; @@ -1739,11 +1724,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) @@ -1759,11 +1740,7 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_keyword ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args, keywords ) @@ -1785,11 +1762,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple Tuple self_and_name_tuple( _self_and_name_tuple ); PyObject *self_in_cobject = self_and_name_tuple[0].ptr(); - #if PY_VERSION_HEX < 0x02070000 - void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); - #else - void *self_as_void = PyCapsule_GetPointer( self_in_cobject, NULL ); - #endif + void *self_as_void = PyCObject_AsVoidPtr( self_in_cobject ); if( self_as_void == NULL ) return NULL; @@ -1800,11 +1773,7 @@ extern "C" PyObject *method_varargs_call_handler( PyObject *_self_and_name_tuple ( self->invoke_method_varargs ( - #if PY_VERSION_HEX < 0x02070000 - PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), - #else - PyCapsule_GetPointer( self_and_name_tuple[1].ptr(), NULL ), - #endif + PyCObject_AsVoidPtr( self_and_name_tuple[1].ptr() ), args ) ); diff --git a/CXX/Python3/ExtensionModule.hxx b/CXX/Python3/ExtensionModule.hxx index a892a6f8cde5..75eb77568ae4 100644 --- a/CXX/Python3/ExtensionModule.hxx +++ b/CXX/Python3/ExtensionModule.hxx @@ -135,8 +135,8 @@ namespace Py static PyObject *self = PyCapsule_New( this, NULL, NULL ); Tuple args( 2 ); - args[0] = Object( self ); - args[1] = Object( PyCapsule_New( method_def, NULL, NULL ) ); + args[0] = Object( self, true ); + args[1] = Object( PyCapsule_New( method_def, NULL, NULL ), true ); PyObject *func = PyCFunction_New ( diff --git a/CXX/Python3/IndirectPythonInterface.cxx b/CXX/Python3/IndirectPythonInterface.cxx deleted file mode 100644 index 2b7ff41b75da..000000000000 --- a/CXX/Python3/IndirectPythonInterface.cxx +++ /dev/null @@ -1,518 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright (c) 1998 - 2007, The Regents of the University of California -// Produced at the Lawrence Livermore National Laboratory -// All rights reserved. -// -// This file is part of PyCXX. For details,see http://cxx.sourceforge.net/. The -// full copyright notice is contained in the file COPYRIGHT located at the root -// of the PyCXX distribution. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// - Redistributions of source code must retain the above copyright notice, -// this list of conditions and the disclaimer below. -// - Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the -// documentation and/or materials provided with the distribution. -// - Neither the name of the UC/LLNL nor the names of its contributors may be -// used to endorse or promote products derived from this software without -// specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF -// CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -// DAMAGE. -// -//----------------------------------------------------------------------------- - -#include "CXX/IndirectPythonInterface.hxx" - -namespace Py -{ -bool _CFunction_Check( PyObject *op ) { return op->ob_type == _CFunction_Type(); } -bool _Complex_Check( PyObject *op ) { return op->ob_type == _Complex_Type(); } -bool _Dict_Check( PyObject *op ) { return op->ob_type == _Dict_Type(); } -bool _Float_Check( PyObject *op ) { return op->ob_type == _Float_Type(); } -bool _Function_Check( PyObject *op ) { return op->ob_type == _Function_Type(); } -bool _Boolean_Check( PyObject *op ) { return op->ob_type == _Bool_Type(); } -bool _List_Check( PyObject *op ) { return op->ob_type == _List_Type(); } -bool _Long_Check( PyObject *op ) { return op->ob_type == _Long_Type(); } -bool _Method_Check( PyObject *op ) { return op->ob_type == _Method_Type(); } -bool _Module_Check( PyObject *op ) { return op->ob_type == _Module_Type(); } -bool _Range_Check( PyObject *op ) { return op->ob_type == _Range_Type(); } -bool _Slice_Check( PyObject *op ) { return op->ob_type == _Slice_Type(); } -bool _TraceBack_Check( PyObject *op ) { return op->ob_type == _TraceBack_Type(); } -bool _Tuple_Check( PyObject *op ) { return op->ob_type == _Tuple_Type(); } -bool _Type_Check( PyObject *op ) { return op->ob_type == _Type_Type(); } -bool _Unicode_Check( PyObject *op ) { return op->ob_type == _Unicode_Type(); } -bool _Bytes_Check( PyObject *op ) { return op->ob_type == _Bytes_Type(); } - -#if defined(PY_WIN32_DELAYLOAD_PYTHON_DLL) - -#if defined(MS_WINDOWS) -#include - - -static HMODULE python_dll; - -static PyObject *ptr__Exc_ArithmeticError = NULL; -static PyObject *ptr__Exc_AssertionError = NULL; -static PyObject *ptr__Exc_AttributeError = NULL; -static PyObject *ptr__Exc_EnvironmentError = NULL; -static PyObject *ptr__Exc_EOFError = NULL; -static PyObject *ptr__Exc_Exception = NULL; -static PyObject *ptr__Exc_FloatingPointError = NULL; -static PyObject *ptr__Exc_ImportError = NULL; -static PyObject *ptr__Exc_IndexError = NULL; -static PyObject *ptr__Exc_IOError = NULL; -static PyObject *ptr__Exc_KeyboardInterrupt = NULL; -static PyObject *ptr__Exc_KeyError = NULL; -static PyObject *ptr__Exc_LookupError = NULL; -static PyObject *ptr__Exc_MemoryError = NULL; -static PyObject *ptr__Exc_NameError = NULL; -static PyObject *ptr__Exc_NotImplementedError = NULL; -static PyObject *ptr__Exc_OSError = NULL; -static PyObject *ptr__Exc_OverflowError = NULL; -static PyObject *ptr__Exc_RuntimeError = NULL; -static PyObject *ptr__Exc_StandardError = NULL; -static PyObject *ptr__Exc_SyntaxError = NULL; -static PyObject *ptr__Exc_SystemError = NULL; -static PyObject *ptr__Exc_SystemExit = NULL; -static PyObject *ptr__Exc_TypeError = NULL; -static PyObject *ptr__Exc_ValueError = NULL; -static PyObject *ptr__Exc_ZeroDivisionError = NULL; - -#ifdef MS_WINDOWS -static PyObject *ptr__Exc_WindowsError = NULL; -#endif - -static PyObject *ptr__Exc_IndentationError = NULL; -static PyObject *ptr__Exc_TabError = NULL; -static PyObject *ptr__Exc_UnboundLocalError = NULL; -static PyObject *ptr__Exc_UnicodeError = NULL; -static PyObject *ptr__PyNone = NULL; -static PyObject *ptr__PyFalse = NULL; -static PyObject *ptr__PyTrue = NULL; -static PyTypeObject *ptr__CFunction_Type = NULL; -static PyTypeObject *ptr__Complex_Type = NULL; -static PyTypeObject *ptr__Dict_Type = NULL; -static PyTypeObject *ptr__Float_Type = NULL; -static PyTypeObject *ptr__Function_Type = NULL; -static PyTypeObject *ptr__List_Type = NULL; -static PyTypeObject *ptr__Long_Type = NULL; -static PyTypeObject *ptr__Method_Type = NULL; -static PyTypeObject *ptr__Module_Type = NULL; -static PyTypeObject *ptr__Range_Type = NULL; -static PyTypeObject *ptr__Slice_Type = NULL; -static PyTypeObject *ptr__TraceBack_Type = NULL; -static PyTypeObject *ptr__Tuple_Type = NULL; -static PyTypeObject *ptr__Type_Type = NULL; - -static int *ptr_Py_DebugFlag = NULL; -static int *ptr_Py_InteractiveFlag = NULL; -static int *ptr_Py_OptimizeFlag = NULL; -static int *ptr_Py_NoSiteFlag = NULL; -static int *ptr_Py_VerboseFlag = NULL; - -static char **ptr__Py_PackageContext = NULL; - -#ifdef Py_REF_DEBUG -int *ptr_Py_RefTotal; -#endif - - -//-------------------------------------------------------------------------------- -class GetAddressException -{ -public: - GetAddressException( const char *_name ) - : name( _name ) - {} - virtual ~GetAddressException() {} - const char *name; -}; - - -//-------------------------------------------------------------------------------- -static PyObject *GetPyObjectPointer_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyObject **)addr; -} - -static PyObject *GetPyObject_As_PyObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyObject *)addr; -} - -static PyTypeObject *GetPyTypeObjectPointer_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return *(PyTypeObject **)addr; -} - -static PyTypeObject *GetPyTypeObject_As_PyTypeObjectPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (PyTypeObject *)addr; -} - -static int *GetInt_as_IntPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (int *)addr; -} - -static char **GetCharPointer_as_CharPointerPointer( const char *name ) -{ - FARPROC addr = GetProcAddress( python_dll, name ); - if( addr == NULL ) - throw GetAddressException( name ); - - return (char **)addr; -} - - -#ifdef _DEBUG -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d_D.DLL"; -#else -static const char python_dll_name_format[] = "PYTHON%1.1d%1.1d.DLL"; -#endif - -//-------------------------------------------------------------------------------- -bool InitialisePythonIndirectInterface() -{ - char python_dll_name[sizeof(python_dll_name_format)]; - - sprintf( python_dll_name, python_dll_name_format, PY_MAJOR_VERSION, PY_MINOR_VERSION ); - - python_dll = LoadLibrary( python_dll_name ); - if( python_dll == NULL ) - return false; - - try - { -#ifdef Py_REF_DEBUG - ptr_Py_RefTotal = GetInt_as_IntPointer( "_Py_RefTotal" ); -#endif - ptr_Py_DebugFlag = GetInt_as_IntPointer( "Py_DebugFlag" ); - ptr_Py_InteractiveFlag = GetInt_as_IntPointer( "Py_InteractiveFlag" ); - ptr_Py_OptimizeFlag = GetInt_as_IntPointer( "Py_OptimizeFlag" ); - ptr_Py_NoSiteFlag = GetInt_as_IntPointer( "Py_NoSiteFlag" ); - ptr_Py_VerboseFlag = GetInt_as_IntPointer( "Py_VerboseFlag" ); - ptr__Py_PackageContext = GetCharPointer_as_CharPointerPointer( "_Py_PackageContext" ); - - ptr__Exc_ArithmeticError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ArithmeticError" ); - ptr__Exc_AssertionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AssertionError" ); - ptr__Exc_AttributeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_AttributeError" ); - ptr__Exc_EnvironmentError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EnvironmentError" ); - ptr__Exc_EOFError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_EOFError" ); - ptr__Exc_Exception = GetPyObjectPointer_As_PyObjectPointer( "PyExc_Exception" ); - ptr__Exc_FloatingPointError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_FloatingPointError" ); - ptr__Exc_ImportError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ImportError" ); - ptr__Exc_IndexError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndexError" ); - ptr__Exc_IOError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IOError" ); - ptr__Exc_KeyboardInterrupt = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyboardInterrupt" ); - ptr__Exc_KeyError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_KeyError" ); - ptr__Exc_LookupError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_LookupError" ); - ptr__Exc_MemoryError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_MemoryError" ); - ptr__Exc_NameError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_NameError" ); - ptr__Exc_NotImplementedError= GetPyObjectPointer_As_PyObjectPointer( "PyExc_NotImplementedError" ); - ptr__Exc_OSError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OSError" ); - ptr__Exc_OverflowError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_OverflowError" ); - ptr__Exc_RuntimeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_RuntimeError" ); - ptr__Exc_StandardError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_StandardError" ); - ptr__Exc_SyntaxError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SyntaxError" ); - ptr__Exc_SystemError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemError" ); - ptr__Exc_SystemExit = GetPyObjectPointer_As_PyObjectPointer( "PyExc_SystemExit" ); - ptr__Exc_TypeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TypeError" ); - ptr__Exc_ValueError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ValueError" ); -#ifdef MS_WINDOWS - ptr__Exc_WindowsError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_WindowsError" ); -#endif - ptr__Exc_ZeroDivisionError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_ZeroDivisionError" ); - ptr__Exc_IndentationError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_IndentationError" ); - ptr__Exc_TabError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_TabError" ); - ptr__Exc_UnboundLocalError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnboundLocalError" ); - ptr__Exc_UnicodeError = GetPyObjectPointer_As_PyObjectPointer( "PyExc_UnicodeError" ); - ptr__PyNone = GetPyObject_As_PyObjectPointer( "_Py_NoneStruct" ); - - ptr__PyFalse = GetPyObject_As_PyObjectPointer( "_Py_ZeroStruct" ); - ptr__PyTrue = GetPyObject_As_PyObjectPointer( "_Py_TrueStruct" ); - - ptr__CFunction_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyCFunction_Type" ); - ptr__Complex_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyComplex_Type" ); - ptr__Dict_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyDict_Type" ); - ptr__Float_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFloat_Type" ); - ptr__Function_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyFunction_Type" ); - ptr__List_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyList_Type" ); - ptr__Long_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyLong_Type" ); - ptr__Method_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyMethod_Type" ); - ptr__Module_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyModule_Type" ); - ptr__Range_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyRange_Type" ); - ptr__Slice_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PySlice_Type" ); - ptr__TraceBack_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTraceBack_Type" ); - ptr__Tuple_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyTuple_Type" ); - ptr__Type_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyType_Type" ); - ptr__Unicode_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyUnicode_Type" ); - ptr__Bytes_Type = GetPyTypeObject_As_PyTypeObjectPointer( "PyBytes_Type" ); - } - catch( GetAddressException &e ) - { - OutputDebugString( python_dll_name ); - OutputDebugString( " does not contain symbol "); - OutputDebugString( e.name ); - OutputDebugString( "\n" ); - - return false; - } - - return true; -} - -// -// Wrap variables as function calls -// -PyObject *_Exc_ArithmeticError() { return ptr__Exc_ArithmeticError; } -PyObject *_Exc_AssertionError() { return ptr__Exc_AssertionError; } -PyObject *_Exc_AttributeError() { return ptr__Exc_AttributeError; } -PyObject *_Exc_EnvironmentError() { return ptr__Exc_EnvironmentError; } -PyObject *_Exc_EOFError() { return ptr__Exc_EOFError; } -PyObject *_Exc_Exception() { return ptr__Exc_Exception; } -PyObject *_Exc_FloatingPointError() { return ptr__Exc_FloatingPointError; } -PyObject *_Exc_ImportError() { return ptr__Exc_ImportError; } -PyObject *_Exc_IndexError() { return ptr__Exc_IndexError; } -PyObject *_Exc_IOError() { return ptr__Exc_IOError; } -PyObject *_Exc_KeyboardInterrupt() { return ptr__Exc_KeyboardInterrupt; } -PyObject *_Exc_KeyError() { return ptr__Exc_KeyError; } -PyObject *_Exc_LookupError() { return ptr__Exc_LookupError; } -PyObject *_Exc_MemoryError() { return ptr__Exc_MemoryError; } -PyObject *_Exc_NameError() { return ptr__Exc_NameError; } -PyObject *_Exc_NotImplementedError() { return ptr__Exc_NotImplementedError; } -PyObject *_Exc_OSError() { return ptr__Exc_OSError; } -PyObject *_Exc_OverflowError() { return ptr__Exc_OverflowError; } -PyObject *_Exc_RuntimeError() { return ptr__Exc_RuntimeError; } -PyObject *_Exc_StandardError() { return ptr__Exc_StandardError; } -PyObject *_Exc_SyntaxError() { return ptr__Exc_SyntaxError; } -PyObject *_Exc_SystemError() { return ptr__Exc_SystemError; } -PyObject *_Exc_SystemExit() { return ptr__Exc_SystemExit; } -PyObject *_Exc_TypeError() { return ptr__Exc_TypeError; } -PyObject *_Exc_ValueError() { return ptr__Exc_ValueError; } -#ifdef MS_WINDOWS -PyObject *_Exc_WindowsError() { return ptr__Exc_WindowsError; } -#endif -PyObject *_Exc_ZeroDivisionError() { return ptr__Exc_ZeroDivisionError; } -PyObject *_Exc_IndentationError() { return ptr__Exc_IndentationError; } -PyObject *_Exc_TabError() { return ptr__Exc_TabError; } -PyObject *_Exc_UnboundLocalError() { return ptr__Exc_UnboundLocalError; } -PyObject *_Exc_UnicodeError() { return ptr__Exc_UnicodeError; } - -// -// wrap items in Object.h -// -PyObject *_None() { return ptr__PyNone; } - -PyObject *_False() { return ptr__PyFalse; } -PyObject *_True() { return ptr__PyTrue; } - -PyTypeObject *_CFunction_Type() { return ptr__CFunction_Type; } -PyTypeObject *_Complex_Type() { return ptr__Complex_Type; } -PyTypeObject *_Dict_Type() { return ptr__Dict_Type; } -PyTypeObject *_Float_Type() { return ptr__Float_Type; } -PyTypeObject *_Function_Type() { return ptr__Function_Type; } -PyTypeObject *_Bool_Type() { return ptr__Bool_Type; } -PyTypeObject *_List_Type() { return ptr__List_Type; } -PyTypeObject *_Long_Type() { return ptr__Long_Type; } -PyTypeObject *_Method_Type() { return ptr__Method_Type; } -PyTypeObject *_Module_Type() { return ptr__Module_Type; } -PyTypeObject *_Range_Type() { return ptr__Range_Type; } -PyTypeObject *_Slice_Type() { return ptr__Slice_Type; } -PyTypeObject *_TraceBack_Type() { return ptr__TraceBack_Type; } -PyTypeObject *_Tuple_Type() { return ptr__Tuple_Type; } -PyTypeObject *_Type_Type() { return ptr__Type_Type; } -PyTypeObject *_Unicode_Type() { return ptr__Unicode_Type; } -PyTypeObject *_Bytes_Type() { return ptr__Bytes_Type; } - -char *__Py_PackageContext() { return *ptr__Py_PackageContext; } - - -// -// wrap the Python Flag variables -// -int &_Py_DebugFlag() { return *ptr_Py_DebugFlag; } -int &_Py_InteractiveFlag() { return *ptr_Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return *ptr_Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return *ptr_Py_NoSiteFlag; } -int &_Py_VerboseFlag() { return *ptr_Py_VerboseFlag; } - -#if 0 -#define Py_INCREF(op) ( \ - _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ - ((PyObject*)(op))->ob_refcnt++) - -#define Py_DECREF(op) \ - if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ - --((PyObject*)(op))->ob_refcnt != 0) \ - _Py_CHECK_REFCNT(op) \ - else \ - _Py_Dealloc((PyObject *)(op)) -#endif - -void _XINCREF( PyObject *op ) -{ - // This function must match the contents of Py_XINCREF(op) - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)++; -#endif - (op)->ob_refcnt++; - -} - -void _XDECREF( PyObject *op ) -{ - // This function must match the contents of Py_XDECREF(op); - if( op == NULL ) - return; - -#ifdef Py_REF_DEBUG - (*ptr_Py_RefTotal)--; -#endif - - if (--(op)->ob_refcnt == 0) - _Py_Dealloc((PyObject *)(op)); -} - - -#else -#error "Can only delay load under Win32" -#endif - -#else - -//================================================================================ -// -// Map onto Macros -// -//================================================================================ - -// -// Wrap variables as function calls -// - -PyObject *_Exc_ArithmeticError() { return ::PyExc_ArithmeticError; } -PyObject *_Exc_AssertionError() { return ::PyExc_AssertionError; } -PyObject *_Exc_AttributeError() { return ::PyExc_AttributeError; } -PyObject *_Exc_EnvironmentError() { return ::PyExc_EnvironmentError; } -PyObject *_Exc_EOFError() { return ::PyExc_EOFError; } -PyObject *_Exc_Exception() { return ::PyExc_Exception; } -PyObject *_Exc_FloatingPointError() { return ::PyExc_FloatingPointError; } -PyObject *_Exc_ImportError() { return ::PyExc_ImportError; } -PyObject *_Exc_IndexError() { return ::PyExc_IndexError; } -PyObject *_Exc_IOError() { return ::PyExc_IOError; } -PyObject *_Exc_KeyboardInterrupt() { return ::PyExc_KeyboardInterrupt; } -PyObject *_Exc_KeyError() { return ::PyExc_KeyError; } -PyObject *_Exc_LookupError() { return ::PyExc_LookupError; } -PyObject *_Exc_MemoryError() { return ::PyExc_MemoryError; } -PyObject *_Exc_NameError() { return ::PyExc_NameError; } -PyObject *_Exc_NotImplementedError() { return ::PyExc_NotImplementedError; } -PyObject *_Exc_OSError() { return ::PyExc_OSError; } -PyObject *_Exc_OverflowError() { return ::PyExc_OverflowError; } -PyObject *_Exc_RuntimeError() { return ::PyExc_RuntimeError; } -PyObject *_Exc_SyntaxError() { return ::PyExc_SyntaxError; } -PyObject *_Exc_SystemError() { return ::PyExc_SystemError; } -PyObject *_Exc_SystemExit() { return ::PyExc_SystemExit; } -PyObject *_Exc_TypeError() { return ::PyExc_TypeError; } -PyObject *_Exc_ValueError() { return ::PyExc_ValueError; } -PyObject *_Exc_ZeroDivisionError() { return ::PyExc_ZeroDivisionError; } -PyObject *_Exc_IndentationError() { return ::PyExc_IndentationError; } -PyObject *_Exc_TabError() { return ::PyExc_TabError; } -PyObject *_Exc_UnboundLocalError() { return ::PyExc_UnboundLocalError; } -PyObject *_Exc_UnicodeError() { return ::PyExc_UnicodeError; } - -#ifdef MS_WINDOWS -PyObject *_Exc_WindowsError() { return ::PyExc_WindowsError; } -#endif - - - - -// -// wrap items in Object.h -// -PyObject *_None() { return &::_Py_NoneStruct; } - -PyObject *_False() { return Py_False; } -PyObject *_True() { return Py_True; } - -PyTypeObject *_CFunction_Type() { return &PyCFunction_Type; } -PyTypeObject *_Complex_Type() { return &PyComplex_Type; } -PyTypeObject *_Dict_Type() { return &PyDict_Type; } -PyTypeObject *_Float_Type() { return &PyFloat_Type; } -PyTypeObject *_Function_Type() { return &PyFunction_Type; } -PyTypeObject *_Bool_Type() { return &PyBool_Type; } -PyTypeObject *_List_Type() { return &PyList_Type; } -PyTypeObject *_Long_Type() { return &PyLong_Type; } -PyTypeObject *_Method_Type() { return &PyMethod_Type; } -PyTypeObject *_Module_Type() { return &PyModule_Type; } -PyTypeObject *_Range_Type() { return &PyRange_Type; } -PyTypeObject *_Slice_Type() { return &PySlice_Type; } -PyTypeObject *_TraceBack_Type() { return &PyTraceBack_Type; } -PyTypeObject *_Tuple_Type() { return &PyTuple_Type; } -PyTypeObject *_Type_Type() { return &PyType_Type; } -PyTypeObject *_Unicode_Type() { return &PyUnicode_Type; } -PyTypeObject *_Bytes_Type() { return &PyBytes_Type; } - -// -// wrap flags -// -int &_Py_DebugFlag() { return Py_DebugFlag; } -int &_Py_InteractiveFlag() { return Py_InteractiveFlag; } -int &_Py_OptimizeFlag() { return Py_OptimizeFlag; } -int &_Py_NoSiteFlag() { return Py_NoSiteFlag; } -int &_Py_VerboseFlag() { return Py_VerboseFlag; } -char *__Py_PackageContext() { return _Py_PackageContext; } - -// -// Needed to keep the abstactions for delayload interface -// -void _XINCREF( PyObject *op ) -{ - Py_XINCREF( op ); -} - -void _XDECREF( PyObject *op ) -{ - Py_XDECREF( op ); -} - -#endif -} diff --git a/CXX/Python3/Objects.hxx b/CXX/Python3/Objects.hxx index 2847512f065a..927618f0ba06 100644 --- a/CXX/Python3/Objects.hxx +++ b/CXX/Python3/Objects.hxx @@ -413,7 +413,7 @@ namespace Py { } - virtual bool accepts( PyObject *pyob ) const + virtual bool accepts( PyObject *pyob ) { return pyob == NULL; } @@ -1328,7 +1328,6 @@ namespace Py } // Assignment acquires new ownership of pointer - SeqBase &operator=( const Object &rhs ) { return *this = *rhs; @@ -1520,7 +1519,7 @@ namespace Py int operator-( const iterator &other ) const { - if( seq->ptr() != other.seq->ptr() ) + if( seq->ptr() != other.seq->ptr() ) throw RuntimeError( "SeqBase::iterator comparison error" ); return count - other.count; @@ -2192,8 +2191,8 @@ namespace Py } } } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer Tuple &operator=( const Object &rhs ) { return *this = *rhs; @@ -2380,8 +2379,8 @@ namespace Py { return max_size(); } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer List &operator=( const Object &rhs ) { return *this = *rhs; @@ -3074,8 +3073,8 @@ namespace Py set( PyDict_New(), true ); validate(); } - // Assignment acquires new ownership of pointer + // Assignment acquires new ownership of pointer Dict &operator=( const Object &rhs ) { return *this = *rhs; diff --git a/CXX/Python3/cxx_extensions.cxx b/CXX/Python3/cxx_extensions.cxx index 59874ad95576..8f2a4886c251 100644 --- a/CXX/Python3/cxx_extensions.cxx +++ b/CXX/Python3/cxx_extensions.cxx @@ -366,7 +366,7 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam memset( table, 0, sizeof( PyTypeObject ) ); // ensure new fields are 0 *reinterpret_cast( table ) = py_object_initializer; - // QQQ table->ob_type = _Type_Type(); + reinterpret_cast( table )->ob_type = _Type_Type(); // QQQ table->ob_size = 0; table->tp_name = const_cast( default_name ); table->tp_basicsize = basic_size; @@ -440,10 +440,10 @@ PythonType::PythonType( size_t basic_size, int itemsize, const char *default_nam table->tp_version_tag = 0; #ifdef COUNT_ALLOCS - table->tp_allocs = 0; - table->tp_frees = 0; + table->tp_alloc = 0; + table->tp_free = 0; table->tp_maxalloc = 0; - table->tp_prev = 0; + table->tp_orev = 0; table->tp_next = 0; #endif } @@ -1602,9 +1602,6 @@ extern "C" PyObject *method_keyword_call_handler( PyObject *_self_and_name_tuple } } -extern "C" void do_not_dealloc( void * ) -{} - //-------------------------------------------------------------------------------- // diff --git a/CXX/WrapPython.h b/CXX/WrapPython.h index 118a8740f8ad..6a73545d2d3d 100644 --- a/CXX/WrapPython.h +++ b/CXX/WrapPython.h @@ -57,4 +57,15 @@ // pull in python definitions #include +// fix issue with Python assuming that isspace, toupper etc are macros +#if defined(isspace) +#undef isspace +#undef isupper +#undef islower +#undef isalnum +#undef isalpha +#undef toupper +#undef tolower +#endif + #endif From ee2f3f4fd57f8c6ad7dbef6ddc0cbed7d33fc0f6 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Nov 2012 17:29:01 -0500 Subject: [PATCH 18/24] Update the CXX detection code to use the system PyCXX in more cases --- setupext.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setupext.py b/setupext.py index f8c3b4d0d8e8..181957a85ed4 100644 --- a/setupext.py +++ b/setupext.py @@ -635,12 +635,12 @@ class CXX(SetupPackage): name = 'pycxx' def check(self): - if sys.version_info[:2] == (2, 7): + if sys.version_info[0] >= 3: # There is no version of PyCXX in the wild that will work - # with Python 2.7 + # with Python 3.x self.__class__.found_external = False - return ("Official version of PyCXX are not compatible with " - "Python 2.7. Using local copy") + return ("Official versions of PyCXX are not compatible with " + "Python 3.x. Using local copy") self.__class__.found_external = True old_stdout = sys.stdout From 8f95f1c8851e0fa522939011a6125c4937212d7a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 26 Nov 2012 17:44:11 -0500 Subject: [PATCH 19/24] Fix compiler warnings about compare_handler --- CXX/Python2/cxx_extensions.cxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CXX/Python2/cxx_extensions.cxx b/CXX/Python2/cxx_extensions.cxx index b9bdcd136fac..611a335d1164 100644 --- a/CXX/Python2/cxx_extensions.cxx +++ b/CXX/Python2/cxx_extensions.cxx @@ -261,7 +261,9 @@ extern "C" static int setattr_handler( PyObject *, char *, PyObject * ); static PyObject *getattro_handler( PyObject *, PyObject * ); static int setattro_handler( PyObject *, PyObject *, PyObject * ); +#if defined( PYCXX_PYTHON_2TO3 ) static int compare_handler( PyObject *, PyObject * ); +#endif static PyObject *rich_compare_handler( PyObject *, PyObject *, int ); static PyObject *repr_handler( PyObject * ); static PyObject *str_handler( PyObject * ); @@ -723,6 +725,7 @@ extern "C" int setattro_handler( PyObject *self, PyObject *name, PyObject *value } } +#if defined( PYCXX_PYTHON_2TO3 ) extern "C" int compare_handler( PyObject *self, PyObject *other ) { try @@ -735,6 +738,7 @@ extern "C" int compare_handler( PyObject *self, PyObject *other ) return -1; // indicate error } } +#endif #if PY_MAJOR_VERSION > 2 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 1) extern "C" PyObject *rich_compare_handler( PyObject *self, PyObject *other, int op ) From da760370dd8eef4adeec24198ff2a6f426b69fd1 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Fri, 7 Dec 2012 11:43:29 -0500 Subject: [PATCH 20/24] Attempting to fix Travis tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 99a71d1d1c1d..f00dce2dfcfc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ install: - 'if [ $TRAVIS_PYTHON_VERSION == "3.2" ]; then pip install https://github.com/y-p/numpy/archive/1.6.2_with_travis_fix.tar.gz; fi' - 'if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then pip install numpy; fi' # should be nop if pre-installed - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install --use-mirrors PIL; fi - - python setup.py install + - python setup.py install --old-and-unmanageable script: - mkdir ../foo From b5443e23f95be750ea646138d7c8b0750114acf2 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 19 Dec 2012 11:39:51 -0500 Subject: [PATCH 21/24] Windows fixes from cgohlke --- setupext.py | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/setupext.py b/setupext.py index 181957a85ed4..2110a6ae1a78 100644 --- a/setupext.py +++ b/setupext.py @@ -124,6 +124,8 @@ def check_include_file(include_dirs, filename, package): """ Raises an exception if the given include file can not be found. """ + if sys.platform == 'win32': + include_dirs.extend(os.getenv('INCLUDE', '.').split(';')) if not has_include_file(include_dirs, filename): raise CheckFailed( "The C/C++ header for %s (%s) could not be found. You " @@ -1295,32 +1297,32 @@ def get_extension(self): def add_flags(self, ext): if sys.platform == 'win32': - # popen broken on my win32 plaform so I can't use pkgconfig - ext.library_dirs.extend( - ['C:/GTK/bin', 'C:/GTK/lib']) - - ext.include_dirs.extend( - ['win32_static/include/pygtk-2.0', - 'C:/GTK/include', - 'C:/GTK/include/gobject', - 'C:/GTK/include/gext', - 'C:/GTK/include/glib', - 'C:/GTK/include/pango', - 'C:/GTK/include/atk', - 'C:/GTK/include/X11', - 'C:/GTK/include/cairo', - 'C:/GTK/include/gdk', - 'C:/GTK/include/gdk-pixbuf', - 'C:/GTK/include/gtk', - ]) - def getoutput(s): ret = os.popen(s).read().strip() return ret if 'PKG_CONFIG_PATH' not in os.environ: # If Gtk+ is installed, pkg-config is required to be installed - os.environ['PKG_CONFIG_PATH'] = 'C:\GTK\lib\pkgconfig' + os.environ['PKG_CONFIG_PATH'] = 'C:\\GTK\\lib\\pkgconfig' + + # popen broken on my win32 plaform so I can't use pkgconfig + ext.library_dirs.extend( + ['C:/GTK/bin', 'C:/GTK/lib']) + + ext.include_dirs.extend( + ['win32_static/include/pygtk-2.0', + 'C:/GTK/include', + 'C:/GTK/include/gobject', + 'C:/GTK/include/gext', + 'C:/GTK/include/glib', + 'C:/GTK/include/pango', + 'C:/GTK/include/atk', + 'C:/GTK/include/X11', + 'C:/GTK/include/cairo', + 'C:/GTK/include/gdk', + 'C:/GTK/include/gdk-pixbuf', + 'C:/GTK/include/gtk', + ]) pygtkIncludes = getoutput( 'pkg-config --cflags-only-I pygtk-2.0').split() From 009b1a01ca7eb675394626c84e0abc730f04e63f Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Wed, 16 Jan 2013 11:52:35 -0500 Subject: [PATCH 22/24] Fixups after rebase --- setupext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index 2110a6ae1a78..1acd44a3b4d5 100644 --- a/setupext.py +++ b/setupext.py @@ -902,7 +902,7 @@ def check(self): "backend. pip/easy_install may attempt to install it " "after matplotlib.") - return "using tornado version %s" % tornado.__version__ + return "using tornado version %s" % tornado.version def get_install_requires(self): return ['tornado'] From 0ed7228a3a55e9c6fcf0f6efc3938c938f59900a Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 25 Feb 2013 17:54:35 -0500 Subject: [PATCH 23/24] multiprocessing doesn't work with Travis, so just skip the things that require it. --- setupext.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setupext.py b/setupext.py index 1acd44a3b4d5..762def28f6fd 100644 --- a/setupext.py +++ b/setupext.py @@ -1403,6 +1403,9 @@ class BackendGtk3Agg(OptionalBackendPackage): name = "gtk3agg" def check(self): + if 'TRAVIS' in os.environ: + raise CheckFailed("Can't build with Travis") + # This check needs to be performed out-of-process, because # importing gi and then importing regular old pygtk afterward # segfaults the interpreter. @@ -1442,6 +1445,9 @@ class BackendGtk3Cairo(OptionalBackendPackage): name = "gtk3cairo" def check(self): + if 'TRAVIS' in os.environ: + raise CheckFailed("Can't build with Travis") + # This check needs to be performed out-of-process, because # importing gi and then importing regular old pygtk afterward # segfaults the interpreter. From 5934e0e05d53ad1b140a5d3f63247a52d6f810c9 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Mon, 25 Feb 2013 18:19:03 -0500 Subject: [PATCH 24/24] Properly install the pylab module --- setupext.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setupext.py b/setupext.py index 762def28f6fd..89bf0cdd998c 100644 --- a/setupext.py +++ b/setupext.py @@ -501,7 +501,7 @@ def get_packages(self): 'matplotlib.tri', ] - def get_py_packages(self): + def get_py_modules(self): return ['pylab'] def get_package_data(self):

)tBM&eh2B))L7-nky?Bz4H9_8B*Xc(v=lCx~gEF7A{Ot zpDSLAlAT%{eM5_H|E?v&SG4qMpO*D^YI)~bec}9NdGU0wtZw>T*1X*&FEunv#rnhY za_MfV%neADr&_90ieznEj?|2+({+wYUH509t{+^YwcljwhOQ@cBMM#<ph}o5e8HcqQ2xcVKW+<4kU} z(%OU)h$RqAAeulpfp}s9iis#Dq?nkFa@;$@!XJRc{4==7H#1EQw@o$I`}fQ9eR8*} d_rfYp^ElJ(GS{?xw=3P9?n=v_gED42?*R6K`>p^0 diff --git a/lib/pytz/zoneinfo/Australia/Tasmania b/lib/pytz/zoneinfo/Australia/Tasmania deleted file mode 100644 index c4604e5386ef6aaec79f1dbc1e8af557ef63ca96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2295 zcmd6n`%jg19LL{>%MjAYa>_lll1qr-1tAs91VJS+?xaYFTrBe-h-7*C%q&`qRc6Vu zCDIuE;zYV=n~TUc)(EYwdzz!#8r`g|Sq_n&*Q4{7`U8ADd!E;GzUPiTkyqbu2kBXY{7*jrJwoUGP+0Xt`i^H!oEaX)HSTd2PazQlP9&r_q#3K)TO&C zKCxw4t-2?(*On*0Zdoz=EIV+ORsMdcU821GIl8ws zLu+;0Jov~;Ml?gc$ix?5E_joO%At?Kw9Z3@d)&Ey8F^;B8yp9NMoyxi(P zoo}1_XWD~Dr`bb?CfJteFWSTQvu*W$Yu?R4YAE|h+j2+LnDLF85(c$B{Dhi=53Bj& zYuYjLoLas%J@Qe5cD`GsM|<1su}+`u+Pl?!yDRPSZEMY=E0>@Db#zJ3cJR-CrN?va z$w^j0q4U|pp$h+hIDyVr-0-q<^FCqRp($BEVn&1+5@t-Uok3wng&7uRT$q7jMur(0 zW^C9U950LxoZ%tH2MiDxA!dlc7+pJq#EjClGfd1lT{{ECj1)6eV64DkfzblP1;z^u z7#J}yWMIs$ok0Vm28Ioc+qE-rVC1fyp<~9589Zk6nBil_4+H=c0Za&h7yv;4q5y;e zh=Xe<5I`g_p#Wlm2?h`iOgMmeU;+X}1QQZWOn{(Zq5^~k6BpM`U@(yZLW7A7CODYr zV8R2$2NNJ5LYNQ%F~S51h!Q4Dm^fhq1w_iV6DlB9K(K&l0pSAT1q2L;7!WcbW|*L1 zqJ{|@CT^I(VIt?+2^}VOnBZZehY24hen0?$2m&DlVh98gh$0Y1AdWyFfk*cP=Cgr83B&Q~) MB<0ORv*(8V3!!2o8vpEmtmLuOi= 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 diff --git a/lib/pytz/zoneinfo/Brazil/DeNoronha b/lib/pytz/zoneinfo/Brazil/DeNoronha deleted file mode 100644 index c60239009e4695a66be6f44df8d332115be14764..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 714 zcmb`^y)Oe{0LSrb5mCXj8q`Bm-D_x@nk`;JTtwJ}CZ>*z%nZ-O!0?RXA8_qNBB5Io zEKT3MEYzS0)wJY1-&-vtp3B|ma@&1>_VPw5YW+AJ<_k9`Vs761_D|N=oPlKC`HHGc zeN1M{DN%@PS*X3p;^4I|W~M}`-7U+9c~L3t$*LU|ZwGb#-Zdv0XN&TqU#RAMP&O}5 zMJsTjTgT6;U2DqE-Lx9YZOhxs0b{JvjZu6uW6S*}}u^>w=LL)Ge;p0TaT*##ape`}8YhbFE$ zbV1s9nm$M)q!ZH0)AT}`d75rWJER}d5b21tM0z4kk*-KvPtzA^>}fh9t&!gRC(V)W pNPDC|vH`LKvW2JF1KGsW?1F5A?1OCNX?8-k!vEeYV5W-(z5&G687cq( diff --git a/lib/pytz/zoneinfo/Brazil/East b/lib/pytz/zoneinfo/Brazil/East deleted file mode 100644 index 8df63a17bd46413c2c5c4751d96b504cdaae30e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2001 zcmc)Ke@xVM9LMp4$_<>FTfeN-w=u_v3*T^rXjUdeAUF&8W=Li#f*}4R@>h|krE6o; zk(C?H_L*DF<(8i|Tj;Wp)6_XfI$Db%lKfMVE1T(gQrGAC@z4IK|NP#L$L)6iu)UwJ zpr)}tFZ8eH4)+ajo|t>{dDI7=G#~05Q#R1~*GzNxO1>WHZ;{@@PqlX_p?%|iw0(!? z%Y~cwYX6>oxp<*N2ZD%Ptx3~A?^-C=x|Zto(GyI(GOY2FCnS-6-X`|P&COp&=x|%B z8Gm|*PT26hnP?uj66rRRwlwM^BTt!(>bq^mr8P2n>K}G;&q>LgG)6Oz4w|gc70r6D zO&*|YG(Y~e6v#v^=x#7m zuYF?+JGaTSi-S6SXV^S(Drsk|9&MgH-mXv0`Q1F-{TC} znP%qJmS|PzArlm3Y4CHQ%*z<5^G-h~)v1@YdjGJ@ztpWY@AS({XNK&8hAw&ez*)Pn zbf3J^cF-=${mLwEYPUTs;x~NmAdQ~Y~8t~X4yT>y6m&rrr~O!jUBbJyr)2$ zHWkZ?Ll5Z6noL=>E1|2Wr^%Yu`|R3rL(;q;ZkunMm6jR3w&jO|vhLw8?Yd)U%=+OE z?S=zC$;Q5z-L!S5dHuv*ePhX5)B4e7eY1RrY~Hq5Q&Vp5E1B%62!)c#!GV-JlgaPC z4W(5?gV3zGRs0Fuh4KXdeb8Io&-_6r-NR8MhwXL8jT|^~Gq4$Z#R!g$x)nV#tso tV}=YG#8yquK0+>;0Ay9)#t+3 zk}bZ>nTy)KuFRB7CG0lU!6#QOuIr#RZfZxNeh5xY-OuRP!=!ub+|=)G%Y5{uZDV=X zG|IQS>D68Htjo5-0rQ#9+o7vtGraR?Qz!FoWGb+ud)sEL_ui)6rJ2ax=(fbKPZX6) zN=4D#b)rM=PW3EieU-_s@bOt8$N$6DNDh0E&9Sl@*^cZ-8pKKmq(!XsK$;+3kTysk uq!H2yX@&Gcn#D>tq+P7^LmDC-*-1;JC(;z@inK-gB8~CCI(w3Q+WQ7f-vFcl diff --git a/lib/pytz/zoneinfo/CET b/lib/pytz/zoneinfo/CET deleted file mode 100644 index 4c4f8ef9aed8bf567ce727c33ba1b97da6f6ee7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmdVaUrd#C9LMoP#8PJTMTJ8GViBQre&hSvH!T1Zx74a>FV%Kpu{nX^A*^?N^8ZC!O&zq4nrXXm+jE}qXj zylz`lf$tyZYWEKpXP3LUpV~Lgzp-!p%*Fi^QS}cT*MT>sgWY>IGPPBs=U3XPSNs}# zF=(GWUu37B&azJ<$@W?G5?wpcpoC{<*>&9^SzCz`8?!Y%oT3?3%WP)h?@G%2Ny#(5 zl0Wv8{FmNR%DJPu{_{hc_1<$zJ#o^~jzlee|3RDGBg@$Sl+9_5*bN&R?8eHlWtN8Q zra*~hrDfaA(^4!uE~xCwMVk9y{6$(XB(jDlqVa=J%daPWQ*kZ9Ad7#@Ccz zH(>>lAuB8!wxTsJSaEv4l@xSX$z+!;NbS{vvzu(;AMILnGHADdS*y~)dX)_?(j7aO zYH?qhmNaE*Y4<|Avpi10##CFDbzY(1q?N~gq>9Y1t>VIWwmkM7TRt{oE6%-SE2FPk z<>=e0+S6mzM-J<*mKIyp^Nd#Cvs-JLH>>8hW`!#&bhp1+YXkGN_DY^=lgh33i|M-e z@?2Z@`Y&2P9&Z~CC0gCk&vsweC9CfpvyJuRwrR(Yx_|K-)=)R9#*BToxh$%tDaW-X zUE1>fUTvL>Xxm7q9ylA;gD1`I3R&QB7uYgiG`;N1`-WV7Y-yI zNI;N?AR$3wf&>ML3KAA1E=XXI$RMFXV&mz8gG9&Eg$Icb5+Ec(NQjUaAwfc-goFu+ z6A~ySQb?$fSRuheqUGtrg~SU97!olgWJt`ApdnF1!iK~R2^pZkl-QF^K{`u v;^*lCh(r(xAreC*h)5KXFyj9*j`6OP^YdwDpsFyZI43Vqm7j;Xh4Fs@!4?eK diff --git a/lib/pytz/zoneinfo/CST6CDT b/lib/pytz/zoneinfo/CST6CDT deleted file mode 100644 index 5c8a1d9a3ea46457985198597d90f95462a70168..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmdtiUrg0y9LMqJAjKa!NEU@iP+BtNfPkTBQWh|FCY1QEJ@bm3u8lI+uGXvZOMWwP*028h zBHaWB(pBhnuTkAz<>?$VVOz%3q)jmrUOQP|SN^M9zj#zfWPK|UyHa&j+}jd$_*E5c zo|nnzyL8O=M~(MnvyMHn$4q%+kBZyhWNvu2Nlk67FgG?-sGF+tOuRo&-Mk>t+>(~4 z5@yVoX^|5uF>IP7{+^(xUl^C9p=swUL=17@aT&eC_c3E;$7pi$VU(5W6B$YS)lF7RmR13zxGz&jJukJqgmRWRULg&B# zoVjQBh`#qFF^d~d>igPv$^B)o=z_XNDV)=;iwc)Y(I4-s;*5=^czD0^d&`W!f4eFf z%{C9b{DOY)%n~Wx(W;jm&yup5YF)l>sw`cUua`Ank>yD#I02#Hzm3u!XpibeR{*ipXITAe)agNklEOhuAVq@!8BHQmF)h+Y|0%| zPd2`0HpdUCrm{}c6dctpd419{a!PMa=#Z_0$8_t}^|Gy}OK(40B0Jie^-}{rX1FB%TeJkxN4=@f7FYqr$6tc&V zkTD^HLPmuQ3mKQw4h$I?GBjjt$l%b8jt_>%+3|4<5E&uI5Row=gG5G&4AW`Hi44?f zN6Il&WURpM@Ekf9~nOq z03-q&AwXil5dz!3}j9!L0)_;Cafi6BP^kr;9W z5s4xaMkJ0%AdyHSp>*0Zs+IS)XMIy=(QY5AvK}Dj<5mqFw9Dzk5%Mn_q zjV%&fr;RQWUZ;&O5@004NQjXbBSA)@jQ^W3N84J@v(@&M&dtop%<`3HXJ=+-W<~!E D%injH diff --git a/lib/pytz/zoneinfo/Canada/Atlantic b/lib/pytz/zoneinfo/Canada/Atlantic deleted file mode 100644 index 756099abe6cee44295a5566ad6cd0c352fb82e64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3424 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 diff --git a/lib/pytz/zoneinfo/Canada/Eastern b/lib/pytz/zoneinfo/Canada/Eastern deleted file mode 100644 index 1698477a48773fb8f306dc4e8f106011d4d1a60b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3477 zcmd7UdsNSN9LMorBrTVO%!s*+gf6mN(k3G<{Nz%WT>7x+gy}PvWFxzTakk^^ux#UG z?zdTPnZ}aKu(Pv?+($l)=2CoepQwGFpR@n$pZ@dhe0%&({r-ME-!bvY&Exg>uV2G8~V1? z8%l!ICZAvBrc+L_`RQi)eNLd*a^Va4!&hD+dvA)|n(nW*EgvkmC-oCMW_6Z3BRh(m zk=}BbZ(Z?Yk4JL1n-;lk8tB~O6Jn3+1HI?iZMFC68U1s1fyz6StM@J1uJYF`)B97F zr~?_Z^}*;=bto}G{}LFd4m)SbBc7q^sQ+mB+hzJE=&UxvYhgAa$j*J zJy8A?)lOU;?Io}Id5GdjfBkp;w(7dCr@qnXuDa<~rf)txscsb)>XOsDRO#UyeS2S_ zxRZTC>J>SnY|&16cg|9AFC|mnPnanlM5oDzJx7Q~f${QjyBX>q&oKGKeYkq^I8K*e z@1dTa4b{(%Hd7V5eRSpeO66EupuF2Q-CYt1^kThsHZTk##;y?n0?Dw?RkxC#cB6 zg*vKEFBP?8lI~a9TJ>MPKn^$^E}XL_%7MFDiRh6|IVjUr3=RvFL#7vtp*~(RCibX^ zDZeL&g=`YTu6gRX=7&|>p)x(ZVuOlbQ>aH2EmR{ja`dRYNosWBQk{@BPzmQwIcEMu zG1fm*zMJF}iFMNCxX3^;t~6dI`Fe?@-@|0G+dYxIrMa9?d`e8r4Aqm4m8thqee~q) zLX{F*q2;0+^?r!bQ&N_yson?lwCI^?TE!)q+AUM07VVd5jnhP0-fB7XalH5-Yp(q8 zY?zppo+M}QZZ6VCN69%~JA}if3P07VSLNF;)ORZ@kL0^JDl2ohI$Z5%cl*0`M4uQ( z#8C6TW8OhAY?ljf%>Qp(4f8); zA+m|cE?UhtBKv4H8;R^BvX#hQBAbcqCbFH#ej*!+>?pFO$etpbitH+~t;oJw&Bh`- zYc*So>@Bjn$nGNBi|jA5!N?9HTa4^6vdPFUBioGZGqTahPFu}ZBYTZ(HnQ8ub|d?Z zY&f#x$d+5po+F!XHM@>%JF@S{#v?nAY(28~$mS!vk8D4(|40Ln4j?T+dSEq8K)Qgm z0qFzM2&5B8E0A6w%|N<=v;*k}(h#I0NK25OAWgBFt{`ne`hqkDZD;sEYj{j=faW0G zLE3}#2Wb$}A*4k}kB}xIU9y@sA$>v`g>(vO71ArDSxC2#b|L*j8isTXX&KTpq-jXk zkhWP(-;l;3okLoO^bTnr(mkYoNdJ%qA{|6pi1ZL?qSbT}X`|Kj5osjSNu-rXFOg;< z-9*}n^b=_)(ov+PNKcWbB3(t=YBhaD8jExmX)V%Qq`63Uk@h0}MH-BB7-=!mW2DJe z(`BU1R?}ys(N@!Gq}52Tk!B;^M%s<^8)-Pwairx)&yl8EP1ljOTTS1Q##>G2k=7%< zN1BgxA89|*f8+*0?f~Q#K<)wLCP3~2C?cv45#Iz-dmA=g$&*mpEKJ%(W6?{@u~pIUqP7 PsH3w}r+`iYK_34C{Ai2_ diff --git a/lib/pytz/zoneinfo/Canada/Mountain b/lib/pytz/zoneinfo/Canada/Mountain deleted file mode 100644 index 3fa0579891a9762b7c131ec5ece5d6d02495bfc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmdtiZ%oxy9LMnkp}>tlrxHU!BP|I6Mi>RMixs4Hr-gV79MKa` zWy~@ORD#wDQ`cy0pgG+7qjT5gvJx#Ton@mxTP*C}&ig!K>rs!|`riHS>v!St=j~eM zUXw2VansCSc(~Wi!~2XE#!j5?8XVAX4h5_3oiFKb?>4pP#Y=i`+jOz7;S=4Pc~res zc2V|4^{W1ik7d8_Bk^fRnD);9y~$e>Ej};5AWz4AE&iN%MowO;6u!Z1>F@KdQO! zU)DGE99MCkIr8SM18QEmU(Rp%Ox%+Bjl6Z)dtyP4dFNL{V#$7ozH4Z=Si1cuefO>{BDe8`zNc-My0>`0zOQz(%3Jud z&d*z|@_!qZ18x9bN#SgMMv+`6PQPCc}w zNSAs7RatDZc9nmpTvsD?MdmS8@qLo4oO?l3jz-9pzEQDi-?)5utWQ+6dF3O+9iqDS zkX+rhRy^uFscYKX)nmyA^yBqzRU5uT*A*10x+@-CAD^u1k5_7UaHMj-o1+_k_(iSl zTp^!086lqZWXq=p#zkXAjBMKO6;EgWCD%0`66>SR$qmJwVuNo|d$JBF&)8YLF?xsE zI6R^^O?cF^T|N4_FDg}YORL^In4?;%>-3hLu_`cN%IBJ(DLpT6eGjwWa=FtboO$LcGtUb1l(@`ngb1)-u79yKzd6>1EDl*6vOKFsS#2nq)JGc zkUAlSvYJXErQ)a+QY?;YA?4zz7g8{eiXkOKYK9aIsTxu?tEn4OIIF1~QaY=t9a21w z>LKMr>W35%sUT89q=rZlkt!l(w3<31g|wPVBBivNS|Y{ds3uZQj(Q>m<)|o9QjVG; zMMbKLlohEfQdq00EK*vlsV!1mtEnzhUZlQAfjKISl$fK&NRc_JjFg$9&PbuHrqW2M zt)|vUv8|@sNV$=EBLzn)j+7j!IsSi(?l7TWY=WQU%t%R3NlkL5rKO~$q&ofvy_=8y diff --git a/lib/pytz/zoneinfo/Canada/Newfoundland b/lib/pytz/zoneinfo/Canada/Newfoundland deleted file mode 100644 index e7a18d601d0255c26885313540cbe755e009a77d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3638 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 diff --git a/lib/pytz/zoneinfo/Canada/Yukon b/lib/pytz/zoneinfo/Canada/Yukon deleted file mode 100644 index 15216d55ff54fa59031ae33e898950fed4ff15e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2067 zcmc)Ke`wTo9LMpyb3b%B_&`p#b+eDonw#70hub`z{j$lNZEm&m^2|(aKe(lBxpivk zxxpwhVxJN<$gYpWevY=VA>;3#h{ZsU>-{W(S58wM^ z|LpY)ZH{(UdH(fe${P+(Tn_hw#Mz6dwFj1#K`!-#g~>Q#|wY$9p7H9e=Cof z>7^s;Ml?Tpdvv#+7ul$C8bf;i$`xusajni>+-CCTG zFbhvl+dEHOF*>$PFB<&7EDmSu!tSrslA53NUF+XhcjtVji%JrzXlBY5XAP+0$xm&` z4?EPdvD3D6B5ukOhizbVn<8idZW_d%uu5QaPHAP`vTlKwJkr~uM zf4T}@%hxOaxTaQpd{ft5`9!Tw=GuGCy`%0O{@vd9#w+Unp0Di#LvNckEo1h<_Loh4 zxwUKScbT=nOz4KPL#koojBd={sTxO*>Ge|^)I-NdZPORsrg{GnyWzbi)3RlcZ9N(= z53i2cM`Fsf`Ri3dSzyC8pPTTvtMsOYKdVh2`E_JwLTx@dqaT|*qqYoP)sK%I zQ(N0F=qD2U)VAhHyZyx@W=Gk1`()Q1)1EzII~pRUV`|8D71f!pOPw~FSzw~?uCv|W zrOZ=DJM_-Wezhyspr1Z9qk6){x_9`hdZzX^y}Rdv>dTqZ{VgX|e`=161<#w<@@r1ui67=*O~a%K6~)>665iDyuMl9G;eywE%>BT!vkJV zDmB>aNpttv?t5-3^``ME?w%ZX&x_QDJdrjzkIHG4Q!g)CtiJ{cQP} z!*fs$_eCjr4!m&aI5Gib2FMhUIUtijX5o}+AoD;bg3N?J!c>sCAd^96gG>jR4>BQS zMoyU$GACqG$gGfQA@f2ehRh6^8ZtLza>(qE=^^uT$^?-aI%SH;9Fa*PvqYwe%oCX? zGE-!#$Xt=hBC|!Ni_909FfwDOOc|LoGHGPi$h47pBNInvj!YeyJ2H7>_Q>>+`8y>6 zNCupe0wf1cNdl4uBn?O&kVGJvKvIF^0!apv4I~{%KAe&eBqL5q36c}1Bn8O|k`^Q{ zNMex8AgMuegCqyZ4w4=uKS+X*3^^r5NRFJ6BqU2tNfVMMBvDAFkW?YLLXw4K3rQD} zFC<||#+;HeBxg=Z8j>}qqz%a%k~k!DNa~Q>A<09s=kv;ER+=x}myvl3K2p4Pk91G! zC*2$D_59O4c_R^#`pt9o%X9aFre=yK=YItO F{Ry)=ETsSd diff --git a/lib/pytz/zoneinfo/Chile/Continental b/lib/pytz/zoneinfo/Chile/Continental deleted file mode 100644 index de74ddf1a095c9b3d026dfe928a3962da8e42339..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9245 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%0D-JUHu8U_7nCwL!B?@ z$aT+Ta^CLIBTdlP)!VU^Y_FXmJ1ks4uD@*;xj``doT1_TCFDju+2;(6M~o*sI*n8X zeV-=YQ3}+_oPEyF)RBG8(DZc!`pwMP=M2rRlq0*mbmF{xxIUlP{E`K^#Rm2{L(9bX zWY=jg=(mb7*93ikw*i;Qt*5fj8QfbYliT#WPQR_~MHO@HnzPRt+Lf@+89c1m=L{bA zR?+Y9aXRNao|sHl?!+iq*J(5RoWb*Wm?BF0|BE$}{{3TYVr(d9`p?fle}RAg0{;hp zfq#AfK>rqk{`~{J#{B&~1HOtC{&NTK^=~2QuNO4Iw3q%Zg#Y>`g8uK}e}5H$Z_1bd EAL$j&X#fBK diff --git a/lib/pytz/zoneinfo/Chile/EasterIsland b/lib/pytz/zoneinfo/Chile/EasterIsland deleted file mode 100644 index de6b8ff5839fdbdbcab3ac440f8e00a7af78f18c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9007 zcmeI1dsGkmzs6_gTPaDRLXwmuNfSv@j7UNWX(yK?NpeY&LPB!CB$u?4TO>(Fu1Ojp zNhE0}p|r_eNIR1H&HLGFo!?sLob~(foWJ&@o?i33=QDe?*85q{+FuXvz_|mM|8c3v zcj%k0o$@#Ru9?rr`WZ2xTJU1R_sZ|rnZ>eclbZ(_?xy}2J^@2}q_(~2W}pT?V# zSzeCVw>(8MKYB>)cWIMkv2Lx{KYqSsIonU<*K8E59G%1gvjT;I4&}VHFisexK8m-| zxGW4-DHClOO~LlADnI0{xn!62jvsnQL$cpe#5<(cNyFx6@WVHiNW$boam2iHlH*XI$)d_waQvju-t$8 zQd0i^{c3GZ2xpkq)}&ZQskQagVOH(mKj}`E$f`NHdN58SCgX?vlVREa`seY#Z%rF{ zOXyp^6l>%k^n0gP`3l_V*oBlfh?KSnDsK`gZ4)VN6e+ffexc2xOWrOL+AvbuGE&+! zQrb3B+Bj0$I#Sv^sJwlow1K3wg`~8Jq_mBsw2`E=m87(pq_mx+w4tQ5rKGf}q_nN1 zw6UbLwWPGUPd5R3N2fAfb*rNkhm)F7qg zAf@ymr34|R6d|P~fy!w@N{K>BsX|K0LQ3gEN(nYyn<7T^GF0R1+LM^zVIG zukr;PW1=I_d`xXAc%xDycw_zr@TQj);LT?q@-(;QW;S^1&hy}H$CAL?7w-e_*q$ZH zW6aJ8;o#VXiQrw9-rzXbNbv41VIs}#vG4)!`R)bYr!fM&@39>?{-ZH?|7Cq}!XJXb z$k*@jE#Sn9M&JX>tHDY8l)wjP{o>^@=FqZQ@L{0}d}K-i_^9D^aPqL1l03#7W0Jwg z4f4Uqt7E_^EveuWQUEyh`4;fWlhGn0UuoACfKP4q2d5u&1D_6b24`#x667)FjEfmq z3~&XXHB$#?I$MIzb?n2_+<8+i@cFN8!53BP!52$DfG^dSfiIuE56&w7A~EuHWtRxf zK2r+5x+D&qv-1M@n)l!Pn!7k2EZN11@?*^P2@&8ty%6vX+kFDvztQ9YzSSiheCvq~ zIRCph`1Xy-Jk1q6wg=xy9t1ADYyiF+-5Ff8p8?;S{R4b|t-i#_SFvLy_`$3eaEVb4 z_@Ph@E>*7(Y3`9>9{ADwZ15k`oZ%RIb-yWz1zdKtDe!r>!{9)Hw@W<(C;7=>=3ygf#*>3}X_7=fk^cR7@+QotE zmACRV_f0Pp{O#33a6^+P_^(?Nz>QCA!QYQtfq&fakQn)Dis=OYnQQ}Yp3?yS72O5g z;-)3iT6KvByNAGP z`}XrR*Y?y}uzJ`EaJ#L3U=7dd;P#8iG4oj|6vYwHIklTiXPz zU1b2)`PK%ko6CSZm%aseIamYknxi5x@^gBtZ-ToWcmvj-nF8*wA0v zeDh#)aK9LBu!TGN9NT}9l|XZrmUZxXH}pByO0xt!z@h>EfbXApnzPnGpJS~bqtCH} zKBCXDHkUKu55AX(dE5QybL^0d=yR-HIQkqrbYFr*=h%CBVcsDOeU2SA0)37h?ukCf z3OzmX{t-6AG4IHt&#@zWOvm{nU+BRf)rvmHI!Vpo(N%`N96R>l zOYpeBXYj|b&Ih}?~Or z$4+@YAHHX%pUBAP{Ptj@K;y-s4}_xWGRfIs(f2{<6RP^A0wE~C$}fzj#U z`TO_65AxdqUJ$+|-XL>l@WyCSFp{>shG@K<>>h%^@&_#C|2x*QzkfUKS0-Y0c-UqzlVKjJS68apwDHDB;-5fcSr@1Y0 z&hWR+5Ww43`bl(uyMqyU$22GK&hAR!*rBH2*ydVrTsJjvTrDTkbGw_+=h!{BUV`^N zxd(sW@qBRnjdudg?Tjz=zuh z!9QZ`0Y37{6`b5ISYqVolJ8rBkA0W~KAxckPARempNL1FV^h<0!6%n%iu7FC*6-j` zo?pP}%X9>~f7%9pj?M5upJUJHUVtxJqtCJ8U-95f?QG0vR-w)n;X*I%R0u{TtV1V(=T#%=UD_GT^m9DD0T9_I6J)xy6WTZQurj-$`9cY?2j3uDsY z-*rz07x`}k-{aBe*!ym&5+k2q+#vw|gZ^8<4?eqqAGSxIV;@%di!@jI$qoLaEN5`p zeIEQrf*H8{lB+;-k0a3M*ot`cIrfRyNBEV?wctOsEe1dHtOq~ui9W|x*_45++50@5 z^FsF$_{9qmT+>=A(fvQKqtCG~t1f_F9SMbBn;Q>)y(Jdszc~~Eemft1j(rz34g7wr z2mB8{4&aY{(dXDtW4r}MKEJMQ7xa6Z32H)MW188mZHzG^=}yX-!gyj^jyR3 z8t`9nmEcCPMPlUp-$Qc1KVs46*rrK`z(0fY;5QG=7HRI6`!R4!wu3}<2n`B8+uI~ox zZbP5rI;V*O&2?FTKF4+45(m~B?~eIy^FzV86}V?x zJ@`G#I)RPqZ6tcm_?@aVL&NQ-Kq`5wE=yROej52WFkZYJXcen)Z zH?2~jIg9S-b6o$SIpF@kR>J4I9Rl;U`+1tP`neW7ARm2>8(4`x$62RLhd(IW3BJvS zVc@~Xd?k9$b}srHH)Q=tu-#}5{?IulV0%mSInH4e`W!b*6Mc>wZu}Ph@J}@&oijp1 zMS$K%pW_@qpwDq5Gg9D>Dk_BUv||%^bb312c{%zVH)h)ou*+{7@&2(3g2Cek2ZF~> zL7(GXJC6gq4O%2I@_XGHEx_(N?qK(77m@ByY#0EZB$Go6*6guxn-$fslG^{ z``0g^&vALB=yTkSy$j&qJQoZ9)-pG6{_YU)?U_M5Jy)>Q1AJ$gE4Xm74fw8sCAi3b zl03qYE2%`E;~u7<&vB*MPvAe=Pzt{+@hbR_xfj6Y z>nj9$?(yh&aK)T#@RQyV;L1@+;HR4CbKJ9D=yTk&x^SMJt5WiXUsdc4uKpM)(ft=^ z(C4_Cdp_VlcN)Ndd3pr+Rk$6_uib78e(j|XezQ;+{C02)_}%!|;P;)Y!5?hU=eQ4z z=yTjBomzpB-}kBf82q}10`O<)I#2h%l%;{c9!8(z>Mv{qe_Im+zu{o2M00=5LZ9Or zSEJ8y-v#tJ?#Ijp@S6Rz8@O2weUAHOfIi3ldTWOFx3qMG-+D)#Si!tTpHr}@ z=yMA0Hu{`Gv8fooQcAr*bIMCT(D@3L4d`=5WaQ7PYIfX&vO>mFA9LyV5S4)ii zT+gG2z(!IY*m&JqaIeG1z$QWHbBf+;Hh@jXq0cG$%$f%_Gxrr4`JBEkF#@T%I{KWV zpBeg`qThQH`2E$;=M??#wgFqdHOD-Ez8BtSbw>j{U=RA7Vqj_=*m~(3_=DoqB}P8q zW^y5T@DlVnh3&v}@Q{hc@a^;qM4B6Fg+8Yk+KfJ@aL_`ZQ#d@`27lO>Wtbm+brD#2 z5+~4eBMzX?DIBka3ak>R_)lNTD*t@_^B4H%FYtf$7mz>dpGP0{%OCj5AM7W^GOGBf fU*q3D>5lw?zs7j_!2iE}=r8|2Z~FJQv~Bw@1S&kS diff --git a/lib/pytz/zoneinfo/Cuba b/lib/pytz/zoneinfo/Cuba deleted file mode 100644 index 96eaf81ee9e489a84458d298e9fe9d67298a954e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2411 zcmb`{Z%kEn9LMo{`4>Y>O_7W+Qc^1Z({&c0XQ`;cg)eb41vE7Ir;=t42ohT>nZ>dP zr8&q4l`>kXnGT)J&Ju|^s&5cujdBK#2W_r4#uyRYe(%%VT=h(Uzn$|syZ7D)#2c4Yciy*Ff|JufOt=M68n z@0*CzsPBud`v<}_`s6ZeeqDh)a4^P-DfGyLI|Hl*EAn+=?sY46VVXXa*l8__cvBZg z4%&;SS|x6*M<2d=KpyEoqmN$PF7fS$G~uXM5)apEQbUp?*A!|>dA6oLo1tl|6ZA1_ zgLtC*WJ&5NSu)u!OQX7V>2R+;K5;^y=sc_G1Mg_Y$sWnPuv?cMJR{4SeQNDIB&$|> zWYtKMu8xhA)jzk%+Q4yH`-SLJLj#iCQYAUvW9oh5faZRct9dooRGKbme#UHhddCM^ z5H%{koPFw>=$Cczn|0mw5nUhAAnQB&bi-(g6n@;UMSV|7@#{x)GlRNof0exG>CoL}dGb=kaov-ZB73GTNp+G}tFIoD+8Ie&d$Cbo{(Y9# z9j%o5??&{MhHTk;qE8z(CCI+F+cm&_yEo8%%MA*=bJy=bZM$54|2MWf$nQUY$`yL^ z%`a=bKG%ws<|*)*&A8ld-Y(z&&n(3J#lvYa58pHW=2SMuokJ#v%nq3zGCxN%L1c!G zW{Suh9nB<>St8R!=7~%cnW>|hDl%6`Gg)M|$aInUA`?bu#(Xekj+rwsX=K*Ow2^ru z6Gvu_OdXlKqnSK1dq*>UWd2A3kPILxKyrX20m%ZA1|$ziB9KfVsX%gpBm>EYqe%yn z4WDZH4qsbkTJV%o~ zBz;K!kOU$bL{f<45J@7EMI?<#9+5;knoJ_8bTqj{lIdu&iKG+BCz4Pkqex1ToFYj@ zvWlb?$t#jrB(q3r9ZhbL<$4HWqEF)<~@{A-J$uyE`N0VzL z*^VaLNV*+OzLA6@8Ano%wGy=I{N#?W(K#pPjw_JKMSYzCYo$ ztu1-Je>@MlU-^>999;l&O8B&feUTrnj~iT1QQ(b+#nf+qtRM6})Tj z#QCf{Ctlru|6)C{x7Bn0l=WV}sI5mv?A?hmZQFH1eUaUIuXkAeJNxB}`p-VTtU#1I zwd6Uz=wPre>^BWI4BI&$vF$s=cvoIY~?NCHR(ND4>}ND@dEo-Pd}4COnR~j_k=&8wk?fK5k^GSf zKxP1$0%Q)5NkC=+nFeGYkcmKM!qZI!G8f2XAhUr?2QnYXgdj75ObIe4$fO{%f=mlC zFUZ6oGvn!|2ALaAH#x}cAk%})4>Cc>3?Wm5|I;~&al5oIkA?Dw^0N!G13CHrP;S6` HD~Ndj&PSQE diff --git a/lib/pytz/zoneinfo/EST b/lib/pytz/zoneinfo/EST deleted file mode 100644 index 074a4fc76ad816447121db6cd004aa83ea41d437..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 rcmWHE%1kq2zyORu5fFv}5S!)y|D78c7+ixxfSeFA^>G2Un{ojFs8bC{ diff --git a/lib/pytz/zoneinfo/EST5EDT b/lib/pytz/zoneinfo/EST5EDT deleted file mode 100644 index 54541fc271644e44973989a27f3846a16800caf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmdtiZ%oxy9LMnslIR5zDhd^;pkg5Z?J6P_CXB9jh4f-bre6)bLnuyaHz>oJDCyQ* z)1ZH&EHi6!WMy%7`BeL=@QuFW_VkvO@cuBz2CzT&)!FFGdi&rMbnlXuI+eLIcU zY>@=LStWk+hE6&XQdb}D(v#lVWRhQ6ty8u(nQJ=k(bqOto9mY5>QsM@xqfz{z9A>U zq-EyF>eAug&FryHblHhBX3lqgy1f54b;rj~ z>pQo9sqT7Zm9A)eU(M~>D0kQFRP!2FN@ZbKRaMTDs?oisI)8<(9^7X9NprRTK&zQQ zlBE~Cx>eo#b%g{rw5Ww2W=hSnfU50@ll#gG)uP9SWpR3n3f7&J;Mk~I;(J$?{5Z+f zXPnUW$1j?tk-fTM_n>)TXq#Tvb!a3$+A3P%FDzWL18TdMFf-#-w)D zR9z@dBMmB)og$%A<*Ir7s5I}(P-}+2l9rw_(|Y=%emI2!s9mmjkuf8KMn;Vc8yPn;aAf4j(4BVd$l#IDBg03=j|2dT z01^Tu21pQ)C?H`#;(!FgX(NGz!f9iH1Otf%5)LFDNI;N?AR$3wf&>ML3KAA1E=XXI z$RMF{+Snk$L860%2Z;|7AS6Oah>#c|K|-R0gb9fg5-6vQ6cQ?@jTI6sr;Qd8E+k$^ zz>tU`Awyz@1PzHA5;i1mNZ_0{a!BZ$Hg-txoHlw$_>lM^0YoB*gb;}#5=115NEneg zB7sCAiGh0lNKlceB4I`1iUbykED~C$jV%&fr;RQW uUZ;&O5@004NQjXbBSA)@jQ^W3du^?Kw%U1t83iQ;MR|eZ;)3FWBJbZZQm>H! diff --git a/lib/pytz/zoneinfo/Egypt b/lib/pytz/zoneinfo/Egypt deleted file mode 100644 index d3730dfbc1d2c88298e08b2362b9d6de80a0cc5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1901 zcmcK5eQ1?c0LSrj?_QkOX@(ks)h^n@Fw411QLs3b>bkejlD zh*BA$`$H*6$%;~YG0j?}kU`Cv?MYcef}Kg^Qk$o_DZ9GX`5vSK#s54Hm(Rn-h5d29 zzm+dqzI3v<<)qu6@Zr?h5AS^&>ksP2RBdqV#%0~~eOqw+_{aVazm5-1>}%COe%Bc^ zzp+#YAFd64+UV<(uYTmU6)o}GIwyJ;`Zf3$TKwSRrIfk!`HSMu<~q~9y+d67^nf&L z^VDBke>WYA7K$s?BV_0FEvl~3umsqPYU{b-N6aps8W zd2fUI`|A$byXlY+Z|9lNvOiR~ZlO$@8x!eOXJy8OcSPo_sOgj4qO!&&WLA4$5y^Pj zM4IEO-}xSsz5g54|5%|Mu&qnnv*!gfa8167zP3XSs;Cr$SH|8PS z`EfEYZ-II+{;eFBxmo1LuA2PwU#S97YYLi5)r8hh!}4n@Mvj+E{c2>6zBi!7hh@iO0vH6OHS?grnSB4Pd`xa#T(c8 zkJZ2A&G=xkUt0Z)H*;%^e!Q|ecw%*>o)xbMWJ$X>Nkxgz8L?}@~Ma*;@s z+h2wFy(qu^wY6X3i|*9keDB|D&-%mj4yIRWWPqfA^W~7R(`JmMjO2_YjbzOsZ6t3baU^pNsUx{_NFK=^Ngv6d!vr|( z3?NhBv~z$=0x}C6rU97;WFnB6K&Aqj3uH2o*+8ZPnGa+_oOVW#DRJ64K_&&66=YhF zc|j%ynHgkikhwu72bmpYdXV`+Cdg@L2$>?Mog-wDkXb^e37IFSohYZBsc`5nJ!$E8 ke8M67-!PWs&#-G{-|br2+x_2raz11A?_%AYED?$P16^j0-~a#s diff --git a/lib/pytz/zoneinfo/Eire b/lib/pytz/zoneinfo/Eire deleted file mode 100644 index 3dec02693d78bbad11809142cc4b6c0502c45129..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3533 zcmbW(c~I149LMoRa?*K0WIM~|63f1UYg)@<|f^ybFAxmwT3zHH`>oTcYY*l6ab ztTGD{F6jmN39f~0pVW)mm+69zQM#b2+AMZ$GmFcc=p~h>_0kO)dfBF*b>X5E{i(?{ z%ir?o74L2}D>IW!QPxURJRsVXBo5V|d6fA)HruQUIcvUXlxn^>^@~|u>C&Y;&*(3A z57A$(+NQr=am9S|L5W^7Gfc0|nXbQmxkj%`&DHA%&Ntt68>Y+R*6IzZ+s%fGAoEM& z&#JstYqLG&Bef%{gWefERqwp;o~{Va)D>07_3lH>%%1PJ=)LPNn0>{^%&&z_^>6u` z&Hk*1%z-iE^}#_M&F@|@hhpoS!|}`Xk+4X8w6WJ5y;M(E){N7~Do*ICy@U1f)j#SJ zMHkJ<4_D|@uZ=RNKc1-1j7T(R^V0Mm{nGWHX+8A0)(y;G2@(3d>y)Vu_tVwC{bVj& zIifGFDKeLi`kKoVmYA9irJ25&Wx8%;s`eXDp#6j5bbx2F4ybIQgH(nN+IU5~Pp9a5 zE1R48TRpnLw96)Vc_SS%Zl6&zqD{krYfPhDWp0a^YZ|AXHBBO_q-nP@Y3BQbgoYMK z=)q6r_Ug&feBCq&+rLP)SX!uBu6;+fnj$KE&KRXLvQ+EWlGPnaUKKH-lWG&yRkiKc zU)t3VRqZ?8CGF33mPmJqM3y&|j+JNR&f;o`+O$pX%CC^l8 z_fP5}2{T*B1L+acz?O5M>&9y`}T4gKs-8CLFAkDG>Sc=2)dMBX1NEq{x8GOb*Vn0QQ{O88toJ$$n~ z6Fx(Yj4zb*z!DkNQe@Q8>GEt%mW`qN2`}6^o6MSBBwysyXCwIxq%NME%TT11X8Q;pp z!rAg_?tICcnkPQKb*?}C>iXXL>F;Ns|KaDH-xLs3`xgcV-R$XivoHVecUP}o3}J}^ z!+q+yT*1mGkiWU=JMZl$H@**6u4_N@&*u*&dtHfxy{?}2)z`jvxqN(loIm+zJbZk- z|2~5C?3cWF9JVjsH@<2gLw<7aK?c#$jv_LQ$T%VciHsyNl*m{jgNckLGMvbGI@$q6 zMid!RWK13HpdzE{XonRUS7cz3kwu0U8Czs}p?9=nj|{$} z9erf@k?}_YfJ6WZ0TKfw2uKu=Fd%V20)a#V2?Y`hM;ik#HjML;{LL6bUI3Q%4(A9z+!hD-u^Eut;Q) z&^p@KBEfaE(M7_G#1{!L5@967NQ{vnBT+`ejKmoUG!khf)JUw6U_07qBjI+m@kRoU zL>vh@5_2TzNYs(ABXLIpk3=2`Jra8)_>MOENcbIX{E-6yIRcPF067Mbg8(@Ski!5u z4v+%@ITDaV0XY_sg8?}jki)^z9uLR?fgBOYA%Pqd$U%V|706+M92dxefgBmgp@AG5 z$iaae9mwI~Xpax%0CBWO2y%!Z#|UzeAV&#um>|aqItNOf8%_v+zq+@62Kd|OfA~4) zHwC(D|H2^m&7S@@`||&OXE)RSS9ImFwEiT)Smd llD$o8-zv3^75jnPo-rPK(nKZS9o;3`(>>5VCc0*?`TkGv)#SJ1q}N diff --git a/lib/pytz/zoneinfo/Etc/GMT+4 b/lib/pytz/zoneinfo/Etc/GMT+4 deleted file mode 100644 index 0ad0ee3229bd1a4dae7670cfc3c0514d6da97aae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 vcmWHE%1kq2zyORu5fFv}5S#7)|KkT37~FkBv`v8A5VCc0*?`TkGvNXNFSQR6 diff --git a/lib/pytz/zoneinfo/Etc/GMT+5 b/lib/pytz/zoneinfo/Etc/GMT+5 deleted file mode 100644 index e53f3febecf64fa59b36cc90405bcb6afc79e692..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 vcmWHE%1kq2zyORu5fFv}5S#7)|D78c7~FkBv`vBB5VCc0*?`TkGvxvRBs~t= diff --git a/lib/pytz/zoneinfo/Etc/GMT+6 b/lib/pytz/zoneinfo/Etc/GMT+6 deleted file mode 100644 index b41149616a316b2647b3bfbf65ffb55fdfefb3a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 vcmWHE%1kq2zyORu5fFv}5S#7)|J4f^7~FkBw9SCr5VCc0*?`TkGvfjP7{v~v diff --git a/lib/pytz/zoneinfo/Etc/GMT+7 b/lib/pytz/zoneinfo/Etc/GMT+7 deleted file mode 100644 index 32fa6dcb42ccb1f685fb3cdb363b52ea61294ca0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 vcmWHE%1kq2zyORu5fFv}5S#7)|G5(w7~FkBw9SFs5VCc0*?`TkGv@*T4NVSe diff --git a/lib/pytz/zoneinfo/Etc/GMT+8 b/lib/pytz/zoneinfo/Etc/GMT+8 deleted file mode 100644 index 512578ca6d7c1e49ff5fdb0ec788e61fb414c27c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 ucmWHE%1kq2zyORu5fFv}5S#7)|NaIB26x{OZ3`ebglwH$HefUCEVuvx)ebTM diff --git a/lib/pytz/zoneinfo/Etc/GMT+9 b/lib/pytz/zoneinfo/Etc/GMT+9 deleted file mode 100644 index d3e47e7b24e591d3d50c317d8e5c6c849a2273b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 ucmWHE%1kq2zyORu5fFv}5S#7)|Hc9a26x{OZA&0GglwH$HefUCEV%&oP7V41 diff --git a/lib/pytz/zoneinfo/Etc/GMT-0 b/lib/pytz/zoneinfo/Etc/GMT-0 deleted file mode 100644 index 2ee14295f108ab15ee013cd912e7688407fa3cde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5SstA40xXE*pp`c0iN30C@!qNdN!< diff --git a/lib/pytz/zoneinfo/Etc/GMT-11 b/lib/pytz/zoneinfo/Etc/GMT-11 deleted file mode 100644 index f1af0e290c988923609d96c86c23f03ea10b6671..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131 xcmWHE%1kq2zyORu5fFv}5SyKWVb%r)26x{OT|+}4KZJa(Ts9C>?0_b50RV?0_b50RW)d3<&@L diff --git a/lib/pytz/zoneinfo/Etc/GMT-14 b/lib/pytz/zoneinfo/Etc/GMT-14 deleted file mode 100644 index 41c6a1d1ca0a7bd4f391c13e069307859dff1924..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131 xcmWHE%1kq2zyORu5fFv}5SyKW;m89926x{OT|*NfKZJa(Ts9C>?0_b50RXNc3`qb0 diff --git a/lib/pytz/zoneinfo/Etc/GMT-2 b/lib/pytz/zoneinfo/Etc/GMT-2 deleted file mode 100644 index 9f63268d09e0b2dff05a1ee179beab9b51ccbccc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 ucmWHE%1kq2zyORu5fFv}5SxvGK}Lar!QD4R7o;PEY@J*-U^DD=jko~hk_f8+ diff --git a/lib/pytz/zoneinfo/Etc/GMT-3 b/lib/pytz/zoneinfo/Etc/GMT-3 deleted file mode 100644 index 38ccd8a6108b6e1001a80414f799a10a6e1ae166..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 vcmWHE%1kq2zyORu5fFv}5SxvGLCb)F!QD4R*BHnRAzLSx4cH7jU1Kf)@c{_y diff --git a/lib/pytz/zoneinfo/Etc/GMT-4 b/lib/pytz/zoneinfo/Etc/GMT-4 deleted file mode 100644 index 43badfb220c42d1577a376c2ce455faa3b35cc7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 vcmWHE%1kq2zyORu5fFv}5SxvG!NP%o!QD4R*96E7AzLSx4cH7jT@x+<{cs5@ diff --git a/lib/pytz/zoneinfo/Etc/GMT-5 b/lib/pytz/zoneinfo/Etc/GMT-5 deleted file mode 100644 index c88cf210c3ba7b6607e57b976ff35e74d7a24d70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 vcmWHE%1kq2zyORu5fFv}5SxvG!7YG+!QD4R*A&PNAzLSx4cH7jT~jUq3GNAN diff --git a/lib/pytz/zoneinfo/Etc/GMT-6 b/lib/pytz/zoneinfo/Etc/GMT-6 deleted file mode 100644 index c1a0634cf5ca81e8d51493b3e7ed1ce53bff6eed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 vcmWHE%1kq2zyORu5fFv}5SxvGAtZr;!QD4R*9^!FAzLSx4cH7jT{A8K7F`Le diff --git a/lib/pytz/zoneinfo/Etc/GMT-7 b/lib/pytz/zoneinfo/Etc/GMT-7 deleted file mode 100644 index bc152efdaf3c9c522cefa7f304db8a4facb1fb63..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 127 vcmWHE%1kq2zyORu5fFv}5SxvGA*q0Y!QD4R*Br6^LgS&5tt|gEgLbgsW8?YI6x|Uo3JE{t6 diff --git a/lib/pytz/zoneinfo/Etc/GMT0 b/lib/pytz/zoneinfo/Etc/GMT0 deleted file mode 100644 index 2ee14295f108ab15ee013cd912e7688407fa3cde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5SsN_@rKW4sm0gV7%&9e2zxQEXT(0?_=f^p(!!!P2jQ7VgVOCy$ z>pxe3`GlLR#@xJjTxrK%UD^0$_NsGx?A2xa?T;#=>@~|n?X{ZZtSh=@uP=ynHe{Z+ z%QAeNjR|#jdDKLwBKn}SY0_n9v+o9HbJGNS%az4WW%MPx^7ssA>(6<1RmEs$Tf+*c z`t9D%_U&Dq9R*L?A1@nc*JSjvcg|hx?25DP-JZSno_0<4-r>d0-e1nxwc&G|+Ot=k zy4xG=`aKQKzVm0D{U2642kLX2gT>37Llq~TLl<(g4`Zr{R~kX@@V?YRALxYp1$;iKwiS&a2i) z7e}S*f;XgFexY>Fo+b~adL(jaiaZ>XAW;#~@`xQS(LTu+J#3$CufN>wlz|N~Bp?|R?G?&PrPNh2N z;#3*@dyx*QPnO5N&eEaflQpq+h(5j~Nr$bB(BXNJnzU%JJTcNolXE-Ch^Q-?lH4pK zeLm4qk>ALurtf5Q>w_}7;eC>}kONR57j(zrB9hW~{ z$3L2{p43tLOjx>R#`M(8n{k>IGE%a>3fAXt^pFX=e$|PM{*t{mNOEef%A}I(GP$%t zrc7>>sSAJ9=ZEc--MemiwWXVn?sFV~sPg*xlRe0|}fM_=4DQS*<@ zk(b^{)Y;|Z<>i@OwP49WnKO2%6y}A=+B6ej`uhAbEm>NkmRGCR_jn%g_A#f8ub+Et|F-w*SXOYEm-%P( zF15VxeD|)l{LCi@yzIZ8fno(&Rzx?ikUO6(pYu!~@3E57JXU%NxA`X7yd?8tSzhKc z55E4n%r~C97bDR85I5IObMxNi4|BB&9-EKU!_^c7sR&XMq$WsFkg6bMLF$4O2B{2E z8l*NzaggdD<#9FjK?;Oa$kmhxsS#2nq)JGckUAlSLMnxn3aJ%RETmdUxsZCfnt~w} zb2TMHYK9aIsTxu?q;5#zkjlB5(jm1&iicDWDIZclq<}~TkrE;`M2d)15h){5NB+1J z($!QFDJ4=%q?kxGk#ZvSL<)*j6e%fEQ&&?|q^d|+k-8##T%@{4d6D`e z1x6~2lo+WoQe;0tZ`mvocY4NcGW8-4d L`o&@2c>g~E-dmAr diff --git a/lib/pytz/zoneinfo/Europe/Andorra b/lib/pytz/zoneinfo/Europe/Andorra deleted file mode 100644 index cf9533a3e4d5acb318419d5829880e7197a13a16..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1725 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 diff --git a/lib/pytz/zoneinfo/Europe/Belgrade b/lib/pytz/zoneinfo/Europe/Belgrade deleted file mode 100644 index 5f0389f03919e0b56de9cf4bf89b591a0e8e9c2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1931 zcmciCdrXye9LMqJ0gf0e_BBV4fRKcs9qyMvq*P#xOmk@LILW%&JA8Gc|lUfA0qKa}Qa zn76ty?D`RX{>L7ja&ni3A3Y`!hx#P)lTT%8hf36z_awT$NnTh{Bh!j~5|izf7u}f> z8xbedpAM5amq+97rfd9-Se-HQoX$KQs4w;Zq3#2>HKFUWCT>5gNt=#pa_wPFsk|hq zP5qLVGa%_pKa`BfZpln-k<9Tn$qMh%tSc*J*289LLzmr4*7A@7DZluvzJ51e zD!%$%myZO=ik?YQ+5f9lwf!d5T|@Fl^@yz8`irj0{aR`&2eme8kF3t=)4GXY>Y7N^ zHMc&}wc|~??o6w$zv9z34=&gGZ#T$WJ94z4w@lt%8>Nly8M0wXwlvj+%EpwbvdMd2 zHczsoIVnV&?_86X;CtFKd`eo!F6ld8^vb(K1G;6;3EkS)t=n1;Xj^BS`rCfyw#+BM z^(1f03KkC9qwk1lJHWF3`^|fg*JqwGpJmxLA9LBZ@9~E>(EO2ytJOUGe&$beRb}6K z1v$vbVMY!#a;TAmjT~-AbHI^9jvRFUaSpqqIq=A#M-D!6_>lmR2#^qv7?2>4D3CCa zIFLY)NRUvFSR73-NHj<|NIXbDNJL0TNK8mjNK{BzNL)x@NMuN8NNkQKI3zkp6CM&D z5+D*G5+V{K5+o8O5+)KS5-1WW5-Jia5-bv}qX`#@*U`x#Et}yMDJ+AN8)!h1AvSGG6cvNAcKI60x}H9I3NRoj07?i$XFnQfs6(+9LRV$ zngKyZ1Q`-!OprlAMgPfEo*WX|A}C+%sxH(HY+vJ*{XlOd0$+@R{gzK{|=V< a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/Berlin b/lib/pytz/zoneinfo/Europe/Berlin deleted file mode 100644 index 96059c7854e1f571ddf97fd285a28df361c4c99d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2309 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 TS!vm6zVxgVe}>O_n(qA@15Z9| diff --git a/lib/pytz/zoneinfo/Europe/Budapest b/lib/pytz/zoneinfo/Europe/Budapest deleted file mode 100644 index 1b787b16cea3331865da27115642fd1e3461ad0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2407 zcmciCZA?~m7{~E*^Ps_uU1W$RC`AMm@+^r#W_Q3yFp)bW5Wz%zhzN-sl*UTuTqAeY z$cBg_5?M293+)A3Q?uzpB8&{wWukyRFwC4~bM^lona$N}&wq!{**UymY`?E7cSUim z^`C2udBe@M#oRo5)sOQptncX?+1lHx4b6LWTXas@w)estx4+#kja#~db`(`(HAzdEb5s*xf3DTer)U z8kMPQUX`Gda=Clq61gYCCBaE4a&JU}gam}jed8udsHamyFUM=x`4A27nV|O{9;*+u z{h<-f7j#-}pGL0#N~0?FX>`$t8k65EvE^+Nm)tJ#^Eb=%zy?W(t(1go)iPspt&ynm<6Y5hPlIzHFTO*Jxi_YQrcv{dHRtkbNgUf200OEvq! z5_M&y>689*bwNb9F1Qk{Iew{=`*uFl_mKdS~RszmL|7q@ojr_S)l5&p?7rowQ^l?q)JzwcImUb^0eg3Rr1`% zWG!vUmgkpG)v^uKWmQ&^lo$KU3o%oqBIQqc(btmIQGU956SOrm zM5c($5t$@1OJthJJdueaGexF~%oUlet(h${U1Yw#NJ@~LAW1>8f}{n>i>*lvk{Kj5NN$kiAlX6EgX9NE5RxGzMM#d2Bq3Qs(uCy6 z)+7qal&wh>k}D)xNVbr4A^AcQhGYy$8Im(3X-L+Pv>|yz5{G2Y)}#)}ovle8l077S zNdAxnA{j(dh~yASB9cWUjYuAmL?W5AHK{~$X={>+WD`jzl20U|NJf#AA~{8piewc@ zE0R|vu}Ef-)FQdHHOWP?i=-FHFOpy+!$^ve93x3avW%n|$up8@B-2Q$kzCuFWFy(O zHR(q3jU*h&IFfQC=Sb3#th+s6 q&Cfn!jlRjqB@#_IW=yUTL5)*qf{&-ol4&Msr) z_rX&``$Cr2L9etbi&hDee>5twp zJ~{HTapv_V6ujn3UZhCJnTR+}J%b_tJ7P<&TYW>S>R7q`zEFJ6tLAI;P6}Z8PNbH{)bMb+VkX zb&8l-WS5?*STSq#6Vntq?taf}TSH?@Z z^6G1{W}sfK>TZ-zU-HS-N0!Li3v0!i?Rm29aG7|fCQ&}SZK7B^f10STc8hgc31WTW zZ(_p;O>E4Fk{it*M1$*&Z18u9#v9+s=i3j9O}!nmY43U2+_qnCZagGgcD6`c$dI9T zFS{c&EHunHEU>~O2A5O48e$(@k*<5aG%e;9f6UPhT8O5N%d|N(EpC(+8N3HhTtXYc zi7hI4&n>XU@V=H1ya!K$pWrF=X*1O>EG*;Z(>&HzUzC>3QhSd2sWw|+s|OzccG+yc zf1g01USf0YP@Cs5f2wQIiSA#KX+$OxnMzAFnaFe^6N*eJGO5V4A`^>DEi$>t^db|C zOffRa$TTApjZ8H%*~oMw6OK$dGU>>)tKUgu;*qIGCf`y`KT-gs0!Rsv8X!eLs(_RM zsRL37q!LIekXj(cK&oM>%7N4aDF{*#q$HNACP-0`svu=S>VgyosSHvYq&7%#km?}i zLF$7P$Wm1ZDUqeB5mF?iN=TWIIw6HZDut8^sTEQzq*_S1ka{5nLn?-p%u>}1DVn9K z8d5f-Zb;#f$|0pgYKIgLsUA{3q<%;NkqROuv{W@jifE~-h?EhjBT`7Dl1M3$S|Y_n zs)>{nsV7oUq@qYkk(we!wNzC_%8Jw#DJ)W1q_jwFk>VoNMaqlR7b!4OVWh-JjgcZ- zswyL8wp4XS3XN16DK%1Sq}WKc(JJ>4`_PcPSLm=XN0=kr8CVgKgDYIUY7ZS;uHpB3 zsZm$4wgRrwtpcvTQn`+>(rx9MXa`PQLJOpOq!n;=SGf+PJIM;Tx(82!pHQOW{eL3< h9~D>Ma;o%?&*q;%TIq!JiRqac6VghvGOec^=U=5NntcEO diff --git a/lib/pytz/zoneinfo/Europe/Copenhagen b/lib/pytz/zoneinfo/Europe/Copenhagen deleted file mode 100644 index af7e9269e5e4517167db0f74284cff125104bd93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2134 zcmciCdrXye9LMqJh(`^LebL}p+%zP#j@-dZpy~0zOpc|TlvKnEq7KU_iwp@8@>SoR^WBGeO&SA^HeV#qf>)CV8ALozr zdHd&8lxJA~I|i6HTpU}?#q$%*@r{d`Lr1$iJ#$xeU7jH)KXqyFBafVVKTEndCCLwg zXgNJf^i17WIUCcep@ppyy7;s76r9kWW5;D^aObUIzG?DQ=HD8XcwM81omW@bNp;;m zs>3gRu1}xYr_X%-p2i$LBC!YBByRU!iEmU%ShrC|R0d?^f~E3op>9Tq~y^`-dp#_N-rQpVIGCk}onI7zvmoI%RGul3r!meZL z+tDa94}7SvR8`5Vjhl7W-0eEMa+wy5t5knsfxhONsdL<8bk5y0Esn~U;+~=U`km1- z@6aDQKNKzt_C-ob`|q-_{XZ$K+L>-3Eaetq+k`C9p1wY;@0PpevrWaWwkUDc2+)w6OXQ0|hq)8l2e_b*u! zX-Q3Ll-At(MQS7NYHjy7Qg`E=zVk(ktPOVPx?RV0ecK-0P`6*}chsxpu=<5PbUOMw zAOC4tu_GMj9~vQ+^TGZ8o4)rRZ;{{fc>U&U4s#fc{zw1&2bmAKINmiE&yoL{qoUzd zJ5~?5nT0IE)~o_q2C@!hA;?OQr66lT7K5w?Sq`!uWI?uOMaYtD&6@aeEDBi_vMgj> z$ik47*_x#xYeN=?tPWWovOZ*i$O@4qB5OnziL4S?CbCXsp~y;+rP`XcB8x>^21pT*Dj;P* z>VOmisRU9Aq!vgqY)v(ga@d-BAO%4xf|LZQ2~rfKDo9z7x*&x?Dua{;sSQ#bTT>mR zJhrAjNP&5>h6lPDr7UN+G2}YK0UFsTNW$TT?HjU`WM~k|8xiiiT7T zDH~EZq;N>(kkTQwLyCt~4=JCmsUK26TT?-#gh&mMA|h2p%81kvDWrou{-=py0|q|+ z)3OG4@srHGzuij{wFt4Ed~i3VG;i+Td0*%=x#a5WW?wmZ3O6wwo6g5>UuH^nN}Ai3 Ko`$KJ;r9TrbtOpv diff --git a/lib/pytz/zoneinfo/Europe/Dublin b/lib/pytz/zoneinfo/Europe/Dublin deleted file mode 100644 index 3dec02693d78bbad11809142cc4b6c0502c45129..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3533 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 diff --git a/lib/pytz/zoneinfo/Europe/Guernsey b/lib/pytz/zoneinfo/Europe/Guernsey deleted file mode 100644 index fe63ff7e7f1e9b47c45c62a7768e3924f8572c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3661 zcmbW(dvwor9LMqR%&_J1Ax7r%(OjC={5F?_C4|PdTz>J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/Europe/Helsinki b/lib/pytz/zoneinfo/Europe/Helsinki deleted file mode 100644 index 19d7babd531f6623710debe40497c4a50e4e613e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1883 zcmciCe@x7A9LMoHb$&GL9m_=}B>8db`sr8sl`B6A>5w1Ek0d07R(_R)G;fuOzU+d7CM;cvqS7X*+R(Jjxjm>>1aU~5BpVBA^GxkYh*bzyJE0d(Q3KII`T@YjC!1-$#r>}(l}B_?;NLN4u$I2f(RW~HA2RxIW#ptL?%SOR8MM~ zq&eNr`CXMszS}bS*$J6ae@Zf%n>2GzwM;#IT&EQm%k=8)nl*d3&L~={ z*~5y|n~|5Ce{C2snX!YvKlk>Fb)>>J$ zD@BXzvSoE)xUSimC~LElrKG?q>tcJ$de2wc5NMOqm>?~E|5VDle%7*kH>CXCL*00; zPB!@(b@Rb%x~2YzZY{6XiaizD&ThT^{Qu|MW^)#DS%cknf153|kFC@1&l5AfHjgKp zFE78c+pRC}zc01D`6nM>OcxXDnUv?YC(!YszJ&@ z>Ol%ZDnd#^YO*v%AyrwLvXHuv!jQ_4(vaGa;*jc)@{szF0+9-l5|J8_B9SUBO_@lY zmZngoQlwO*R-{;@TBKa0UZh~8Vx(lGW~6AOYD-f#Qn#fk9H|^B9jP5D9;qHFAE_T% z0AvM_B|z2ySp;MikYzyD!O|=QvJ%KrAZvjv2C^E+avtbmZ23Z+Pvoy%sAd7>n4zfJR`XCF0tdQNWo%Qy2{LlBV88TyJX2^_DM{A6_{QjI_ k#^}#M`ngEvJHRZ|&^Wfrl^GwM810UUcV))9t*3;59}7mUG5`Po diff --git a/lib/pytz/zoneinfo/Europe/Isle_of_Man b/lib/pytz/zoneinfo/Europe/Isle_of_Man deleted file mode 100644 index fe63ff7e7f1e9b47c45c62a7768e3924f8572c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3661 zcmbW(dvwor9LMqR%&_J1Ax7r%(OjC={5F?_C4|PdTz>J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/Europe/Istanbul b/lib/pytz/zoneinfo/Europe/Istanbul deleted file mode 100644 index 864099556bc9875b7e9258af6c3b221d84c68eae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2721 zcmbu=eN0tl0LSrj?*%TGp*>oNB#Na7Dk`8T7>I?)RInpn%@p#ah?qpj*NHE2r_N=$ zd|WhjR3jyF>ZqmJ)KV*#7MeYsa;6 zFiz#T^_Kh&!LRx*vrhNF96aMIwp!gAjn)g<*4LM}8D~!v>E}*aM%%9S)-PA~8o!q8 zv)aqTjNjwZEvCM;{@Lpe}`C{s8eP@RU zBW$k~DVmMQ*4}!Dx(uUZ{RaJk)!huSW`W*$_NK-M3x;YBeUwLl2Ftb?Kv3e z>K)M-v$k4~Ial2nd*r0my(UWUv2LXnw|s%tv%Exmq-c`%X#QxeSLQIScT%Dj9~-0f ziHy(^Lel~X?On~p^FFihsXxqqhcBA_cb_wp>b@`sR39)0u71xPw6NApF4Q>WQOZ_KdMyDc%(+eXjbb*%kF?gcYv=AZVc_+w^nPSDQXlo}izdQ|51`bOkk`az8G91>%i zo5a}fw~BEM+eQBIgR)?Kn;gIMZTVzHh0xcnk`tbKSr(Shk`srOOMiZzoD@A?PEP78 zCtppLQ=&$TDW^Njr`r?7)IC?^w3Y}_RNF}u@BUdlQ}vseUfnE==`G^f6+g)t*&m6S z#m8ky+-5N=t3j5Ae<){nmvZ)x8)eyz`EpKErF^cv*`bbv? zzR^10`TgzRj4AMIxw#Yh$FKPd)r-H-&!5pWmpXsHsaOAhU+@U^13sLc>cjiPH`STE zr|ArG*^vwHs4hKn@sZ1q1OSNu5&|R!NDv%V6p%0=aXpVNLU z5>zCrNLU?JT#>*!s>mXtMPiEt7l|$sUL?LqfRP9zAx2`11R04k5@tsgXC%-_q#aeL zkytybU?b5+!i~fm2{;mQB;-iUk)R_{N5YQ89SJ-Vc}Ep`B=(Lf_(=4T@FVd@1^^iW zWC)NkKn4LB1!NeIaX`3Kj0!R=$haT_ zgNzI^G|1REs=+}<$59OrGCs%vAtQtg5i&-|AR(jV^0@Ei2?@RRxIJOsyL~+2zWaI9 zDmfQeZIfChwL9U?HmOxo+tkU~rY?7WfBQH2YMcINpZ+;e>ODd&*nm{FEU94dz_fwM Pg9axRq$E3ULn8hH9ONz6 diff --git a/lib/pytz/zoneinfo/Europe/Jersey b/lib/pytz/zoneinfo/Europe/Jersey deleted file mode 100644 index fe63ff7e7f1e9b47c45c62a7768e3924f8572c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3661 zcmbW(dvwor9LMqR%&_J1Ax7r%(OjC={5F?_C4|PdTz>J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/Europe/Kaliningrad b/lib/pytz/zoneinfo/Europe/Kaliningrad deleted file mode 100644 index fa6bab8620370007ccb2a308c44b84ba8b596286..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1494 zcmai!TS${(7=YiE^DuQTLgy(n%|mKsT4rUnn$tXmrQLLZE+i^~w7QJ=2#JWOb&xK! z42dF0A*zcqp`eQ(vlRu^DuRf>i~4UOD5Boyx51*&_v8DY&(AS7d>-33@7hrz|4fSB zu$dO!oO61UyxV(UytevY4F%6%x)r=|I~eTmJ{NqL&=nm0)Z}@5)f*fe@Oz$|UhD}S zF7SlDJ362CbZ>ulY_RoNxbS^y(UnkI`Wv4&KHTd4o^mgJ+#SjY`+b?CXF^$bFIw5x zPFb`14qG|L_gk|Mc38Q4Hd%AF)>(PYORfBxVry<$hE^8m8ZnhOs-+_@PIdhWey=^tx#|aY)25ZF*!mW1MlZ z6DvL;YPk}Vl3j^YFSkf`u0#J4ZjU(sK9`hppPkEnwa<|tQc^C-k!R$_F~fdM8u!s> z$@B->+QlDemzK6#-AxkUBA^#_y7gP|_WFeOkstp|`~Ma4=&#w#dflA!e(CHT*s>0y zlTB3$q7_6fh+YuIAeuo`gXjiP4x$}IJ)5c@L_vs#HdRIaEP{>@B_UecR5c-bLKKB) z3Q-lJD@0j{wh(n8`a%?jXbe#qqBBHkh}ICbZK~c7#UYwQREOveQ68c_M16?hc149xFSumtwQ}bX*#HMD#kP0LhhGZbwK+=Ka14#&y5hNvsoFGXtWCcl!AumW` zHZ?Pb)NE>Q49PKM$B-T*ziFCZOk~A6W8>o{R)Q;PX@2g+q^Xzw6P#JiJ8Ok8c7@tm w^jWLYd#zCKwYiD@v^i~2pOG6!s{NWwyTYimS$7`C7l32qeZY*U7{OUX8yOlK8~&otgI^ zOWZZ@hbnLSWW@W|?VruNl9BLDhN|u!Ka|Kid(`%ye8bKje8tY`@3M3E#O%EG4fZ{o zYwY>;%k2D$1@^s#KD)s0u?ybmirn{lz+U*>)z(GlzKuLE8gDHe`Y5t^;8bg1|Dj0H z?z0+Gr8k-EqEGpS~2;XO3^u_AhtIv#(Za$8du@w>?*P9w?Jt z>nfzP%`08SIkLO@PkDZ>CEZ1t+HLL zT3+SKOun1Eclmh2E1#_kN3H7Ws1Ib1I1g5=?HMQ{G)zs>vx z7e|k|xS#)zIU3J=6+?!Ai~$)0G74lE$T%F$K=@;f1Q`l47DqD}WHiWdkntb`LPmrP z2^kYIC}dQ~u#j;f14BlJ49(Gu4H+CVI%Igr_>ci2BSeOXj1d_mGD>8a$T*RKA|pkH z>S)G_4A#+%78x!wUSz;;9V@3vzj2am>GHztx$jFhQBV$Jf?`TGk4Byd=9|-^w z0VD)S43HooQ9#0g!~qEe5(y*}NGyi5iX;wR3xIqeMT4f4n zI%f)(A^f+db9W|RP1~HR@ow_omF;xSyz<$4)4Bg`-OXZWo_S0l7ncyk!fwf?M diff --git a/lib/pytz/zoneinfo/Europe/Lisbon b/lib/pytz/zoneinfo/Europe/Lisbon deleted file mode 100644 index 168accf060c3837af1bd64361bd0dc157dec0ae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3439 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 a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/London b/lib/pytz/zoneinfo/Europe/London deleted file mode 100644 index fe63ff7e7f1e9b47c45c62a7768e3924f8572c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3661 zcmbW(dvwor9LMqR%&_J1Ax7r%(OjC={5F?_C4|PdTz>J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/Europe/Luxembourg b/lib/pytz/zoneinfo/Europe/Luxembourg deleted file mode 100644 index 6c194a5cdcb22da9319183df65478ec4e55555fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2960 zcmeIze{{`t9LMo{o5hyR+px)oTWbx?es3Xbm~mwD^TzU9X2_arX=f9b(~iiF^VV^a zM!RM<#Hfa8Lm1}7QcNf(ha;tqZpqP)v!l=Ro9cA(PyN$BeZS}XeSFXTvA=eoFXy;f zS+Tai9scGOE{+;=@f=uGwymzDOYxMFrt_Y)*D5crD_`S!bB}6i(P}NdSnqOA+2~on z=!&~6GQhK8{wyg^SnSz2DOoGR5El=m^`k zW0jt&%2?ZW_i)#am)qOkUN+nFjw|}bcXOAzsz*e+cMcin*cC1A-LZM@nl|6NYi?h5 z@A>w$`@J*E9kpk_bJR6la_p@+<=9uc%)S5hosRcQf*l9)S33^QTcnm3fKUHZxoUoE^1Y`ao$P_p^2g{aORteWpQPCp75BKJ9pU zyWW4wt(^|7)Zn_k60)^QIcCI`yVVXRc=9JLBsq#=nqJ)Kn%fqcZ zO1O85hTn|WZdbyzdsCqHINVYnss2$T%D>W{tIlg=(FYneuTG;gw`t78a}t|dEpbV; z5tDzauLClqu|b}=yg`OmZIQI&`!#(< zu?*X~UWe!8$cW;XbmZ7qbX4|q9sOvwI@1R0lR?9DOhk7bb1PaiIt-GGPXhF*o84sG zt{-%Kldnv0x0Q+2-^irG8!~xSqfD9HBvTh&)2EYn%e0BdHM8p)nVwXoS*>>JjLxbv zzFe&{n{#zmLxDbX!Kt%1jo0iWbLH8kNt#nJTIS5`s;(soGIwNO$;}Fq=VH3ZywsoM z`L;I6i|U|xo=cMNe@pXE)=RlnAL2QY1@LC8SJ9osdEyl|o8|)CwsUQZ1xh zNWGAPAr(VPhSUrxnx&~4QZ}S+Na2vmA*DlVhZGN~9#TG}enKS^+gJdR2V5SQe&jZNR^Q?BXvd!jZ_*bHBxJ&*p{Z+NV$=EBLzn)j+7j!IZ||_ z>PXpLANwY1Ri>AWO4C z$PyuIge(%WO2{%H>x3*6vQo%WA!~&!7P4B%av|%5ESRNPF=WY*HA5B+Sv6$Ykaa^A z4p}*5>5#QU77tlHWciTwLl)4|tRS+4mSzo+MMPE+Sw>_Xk%dH768~SyJA3)Bm(tg4 YYR?$fH6lGOG9fZLB0VM=qvCvj1?KmuQ2+n{ diff --git a/lib/pytz/zoneinfo/Europe/Madrid b/lib/pytz/zoneinfo/Europe/Madrid deleted file mode 100644 index 931195955a1b17d8b0d60c027845decbcc68b0d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2593 zcmc)LeN0t#7{Kv!g{w${51L*Q@Qn;LR1hUG$PB@m;OkAvH?E4PNp>W1QYv$rnIrbp zoXsVP$<&#m6_yKMmhYyLrLL$fmP^Z;orXkj%zoc9-CWV%p5M;>oO}MbV{Fg&@lTnb zKhXNm6=L3Sb8Rs<&%TWfj$MAR$$s<0W6q|EzD`Bi$M)tGGwdDSU+f)MbDdqMwmDVX zVx8R;W9>aJd7XD&Uf{fI_q5+DTw_;{3$_n$Z?cc%jB$>p9I}rMNpOx2UGJRek!_!7 zEOSmbeiJyeesAFHk+8B^*4JIx z=Y)ivtq-~Jn%(xdYk|-UMfN>4(e>@#j&i~(Qv%^@o1OMA7Su~o7ds*^PCNJ`wPW@O zxi{%g?G*cycJBDK`hw1?ui>CZUf!+uov+X?M_$#a{Rbp^XO+Zk+$3E~Rk|%*A>9iK zrN^|{(lg61v8fqye|)m^ijI>9+C@s7H(lcz2Wju`dugAGowe_=Hu_-o?;2nEqxM_( zrS@NSS_c&E*Mz)XnmD~q1{PLJQd*4+ny_95$COL*z$KF0Tp~lF*6EN-GbQD(#X9sr zx;*?4ARq&$9ki;S+?Az5b*X?9tujM=$a$1Yqb<4RZR_{nQ^LctuJ_)vlRvqtI@ zzA-u}zK>37O3<86nUeE)2Ys@!w@i8ehEBa0D$^<=WP0__GNYtHa@W;LAorroTy{-o z4f{Z5Pd}r1-8RUav?|RH*{gG7ROkNiy3T7Z)cGfi^{GpKU9f$s793wBPp?VSgIx@oTE$@_|s=|v_O znPOy;k!eOI8kuTWGug;=BNL8HIWpVgyosSHvYq&7%#km?}i zLF$7P2&oWKB3Dx*q)14WkTM~4LJEac3Mmy*E2LORwUBZl^+F1UR17H@QZrXmG^A=s z*^s&+g+nTbln$vKQaq%3NcoWZAq7M#h?Eeip{pq(Qbku&Mx>5NA(2WVr9^6p6cec? zQck3vNI{W`A|*v?iWC*8s;en0Qdd_~SfsK@X_49@#YL)%lozQlQedRQNQsdeBSl84 z>}tx4)Y;V(8mTl=YNXakv5{&cX;B0@)bI)<8A~vOSOuf^3mi zo|aFL$34M8t-W`gHX(Q8+`RdBDSxk7Cc#MA%>oI#{l+|ZaF>bCeShmY%dC+9St$S7 eDCTRZ*)#nT**NjpN&N@+Pl(S>Ouzw2q5lA0QUR3! diff --git a/lib/pytz/zoneinfo/Europe/Malta b/lib/pytz/zoneinfo/Europe/Malta deleted file mode 100644 index 5f518a1f1773e00b8b3ebe8a3a32c8ae69256b67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2603 zcmciDdrXye7{KuZhoeAh4_?3o#6t3h%H2z%;Rzjiu+)>8mqbO>B6}qxEfu_G&AF#W zI43H2VcLwEp{>wbrj4eOVwg}amNP4xy_*?1Mf-i<`3GJ6*WbIB&-#5b9UPmD{8DA(}!3) zeSNLk{8anIrEzj{Z-mzE@XFV3r^u;QadNsKTbV-H*Z#3t((_3-@16pzP)O9j_cTdJ7D(fIe}$UE%)eG zte~}pwr9ZF=5{@jt@fe4t>B1oE4V4e3Tf%8p+`Cv-*@&;?NIT1amRz_wA0Gd#rKzf zqB85l;;_Op?VRyWahJ?#(zXA7SGU;98s6o5jc}jTh^wD!_Y3dq182&$#}{vDF zL%8-o)?Nox|E2M}e$jy?O*&}JaUHz)kS655r-?HfC8?lVlGAG>Wn!tMMsJn0q$QHp zS|mdwOLXY@Su*TKp$yW z?viGDTV;&rD;*pAgN(iMlVrI+m#n&4dHljo8CUhL_)dJL*&8>=_zxn_i`P!3T6+wCcQ{H|hM=0$otMRG&NV z*XQ?4)BGTI*6}(S#9FkQX5@CH9oXnb+mzFqae#?xuzIkFumw zi!M2JRF+<8)K@>Kl-KHNblK)3y1Z(uu2{NDi#8UiE8w43;GOqCciW5Kw0#fq-0REb zis}_$2C9>|Ja>EcW=`_EyqSJifcYgifBpYItnJO0+?>7U=DFi-bF9N>a*@GxG{cJw zFfzo*AS1(!3^X#-$Y3MGjSM(4F(cNJNp4A~8jRibNF&D-u^Eut;PbO=ywWI-1}j(M7_G#1{!L5@967NQ{vn zBT+`ejKmoUG!kh?6KW*ZjwaYhw2^Ql@kRoUL>vh@5_2TzNYs(ABXLIpk3=2`Jra9I z6MQ84NcfTXBMSgo0>~mjmI1O5kfneu24p!P3j$dZ$f7`&g`-&*$kK2$ivw96$O1u@ z2(n0!Wr8deWT^xO{OfYxd3Oi3z4%qzcTc-}eVOc(@lTuG66EZbkh?wmvRN&6_Dh=u dV;)1z${Co*m+{%jgHi`2#Ahca;NaxYzXA5l@uC0# diff --git a/lib/pytz/zoneinfo/Europe/Mariehamn b/lib/pytz/zoneinfo/Europe/Mariehamn deleted file mode 100644 index 19d7babd531f6623710debe40497c4a50e4e613e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1883 zcmciCe@x7A9LMoHb$&GL9m_=}B>8db`sr8sl`B6A>5w1Ek0d07R(_R)G;fuOzU+d7CM;cvqS7X*+R(Jjxjm>>1aU~5BpVBA^GxkYh*bzyJE0d(Q3KII`T@YjC!1-$#r>}(l}B_?;NLN4u$I2f(RW~HA2RxIW#ptL?%SOR8MM~ zq&eNr`CXMszS}bS*$J6ae@Zf%n>2GzwM;#IT&EQm%k=8)nl*d3&L~={ z*~5y|n~|5Ce{C2snX!YvKlk>Fb)>>J$ zD@BXzvSoE)xUSimC~LElrKG?q>tcJ$de2wc5NMOqm>?~E|5VDle%7*kH>CXCL*00; zPB!@(b@Rb%x~2YzZY{6XiaizD&ThT^{Qu|MW^)#DS%cknf153|kFC@1&l5AfHjgKp zFE78c+pRC}zc01D`6nM>OcxXDnUv?YC(!YszJ&@ z>Ol%ZDnd#^YO*v%AyrwLvXHuv!jQ_4(vaGa;*jc)@{szF0+9-l5|J8_B9SUBO_@lY zmZngoQlwO*R-{;@TBKa0UZh~8Vx(lGW~6AOYD-f#Qn#fk9H|^B9jP5D9;qHFAE_T% z0AvM_B|z2ySp;MikYzyD!O|=QvJ%KrAZvjv2C^E+avtbmZ23Z+Pvoy%sAd7>n4zfJR`XCF0tdQNWo%Qy2{LlBV88TyJX2^_DM{A6_{QjI_ k#^}#M`ngEvJHRZ|&^Wfrl^GwM810UUcV))9t*3;59}7mUG5`Po diff --git a/lib/pytz/zoneinfo/Europe/Minsk b/lib/pytz/zoneinfo/Europe/Minsk deleted file mode 100644 index ba9971c6313838b0bd33ca5c8703d22a4b7d6bf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1328 zcma)*OGs2v9Ebn&(s4|iMK<0X%{0?|l=*5Zt*LPo9|M+Ci>R1|NJR_FmJx>#X%W3! zB^4n?QbP1tWI~G;VUtbJqL^Go1QK;O5foA9yTgc(3x9vk{mwm?I|G;R7u|oPzfS(k zGJV1#t$ML988^lQk4KHz^r3-7{7aYj^Rz zzm`AGpUX`c$xv`r{7RzW*)7w5?~++Ka>gt=H)yUt)n^tT+iR{l&}No&Z#GMtE6lak zhFRwKm}NHxd&+<04^({isrB!^#wuUT#;P98sp`?Bs<|3h8-}LT#*-7Ow(q9ebnunb zofwn)miyAM=d3gqUXZ4`qtf)}xC9D@RbaMPw){S zdaerg=c%1TRkADmQ-%6+q_ymW3WvT+n`=_Fm%f$uZ||kU@lZNuo=WGZYtl6_BHi%^ zDsuj`*z7Kc)8Vvdq$blnKlUuo(k5HPc*#fh7mHJ*vR2$8xn91vzu4wYUjso~UixWz zZ!;FWRTPOtB^-`Qq_;~#nxSwnH?8_mZ`$;Uj?Ko>;U=Bv;s)gC=PVM|i~YL4I{ThX zS3qol7y+>YVg|$xh#?S5Ag1Ww5^RAO1F^=UHV0x4#2|=85R)J_L5zY}1u+X^7sN1# zWf0RKwn2=usI7yT2eA)gAjCq5i4YqhMnbHFms3C0qvwW!S{*lST6 zOt2VYGQnnu(GaU4W<%_T7!I+VU^>Khg7FaR3FbrWx2PLHXn{rD1VS4KjUcoFrkdf% zaJrl>M`mi=S@YxYWG`)W1q|z-bwPABbU}1AbV2mFE{NBv#)|Y+mqOPe^)$V=6)t$I Uq+1tcNhMjlCF0Q?s;T$<0~v-awg3PC diff --git a/lib/pytz/zoneinfo/Europe/Monaco b/lib/pytz/zoneinfo/Europe/Monaco deleted file mode 100644 index 664f6161ab6c74de956253c7ba8f82eac3b8d327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2927 zcmc)LdrXye9LMoQzADCc*ViKZ;+#xjy?TBOoqMnpg1QSt{?2*i&Y2p%dVGVf-Vmm@ zl@GPHzvw%R16KMj!3FTp!D>vW{J7 zQGOz5j6QM6^XL7iFji~h7IP<@u!Us~4nakSbJtXo%1 zkT!31RBh*{ikgum{`nCS;OQXkG6t%L;{TBLVLwS=yRRk4>$C*j*ee|_ZQY#w9vM49bxrrEuzsoP(a0nf9ulFtwd$ZETyBZD znIPT23zr^e1EuE?A9<|iH;JtHL3)*5kf`}5C3;4^#N=<4*qrk!uBb-EC)cTj;mcKG zr&TH`u2?1AE>XRMOQrY4@v6_CGo|kyw|e5MZ0T2-E6H_z<;evDB&94w`WJ-BfcbsY zQ-fUM&JR`t!>>xJ`?eb7IxcBp->9_fSJYsy18Q(%gL>xjIyIzvvr0d;PcoJ+QJGb1 zWazYMDr?CbGHldh8D2P1Mm%09p7b<%HYig@M)r`Aw_+r_{UDWnE!-$+`>ULqYieA{4V7EksPb~ps_}Dwl;=}+sR=o!BtLY8nwVTI1-?6EQYVo~-@hZ1 zZx_jwhFS8$MUPC~I7SMOPFF83OqOYtBh*WiL&aKQ(aEtO_YvS|ToIv-`Wfyqj*H z=03hH9@On{G>hdQwT*ImqoYOBIi!oTb<-Pj4&c2b$l>_+oR#5mj7lBB7asG;%_q0{ zNLrA* zAc;XTgQNz@4U!xrJ4kwLO@5FBAsIqagyaZG5|Sk(O-P=QL?M|%QibFSNfweVBwe;9 zUr54`j3FsQa)u-g$r_S2ByULKkjx>eLvn{C56K>qK3kJNB!RXjgGdUI93n|XvWTP+ z$s>|TB$NEnNhKG#M3RYQ6GNUo7&BiTmMjpQ3iIFfNB^fl8{+KrU{uRWTKFnLZ%9tD_b*J$ZR3gh0GT+VaSXjQ-;hLGHJ-HA=8G;8!~ao z%pp^U%$=>7JY@E4&GaGjhfE+cgUA#jbBIhLGK3loCEE347S(t?m6A;;r}hJUUwbou|j8Z1ia9M1PU`)_Oy`~BM1Zr@g; z{#xT?!eO<@;T}4@G4%ZG(vPQlA|C=hpBEiE*WDiIeZJFoUKNJV$1Wz)<980G<2C(# z1s(l;arfY*P_p$_x_DDT#iilGz>7qYZ=|*8Oa5Ts-MHc6k-Egh$H#{!4fLAem1Cyl z%mEWRyvI!5ztv3HvD!>s-(aS-EHtIDu$exq*pvnRrabSfsjw?_#ixJ{zbWdP(RsgX z#WaviK%$qOttn?FIdE%a)-F;op+1snDwjR^f8wO0x?vrM2yvNL2xzEfm=`ssy z)|mz0Hk;_AP91$&Zx(%Bs~6ubH%mrhI(D&6$M1yn(t~BX_O#N8Z8>^bchD?PzSVVG zzMJ~8M><*e$~4$lbz|uR)A;_OX>zAc)6>gl#p{En`PvcF^7w*I9o=PImdkCqZIA7> zJvkmB+n1ZQ{dqpylRX&iK1Qk1Fn>mMhvkubJNMd7%coSNN{v-2ny@A))zHc_I7Jow zIgeCX#hH0Dk@frid_)H9ExQS(;SLz5aS@$$!{yngV+Z#(4kleF%e=T z#7Kyh5HlfmLJWmi3NaO8E5ulcwGeY5_CgGXSnN2ENKcoOi1&|UPN)3=A97+|CG9Yz83V~DtDFspsq!>swka8gPKnj9X1Sttp z6Qn4IQWc~uhf)`$Fi2&P(jc{2ZkOBR@_21;j@R}{bI#87XYIT(xn4VaFxp*$Dvj~Q z5}o8G(Mf0$o!liliBY1H&?GtuO`?;hL??-5&n3E&%v_@T{rMK6`>*iSzsgg73AJ*b F|0gT@fExe+ diff --git a/lib/pytz/zoneinfo/Europe/Nicosia b/lib/pytz/zoneinfo/Europe/Nicosia deleted file mode 100644 index f7f10ab7665e94ca44fd8cd98a362cd4b304eff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2002 zcmdVaZAeuI9LMqNOjy@ye{0UQ>qF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<Z91c0qO^C*L2;4Y=QCdH(?jq|NOB diff --git a/lib/pytz/zoneinfo/Europe/Oslo b/lib/pytz/zoneinfo/Europe/Oslo deleted file mode 100644 index 6326961453f404a4a886362ee8b684b56fd5b4f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2225 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 XpJMN8bVg!Ka!g!wMtmH`CIXf=i diff --git a/lib/pytz/zoneinfo/Europe/Podgorica b/lib/pytz/zoneinfo/Europe/Podgorica deleted file mode 100644 index 5f0389f03919e0b56de9cf4bf89b591a0e8e9c2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1931 zcmciCdrXye9LMqJ0gf0e_BBV4fRKcs9qyMvq*P#xOmk@LILW%&JA8Gc|lUfA0qKa}Qa zn76ty?D`RX{>L7ja&ni3A3Y`!hx#P)lTT%8hf36z_awT$NnTh{Bh!j~5|izf7u}f> z8xbedpAM5amq+97rfd9-Se-HQoX$KQs4w;Zq3#2>HKFUWCT>5gNt=#pa_wPFsk|hq zP5qLVGa%_pKa`BfZpln-k<9Tn$qMh%tSc*J*289LLzmr4*7A@7DZluvzJ51e zD!%$%myZO=ik?YQ+5f9lwf!d5T|@Fl^@yz8`irj0{aR`&2eme8kF3t=)4GXY>Y7N^ zHMc&}wc|~??o6w$zv9z34=&gGZ#T$WJ94z4w@lt%8>Nly8M0wXwlvj+%EpwbvdMd2 zHczsoIVnV&?_86X;CtFKd`eo!F6ld8^vb(K1G;6;3EkS)t=n1;Xj^BS`rCfyw#+BM z^(1f03KkC9qwk1lJHWF3`^|fg*JqwGpJmxLA9LBZ@9~E>(EO2ytJOUGe&$beRb}6K z1v$vbVMY!#a;TAmjT~-AbHI^9jvRFUaSpqqIq=A#M-D!6_>lmR2#^qv7?2>4D3CCa zIFLY)NRUvFSR73-NHj<|NIXbDNJL0TNK8mjNK{BzNL)x@NMuN8NNkQKI3zkp6CM&D z5+D*G5+V{K5+o8O5+)KS5-1WW5-Jia5-bv}qX`#@*U`x#Et}yMDJ+AN8)!h1AvSGG6cvNAcKI60x}H9I3NRoj07?i$XFnQfs6(+9LRV$ zngKyZ1Q`-!OprlAMgPfEo*WX|A}C+%sxH(HY+vJ*{XlOd0$+@R{gzK{|=V< a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/Prague b/lib/pytz/zoneinfo/Europe/Prague deleted file mode 100644 index 9ab78e9156f206440fe847d28e80d2807bc62a8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2246 zcmc)Ke@xVM9LMqRg{Q)lz0vSU4zP%jI{6KuL1yQ{$UA>=8L5coiCPx{8H3WO#hhzo z?;O)PB()f;W>a%EaMH*;Ez+2{HFr#AI(Ki_?Me7WO~yN%Z~ zxO9C(p>@?6YhK~zyku^k<9jB!R`x_soZl6TXm8(sef0y?-JLshD85;TPtTJ>Z@P5k zHLo1rRxC#vSLoO6SLEp41#;{;w|-N7RHFVe`8H=jj(eucck$aL=4g`GnKqF>LQP4b zY@HNL(aC|ia&yt&nw%xbca_Swu<=7sb`spj0df=eA_eCUa*KSGg zQpwo(yi5zX$gRs)%WeLkWS0Bnc2B8fxwGYt2`Q58^lJ9SVx9hTmgYpK=$)UB)4K*P ztEcab&ged&xt(8W-i8C3A9`C0>S9vZG9X12gHpVByOgB$N@-!6l#X^tS!%bIom?d| z|7q1(2fcF7_qAHyU#}H|v-IB0b98o(TkmVg)H$6q<^D>idPAu)H|wBueHgQQhR)oK74VyEPd}!T^3D{<$IE(Zs2!W(Q!fQyGLYYeNv=nXv6sZx;9O9?XNp@-Dr!hA8OY}PX_g|H&oHydKEcY~r`A<$1%Xz(LudgO(d3{0iXAW}= z#^AMAGTyw&&3W0}JSSZ-C%t;xWeguaYs+%@o%J9KLRN$<30V`eC}dU0vXFHl3qw|h zEDc#3vN&XQ$nuc&AqzxSh%C|8tdTFnB9T=h%S6_REEHKOvQ%WPwq~)&YLVq4>qQof ztQc7`vSwt_$f}WLBkM*Mj;tJ6I4{Iv|BW zDuI*&sRdFDTT>0B9JZz&NI{T_ASFR+f)oX*3Q`uNE=XaJ${?jdYJ(I9sSZ*eTT>sT zK(?krNQsadAw@!}gp>)X6H+LoQb?(gS|PLKMr>W382)>IHFAyPx6h)5NYG9q)`p4Yhtng8&4 z`!{TB&NcpVMe8?wxH|QR=Y_9*)a^Rj^{lI}yR5tK+yU3S`zevd3t+H+FOCSvEP+=Tw_(9KWBd$I}sg-8}pXjHvB>${&b(6 zaN;>T@zwqIyq;Zl(%wdUe(QRB!KN~MVdZi=xhUOUlo4mAB*Yo1QEnqGvcO8al4_;@ zNz0m?t4b6Tbrb2d8_y<%VoW1t<+{LmfEY?QWsOE>b|)}?!S_*Hk|rHHjcX0 zroK6<{^T#}fzIDmL+^;%+%T#h+&3XxR(_}+svnldq{FJIctDz6AIR23k*$|rl9tJx zvTdkC9{%1hj~w49tzYa=k9HSJTYrsutR+ddA1qKi))lFp%^tNYXP(+!dQCk($54B+ zVq}l~qiT=7D(!)@s^jvv^2Gc7>dBEo*?ahN**9=Rp6WOzorgNbG)yBbd|E`LKH<}Y z$2DW>xM$vY!lGtzrU-tyxw~P^eVM<-MaRtu!$_EKxC~=Swh^WOGL@ltW8NCN7nYcD zp`V7H&BW`!6?(4r`HjjNzfoH1H+(e}hF9w?)h~QCtMyC$z-5|zxSX$3H`Db0`*3FK zf53;!(jT5v|I%0Osq-z!h>#&6V{+7kLPmuQ3mF$OFl1!N(2%hqgLBlQ)BmTz@R0E# z19a3QM23ir5g8;hN@SSGIFW%OBSnUaj1?IyGFoJ~$auLJFc%|s)I&zbj0_qXH8N~u z+{nO@kt0J##*Pf0i_tsk;UnWm0)RvS34x=I0TKj99R(x|NF0zrAdx^qfy4p{1`-V< z97sHnfFKb;LW0D^Q3nNyilYt-5*H*eNMw-EAhAJ$gG2`j4-y|FKuCm;5Fs&g)Ima` z|nn*a&iD#G@W`;*hkDR7Y zge!PvxTns{s2flCtZ2>@!7n#=57kpQRM%5CRM%5CRM%5CR5=X|)-%>=sJ`oN>S6|e v8hSPtT>q`mbER(R|Lf>~gjBzF>i{p!CAb;Byv%~k?5w;DUrx63l<)o=Ht$WgNL1sd+VG{Z(OxEZ)&l($;)pn9$|k|(pj3ao1CLVll9xICTWhnXdmlc z=^Q(|M89vlRxYLPbuP6W@L!H;vM+y9<-c;J#%^7=(tq`IqjT-Go%z2%B)Dfg!St)1e}YUhqWYE;k>jXJ+yyPSGo?>o9h zyMFPeM%V3=nBCP9yJ53*Tdfke@KxzvR3i6Johc7w`y_ryraYK1KzhXVl!w}Pk)9r} z_Po$vd!6o~y_-Ah!v{mOPt9MNu;VxFTX9?ymmSuA^XoLJV2>tGYmtvP;`Y3Ix$_+FPG}zeO`IwheMe+tkv-06rngl_dA`!o@h4^UxnCqJ=rhS`I3$mq+Ad?NcS&~rr<${7wT#`p zRUa=dmM2y()o~M7>G+~qnme#aec7Y+$*8e9A)&WUxR|7qI*pP^-$m+E7kbI$kN(st z&0#WiON30T`9q#AKQDO|4U(VNEYlbLt}}*xEHkIoYeC#PnUztkg`sW@vF$t~@^{PVE(GGH=`vDJhJS7m~Zl{LD-8VuU57 z{W@u>^OKZ?U(~Y31G3;;i@y9pmAukWs|(kCu8XQS>f!}Ew0upuS^@ug1qKA(_#iOo z*4ND+1_gWW{>!prx(Aq}6)u+NPS4)VT%YC5^jQJsm)yMj{{Ps9nlHJzcAJ~$h->D` z*x#)l?YgC|9A*CII3q_IIo8P0Mvgaf#F1l;9ChTlBS#)N_Q=skjz5wBBm=G{1xOB% zBp_Kp(tzXvNrbD(1d<9Q7p^85NH$zeI*@!I2|+g_JdhGDlM^5*NLG-vAbCL&gJcFt z4U!vIlN=;Ft|mQ5eq2q0kPIOyLUM#83CR+YCRdXuBvDAFkW?YLLXzcbvW27z$rq9^ zBx6X*kene&L$ZdX4apmlI3#mO>X6(a$wRW|YSM?~4@n@BK_rDp4v{1xSwzx^Z&nMP8Lyh=8@DRxkr+ZWFJXCl7D0ZkQs0_Q-I6?G6~2mAk%=%12PfFOdwN%%mp$T$ZR0f zfy@UoA;^rlnkhl%#MMj+GAqcmAoGGu3^Fsw)F5*caOYL2h2|1~WX^BY*Imt=b HFE#8R^6CxM diff --git a/lib/pytz/zoneinfo/Europe/Samara b/lib/pytz/zoneinfo/Europe/Samara deleted file mode 100644 index fe5060094b501f885ba1e62292467300ef7c52ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1330 zcmd_pPe_wt9Ki8+)8*V!3#zR-Yh`Y2`DZORR%vaT4s!#^6%+*zltF)>As#ve1zHe9 zghWsnAz7yo4|XzZM9{@{h;AeJL3HU5Bj`{P^?ctoJamZ8JumO`dG>5Phw*)~$IhIN z7=MhldWV;h)Guq#wBet6I^!IAp7!V02kz!KxC>#I{Y}F4-7@F?WaKv%qhZg|)qLZ# zN%1}zm!_#P*>qz>HeWg-zVj*Bay%|u(?MzO^2oMUr?hw-CBJjI6tD$yfv@h|_K&VB zLF2U%eD^XOdiBV+W4@qTXI`kb+jFXYVp?^KO{(yzakcZrtVBky%dYNQ(s}5dM4Lt> z7RgBLM^@sEXI1=tOm;7))t*JS>@BvduE$Z;y|6~@yXI2+?|o5;k#8zFQ7=7xMb&$< zBnMg+RbTI0>9;*lspfe}eO{1(syi}JxGx7kT$I7t%aUGtn9JO}P_kI7tICgU)$gaq zUSqGdTbeAxo{fZm7(a9rpDv^?oSK+UsMjzg<_E z%O}JW?5v!b&SZ_@q@D&3A00Ml^Rr%>!(tAjJeRjt=IlQt@ly}7K+-_+;4~6JGC@)? z)wv+aAlV@4Ao(B(AsHblAvqyQAz2}5A$cK*A(f&a<1aB!d6Ivu|Np;8=B diff --git a/lib/pytz/zoneinfo/Europe/San_Marino b/lib/pytz/zoneinfo/Europe/San_Marino deleted file mode 100644 index 28ddffe0d93ee1ad7d1f3f67492f7f3b85406e6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2652 zcmciDeN0t#9LMp)!xcoOFPLHiVv(td$b+buXnI9Qf~DNld=Ht$WgNL1sd+VG{Z(OxEZ)&l($;)pn9$|k|(pj3ao1CLVll9xICTWhnXdmlc z=^Q(|M89vlRxYLPbuP6W@L!H;vM+y9<-c;J#%^7=(tq`IqjT-Go%z2%B)Dfg!St)1e}YUhqWYE;k>jXJ+yyPSGo?>o9h zyMFPeM%V3=nBCP9yJ53*Tdfke@KxzvR3i6Johc7w`y_ryraYK1KzhXVl!w}Pk)9r} z_Po$vd!6o~y_-Ah!v{mOPt9MNu;VxFTX9?ymmSuA^XoLJV2>tGYmtvP;`Y3Ix$_+FPG}zeO`IwheMe+tkv-06rngl_dA`!o@h4^UxnCqJ=rhS`I3$mq+Ad?NcS&~rr<${7wT#`p zRUa=dmM2y()o~M7>G+~qnme#aec7Y+$*8e9A)&WUxR|7qI*pP^-$m+E7kbI$kN(st z&0#WiON30T`9q#AKQDO|4U(VNEYlbLt}}*xEHkIoYeC#PnUztkg`sW@vF$t~@^{PVE(GGH=`vDJhJS7m~Zl{LD-8VuU57 z{W@u>^OKZ?U(~Y31G3;;i@y9pmAukWs|(kCu8XQS>f!}Ew0upuS^@ug1qKA(_#iOo z*4ND+1_gWW{>!prx(Aq}6)u+NPS4)VT%YC5^jQJsm)yMj{{Ps9nlHJzcAJ~$h->D` z*x#)l?YgC|9A*CII3q_IIo8P0Mvgaf#F1l;9ChTlBS#)N_Q=skjz5wBBm=G{1xOB% zBp_Kp(tzXvNrbD(1d<9Q7p^85NH$zeI*@!I2|+g_JdhGDlM^5*NLG-vAbCL&gJcFt z4U!vIlN=;Ft|mQ5eq2q0kPIOyLUM#83CR+YCRdXuBvDAFkW?YLLXzcbvW27z$rq9^ zBx6X*kene&L$ZdX4apmlI3#mO>X6(a$wRW|YSM?~4@n@BK_rDp4v{1xSwzx^Z&nMP8Lyh=8@DRxkr+ZWFJXCl7D0ZkQs0_Q-I6?G6~2mAk%=%12PfFOdwN%%mp$T$ZR0f zfy@UoA;^rlnkhl%#MMj+GAqcmAoGGu3^Fsw)F5*caOYL2h2|1~WX^BY*Imt=b HFE#8R^6CxM diff --git a/lib/pytz/zoneinfo/Europe/Sarajevo b/lib/pytz/zoneinfo/Europe/Sarajevo deleted file mode 100644 index 5f0389f03919e0b56de9cf4bf89b591a0e8e9c2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1931 zcmciCdrXye9LMqJ0gf0e_BBV4fRKcs9qyMvq*P#xOmk@LILW%&JA8Gc|lUfA0qKa}Qa zn76ty?D`RX{>L7ja&ni3A3Y`!hx#P)lTT%8hf36z_awT$NnTh{Bh!j~5|izf7u}f> z8xbedpAM5amq+97rfd9-Se-HQoX$KQs4w;Zq3#2>HKFUWCT>5gNt=#pa_wPFsk|hq zP5qLVGa%_pKa`BfZpln-k<9Tn$qMh%tSc*J*289LLzmr4*7A@7DZluvzJ51e zD!%$%myZO=ik?YQ+5f9lwf!d5T|@Fl^@yz8`irj0{aR`&2eme8kF3t=)4GXY>Y7N^ zHMc&}wc|~??o6w$zv9z34=&gGZ#T$WJ94z4w@lt%8>Nly8M0wXwlvj+%EpwbvdMd2 zHczsoIVnV&?_86X;CtFKd`eo!F6ld8^vb(K1G;6;3EkS)t=n1;Xj^BS`rCfyw#+BM z^(1f03KkC9qwk1lJHWF3`^|fg*JqwGpJmxLA9LBZ@9~E>(EO2ytJOUGe&$beRb}6K z1v$vbVMY!#a;TAmjT~-AbHI^9jvRFUaSpqqIq=A#M-D!6_>lmR2#^qv7?2>4D3CCa zIFLY)NRUvFSR73-NHj<|NIXbDNJL0TNK8mjNK{BzNL)x@NMuN8NNkQKI3zkp6CM&D z5+D*G5+V{K5+o8O5+)KS5-1WW5-Jia5-bv}qX`#@*U`x#Et}yMDJ+AN8)!h1AvSGG6cvNAcKI60x}H9I3NRoj07?i$XFnQfs6(+9LRV$ zngKyZ1Q`-!OprlAMgPfEo*WX|A}C+%sxH(HY+vJ*{XlOd0$+@R{gzK{|=V< a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/Simferopol b/lib/pytz/zoneinfo/Europe/Simferopol deleted file mode 100644 index ebb63b4450b0ac035c09d064ab515eb016850ff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2113 zcmb`{Z%kEn9LMoq*b1X1VxH$Hhi~H1LiNooqh7+46JO{#)m#gIKj}vt2{eVm#E|TeYOD@IV z|6%y9Mc?}qyfeXszi$6>(UrJx;!MDQ_vGv0q|b)zc721AOC%cY(D*)Zn@x-twRf?;pA0$qVHE}9GsG- z#tX7-?-hM=^{4Vw!=yH+9g*#2quSyFKf3fV^P%0fQ3DTLLD!a@7lou9S(v=&pUG|UC9d}*3!{gF(?K^$( z#E9&f8q?k*XLRrAQQg-wtbGUj)D;!&_P9M!^XASN?~OCc70coe=EfW@mvcenaJfP^AH;3uJGeM{&BguVf6P&LdfbbQ0~rW15@aaISdhUWqj5CD zF+a;o)8X2{t88$L*WZ=lik)b1F zM+T3K9vMC|ek1@$1dtFQF+hTVM8VO70f~d72?P=eBos(2kYFIuK*E8<0|^Kc5hNr? zOpu@;QE@b3LE_?Q0)s>b2@Mh(BsfTPknkY!K>~zC2ni7qBP2*jl#nnXadI?)LL!BP z3W*gGEF@Y;xR7`u0Yf5&gbaxp5;P=gNZ63LIhw#Bk#jVmLt=*n4~ZTUJ|uof0C6sY z?s=YQPqaH`?)1jqINeb`PUnqSuY3N2TYZ}4{=x5IT4*Y0dS)tUT4*X5C;Y{xg?C0? zP5+$o@owbamEyF}yz<#<)58Dl;mv|*p7~5fvkQo3R!w0}aZX-tVOC9ko^w~^`xoFK B{Cxlb diff --git a/lib/pytz/zoneinfo/Europe/Skopje b/lib/pytz/zoneinfo/Europe/Skopje deleted file mode 100644 index 5f0389f03919e0b56de9cf4bf89b591a0e8e9c2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1931 zcmciCdrXye9LMqJ0gf0e_BBV4fRKcs9qyMvq*P#xOmk@LILW%&JA8Gc|lUfA0qKa}Qa zn76ty?D`RX{>L7ja&ni3A3Y`!hx#P)lTT%8hf36z_awT$NnTh{Bh!j~5|izf7u}f> z8xbedpAM5amq+97rfd9-Se-HQoX$KQs4w;Zq3#2>HKFUWCT>5gNt=#pa_wPFsk|hq zP5qLVGa%_pKa`BfZpln-k<9Tn$qMh%tSc*J*289LLzmr4*7A@7DZluvzJ51e zD!%$%myZO=ik?YQ+5f9lwf!d5T|@Fl^@yz8`irj0{aR`&2eme8kF3t=)4GXY>Y7N^ zHMc&}wc|~??o6w$zv9z34=&gGZ#T$WJ94z4w@lt%8>Nly8M0wXwlvj+%EpwbvdMd2 zHczsoIVnV&?_86X;CtFKd`eo!F6ld8^vb(K1G;6;3EkS)t=n1;Xj^BS`rCfyw#+BM z^(1f03KkC9qwk1lJHWF3`^|fg*JqwGpJmxLA9LBZ@9~E>(EO2ytJOUGe&$beRb}6K z1v$vbVMY!#a;TAmjT~-AbHI^9jvRFUaSpqqIq=A#M-D!6_>lmR2#^qv7?2>4D3CCa zIFLY)NRUvFSR73-NHj<|NIXbDNJL0TNK8mjNK{BzNL)x@NMuN8NNkQKI3zkp6CM&D z5+D*G5+V{K5+o8O5+)KS5-1WW5-Jia5-bv}qX`#@*U`x#Et}yMDJ+AN8)!h1AvSGG6cvNAcKI60x}H9I3NRoj07?i$XFnQfs6(+9LRV$ zngKyZ1Q`-!OprlAMgPfEo*WX|A}C+%sxH(HY+vJ*{XlOd0$+@R{gzK{|=V< a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/Sofia b/lib/pytz/zoneinfo/Europe/Sofia deleted file mode 100644 index d8032335b20aeb201c8c3851844fac5baa815071..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2104 zcmb`HeN5D49KfFwF+_4-FhT_c0|M>j9p8e`=wKw+DF=~CoQa4 z)m*u0IabXPZDfB?>qXaWqvKk+*2=}AWov3}=3F&a&*yhzZsDJPpFQ_^_Iqx3_s4xc zzD+xu^UbuGZJ)52gLZR{8@;?vzI;1DgKw0{SYM%p4rNH_Z&&+Q9qFmD+kW@P)s~LW ztDY0Or)cqby!&eC-g%$2C&Y|}60Q#g=1-goEcm)Fu<+dBK;nn*nxr!)P4eq6nMJ*a zOv?VThox1v?GI{X(dMzGk)RK|a`q0s}TKZa&u4zuwwMSOT!{w1$)|4oZ zWL#EH*`$<5exVghGIkVhxply!seNY&`aT79fn)}J}0kF~XlxA(Aa zc>G1(*t%V7R;_MJXIG$8weBf9_iXL?}pgdXfZtv$zj)HTDd2s1OhB4_^L_uAL0YV35XXEHz0mEw2nYLv7cpd1>y_D8HhI!cOd>i9CBzqg17|n z3E~vQD+ae1{9DJ`vhqeq*IVqL3#yg7NlE{ zc0u|DX&9tqkd{Gu25B0kYml}%w0(m#&Y|rbq;-(qL7E5Y9;AJc{=skqBWBtaIb&9M zO{?70g~Qp=cY4_>{J?KXYzbG;gew^16j7Wa+OzFnyi-Jb8$RE9QdR9Um3H5zjMLi4 dgJ}E4W%;DjU0sk}l%1PX;I7WgbxwuR{{cw$=C=R< diff --git a/lib/pytz/zoneinfo/Europe/Stockholm b/lib/pytz/zoneinfo/Europe/Stockholm deleted file mode 100644 index 3bc6dbd9d12b44e0a04642a346aac17aac65a34a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1892 zcmciDYfQ~?9LMp0l1ppt8xp!9$>r#(+{*2!79F?#$R)WXMM7vrG-GDg>}zYxVlmdt zhzH?8E^{42v)P%s&Bol#Y?#{`zxTiKgvU<%pI1BepaLKGG21+Zyumy!Lo@LVMmlpuH~d($KT#Bum>jCz=>sSWv>);v;2ZyTp$>cVtvVU&*BIzq;0_^G=fR3=2f)O2^N zWcc0C%%~@l`Tm7u`CgQ)mg_R{*&&(KcvP})T~N=?8kv0TpiU_*m8msbblR*PI=y6x z<_s%QJ3CWngiO|%u7Nu9OT6X=XGre7E;{@30GV_8lg{<}%e(_YlGpT3=2w4|{Mr^- zknfd+8{g=nF=u3P-YqSN+$&4c8nv*~DP0<_y7bi^Eov>(;_H>V?6IxOkIdDQYpZ3& z_B1VR$dQ#rk-BPIvaFt#DrJQsvL+!y)~0`xbwQSt#|3Noho@2z_(d!3T#?H6_jUcr z2HDWktW|q2>Bh$Wx~cN8R`0Agon=j>=s8aZp^w2|{h zP8>ONZ)dNMcB4NNPxKNODMaNP0+qNPki{B#&f|q>to}OaL+i z$P^%RfJ_213&=De^MFi*qnQb0Dv-HACIgubWIB-fKqds45oAh`IYA}`nH6MOkaBWya%{ZIlMs(_N&de8Jt?k* diff --git a/lib/pytz/zoneinfo/Europe/Tallinn b/lib/pytz/zoneinfo/Europe/Tallinn deleted file mode 100644 index 4ba4424121aeac25767ee83ef57ca579df2b4a96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2175 zcmb`{YfRO39LMqBIdJfBgu{Ky8igbB^*vJYlU-i`B};nmb!LXPc|v`w!<4t)BS%@BCkX|L1Hx z@$>fYI?z_2mYg{Ah7YIDe0WYdxicqt@uh#0X z-}T7Uo0a;TSBms>_m#PXjJK!nT=9K{$2r^J`77?T74z=t#M#Py&PwqduLDs+Km5R1>*)Vvo-dOFB%GM;kY1LJ! zs=TGE9bZaK`j5Ki+OK+Z#OHeR)TDmk=eKn2_4r~sBvk7i-`*iRuV?CA7yp#qGcLX7bi8gp|GR#8 z;1At0Jf$CLnbD8-&&y-$KhTdi2cWvM*U=-)|$b|5m3QnCz7&e(=ka z@9dWL%ZK$-$I7K+tWh7_pDKrr7VE=X%XDX(M|b6?=7Az7}nM!iUpuK0L4d+nlD0 z!6336OS2wiLCA`bB_V4<7KN+|Sr)P`WMRn4%->Qh4OttqI7_oSWO>N?kOd+uM3#uG z5m_X%N@SVHI+2AUD@B%ytd+xJIjq*wEEicXvS4Jz$dZvYBa22>jVv2kH?nXJE9bCu z4r}MIcn+(#G|RU%>qiP;X)1t}0I2~|1f&W`8IU?4g+MBSlme**QVgUTmZls?JuFQ@ zkcuEBL27~&1*r;B7NjmnVUWror9o`~5zE84YqEst4p#l^Z~9d2{G z9alJ$CYC0XCYDYslO}s^y%;}}NfS#G$c1lBAgvJcCj4wmwlZl2m8_afnm63*Of3H= hnEz2szH*tw<`mG@?E1po;#^-|VRn7K&w46y{R6={5l;XB diff --git a/lib/pytz/zoneinfo/Europe/Tirane b/lib/pytz/zoneinfo/Europe/Tirane deleted file mode 100644 index 0b86017d243f1b7bbb41d6b4feefcb2b7edfc7d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2084 zcmdVaZ%kEn9LMoPdKbGQeZlZ%fLMs2U4hF#MM1M0pb46CRs4e-6A=^XK*Yd5v6fkD z%zYo+S+1PA98;&{8vSwTtfmepGS|kMI?L6{XpQbx&YZIRz0V^z*Mpw4bY_F#+ z;=SB-W6aQEC#Gk_-E9BGNMr%KB9H)K*nvpltCy*ynWlGLIS znd~o+w4`*I67z(ldxDyND^D|iO4F%><8|7(NA;PWztn$dNT-LdYUa+1n$>bjvulrQ zp!$mBH1|kuaj)bp-6Q$Q`=lVJO$tUjWM*PmXI@_?g?C$Z*6E2%npV5llowDfIL0#O~C@*%tsY_P8t4kX;XyuFs4V9PaGT$Oy?w_j5Z)a;&La9`J z8?P&GWyq?}{?yfjURiS>PO5u;leHaxNKJS^?3zJYx8qlRY3}E;zPev)Q})V+;%=>r z{!}+6t8V<|J*^*U)=how`ttRVZa%zP8_qY$mUoJ^v8z&EsZUX7SH3hYDU#+opS&8F zC@m#-r^6(K8F!c!UIS5Z;!N9bRi{J+h`=|>iTtN>Yp zt62ko&mvsSDv)Kknsp!xK~{n+1z8KS7-Tiba**{P3qn?eED2c?vM5)xDr8x%W?jg_ zkd+}zL)L~Y4p|+tJY;>y0+AIWOGMU)ED~9zt63(pPGq6TN|B`^Yeg1|tQJ`=vR-7t z$cm9ABWp$$jjY<$EE`$3t64a*a%Abq+L6U0t4EfPtRE==QURm{NDYu8AXPxhfYia& z6auM)t0@Ii3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAa!vyg+VIgYD$CD1}P3w9i%)+ zeUJhn6+%jc)CegOQYEBJNS%;EA(e79r9x_j6bq>qQZA%kNWqYbAtggWg#Y3uxln<#NQb44FND1-(T|=)a@#_IW=yUTL5)*qf{&-ol4&Msr) z_rX&``$Cr2L9etbi&hDee>5twp zJ~{HTapv_V6ujn3UZhCJnTR+}J%b_tJ7P<&TYW>S>R7q`zEFJ6tLAI;P6}Z8PNbH{)bMb+VkX zb&8l-WS5?*STSq#6Vntq?taf}TSH?@Z z^6G1{W}sfK>TZ-zU-HS-N0!Li3v0!i?Rm29aG7|fCQ&}SZK7B^f10STc8hgc31WTW zZ(_p;O>E4Fk{it*M1$*&Z18u9#v9+s=i3j9O}!nmY43U2+_qnCZagGgcD6`c$dI9T zFS{c&EHunHEU>~O2A5O48e$(@k*<5aG%e;9f6UPhT8O5N%d|N(EpC(+8N3HhTtXYc zi7hI4&n>XU@V=H1ya!K$pWrF=X*1O>EG*;Z(>&HzUzC>3QhSd2sWw|+s|OzccG+yc zf1g01USf0YP@Cs5f2wQIiSA#KX+$OxnMzAFnaFe^6N*eJGO5V4A`^>DEi$>t^db|C zOffRa$TTApjZ8H%*~oMw6OK$dGU>>)tKUgu;*qIGCf`y`KT-gs0!Rsv8X!eLs(_RM zsRL37q!LIekXj(cK&oM>%7N4aDF{*#q$HNACP-0`svu=S>VgyosSHvYq&7%#km?}i zLF$7P$Wm1ZDUqeB5mF?iN=TWIIw6HZDut8^sTEQzq*_S1ka{5nLn?-p%u>}1DVn9K z8d5f-Zb;#f$|0pgYKIgLsUA{3q<%;NkqROuv{W@jifE~-h?EhjBT`7Dl1M3$S|Y_n zs)>{nsV7oUq@qYkk(we!wNzC_%8Jw#DJ)W1q_jwFk>VoNMaqlR7b!4OVWh-JjgcZ- zswyL8wp4XS3XN16DK%1Sq}WKc(JJ>4`_PcPSLm=XN0=kr8CVgKgDYIUY7ZS;uHpB3 zsZm$4wgRrwtpcvTQn`+>(rx9MXa`PQLJOpOq!n;=SGf+PJIM;Tx(82!pHQOW{eL3< h9~D>Ma;o%?&*q;%TIq!JiRqac6VghvGOec^=U=5NntcEO diff --git a/lib/pytz/zoneinfo/Europe/Uzhgorod b/lib/pytz/zoneinfo/Europe/Uzhgorod deleted file mode 100644 index 7032ab9b34f97640d1ef631dc4cc790abeeed606..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2077 zcmcK4e@xVM9LMqR0f%rJy=f63Ka0p8opAh8G)VM3n8Dd8r;$ovA^wOcz!;cDE9Y7x z_byq@l@7~MHe<9={ei6?bB#8_Ys)o9u2w6ZbL_j7bJbXVp5IG1`|+pW&+Z=Ieg5G5 z!`CysaYt*h^{;1+x#7dpYd*Zs9Z&4giSxDc!kWx-qoVUvr^nSDkYU;Qo8OHDa$%6i;H_?@l2nTXAEfhxh=Bvk8WM| zkzekaYS4ruXh&q03*()T-7zU9oSetgLpcza>Lf<)7Dpe@3d^UuaF1``g5Wec%OM*S1ybm$YfPu143V zuF(zN1-jviPa9IIrQw@f^uf#XW#b3G>ZUUu**usmjiZ<3p}t?FX<$;Co6g9Vy%+W2 z(=-ZpL?eh+K?D(K(*kH{w`UlJLJRGuIV&{d;+pE77tR z`mCF-en)RIbFE}Dk(?I5dOvKU51epqdmAN33L1yDpsRn%N=KL*|D}5Sbw|MP!c1B#~Jn(?sTpOca?Z zGF4=*$Yhb(I-2Ps^K~>6MrMpm8JROOX=K*Ow2^ru6Gvu_OdXj!GI?b7$n=rC?k`5#vjwT^UMjTB_kenb%L9&9R1<4DN z7$h@DYLMI@$w9J%qzB0lk{~2QjwVG&j*uiFSwhl;k|`urNUo4%A=yIGh2#rK z7?LqZlQJY{jwWeH){wLzc|#J1WDZFkMspV%6B`rfig!oPtb}VP-j(Qa&g?li;#k(L z7x-5siDi0cs+Vy6yJ=jscTVFdUG&B@F50_vr+Vg_o4O#?``_|Ki}%m;nOl#kloj|2OT57%pYvAg`3s~A_i6wD diff --git a/lib/pytz/zoneinfo/Europe/Vaduz b/lib/pytz/zoneinfo/Europe/Vaduz deleted file mode 100644 index c4e20dbe0e8c683863e7132be9438f95335d017e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1799 zcmciCYfQ~?9LMp0(xlP8SVE;payi|VTS<;nL%DS%m*kS%5*@UnG}FwiwXdx)!!Xv& zhzH?8E^}Qb%|&fT+buU~~7;pXc@iyP^@bQ?3 z_nraa@3nuwXBy~zPXj++(E%N2b>M@eI_Sn;4Z3t$f=@R{$e|-LxJD(kVuyqkd1T1q z6*4r_E#b*78Rkfmh~P*W-fMtF`ZzW6>lhvJGD1hT_196idg$oJ@9H@5R-@{kXms^m zjoExjV++n`T;5}e_cTgEN|TJ4yH65B4ogyenIv^q$+)089oN20#{VqU374HR@oBCm z*XL_W(*&KgD@{`m2J7U)a80WoFH_Qe)L9TDQzKrh%h@UEK6f-D{JCU&d?nMougSF5 zW|`h`TxK+!lFXK?npImPGfyAWS;fUNyJn}(nZHNp7Om9mu|?|6%+Ps(Gd0ICQggn= zYHmQfF4wi~Ze4eBkrv%9k@dS%w75Q7HmnZSjk^-1WKObp z3Ik@}xTWgb69JsEP4Tp7m`3bG6 ztx~UU|NF7MRw#amm`63fWW{gZ3nKLqJWY);Ek$Kyii6b*drjE=V znLILkWctYbkpz$okQ9&{kR*^SkTj4yY)v9aCblLOBo`zZBpW0hBp)OpBqJmxBqt;( zBr7B>BrhZ}Br{u+8j_o>Ne;;lNe{^nNf5~pNfF5rNfOBtNfXHvNfgP{)})H$YHN~3 zvPIHG@IyvPRNI@=Ht$WgNL1sd+VG{Z(OxEZ)&l($;)pn9$|k|(pj3ao1CLVll9xICTWhnXdmlc z=^Q(|M89vlRxYLPbuP6W@L!H;vM+y9<-c;J#%^7=(tq`IqjT-Go%z2%B)Dfg!St)1e}YUhqWYE;k>jXJ+yyPSGo?>o9h zyMFPeM%V3=nBCP9yJ53*Tdfke@KxzvR3i6Johc7w`y_ryraYK1KzhXVl!w}Pk)9r} z_Po$vd!6o~y_-Ah!v{mOPt9MNu;VxFTX9?ymmSuA^XoLJV2>tGYmtvP;`Y3Ix$_+FPG}zeO`IwheMe+tkv-06rngl_dA`!o@h4^UxnCqJ=rhS`I3$mq+Ad?NcS&~rr<${7wT#`p zRUa=dmM2y()o~M7>G+~qnme#aec7Y+$*8e9A)&WUxR|7qI*pP^-$m+E7kbI$kN(st z&0#WiON30T`9q#AKQDO|4U(VNEYlbLt}}*xEHkIoYeC#PnUztkg`sW@vF$t~@^{PVE(GGH=`vDJhJS7m~Zl{LD-8VuU57 z{W@u>^OKZ?U(~Y31G3;;i@y9pmAukWs|(kCu8XQS>f!}Ew0upuS^@ug1qKA(_#iOo z*4ND+1_gWW{>!prx(Aq}6)u+NPS4)VT%YC5^jQJsm)yMj{{Ps9nlHJzcAJ~$h->D` z*x#)l?YgC|9A*CII3q_IIo8P0Mvgaf#F1l;9ChTlBS#)N_Q=skjz5wBBm=G{1xOB% zBp_Kp(tzXvNrbD(1d<9Q7p^85NH$zeI*@!I2|+g_JdhGDlM^5*NLG-vAbCL&gJcFt z4U!vIlN=;Ft|mQ5eq2q0kPIOyLUM#83CR+YCRdXuBvDAFkW?YLLXzcbvW27z$rq9^ zBx6X*kene&L$ZdX4apmlI3#mO>X6(a$wRW|YSM?~4@n@BK_rDp4v{1xSwzx^Z&nMP8Lyh=8@DRxkr+ZWFJXCl7D0ZkQs0_Q-I6?G6~2mAk%=%12PfFOdwN%%mp$T$ZR0f zfy@UoA;^rlnkhl%#MMj+GAqcmAoGGu3^Fsw)F5*caOYL2h2|1~WX^BY*Imt=b HFE#8R^6CxM diff --git a/lib/pytz/zoneinfo/Europe/Vienna b/lib/pytz/zoneinfo/Europe/Vienna deleted file mode 100644 index 8025ba520a85f2cd2fb72b54533f225ce20fd6a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2211 zcmciCe@xVM9LMo59H+s|-ez#d53z`lI^p=47-V)HjO0w^G7nqB>YwT9-(YP670y9~{><;s4|vCLU(tUk~0AN*7P>*w~p$7kIA0UNJp zV9ln+TUtt)C-#nqwYUGUzW#ygzRulx;P+!KeJzP{aA~y; z$F}Oo#bt8hO_z@LdF9L3@@4GBbU7JJkdq;woI003ak@T9zbZc^k)q@Bb>^U)aVN?* zvAblpKV#ySys^6Yv|lx0_P6SCoKV;04|UFkcl6fN`!(_StD1D=s3ac>OUmATGPg@5 zb?XZM?2|j(g_53}A$QK0BNlJWf|On<%x#y#$&f5e>ehwl*GbXe zZMx{FSMEJmrNslaS~9dq@7u9N7xyIV{f%k5q_apKD0Qm0AxV~|UsRuWQc9hlYgyWN zQg-P_DR+D%<)g#$;Dv*-Ec}*Kj2u({&MsMg=zu=d+$<})w(H7AUe;Aj>$UQpCJj`S z>BFw&y4szotFL;rD!x>z&fKhzUYRdz-upwVBXP2J|17B){7oJUU6$JJQK_qq$hvL6 z=;Mpum-?C!ZAjfC>r2Agc*9}ckfOTbr`@`7GN_w|JM@Y30e$j~YHj+gRi1jOM4JaH zW%I^VZP`&Ett*Qq*yxg{bLPqx-(T{~EKAz5TF!$Zc03=kP1GDQ9;#)u3O86`4IWSq8UpvXv(p(0~N28)aq z87?wjWWdOXks%{vMh1cK|rE_ zgaL^I5(rxp2_zJ@CKgCAkZ2&`K;nS}1c?X|5+o)_P>`q~VL{@81O|x=5*k|*8zeZk zCOSxXkoX`0LL!8O2#FCABqT~mn2$3JI32i53zrBwk3skcc56Lt=&m z4T%~OHY9FH;E>26p+jPa1kct)4+$RQANTUZJHY6h_T{MjUCC+4bK@K0f{drjhSsu4P$Aj50noMfttKmqMvmPFrb1FIed( zpS9-p@3k@xwp#N#Hd>k6tF8HUORcQsIo5r7Db|8Cx3w_#cPrbO-IaYSxhv;;Z(z}w zE0BBbPT>Aa6M?+*Aogb^3 ztgof!<`1$u>H}FlIwEVnJ14cn7o;xuzN$aoFKdU+sCAv4($N2$TEFRewV`9DYFyf( z{B<>Iqj#-p%3GwGZu`{cq-xpxd7|2KD@V3o{#9)obIbPA3DSJ&CwZvv7uhi|DlI$4 zXDW2$fM0c)tYfac9spRHrLx~SGrQWetcQAPj;)_BfaXeul(xqH@2yckM_tD z$I4XaV52%cZ-`D|-v)%D$>Q@>GH$`wNoPe(PK5@!VEDp=;86^9yz0 z;-EY|`mQ>7;zM<4_>_94_q^&m-lxnNQ8OGd&S+<}!xcVfx~HA7v!ah|yND2cxt zr(w*#$bZ|McEe#99x+^okv7kmWf-|WL;iYV-otZVmzA3-k)KBH&Gg8p!teR}_n7IM z>itHozACExMwPzm8*BA_BR7@$fxfX1(=-fo>IgrXdgYn_-zSr(-@?UlKwsQ1{6im2 zmxGnae2@ttGeV|>%n6wkGAm?S$h?q=Av4pz!(eL2+>puH>e(UFL*|D}5Sbw|MP!c1 zB#~Jn(?sTpOca?ZGF4=*$Yhb(+Un^d^F=0%%ov$6GG}Dc$gGiRBlAWk&cVz%m^ue@ zx7CwJW{*tYR?iNLrA*Ac;XTgQNz@jjc`&k{w%}9wa|Vf{+X$DME6DBnin9k|rciNTQHT zA*n)gg(M5fmaR?~k}o7-NXC$qAvr^mhGY#%8qNJMEkmH~n;Y;yvO>kh^i}U0>m^(3RAE z)RokI^ay>_l@z;!x`~k|X0lyL{i@5To2VNaE~b5NW=1}xE2-ZT`BeCO%*;An$p2YN joyq@5r5#YWj_l$h!kSlKoL`#nD=5yZFZ9`WCGI}~40#FG diff --git a/lib/pytz/zoneinfo/Europe/Volgograd b/lib/pytz/zoneinfo/Europe/Volgograd deleted file mode 100644 index b91e4fbff6b4508668625770fd38880b186bcc57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1234 zcmdVZPe_wt9Ki8s>E`}KC(EhR{@5Hdt+iBE&6-U&tVyH2c(8)#j}QbsgolC-LAFx` zMG#R$(dc4-gzA*Vh%S+O@*rsNLZ>3)ckz<+=lQaFAp#8Vb6Eg@X3+5 z`eUs$JKU_4xp}U?znEDVpDX5HlmdB~$fZ_CZk5*rXJU2U=~Ue}*F^BMD%a0<#TuqA zl^Z9o+o4An?WQ}UcJt*E_S*A9_PSG9d;Ot=y&)I1Tapd-#`b_64*8`uup|+8L`N2b zIy(F1NZZ?Iu}#kxbbD!9ciecbH;+BlTSo8c*zs$6>)}a>pSda9dhSZ+fpgN;bV0h~ z2c`S_QAsqO)rk*%vVCb-?|9WJJLi)+`7o_}UN-Ap#jxIeTj|tDjqV)_$)5gCI(_Vi z^o8H+{vt0(2&@W;E?E$@R0bB z03A()NQjOmMkGiiN+e7qP9#tyQY2I)RwP&?S|nT~UL;^7VkBfo6EhODqlp>`8;KhU Q9RKUc{pOEgb#(fF0nF4QrT_o{ diff --git a/lib/pytz/zoneinfo/Europe/Warsaw b/lib/pytz/zoneinfo/Europe/Warsaw deleted file mode 100644 index 3797b1cb653206febf14619e62e6b82cf4bdcf40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2679 zcmcK5drZ}39LMqJoC6A^_C*vFK{PUzP(c(GAu~c}f_XXK@P>w{MTVCMP2x9Yu9Ztd%P-Bg53JHD=HI=bS6;PoJ}MUeAH^@9+KbXD`U> zZ|*rE_Ak6S@7p)`@J&18>bJCs$l20xws~t~m2Rupr*D0%`gZ9?-M)Fh*)jK!sVrWR zbF}b#Id);Re7!3|>)uJ1Z`KcxdS_Qoedz&ne8c*J6KiU7PR_YiaB6g{Hq6{Br+e4P znfOTgHn?0Gy+^e1QjuKrpD-7%);O1be9yUjyxeK(P;QzId}w~%U16?l-e7(^m2H}r zzhbV|q?+HerZ8}NMz;x|-V}SPhxrg>{2-mpJ zTkGRBe`A1;j zbbS6?oiHe0{h1?mV#FAo6yIAX-AvFa9Y@HNGwpTijb4(y|GG|V2$AXALuE!ylguo+ zCbP=wBxhEG%r3sHbB28+&&@cdxiOn$Zd#S*1?|&$(W>(=#W%~R%zrL_@ zn&yA8NM3wBO&3;9keBAiXu;}%vS?hYEY6FNC5c^SX~tjja;TBQejT;2`6nrAcTll05kNwK z!~h8b5(Oj-NE}>kAdpBPp+I7R1Otf%5)LFDNI;N?xZ02)F>$p)L85|$1&NER4Ga<) zBs55Dkl-NELBfN?2MG`oAtXc`V&rOrghYu$n2Xd>Z6;)w**)kYKvsjH1C5>zCrNLZ1$B7sFBi-Z=5EfQQLx=47D z_#y#DB8-IC)y5bJva5|U5@saMNT88OBcVoOjRYHsHWF?m-blcah$A6)wJ}G6?rNis zgdK@H5_lx?Na&H+Bf&?akAxqIKQaKw2p~g%i~%wTu67iVVL-+K83<$~kfA`v0vQZs zG?3vy#se7;WJHi5LB<3b6jwVc$gsHDaX|(K85v|~kg-7q2N@k?csxG4CxHP$ty=rM zf%f9P{hjMQFMfERmoGTv!N2Y-Pgu3F%VYN^$lV`zZSLOf{)D>A6Mpye&VMuQ{`~I- g{da`y_Yk{NeG*x$_^hP91N$b#XC)?Jzod|V06(!8vj6}9 diff --git a/lib/pytz/zoneinfo/Europe/Zagreb b/lib/pytz/zoneinfo/Europe/Zagreb deleted file mode 100644 index 5f0389f03919e0b56de9cf4bf89b591a0e8e9c2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1931 zcmciCdrXye9LMqJ0gf0e_BBV4fRKcs9qyMvq*P#xOmk@LILW%&JA8Gc|lUfA0qKa}Qa zn76ty?D`RX{>L7ja&ni3A3Y`!hx#P)lTT%8hf36z_awT$NnTh{Bh!j~5|izf7u}f> z8xbedpAM5amq+97rfd9-Se-HQoX$KQs4w;Zq3#2>HKFUWCT>5gNt=#pa_wPFsk|hq zP5qLVGa%_pKa`BfZpln-k<9Tn$qMh%tSc*J*289LLzmr4*7A@7DZluvzJ51e zD!%$%myZO=ik?YQ+5f9lwf!d5T|@Fl^@yz8`irj0{aR`&2eme8kF3t=)4GXY>Y7N^ zHMc&}wc|~??o6w$zv9z34=&gGZ#T$WJ94z4w@lt%8>Nly8M0wXwlvj+%EpwbvdMd2 zHczsoIVnV&?_86X;CtFKd`eo!F6ld8^vb(K1G;6;3EkS)t=n1;Xj^BS`rCfyw#+BM z^(1f03KkC9qwk1lJHWF3`^|fg*JqwGpJmxLA9LBZ@9~E>(EO2ytJOUGe&$beRb}6K z1v$vbVMY!#a;TAmjT~-AbHI^9jvRFUaSpqqIq=A#M-D!6_>lmR2#^qv7?2>4D3CCa zIFLY)NRUvFSR73-NHj<|NIXbDNJL0TNK8mjNK{BzNL)x@NMuN8NNkQKI3zkp6CM&D z5+D*G5+V{K5+o8O5+)KS5-1WW5-Jia5-bv}qX`#@*U`x#Et}yMDJ+AN8)!h1AvSGG6cvNAcKI60x}H9I3NRoj07?i$XFnQfs6(+9LRV$ zngKyZ1Q`-!OprlAMgPfEo*WX|A}C+%sxH(HY+vJ*{XlOd0$+@R{gzK{|=V< a6=dEgq%dUelC;E(#AJ6#N-`#;1^opcM$9+> diff --git a/lib/pytz/zoneinfo/Europe/Zaporozhye b/lib/pytz/zoneinfo/Europe/Zaporozhye deleted file mode 100644 index 2ccf8998b24f3493e68670c5d08c51ad759bf7f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2085 zcmcK4e@xVM9LMqR@k7tU=xvLRi=Rmb8o~jhXpqpb zy_-zu%FU8dF=Mu&{eiAuu34k&{>Yjm*H$f>Gxy!fSvgjp=a=2)mRo=M{qB2@FW=)B zY`mVK4cps`t^XWz%@Zz;K67!OIpRC+KQ-hFe>pN0otUbXuio=&_c|ZRaT=>nE@S<~H2Ok`Zg!6|!2reEx z87|m&Fj% zWKH}hvL+F=^z$?1$@z->H#};i^)}f)g8g2Bh z)u#M~+H~Eo%_-H={M}vp#I-!xaQYA3c)=r^j?I&nu`BXq|L@W|7?E)61=+m!vOcx) zLwUMoLff*A$d-yxZFis2tr@CYe?6?*rn`0f`96K-Qb?bDccXTEzC)gSwL&|G8|3+I zS=zO~RCcT@m+p42>@3QZT~&X{3-c`LDNNBG`$y?bzOKE|bJBP9qV7I9EH6gJbcdAb9$0)$7xyFQU2S~v#kWnTI9FfmX$30 zjDe~KzF2J@nj3StT+Rit!{rLy zdIoox@8IItZ7%NT|6`7()1SGKNg%U8rh&`@nFulyM>7?E7;`};gUrU!Ob3|{G9hF} z$dr&dA(KL8g-i>X7cwzqX2{f#xgnE7W`|7A(aaB-ATmQ_ipU(1Ng}gErisiGnJ6+- zWU9zqk;x*nMW*X$=8H_&(aac`GBRgm(#WilX(RJSCXUP;nL09eWb(-Dk?AAzM-t#@ zGJvGO(c}P00+IzJ4M-l4L?D?!Qi0?GNd}S)BppaTkc2pzj36m-G&w<%f@B3r3z8Qk zF-T^R)F8P*l7nOiNe_}ABtb}qkQ6zZ93e?UvV^1w$rF+&BvVMLkX#|jLb8RV3&|If zFeGD0${bD3kfb@9tRZPb@`fZ1$sCe8BzHKIy!crOi3#zuXHNH=n@&&M%$YRzcARFX zfAU*oM`@m^mua3UpJ`sQ@b{YX-5q;1wR1YhyRmy$hEqQC%4h59P3``#ez(e>dFC<6 ZTwF{d^Xp3rN(=mjCHeJ5e&=q9=U;l9^aB6@ diff --git a/lib/pytz/zoneinfo/Europe/Zurich b/lib/pytz/zoneinfo/Europe/Zurich deleted file mode 100644 index 0cf15c17eeaefb7ca6e7af02896d1fa957c3e09d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1892 zcmciDYe?019LMqBnI3Dh$Zd!?Uvsgq7 ziSIy)D9K1<4Ci`a^}sIFF1T_sD2rAxP-<6X(89)$_Iv+(B5aTQ%fHvD(}Ny--=BiT zo2$~zf1XhLC%ilj_T}@7*F0OywV^t5eKcVDuNIi7_}_KP%lFh1^1XT6veFwRYphx3N4M(y`(?7=p9Woc(I<=U7HM{8spj-9)Wrvv>XPFz`es$UE1M+_9pp@w`laI+ehalH`oynl>|nc=c$6(Pnw z{u!b}LeAFFo-T5}$O-ds z#>gon=j>=t8aZp^w2|{hP8>ONa_-NMcB4NNPxKNODMaNP0+qNPki{B#&f|q>to}OaL+i$P^%RfJ_213&=De^MFi*qn!z4Dv-HACIgubWIB-fKqds4 z5oAh`IYA}`nH6MOka%zg CSha-! diff --git a/lib/pytz/zoneinfo/Factory b/lib/pytz/zoneinfo/Factory deleted file mode 100644 index a65f97edd26d012ce00cf0e2cc5bbce807844eec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmWHE%1kq2zyORu5fFv}5Ze&K@ySn4%uy)G%uQ9O%Fjzx$So}{QAkQvC{8WW)h$j1 gie@G&J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/GB-Eire b/lib/pytz/zoneinfo/GB-Eire deleted file mode 100644 index fe63ff7e7f1e9b47c45c62a7768e3924f8572c40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3661 zcmbW(dvwor9LMqR%&_J1Ax7r%(OjC={5F?_C4|PdTz>J3G{PiHv$Tw~<8*f%=UqoF zAs?4mE_2(Ebs-wU+?tqNqA>SMGG?pK^V@Nbb99`;?{{_{Kfm98&hdx$^W_~dGBL`z z<5AJR!w-+k_J`M1W;9)DX6y^lGk1E-toa+wmosOX*%@_>d2gMblX}z49X?afo3O>q zk6&xP>R6%|G#RWHHp|nQ&BJx(nPRiZ*=rUR)Y6NKF6t$lll0Q9dvw;qc)iS|ndKjN z^omb*nU%@0W>v~clie%AaF8pHF6*)S0|0VtH!T$QY zwR`pVE6U6dpXccHGeY!+aT)r@@uhmBFHLXiJ>UG)cA(B{w?S|A?K7JT1I^FDP37l| z=VjaO2D1Il_OfGzBl&}UYNs5NU87%=-6_FpcS)4mGqOzY9U5kSi8-nZ8Z^!=5O{#Ox63Zf2s?sChNj8XZ689Yn$J;v+H*1bE|Hc z^Ixpc7bcA`7iUk@mxjcc%jpUFN{>YSS3)O!wNVxGcgIkD&ADKT8wTj&qr1)ZvXlD8 z`cQoTtl&`E)?9OkE+cov!GatSc7P(}5~U2W~0TK^Noo11syA z%DX(e%EvcN)#WvGwK0c{njT@Q_g-&mq$%@Y7*3ZXi}VdIM%B|hqO?Q!`rAPJ$g#h z%5_w;=8s9UtF0s~sG5Wo1WWUxOY&%Tv4n5kE00Ypl!&i$q{Y~8#q&{ycuqEUA_pB% zQ7PG~Wpu7;)#o$Sy8bNHCTg5&Q<|>YhD?*ThlZ#pN>ZiWcU@HbgFfl7AVH#Y+sTvf zcan}X>d8}yq0;HyCsgNd0n%kyhT!IY z>Y24j#cuyW;-*ef@k{2&v!h3=UQ^zY-u)*_pQPc^_wgk0#&(zIYR5~z@G$9j%_F{A z-IVXw8uI+rN7R7Tf62gtAoYT&t_EeFRWGJrQ3=!X)!>8zHDuyxd8y+XHFVH+8P;&R z8Xlb`iIs9>M17GFr!wT_(i9oFB~4yACzN$SO8YFyQ8GH%x<_Q2|6?C@2L*0J&Zet9 zoyhq_PAGClkyDDCQ{DXa-NYBjht!ZR3qmaIoZhBcD1J)Ip4?$N6t8M%8_%9oOI-@Bc~lX@5qTq z&OCDJk#mond{=w+k<;&L&p(m?Bm+nakQ^XMK(c_O!PVvgNd%G!Bo#<5Tx~L3Z8nf} zxY~Rm330UZL5J@4DLnMhv7Lha}c|;P4WD-dwl1n6+NH&plBKdT+2}LrBq!h_1 zl2jzCNLrD+B8f#Zi=-CGEs|U$yGVMG{JPo%BN=wJDMoUPBpJyvl4c~&NTQKUyV_Lq zAlFE;k!&OBM)Hj$+|_0rNx7@dIg)fF>qy#>yd#N6GLNJl$vu*MB>PDEk^CbQ0GR>E z6mYe30GR}?b`~Jh0GS8KL_lT&G8K@yfJ_EtHXzdhnGeW>KxPCoC0y;CKqiH&ofXKm zK;{K9F_4*oObujiAd>@`9mw=R<_9uCkQstZ5oC@alf>1|5@ebn^8}eF$V@?|3Nlxa z$%4!lWV#^p1(`6&j6tRhGG~xU<7#IOGHqP#yg?=oGINlrgUlUd@*uMZnLg$G?)B;K zck9VF{qN!XWp@GDcW!^5Ph(j> ix38evXApBJ$nGPL{f+RrmJzKZJS`%_<03u03i=lXY*fnt diff --git a/lib/pytz/zoneinfo/GMT b/lib/pytz/zoneinfo/GMT deleted file mode 100644 index 2ee14295f108ab15ee013cd912e7688407fa3cde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5Ss!g3%07 diff --git a/lib/pytz/zoneinfo/Hongkong b/lib/pytz/zoneinfo/Hongkong deleted file mode 100644 index 45db6e226144e0d72ff942f93d51f1eebc8d2d45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1175 zcmc)IOGuPa9ES04t};^=3T8jJ{nB7&fx zphc^{6%n=Qv~lSbqpM9*X*XxmGP|fbH9DQ=Ytf=rwCD_Heur7k`$QXKd)7FAoPhm> z%h_x%?}Fp8#%#}MgXvAKlfKB2wg=U_TOaPdtskAOlE)P{^uUEX@?=A~Nvv8fiAUCXAzd3YOyx3CZtAJZ3H5D7Tu(39r80q?Iy1RReIKsSKL(p5dv}MK=_r@k>t!Z)X_+{uml{tz zAl?Ih z$Lq8A-#(7B&(A*{KjX2swmBi*PX4cVbxqXS5~=4a>Qq^OpXgt#m$Qcjkrk08ku{M; zkyVjpk#&)Uk(H69UG3V);;wdeWO-zLqyVG>qy(e}qzI%6qzt4Eq!6SMq!d?M3sQ`$ ztp+IvsRthruG#RO8d8WZ|vml6BhrphQ~z#oBr; zppUxRr0w)lZI9lR$F+Wa5^0dwrj$NCeqB43wdk|zv)Wk}lX%5`eLnBDB#J|t7`q_J zS^FgU;*h-TE!3{N+vQdJD(P-KsIPAnNKf51eRC!)Z+DjIyS+(yADFMb!Ki##^jrH@ zCp0y)Ncs!zY5zb*21X+~*wQT@vil;pZx47)n6%(W}+36Y$;X;z|HaKIw>Qsov-bGni!;b@$au(r$cV_0 z$e75Wu69&pSXVnPGO(*185tTG8yOrK9T^@O9|-`700{w!0SN+$0tv&_#(@OlY9m2H zL1ICIL83vzLE=FILLx#!LSjOKLZU*#LgGRKbG4Bnp&_v$!6DHh;UV!M0U{A1AtEs% zK_XEiVIpxNfx6mAkx-FXkzkQ%9Z$~q<@HVF^4qUfZ;acnm%^OsZo7FCpH2Q|o9kr# N{tMXT+N77~{sm<$MphXAD+89|CdNU-NW5P<9g(IET4G#Pes0bQYM%mn}sfGc|d diff --git a/lib/pytz/zoneinfo/Indian/Chagos b/lib/pytz/zoneinfo/Indian/Chagos deleted file mode 100644 index 864d3e29a2b0c9d4d3f35b8d71fb2f3038354f94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 187 zcmWHE%1kq2zyQoZ5fBCeCLji}IXdgU&oOv*cLO6(#Q6zG$}NC_g@GX?fq})xH-y2{ cKLjKQ1R*4t`X2~DCWG`5XF3ATpfM~yz9CSf7#O&KX6l+*85?i`0Ap(qTmS$7 diff --git a/lib/pytz/zoneinfo/Indian/Comoro b/lib/pytz/zoneinfo/Indian/Comoro deleted file mode 100644 index 297c6db63c0689a0ad0d71c9110baee20c9bbb05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOI-_yNe#m;e&hGGJiw@eN^cbqoP<8A3=f=sytP MHH-^rs;)5?0Ay7a4FCWD diff --git a/lib/pytz/zoneinfo/Indian/Kerguelen b/lib/pytz/zoneinfo/Indian/Kerguelen deleted file mode 100644 index 1f42bbc1ffcba50b2fcb07f959ac5ff30e4dc0c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIc_B;HGnu^;1M IR9#ap0K4=P1poj5 diff --git a/lib/pytz/zoneinfo/Indian/Mahe b/lib/pytz/zoneinfo/Indian/Mahe deleted file mode 100644 index d048242cac78343ef9bb795d8e65bb9feb434855..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIXY6FwE#KBe?X!Z4h$?lz99_3&LJQ!LkI~5{RaZP MhH(K+)ivP)058iFiU0rr diff --git a/lib/pytz/zoneinfo/Indian/Maldives b/lib/pytz/zoneinfo/Indian/Maldives deleted file mode 100644 index 65e7eeee8db784070548f3ded2ab7b1ba800d65c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178 zcmWHE%1kq2zyM4@5fBCeMj!^UIo|3Yo&n^zya0*11u(Gq`i3z0hJ}E*3?bMJVg^cq tFbIGQ0kL`h13}of`4S)+Y$#9$Vk(ei0h`U?12P-Qd?SbdH{tHZuK*+#g`U0fV zEr5}Qfx*Iofz!t~guyp77(|4CWPl)q1e^W?0mwFxK9G%I8fYts2H6azNwS>_=n!2K FE&xayB~AbU diff --git a/lib/pytz/zoneinfo/Indian/Mayotte b/lib/pytz/zoneinfo/Indian/Mayotte deleted file mode 100644 index 8401a37aa0ba974b3ea7f748a32d58c65bdd5149..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVOI-AOYlPWq?Gr3>a8^d_x#q9Ya7|h7b}A`VRzn M4dVius%y*z0M}C!4*&oF diff --git a/lib/pytz/zoneinfo/Indian/Reunion b/lib/pytz/zoneinfo/Indian/Reunion deleted file mode 100644 index 9b3830ec31a1f7b12d0b3f8e8e7a521f3a7ceef5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmWHE%1kq2zyM4@5fBCeMj!^UIVPU5YyfghK!OYw4h$?lz99@jt|4H42nh!L2Lil? LaRE)$HQ@pPihdFo diff --git a/lib/pytz/zoneinfo/Iran b/lib/pytz/zoneinfo/Iran deleted file mode 100644 index 16149ed6bf5bc85657f6a684a70341d719df4f58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1638 zcmdVZNk~;u0EhAGP>N`p8blkVC@p6#J!$I8QjfFg^I2+{=A1)0Rhp%Xj3QkWEtF<3 zkZe&D9SNm{!4V5AED8&%O)eCJ3ZeqL-&+N(TD0gq?)_aZ+_(CF)}q>~NaK&=V!q+x zRG1gf-h=gB`uVK4Uh(jT^lS~Wc=cPty%u6ED+{W%cXGP&iJ8~FA*)oNf4dHxy{tA) zUDBJz*Q%hAX&HRgCPMn1bZGY(71k6Z!^_4*L~fmqO!}mvA{X`M^=)d4?>ZU1d{{(( zwdt6TZR&Jg260xJ6GVazzv28F($Dh+Gp|f2kHvANpl3~3)Crl+JhUy&=_f+bK zNhx3Ch_uJqGX24f$hg^~GY4E$*6I5)yCY8I)XeGJ;zqSAqe17ze^&Xy*QM1jKooe) zXq!=_Y>Te4@O{77{j5*!neY)scOU8Ep%hhe;fvhc+adO~1?bZ1+iHK|h%QTyRORBG zJP=eRD%SYuO7{U(`6E?UEj$&~Z=cAT={!+8zNG8!oKgp`MalZ}qoSdwN;kI5tETcn zd8oi&98UI=%`rowWka5BUHwY6x%A4m@9v^~Zd4zcO;ksx67;dL3Dq&uEIY4!6UY08 zbXRwfI??!Ao-8XB4vx-F&W_9e>CZ621tT!;&V~^o3|GTQ$#w8B3}N9pQS!|D%q**6 zHLtY1d~Q3feD>S1{>9Rk%){D{#ql?+4p|Ou-bDnm*` zYD0=cszb^{>O%@dDnv@OYu1PqiByS{iPVV{id2e}iqwh}i&Tr0i`0u0j8u%2jMQw` eEE=gADI2L9DIBRBDIKXDDITdF|G)Cx+BSsff<576UhtMZ`Ni+ z!C&T_P;RLk*3wWjbCI<~+en_&g_`EC3vf!ThgDquK>EEOH~FL1zkbi2y&lf^i}85} za#j`25dXS6%r`t-wRw0Cdnb0`>!+7B=;pRB{NH?VL!4>)%WkPD)OP(w``gznefEv7 z<+*}`>U@#5TXRNRtyd#XT!=X$FNP=SOQV9$rE7=u_lJGr^07#LMZYC}IDAH3-SfH9 zRb}GG>LZI5UhJJxP5J*PXu&Z=PafCvUN?a=Zn9om1;9@hPvHGJPp zdwgTBzOS;&4sRZ?BCMVM$gLk)_op1OC*-DE4@8WxC+5Uj4~lvIs1et7)OYQ6^tBfK z(1{TLr1PED&{%qj8DoPNmi-Fw51 z3)^nRb?x)d_J*q2Egl))ov$9b+@~M4ugk|iTyD*IZ?~MgyTN+=)va<~`MWw{-7GoZ zzsE{Us}WBmXUYXr*NTPV-A>ZTERoc?!dcWACz3n| z+ai|NRXfkrSt565q|B>G6!~jTIacmO@$6im^ITGbS`ptQpO2cL3hpX)3Ws{tO3zo$ z%C>g(!iCjx)ydQ9#RK;^MSJ(F)%*9#;_6ePWW(KZO-a3w8ONNp8CBw?)Wve$v|>>@ z?i0EG&P=iX_k5?Ur%1j0YnR;6nyxk;&6Ass#;DB=e>mkk!c;}&4!Nc5PxZ=DuN>mJ z^$8h#yv3Xk+Q%%S!iAcFYw<}8ESrmhpRCU z?_&ncWq>yG2_Z8=ri9E1nG`ZBWLn6)kcqjPnITg{=7vnp)yxi=9x^{< zg2)V!DI#-3CW*`vnII9E<47HnJ0y8X z_K@@;`9l)uYBGqV5Xm8uL?nwy8j(D5BofIaM=FtAawHSUCPzAve7c&1A{j+eisTeY zDw0(stw>&x#3GqRQtJsBa_i$Ae7#+7X0)cRZgEX(O>xanrnsiHrnsYSev@X3`#;q+ Hof!TPYgWv} diff --git a/lib/pytz/zoneinfo/Jamaica b/lib/pytz/zoneinfo/Jamaica deleted file mode 100644 index 09e3eb93996d4498012f7fd8dfebfad416ebf102..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 481 zcmZvYy-vbV7(h#5D6~kGKXEcTm661OT>=E0?1EDlAlF!y;$O2|_ID3UKc)0*^a0o~O2tu%1&I*(QVG!U3Vh~&4 zKM diff --git a/lib/pytz/zoneinfo/Libya b/lib/pytz/zoneinfo/Libya deleted file mode 100644 index 943f9a36b1200450ac52d022b40f3a3594323958..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 599 zcmb`@KQ9Ae9Ki9XJp=V8XK_kPX=~7kH%piB-tcL?a=QhecxH`5q>d#B+J>bN4KFzi+U-x#5dntI3|QSxLKj?mT$C$lRV) z-MjRWte3Cd`op?zj83V>VNE}kE=||&jP#n{l=q&~-H*d2ezPijYR9Jc{9YzbwoP*1 z(|vobs(L7)XN=PZB7E%nUhLl6|{}+zg+#`PM6Bikt AG5`Po diff --git a/lib/pytz/zoneinfo/MET b/lib/pytz/zoneinfo/MET deleted file mode 100644 index 71963d533e444362250dec5465ec58517ab6c09d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2102 zcmdVaUrd#C9LMoP#7buLMT0{EViKZtFV%Kpu{nX^A*^?N^8ZC!O&zq4nrXXm+jE}qXj zvTj>*k?$Ypa`z7xXP3LUpVmL!zp;Pf)cFIGF%1kJ)pKu32YdEubXuFn&aSc(FZnh8 zLeM^Wro>J@nPZ2%?dOLy>%FIye(bnq9En-xfrB=?SC+N?37gXrwd*!C+T7}hWtWHS z`aqfGWaQes>1mdm5LE8P63zcMM++uWb;Ac&=*Hn+6&U^h zpR}UruoYK~Sjn1atu%AM%8ELzY^vK9rT1yk=}oryj}9$49<-aktW)_=gDOUr=$4(! zwX{D&%bK&byl1i9TA83=Q@X9lIjc}`$|@5+QdRcXR(0+>TN(e3tsEb<+s?dbt70!( z_1N1A@9njkBhTyh)>gZt_bIKuYq!?4Y*y_}Es9iE=}v!*)&>@6?WF?MrBqto7c+GC z#rd}G^~ou$^cy4<48etWoZwzY?T zvqzGB){&p0j`QDGXVN8go_ycB&Q0pk*M{t|@eys`|E_k#2K0E>pt|>V%NKW9{D0x+ z^JUD5b02Jy`4awq9}d+}77)UfcT{w_< zAOS%lf`kN#2@(_}Do9w6xFCT+B7=kmiH)ZV4iX(t7ak-&NPv(CAt6FygaiqR5)vjP zPDr4TNFkv@Vub_?iI%4e7ZNWdU`WJ}kRdTcf`&v52^$hOBydRNkkBEqLxP7y&(nnu viJzwnAQC|&gh&jLARG2Un{xpGmY)pj diff --git a/lib/pytz/zoneinfo/MST7MDT b/lib/pytz/zoneinfo/MST7MDT deleted file mode 100644 index 726a7e57176567044d585800c37cbc917b441d22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmdtidrZ}39LMo5NFgUKPZtaU&9o#45Kt0MW>nA#=>*{s&7cX4}0QGc-|jv;l>pCYwQs<{zIKioT*il zA9!WzNU@5%nJ%(3O+|H2N%W(WYTEi#9n(0|TvRooFD@B3v3Vmp_L)Kxr;h2ky$6(M z^c8){7Xv2#>`_TL)@c&o8<3>8`jvX2Q!ed!QeC#CSuPJYsVi3cB)R-{HKRCFuFSkn zrOYkUGvhoeH9AA5{x;vFeHEwE!_&>I<3H)y2hN+T22ScZp;_wcC-&*NDKk^sP~gs>gI;#vSU0f=~70*eq3)_NNqmAFqnX&x-fNFY3n624%^9kGW}Z zw=CWMv$=WKHYsWS*xb^!OW#_#-`v);RhKS!)|8d5)@8pBD_>5#_)hOpFL-xXH(4)sVw(_yu`Z=KxdKV=%byY>A!2h9U5LEV(F z!!-LUbn}IfY01dZEhp9_Kq^Y*;VOd`| zsW!A8mW|2h)TYW_*)%n7LPZC4XykLVIc105Jap7-84Kyh`UcG7XXLxzTo4H+D|(ec6XI6FRIfE*)4hKP(286+}FWSCAnPGq1? zJ5pq*$XJoVa*P%kF2{J00dtHP88XM1kwJ5e8W}dnxRHS)BS(hrv|~pGkBlA}J~DnJ z07wLo5Fjx?g1`|4Bn%vJKmy^kkw8M>w6Q>f!4VB497sHnfFKb;LW0Bu2?`PwBrHf= zkia03K|w_ff`mi~2@?`0Bv4KpDI`=*8!IGOP8%&G zTpaO20)|8k2^kVIBxp#~kgy?fLjvctkwZe~w6Q~i=d{s7!p9LmB!CNx0EJtLK&^m2w zk>EOQbdm5nZG4dcBN0YIjKmlTG7@F{--Ov?YrWW3JKMi7w;(q!+n=AGo1dHK`5U$l BL=yl2 diff --git a/lib/pytz/zoneinfo/Mexico/BajaNorte b/lib/pytz/zoneinfo/Mexico/BajaNorte deleted file mode 100644 index fffdc24bfc4c076584787843a5a6b457a23c5bf2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 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 diff --git a/lib/pytz/zoneinfo/Mideast/Riyadh89 b/lib/pytz/zoneinfo/Mideast/Riyadh89 deleted file mode 100644 index a50ca48a91b9f37ae573a09c21bc208d8b0bbe60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8539 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 diff --git a/lib/pytz/zoneinfo/NZ-CHAT b/lib/pytz/zoneinfo/NZ-CHAT deleted file mode 100644 index 6329e4fce0e5e7cd61329685a3e80adaa2107fb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2018 zcmdVaT};(=9LMqhF>~Yaq~;isp{Du3!{I?dFd~#^kzwW4y2 z)wE?-)GTL?TBL2(MS*P9x~QzythMZ$ZE?}iT&*V!`@R2NcGXqu&(3+BogMDJ?@y$q zBUb4B87;w9;%#8-G;k^XrxV{$^zavXpV8PFH`Mq&ZJ4)itB% zlo?Od+!s!1UhRbD?>VMx^Al`A$49m>^#{8y6wsn6t88)dcUpXQp)HwsS4+pHS=NU~ zls&XSIj`U$7O&JMH?B6qO%nvKt0}RK<=0yRr9ERkp6x%C&0_NeCK z&#IklQQfb7R)3~k4X5L_`khRzIniK^gPy_%vu*9Jvuf&2wwq#;cC)f{ORZURWs)L` z#%$f(bBa!T$)cA}>DKQbxAor~(}wrjt!3mH-S%3aT3;Tv+nHkz02-w z%GSpEsBOwi)?G_VZF9WOh8}#Y#vVFa zVhsef)vv7f-E- zIz(DTdPJH;x4YD`BZgY^`LAD3kA7q1&9YVGU*&}3=kX=Hy3E3xP zqmZ3KwhGxRWV3wTZXw%+>=&|O$c`afhU^)#X~?eO|8d)bZt$8TxdnwQii-X1%L$i- UibMH%e326_3Kh7|%iQPSUysKGR{#J2 diff --git a/lib/pytz/zoneinfo/Navajo b/lib/pytz/zoneinfo/Navajo deleted file mode 100644 index f8908febf220f27b3efa68bcc119633c8efee299..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmd7TeN5F=9LMp)g90~@Q;8vb6-07=JX* ziZRO|P|{j6@nOxzhPsApE1ScuX)UzpvTXFQNdotF-Y4uI`@g<-KVHAx`}gOKYqe)> zhPdW}%{M$;r+IjnU3+u%8~q`w`^7lj^V*MUca2Z)X`U*2^DpS$w!P}3)^I&E?~nSS zs%UXJ)vHGrw2MC@-TF$XS6mr=T8{nT7UO5j<-~_M!gn-V`rnEZVrQ%jXz_`_XC`FO zh8PuGHB(P18CO$t$8<>AunKu8Q-{gpDs2Bj=@{9quDj5q!_OTP5yzYKwD)^N|R~3k;!u#cn>;!RB!U7pRH($*RbI6#$cop;8d>#8$n2H+; z)w53gq-GzysBi8$rRI2N$y;_DP;*!M<-Bzti(50ll(#K=SIm$4K*lF(5$`*%6C4{w z!te>5c+n+pAK0Ul&eW^qt`~I5;Zl{_SgX@sS)|fyn`OqP8ERp{TDhonRAt6LAn(Zd zOf3#clv%NtMb`J>GJEWt$T|6oyz}#Zv82zT@9OUqOWS_dckkLRa_c_P_cZTP_ZIi* z`>MC8ywsO0D|NEdUNNx}XXZFd$h)Pj-xK%E@lq-r}e^W32v_d%>TJ(eOEmg%8 z9$nHgM?JKpNSAs8)rz=e?OOSba*apovdojJ?As*ip8d6O4^ES-e1l?j?}&VOc%P_f z9+Hm?w2I2=BXUjGdhw|9w61DtQI91b(vR1ARCPqVt|=%|HJ7})Ha=O^o^oqXNTl-Y z&(Z6?`&F&)D3?#1o+h63X3M7zjEK6jSXtjTBsOGD$c=SJ#HOh8a&vKq*z6nA-mF8) zJN$*-65X!03>?#2N4@IVt{(l|S+{CvY|`6~=BUQX8ohmIoDu$$7L${i-BZIe^(Idl0#*YMmBLYYWIAVYVfg=h?7&zj91cD>vwq2Y)P5*(|E4iX-#i4PJWjtC(kLSlpj z35gOCCL~TsppZx*p+aJX1Ph545-zKW7ZNazh#?{4h#3+zj;JAFp%{_#pwbng}8xL?ntx7?C(4fkYySgc6A*5=^U!CK67oi6;_JtBEKQ zQjVA+LFI@l5>}45B7xN?B<@Jyk;o&V4-A<61O@-|diAUS zUeow?VVY-pZ%S`^KUsSFja=?DoxisEHu@sKVg3~?Ha{mh7p7#Sq$N4i(^Jw@(j0#Q DJ6nx# diff --git a/lib/pytz/zoneinfo/PRC b/lib/pytz/zoneinfo/PRC deleted file mode 100644 index 240c4c6f76dae5e2b0e4156805098a72034dd287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 405 zcmWHE%1kq2zyQoZ5fBCeK_CXPc{co;wctbyW5bDG>IEmS@->{g9rZzOml=b6W_^J| zT}FeVXJUa;oL7UgrgMRcdpd)vQ2Ylqbx#JhPmUin*tHonE-8OtVnl-s422JXhBMSn zU}RxnC}?2d@bL{{aCQOW;1G}m5QLE6$p1h9awv!fITlO<9SovDjt0>nhl9)oIUWQ+ z9stoGPk?BUM?f^lGawq|ArKAn6bOJk2BJZp1Jghcf@qK@!8ExZs*V+C5^A4_S zsLS*GA)oF}HG?yM-#S=5TU{P|N?*BHr^e6J z>c2iNRud-!I`W2Bc@AXisAm&ZbZdg1wCy&Dsm?HySI5hgC2=M;=O>BXv&_V)&m`{X z`#S!YW0Ek^V-mj^P)Yq==IVEP)HO%m((1)7b?t7^*R?gP>l?P~8>-f*mv*$IQ(K&x#Js(YHMLp3JCB(lZ;s zRkQMc*0-*BSItiTQfGL>Dq~{QWXA7OnZutO?+=^QoWA2GYp7ka!+VXdccaX0f5hbM zT`IZtFX+7HSu!usqUTpkk^GEGU66NC7R36sKW(z|Ur5ypuUt@zJ{s4BXFpMkkENK~ zPra$`=)7$1e0h($tLZzlq~nMzE$cJOYMz&(xyCFn+9Jz;8`6R7=TulLG`)ZMT2nw4KSO6ksSv+C`YQnr4FDc|Rl)r+glJs~9(X@w@Z=8^=*(@kamS5kRy zkzPCfSGD%TG+i|@q}Cmt(Dx0WQ0qHJ^!*WU6V+Q6a-Z#^tmFLq>)S4H+9UICP`q!SFbCe82#a5h6oG#)u3O86`4IryVCU zP^TR!GE`)&$Y7DtBEv<-iwqbUF*0Oi%*ddTQ6s}f#*GXd896d^ryV;ocx3d*@R9K& z0YD;vgaC;F5(Fd)NEnbfAc1h&NFbqb+E^gLK%#+!1BnL`5F{chNNAikHb`)g=pf-i;)4VTi4YPZBt}S(kSHNxLgIu3%4s8ogvx1Sg#^oKqlJVE zi5C(uBw|R&keDGsL!yR+4T&2PIH!#q5;~`i9TGgJjUEy{Bz{N$kq9CoL}G{p5s4xa zMkJ0%AdyHSp>*0Zs+IS)XMIwrX6p1MkR3xfMSdq9Qfkh&Vgw|O_vVkE{$kdY|k|0c}ww$^@I?X1#yzC2$}R%vdoFV~k7|2MIyR0IG3 diff --git a/lib/pytz/zoneinfo/Pacific/Apia b/lib/pytz/zoneinfo/Pacific/Apia deleted file mode 100644 index e6c3c59f04e7789122c5dc47a7f78c5a7a48e5cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 343 zcmWHE%1kq2zyNGO5fBCeb|40^g(kB8VYrpVV&OAieS`0G?FW9fj}rX;b}#TR=Y7D) z#LUFZ!utPzJW%ET|8X7+EdT$f1~72`|6iQI$jiWRc7cJ@$2Wu_*bzvC2ZOLn z2v7$CgkX0N$Ppk60vtdLVhjBTg3uFB8$dM3aUdGxK#(GkBSAFCp&%OMSTGHAFo=da bng!@+pyxI;fLu+f+ZhCCegnyaa0VZZnDPg~{RKF^->`t86U=lt<`pS;4d zk~r%>mzQ~mhwF9oa1LziXm{;hys@CY=8SXS{4>%~(C>UNtY7vgv^qQ8Tcs-^xfOAoz!(RKLf$J)Jl$ko%dTaT^JC-obyV_wJqQbAG4zHvXx8Lr2uV_M`@MHECc`kKXud zosLf4p<`-Fb!_N!I<6p7$BmR|P(p+To!ub8lQSf^f2D-Dg-b~D0=el2Kbf#`hTPn9 zPC`q4W#XHIGAVsnCO_RSx5RjBSlMSfCGaP`)!`;nN6ph|{-rxKC#EdTIEl z%@VOIOd{XeBvJLA;%Hbc(W}l%OnJ7%F8oO1^2>B)_%4|hzes2MG)R0cakd2OuTS$kYkmgmUaq7Ipt6eIJKUy;-aVde%vMoY4{MQG0YQ<7WluXmM<=wb<%yVF&d zr1(kR)LvaW@tov)y{-9I2j!k0pVxx#+hy4?rxtd2D$ z{H5~BzhqP)^l{`BB4P9sD%evp6(P~YQny-uXv7Qil z{6LyM(HgH$?pPt~HwA0$v#Iiw^AEM$MqTUnboaQfw`J`aa5H;&tIP7Vtd<_m`v={8 zIGdyWnp3zW&&nyx<|Q?ccis3muDt(W+zsYWJY3t&!+GpgbIt9{YC+bAED%{CvP5K! z$Rd$dBFjY9X=@gWtQ1))vQ}iV$ZC=0BI`vKjI0=0GO}i5(a5TiWh3iG7H(@+jx61L zSBtgVn#CilN0yJQA1MG*0i*;-4Ui%rRY1ys)WOyi0;zNq+m$Jkdh%aLyCq}4JjK^H>7Y#<&e@LwX-$FL#l_A52+tg zK%|0536UBiMMSEIlo6>TQb?qdNGXw8BE>|iX=}=f)DtNvQcKoDkEh^>WmZ`sWeh*q}E8Wk!mC5M(S;A z3XW79DLGPer07W1k+LIoM+%Qr-Zb9*TDO;n=XJd;t7(YOX=3kT$KKnHy*ZoM2iTc6 s=awGJBg@YGzk~lz@hu;I4x(b?_$`RcPISz6#6)J#a>P1fqG$U24ct};!vFvP diff --git a/lib/pytz/zoneinfo/Pacific/Chatham b/lib/pytz/zoneinfo/Pacific/Chatham deleted file mode 100644 index 6329e4fce0e5e7cd61329685a3e80adaa2107fb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2018 zcmdVaT};(=9LMqhF>~Yaq~;isp{Du3!{I?dFd~#^kzwW4y2 z)wE?-)GTL?TBL2(MS*P9x~QzythMZ$ZE?}iT&*V!`@R2NcGXqu&(3+BogMDJ?@y$q zBUb4B87;w9;%#8-G;k^XrxV{$^zavXpV8PFH`Mq&ZJ4)itB% zlo?Od+!s!1UhRbD?>VMx^Al`A$49m>^#{8y6wsn6t88)dcUpXQp)HwsS4+pHS=NU~ zls&XSIj`U$7O&JMH?B6qO%nvKt0}RK<=0yRr9ERkp6x%C&0_NeCK z&#IklQQfb7R)3~k4X5L_`khRzIniK^gPy_%vu*9Jvuf&2wwq#;cC)f{ORZURWs)L` z#%$f(bBa!T$)cA}>DKQbxAor~(}wrjt!3mH-S%3aT3;Tv+nHkz02-w z%GSpEsBOwi)?G_VZF9WOh8}#Y#vVFa zVhsef)vv7f-E- zIz(DTdPJH;x4YD`BZgY^`LAD3kA7q1&9YVGU*&}3=kX=Hy3E3xP zqmZ3KwhGxRWV3wTZXw%+>=&|O$c`afhU^)#X~?eO|8d)bZt$8TxdnwQii-X1%L$i- UibMH%e326_3Kh7|%iQPSUysKGR{#J2 diff --git a/lib/pytz/zoneinfo/Pacific/Chuuk b/lib/pytz/zoneinfo/Pacific/Chuuk deleted file mode 100644 index 0ef473871d5569e7db3b4a5a49de10c314f6449c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 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 diff --git a/lib/pytz/zoneinfo/Pacific/Efate b/lib/pytz/zoneinfo/Pacific/Efate deleted file mode 100644 index c46154a8056cecd7310434e01bb646c72b253716..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 464 zcmWHE%1kq2zyQoZ5fBCeQ6L7fc_)26v_oZXJ-mm3Bd9(Vhdcv%dw%HO)I9 zUwtD$A$zxjV)U*6CGWWo%GPrNRJ7|IRHf?z)VLEJ)P5%fsK0i0(0EdFL9;Q?LF=W* z1?@y*2PQ@=kbzJG{`3)8sr-g4e}9)2Kfp^gM0>}LB0dgARmHgkS{?r$fqD0b0|OVxZe2rTE&$ASBNhMv diff --git a/lib/pytz/zoneinfo/Pacific/Fakaofo b/lib/pytz/zoneinfo/Pacific/Fakaofo deleted file mode 100644 index 2a4e7afa5ea52474c883a7c407a015d48d8b6b1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmWHE%1kq2zyM4@5fBCeMj!^US^WNXFJS!tzc>NNVL0-Dfg!{@1jJ+r!EOjMPzr=W w0Av7&&G8=y>dZqsK!RWcng0KeuV7#Ro67<=m&M071a3A10~gR5T|*Nt06uCSE&u=k diff --git a/lib/pytz/zoneinfo/Pacific/Fiji b/lib/pytz/zoneinfo/Pacific/Fiji deleted file mode 100644 index 797842aa3e1e02795df1f57e7382e31a456322ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 324 zcmWHE%1kq2zyQoZ5fBCeZXgD+d1nc4vN5w3e_(d~SAvC#NrJ`pI|<%`IuE?p@hA8k zdX?Z?_P2!jAf4~Wh29|-Eqc>Vwd ZRsanF8^hw`8v-?ofq@HXrmmq87XXt35jg+= diff --git a/lib/pytz/zoneinfo/Pacific/Galapagos b/lib/pytz/zoneinfo/Pacific/Galapagos deleted file mode 100644 index 7504cc66f5006ace130bd71e12cac7bff2dca37b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmWHE%1kq2zyQoZ5fBCeCLji}dABX`X^@jR62Qpx|Nk1G!2ka{H!!gL|G#!3r*rb!J=utkfux diff --git a/lib/pytz/zoneinfo/Pacific/Gambier b/lib/pytz/zoneinfo/Pacific/Gambier deleted file mode 100644 index fc49c03f6e043bf58534f6f4191717e6be1983d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 zcmWHE%1kq2zyM4@5fBCeMj!^UIj018urU7r-&n)I03-_-SbTg#7~CC!1PFwXVA6je Mz;7BC$XrV<0QR&STL1t6 diff --git a/lib/pytz/zoneinfo/Pacific/Guadalcanal b/lib/pytz/zoneinfo/Pacific/Guadalcanal deleted file mode 100644 index 3a4ec12e56d7663327bf083dbf819ddd86eb7b81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 158 zcmWHE%1kq2zyM4@5fBCeMj!^UIi~m<_W(Ilzkoz%ZD3&W@eN@Jb_xM;8A3=f=sytP NHH-^rs;;3S7XWgx6{P?G diff --git a/lib/pytz/zoneinfo/Pacific/Guam b/lib/pytz/zoneinfo/Pacific/Guam deleted file mode 100644 index a05292f4bacfb1b9468afd759ca08abe0e36f9ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zyM4@5fBCeMj!^UIjx-I5`dhZ1wamnWN{A;VQ|g>5+D$Q-6R&E6bOR= zGZ2H=y#Ikf*9RmCHl2z2|9>+R5Vw5`hy>XJCOLe3Ll{u(14(m%Y}Yk3 G-~s@L^C5Qt diff --git a/lib/pytz/zoneinfo/Pacific/Honolulu b/lib/pytz/zoneinfo/Pacific/Honolulu deleted file mode 100644 index 1b4684b9b47fac79b03841013853d50a5a53abd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 250 zcmWHE%1kq2zyQoZ5fBCeRv-qkId-!;d+b&$j5ytCd*V`}r^VIYVh=_JMh2$;|8pW3 z82!g3%07 diff --git a/lib/pytz/zoneinfo/Pacific/Kiritimati b/lib/pytz/zoneinfo/Pacific/Kiritimati deleted file mode 100644 index 7131453c55407adc34e83b416603dad85950af1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmWHE%1kq2zyQoZ5fBCeCLji}S%pGBG3c|^Dljtr|DOdE`2W8+0Z1_%dBDKnV!AG=S^?+Qb6338(>R6N`^; Q2(oPq3|t_)bq!6p0OD^WM*si- diff --git a/lib/pytz/zoneinfo/Pacific/Kosrae b/lib/pytz/zoneinfo/Pacific/Kosrae deleted file mode 100644 index 61b7561589cb7897117aa8a4b1f8c8d606a34884..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 zcmWHE%1kq2zyQoZ5fBCeCLji}S^u|52bguIJ1_z{vo-(;h7|`uB#7 diff --git a/lib/pytz/zoneinfo/Pacific/Majuro b/lib/pytz/zoneinfo/Pacific/Majuro deleted file mode 100644 index eab93a2af9905e0b3865af9f85f93daf2b90ee39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 171 zcmWHE%1kq2zyM4@5fBCeMj!^US^l?42LL&VAHV`PYpaCcYGM5ExE{l(E2;6K21}>mAx`swv074=gc>n+a diff --git a/lib/pytz/zoneinfo/Pacific/Marquesas b/lib/pytz/zoneinfo/Pacific/Marquesas deleted file mode 100644 index cd2d5b073afffce74f34a5f984c3e5b7c95086f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162 zcmWHE%1kq2zyM4@5fBCeMj!^UIj02pcrgC|Uu(g@@c(~R1_O(aZwQ00V^9c46+;LK TCjAEj{HAe%%(b*KHsAsPO8gu9 diff --git a/lib/pytz/zoneinfo/Pacific/Midway b/lib/pytz/zoneinfo/Pacific/Midway deleted file mode 100644 index 8889a26fa7c87074fcf89c15b5bb5ac3c7cd3246..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmWHE%1kq2zyK^j5fBCe7+c_3Y1f8lZ%Y+^T?*YGrEOrq$iT$>|9@%#1H=FS#R-fo zU^WMsP{!9WZHA=vF>1I;7$PFOH qV0SPvG6OA-+yQb3&^bUh&^b_tfJFp+e1Xov;UoqIE}#ny4Y>d}`bgve diff --git a/lib/pytz/zoneinfo/Pacific/Nauru b/lib/pytz/zoneinfo/Pacific/Nauru deleted file mode 100644 index 1d8179bcb50d105c5c6ccff136832eae9310f911..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmWHE%1kq2zyK^j5fBCe7@KGDb8VK>TlRZga0)08>}EN^$i&FZz%Zu*v$D-JNQ`1pn}_yvV9cm;=mq`@GB1iStN0mwcO4YCtNgX{$vM2_8DK*#7B8gT&t DxL7Z> diff --git a/lib/pytz/zoneinfo/Pacific/Niue b/lib/pytz/zoneinfo/Pacific/Niue deleted file mode 100644 index b9f18a544ab4cffee02a84dfdcec9872675b377c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmWHE%1kq2zyQoZ5fBCeCLji}S?)NSCJ2|Ke-w-6r N7#O&KHX9mp0RSK#D_;Nr diff --git a/lib/pytz/zoneinfo/Pacific/Norfolk b/lib/pytz/zoneinfo/Pacific/Norfolk deleted file mode 100644 index 2e989c25561771e870d4b45ab405fe7105b2cfb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmWHE%1kq2zyM4@5fBCeMj!^UIqo?AXaI8NHUK#c3wJQE`1yt~__>9ExC|lK4PpjL zfiMVw3<0ru{sTdsnRo|?1{(^LnOgx;0yLWiY&M4v$ZRC@85p>LR_PiVS{WN~0RZqn B9?}2+ diff --git a/lib/pytz/zoneinfo/Pacific/Noumea b/lib/pytz/zoneinfo/Pacific/Noumea deleted file mode 100644 index ae9e138fa566f2053c96d6c9689474068d3d03d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 300 zcmWHE%1kq2zyPd35fBCeb|40^c_)26Qo{FaR{($5?gIkH<^%|uzjrWN;Qhf^!li(T z5eS)C7#Qa8fb^_5zzAf|+Q7hx%=YmOVeoSf1`#13Rg8=vk|BfyH~a?zkUK#7KyCri eAoqZ1kefg>$Xy^B4 z!2o2Z1~71fNnS81=;Is05bOvf{DMOmoPanOh!G$JyX9;^6(9@(Ad5k4(f>dYdg4h3 lhz26^LLqK>4kQ0Jk9}`dtgh2qL2gK(14+M2)W^aH3 Zbs``cpfM~yz9CSf7#O&KX6jmU0RUJc5K;gD diff --git a/lib/pytz/zoneinfo/Pacific/Pitcairn b/lib/pytz/zoneinfo/Pacific/Pitcairn deleted file mode 100644 index 51f01c6410da8f9b518d07c1f040d830d0f1200e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177 zcmWHE%1kq2zyM4@5fBCeMj!^UIZR!gI2ix`@2Fs4`2WAZfq^B!FN7f=I0U4KAq2ZY z%s?p+1_6*EAU4l`AgD9f`vMXK8_M+me;W_TRG`@`V6!=Ve1T>ona{w$1+>b73jpHE BADRFF diff --git a/lib/pytz/zoneinfo/Pacific/Pohnpei b/lib/pytz/zoneinfo/Pacific/Pohnpei deleted file mode 100644 index f175ea587502fb875d165ea4ac3ad4b657b58b99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmWHE%1kq2zyORu5fFv}5Sx{OVb%r)h5&!R5FjrEyGACU6bOR=NE3+7`5y@C%oNrD a1*U-Xg3Mv@@eP5Q#lXM?GF8{mkP86B{t?Fj diff --git a/lib/pytz/zoneinfo/Pacific/Ponape b/lib/pytz/zoneinfo/Pacific/Ponape deleted file mode 100644 index f175ea587502fb875d165ea4ac3ad4b657b58b99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmWHE%1kq2zyORu5fFv}5Sx{OVb%r)h5&!R5FjrEyGACU6bOR=NE3+7`5y@C%oNrD a1*U-Xg3Mv@@eP5Q#lXM?GF8{mkP86B{t?Fj diff --git a/lib/pytz/zoneinfo/Pacific/Port_Moresby b/lib/pytz/zoneinfo/Pacific/Port_Moresby deleted file mode 100644 index 8d4d12ccb09468721bb4473d729f55ba725b93d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmWHE%1kq2zyORu5fFv}5SxX8p=SXDLx6h-kQ0JkA2U!2gh7A_h(T=L|3DD7Es6s~ o7rk9Ffe|Rv`2(b+^8?gWP9NV8h5%m>0X7~a$pvKU8X9l`06WDRX8-^I diff --git a/lib/pytz/zoneinfo/Pacific/Rarotonga b/lib/pytz/zoneinfo/Pacific/Rarotonga deleted file mode 100644 index 581299788a6129d4565a8dbbb0fdd53f20e2116e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 548 zcmZ{hu}T9$6h(KF1to<<4Pn?#%otrFR>nrf!eS96(aJ51l_E$Cb{3KpLOOpy+;Z(K z()t6bf;N7FSjEmSaC~Pv(Y)c!8QwH=&%`H}7wgWS%F2YMd}+?P{2*AF-Fa4X-M*f$ zJg7qJTo+7N6}NVEaeSYs>RGBrH;JE#Qva!y1Rr5qy4z05!>M$kT}~>GpQ+w6$zuOC zt=3CwsWaBg`EM0AUUc~Nu4=0TU3(jW=qKp$!;n6Ar36X1H=Wy2gC`)3&ah? z55y6~6T}t77sQ#Rc!RjJ6n}0uGie#q*+iXa^sGkNMdS3rAsTL!4sdKN%Q7T4 z!2o2Z1~71fNnS81=;Is05bOvf{DMOmoPanOh!G$JyX9;^6(9@(Ad5k4(f>dYdg4h3 lhz2b2mz^L2qD3w P|3HA>G%k?2h6Y>!m{1*E diff --git a/lib/pytz/zoneinfo/Pacific/Tarawa b/lib/pytz/zoneinfo/Pacific/Tarawa deleted file mode 100644 index 065dcd819473ff70bb1171eb97be0d2efac50f75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmWHE%1kq2zyORu5fFv}5Sx{OVZ{Lk26s=N5FjrEyGACU6bOR=NE3+7`5y@C%!JMW b1s0irWPs+d`1ppv%wk~R0-367Xv75o%jgl& diff --git a/lib/pytz/zoneinfo/Pacific/Tongatapu b/lib/pytz/zoneinfo/Pacific/Tongatapu deleted file mode 100644 index 01ab6b87ef92e1a1ba7191614e73d4fab354b1c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 313 zcmWHE%1kq2zyPd35fBCeb|40^IZqZlO)&rMe!=2$?FB0qjsUBo9S+uyUj^6%&2nI5 zVrF4vVPs%fTL99t?E;8A@_>;AnH}OE!Vuyg90HVL1S$oA5bXA|0i{3~1UP^g#OD1E z1a)TYJ3utZEg(sddq6bEO&}WNE-(#r8;AzE4@AS<$jZdZ1azbaNDSyyi1UCX(5XOs ZfX;@peSASqg*zASUIs3psIH+g7XX;rJ(vIh diff --git a/lib/pytz/zoneinfo/Pacific/Truk b/lib/pytz/zoneinfo/Pacific/Truk deleted file mode 100644 index 0ef473871d5569e7db3b4a5a49de10c314f6449c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmWHE%1kq2zyORu5fFv}5Sx{Op=SXDgR@6y2#^_P2!jAf4~Wh29|-EqI931! a)w{MTVCMP2x9Yu9Ztd%P-Bg53JHD=HI=bS6;PoJ}MUeAH^@9+KbXD`U> zZ|*rE_Ak6S@7p)`@J&18>bJCs$l20xws~t~m2Rupr*D0%`gZ9?-M)Fh*)jK!sVrWR zbF}b#Id);Re7!3|>)uJ1Z`KcxdS_Qoedz&ne8c*J6KiU7PR_YiaB6g{Hq6{Br+e4P znfOTgHn?0Gy+^e1QjuKrpD-7%);O1be9yUjyxeK(P;QzId}w~%U16?l-e7(^m2H}r zzhbV|q?+HerZ8}NMz;x|-V}SPhxrg>{2-mpJ zTkGRBe`A1;j zbbS6?oiHe0{h1?mV#FAo6yIAX-AvFa9Y@HNGwpTijb4(y|GG|V2$AXALuE!ylguo+ zCbP=wBxhEG%r3sHbB28+&&@cdxiOn$Zd#S*1?|&$(W>(=#W%~R%zrL_@ zn&yA8NM3wBO&3;9keBAiXu;}%vS?hYEY6FNC5c^SX~tjja;TBQejT;2`6nrAcTll05kNwK z!~h8b5(Oj-NE}>kAdpBPp+I7R1Otf%5)LFDNI;N?xZ02)F>$p)L85|$1&NER4Ga<) zBs55Dkl-NELBfN?2MG`oAtXc`V&rOrghYu$n2Xd>Z6;)w**)kYKvsjH1C5>zCrNLZ1$B7sFBi-Z=5EfQQLx=47D z_#y#DB8-IC)y5bJva5|U5@saMNT88OBcVoOjRYHsHWF?m-blcah$A6)wJ}G6?rNis zgdK@H5_lx?Na&H+Bf&?akAxqIKQaKw2p~g%i~%wTu67iVVL-+K83<$~kfA`v0vQZs zG?3vy#se7;WJHi5LB<3b6jwVc$gsHDaX|(K85v|~kg-7q2N@k?csxG4CxHP$ty=rM zf%f9P{hjMQFMfERmoGTv!N2Y-Pgu3F%VYN^$lV`zZSLOf{)D>A6Mpye&VMuQ{`~I- g{da`y_Yk{NeG*x$_^hP91N$b#XC)?Jzod|V06(!8vj6}9 diff --git a/lib/pytz/zoneinfo/Portugal b/lib/pytz/zoneinfo/Portugal deleted file mode 100644 index 168accf060c3837af1bd64361bd0dc157dec0ae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3439 zcmeI!X>d(v9LMo{8z~}qPzho=q-tqOB(^A3ZWB$DSdxoa(pVz4h~ru&lqMxrC1W0H zsjZHPWl~~`t@d4r*s4T@l-jqWp{S<%e9ug0bo!z?<7LmCo6mJ8yz~41ojnJ~2iX4c zlu_UC<|$BbKKsnPHdibN8>TP#<50@Ng?IHuIg|8nl3n`Z%uS{d>(rM_yQQbM%h#7C z4%ah$JE`O36=v27UvrJoNniVgySeVmq2_wMj=sS)MbGYBLf;$^ zu5T%SSl{w|tG@MqroR2~W^>1umFCXHvHGsBr<%Lxo93RR1at487;|5AM{|E$cl|(1 zfAe6gIp(40Rr;a)OL~sIv7Yll(~n&4XCB=cX&$|^v@ka%tT6XNx_NANQ}fuqus(UN z^uoLYyY%Cuz0BjQ1{R)(Of5XIY>9r-`NTY#7Fu{JAinU_=acl)J@%X5hi){_1fA4= zXs}m1TXlnWu5^ZW?&)kT|K?=v!qy&I!TMC=V)|&~(#&|HaAJ4kC)bC@<$giNmB@z1 z&+UDTs{x+Iwc5qTb)N>>jWX4=8_&vUH*fu}-8z3)yM5%McIUg}+TG0E+P(SfwEI)j zHFMlo+Jhmf+Asar7)4Qr@z62DcoaC%_|`q<7IyS>?(Oqv~lxR@*m2 z`fT4Js;|ltH5M)wHPfW1HU2Z9CAdWG-u*?LaHsHX9W37TYcA?muP5H}tRm{UJ7m2_ zO=bP7b!CGyUb5kVlJf2BC(x1i zn$=h&ng=9_=EcdPrOzzcvY@XBdNxM3+TjrI{unJ=FOQXNwzZP)O>QUKE~qZwkN1`B zQiDYM5O?W_^AR7^y)J_t#UjK#M|SYNBs$!?CPLlzh|s*l;-f1|MOap*2+!RmBc`W` zj;of)PKk-4bJ`@?rTbJFnJ_>`wMdZ8@D8%8cSqUHuYv6L*k49h4iV93E6N^^>WiM6 z9?D*4JVbA!f{4k!BR)#AG4@`*9JhA4_#|(e96xWboRGChemXWoCQnb6ui0O7 zEAf&qclCQOzF+F^z5Z|ie#uhStF*_fe?5QxSZ86%33~~&mHzwZ>YBYQ-`Fbt^;3Q0 z_2Tb@M>uWWgQNJtTm8wQJ~;SBJ$AdDx1G=G;iL0E?A>$quzAStS*qcdx>l&vYW_uBKwJKD6*r-mLhwKY^tT&Rb*R{eML4F z*;!<3k-bGW7uj88dy)M`HW=AqWQ#4;9wVDfvg4L&%aJ{|RGW_Mx~1B7WZ#jEM|K|BdSvgB&9_v$k8D4(|40Ln4j?T+ zdVn+m=>pOQqz_0VkWL`2Kzd=Rnt^l!X$R5|q#;O0kd`1lL7IYe1!)V?7o;&rXOPw) zy+N8|sk+1eA=<-3e|TsR4;?~Ug!Bk$64E84O-P@RMj@TDRINgKg)|H47Sb-HUr57{ zjv*~WdWJL&=^D~Dq;E*$kj^2kvsAr9nul}`X&=%*q=85WkrpC7M4E_n5osgRN2HNR zCy`cKs$L?^v{cC zWAk_OZ^OnL2M&t&*-3HmdwYA{@B8}t`ku$vJ2coJzs70ru$gMRIlB&mVL9v{SK&aO zK5APvk=`abu1u(t<}Hcl4XRk#tBxfX&FNQ_obB$b^LUTGSP^qMJR(C{`)JlsU(F;b+Sb_#WRz13viKjnF0+q}f; zvIa(*zRc!dz`(a1RmWoIInjhXioYe5Hk@Ld`(~5?_ zOSyh1EOseS%(G2UYE~;y_LEOwWME`wVrF1u0YV0b@(z$;brT>YBMSpVK?8{0vjD^f ziF*f!FnGI!fCS+n1iSm#feJtv1bBfM#OC=A1et9q6(AbqRuBzxFNg-Y8AOBJ4WdDA z2hkw+gJ_T+Ks3l7AVWcZ0ns4;fM}4PKs4B2OpHt{%q)ydtUw6#7zaoK=sk!xz$7D3 f4Cp-|8|XbC8|Xb2A77yNuy~PyfeR?CYsm!wMOto6 diff --git a/lib/pytz/zoneinfo/Singapore b/lib/pytz/zoneinfo/Singapore deleted file mode 100644 index a6f2db8f3a887fa0f19283b52c2f801329bb4f53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmWHE%1kq2zyKUT5fBCe7+bupxpncbbiWA)xSk}O+Wa)(^u&0MOCGr&zVGtw5S#dw zgOQ1ug_VVkoq-`S7Njw$fPsa9Azguy6GVd8nH3s51**45C5K2GJm=gJ_WRK{Ut_y7O^ diff --git a/lib/pytz/zoneinfo/Turkey b/lib/pytz/zoneinfo/Turkey deleted file mode 100644 index 864099556bc9875b7e9258af6c3b221d84c68eae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2721 zcmbu=eN0tl0LSrj?*%TGp*>oNB#Na7Dk`8T7>I?)RInpn%@p#ah?qpj*NHE2r_N=$ zd|WhjR3jyF>ZqmJ)KV*#7MeYsa;6 zFiz#T^_Kh&!LRx*vrhNF96aMIwp!gAjn)g<*4LM}8D~!v>E}*aM%%9S)-PA~8o!q8 zv)aqTjNjwZEvCM;{@Lpe}`C{s8eP@RU zBW$k~DVmMQ*4}!Dx(uUZ{RaJk)!huSW`W*$_NK-M3x;YBeUwLl2Ftb?Kv3e z>K)M-v$k4~Ial2nd*r0my(UWUv2LXnw|s%tv%Exmq-c`%X#QxeSLQIScT%Dj9~-0f ziHy(^Lel~X?On~p^FFihsXxqqhcBA_cb_wp>b@`sR39)0u71xPw6NApF4Q>WQOZ_KdMyDc%(+eXjbb*%kF?gcYv=AZVc_+w^nPSDQXlo}izdQ|51`bOkk`az8G91>%i zo5a}fw~BEM+eQBIgR)?Kn;gIMZTVzHh0xcnk`tbKSr(Shk`srOOMiZzoD@A?PEP78 zCtppLQ=&$TDW^Njr`r?7)IC?^w3Y}_RNF}u@BUdlQ}vseUfnE==`G^f6+g)t*&m6S z#m8ky+-5N=t3j5Ae<){nmvZ)x8)eyz`EpKErF^cv*`bbv? zzR^10`TgzRj4AMIxw#Yh$FKPd)r-H-&!5pWmpXsHsaOAhU+@U^13sLc>cjiPH`STE zr|ArG*^vwHs4hKn@sZ1q1OSNu5&|R!NDv%V6p%0=aXpVNLU z5>zCrNLU?JT#>*!s>mXtMPiEt7l|$sUL?LqfRP9zAx2`11R04k5@tsgXC%-_q#aeL zkytybU?b5+!i~fm2{;mQB;-iUk)R_{N5YQ89SJ-Vc}Ep`B=(Lf_(=4T@FVd@1^^iW zWC)NkKn4LB1!NeIaX`3Kj0!R=$haT_ zgNzI^G|1REs=+}<$59OrGCs%vAtQtg5i&-|AR(jV^0@Ei2?@RRxIJOsyL~+2zWaI9 zDmfQeZIfChwL9U?HmOxo+tkU~rY?7WfBQH2YMcINpZ+;e>ODd&*nm{FEU94dz_fwM Pg9axRq$E3ULn8hH9ONz6 diff --git a/lib/pytz/zoneinfo/UCT b/lib/pytz/zoneinfo/UCT deleted file mode 100644 index a88c4b665b3ec94711c735fc7593f460668958cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5Ss-YX!W5+Jvm7%3#iuo4W$@Qu=R=2lX+ zIh>7-b8NLqJJYRnExKi`P0TUedKt^qt(h!c>unar?R*dGubS&G&$H+GoZayk+wbdL z*Y;Gt^RE+Oe&OZxnU{Oo$bmxt*!*8Q#+sMQKgKH5)ai}xz*{S%(_iimdTF5y?n!rt zY%SBF&87aZx-=c`N%gz(BDCw34gSd32^~2!?vDELyuR!5h(G%4>oUea7=aq*rcD9 z>p53bRr1&Zec#6}m2xs%-+%1765Yje?(Pva&o@WT-~7E;Q1F*bU3pHV&H7fRXPyx0 zQY&KD^o`D(=nz@MAL{IjFRPq^V>iRe7yS=6B|+#T9$xlKOa6 zklrE-^M6xIT`Oc!a-1l-won#N{wf~$EJ{8&{-r3f==Ri_5!${USh)f*q_)nD|e>Yc~+ zBk!(LHI4gp?cowtSJJB2bf>8L+FY?!(t)(u9> z$1j}~jeBp(Cx!>b`j%0-VPL;#s{TPY??0}d%(wU3I=A`Hf zBZtDfO;z3tW^wSC|Nz2mDcwX^q4z3a43^{(HopYJbHLBUQ)=>cLasnZ>0TYhP}t}brJ)Cz88X$?R{>k$Lo}O9^+H%bv%{ze9F8| z1D93i;#p;GjuT{F&a~eD9#@q4176N+=H;FlFlU+nas=+$@2Nxvhm6i@hKGy~?Etwj zLXH_CFh*pM$S9FvBI85`ij351hKh{UY6gpp78x!wUSz;;9V@3vzj2am>GHztx z$jFhQBV$JfkBr`GhHo|FM*@IE00{vS10)DY6p%0=aX}O(dLF6Hg?dRufSqq*fDCB&bMK zk+33hMFNXN76~m9TO_zhbdm5{O?;66TTO(K5L-=*ksu>cM#7B583{BJX`BvqNN8|a z`0XB7WW*hO9Osi;q`I@mew&=>V4F~yc*odm&$Rahn`#qmlWk$|sjI6g_Ww)wKhfqN cF`e%yqFzkiv#S^9=I6@n>b$(%yj&UeH}EZKga7~l diff --git a/lib/pytz/zoneinfo/US/Aleutian b/lib/pytz/zoneinfo/US/Aleutian deleted file mode 100644 index 391ec98ec0f31cd595ed05a9b91a41c4cdb25d31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 zcmciCUrd%&0LSr%zb~K|6%ZndLdHwdwv5!Hz6D=S$_GwO zxKVG9$_M+-x)1GrPd?l_=tghaCu2%`-Prs_`ABMm8<*6h7ls$Q@qt@({K}-I@xQuy z(NEbbVLVGO{yIi2`8--DzJFUS?JSYY_D`y$npBy*{SWbI?mW4?Y(hL1Gc8kAoE0hl zaGe@4C{m|>(JOxL6)VRs>a@%6sPv)FbjC=xTGe|@i-CHT+48B(>X0hCu}0^hF$-_Z~dY`^WRlkE{(@oYkxjSsvQ;abbZR zvqE5r$QqGFBCAA}iL4V@sMV|#S*q2n68Wq-;ptkisFALrRC#&T5K>RL^S4 zht$t%3W!t?DIrorq=-lrkuoB6L<)&i5-BB8OQe`cHLa$cNIk8lph!inrld$sk)k41 zMaqiQ6)7xIS){Z`ZIR+4)wP=PBK5VJ0wWc+ni3;5Mv9D787VVTXQa?LSLvYOz>v^; zJ)ZEe`}jD{CqL5Zx~+Uov;V2JDYvP$`Nh^cz|^{&s2A|4+C7E;j## cxpqfT^h`nA)5^0mvNA+kd1hutW`>CP3w~*NkN^Mx diff --git a/lib/pytz/zoneinfo/US/Arizona b/lib/pytz/zoneinfo/US/Arizona deleted file mode 100644 index 67589026c21c6bcb83587d25342c93f10570bc24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 327 zcmZvYAq&Dl7>2*w299}QO_2Qxi(odoO(?YL!=cxMNs}%Y0#a~T!Sz17cKZ3}Cpw>NgF9qmu+9aR--XCrsnSyZ4tJ6R>Wa>`9!VX^F9kZxMSt1yQB&M?k}ke9UhVblr}rL-QeVC7(g!Pxwhz|`BTjI<%{*PHLt7kymbA; zyysO#)(Bmh6t9kFgzFR0J=DojzWUUVFjEy3CZ~J)m@|Gp^5bn{sy#%ie>rZ>Rvnk0 zN()U*QK6jMU8!nwDzsU)N1b0#pfAi?sp^um^~KS1)z5Kr^e+!3sb9NI(3kFe$^6zb zMqh4{Xf9t$lq+YV&DA5(@_TU?Q{RjS>h>fb8Ah5skPE@a&zTA<|f^!|2fsT zPmT5n{6=}q_tQ;VZB|V;d??M#o9d>DMY?&}M&p^Es$1+>Xj-mWD6N*Jn49ON$Svs! zrgc(+v>6s^yrM(p)?V$*ZJpXl+YUX|?M<#qy9T$bb{E>}_LWzZ_kqj$j?a%NpH1Iu z-xa&nooOxQuGuS8hr#EiCuW(s*K3RTb)IefTnBWgW@AmK@?71yI?{B> zdrSM5Jf*s3P1OOpeO0%NVLEWpy(%a%O@gO1QQf14%KZbYRfu12=@I<3>gnMvq3zF@ z&?=Yoy0X{wE~=0Rj;=RhIahV~&ezO?3(ECF?<&(LIbT1VIbS^z_koTWm#q4B%hZv5 z2dK!pZ4%Y>Srb*VRH8lOOmyxHiKz)PkG;28KVI5T#m-FE{k8_GxRE1t|F>^Z1H!`f zz|@OskhianA6%;9ue#}kknJkrl#dMcIb?=@Au`Oh)eO%*E+fj9n30)<@^z&7T`(kvGhnq^;;IAiEolwub z9W9gg*PCb4y2x`ml_ojCQ`CYzW^zcaJfFPMOz}D(DRFa6imOJag=VX?^8I>R+c|1l z-X@)XX@Z)bwMfr65~F5jr0N&8`>TvmL-edAEtI(Z_g91KKGV?sx*z`gSN~6+sIT9# z(M{^>*DV)!UP}|_o#xK>R@dH-=o>E)gW@I9J`qFg(?6coX8(+9-{b#z4cdQV;bDHV z53k$S+Zol+wH#TA$XY~JBeEWm6^X1#WK|;T5?PtZ+C)~Tqg|iK3U#z=6j`OnIz?70 zvR0ARimX>;#Ug7KS+&TzMOH4dc9GSKtY2gWJK8mjtYSyIj**p&tYu_1BkLJi(a4%c zRyDG&k(G_CZDe&L>l<0&j&_YBtK8A9b7Z9>Yu(YVc4WOHD;`<%$f`%yJ+ktVweM(G zKeGOj1RxneQh?+DNdl4uBn?O&kVGJvKvIF^0!apv4I~{%J{)aAkc=QHL2`m51<4AM z79=l7Vvx)rsX=msBnQb3k{%>KNP-+~hL98?IYN?zPL_B*_NEwndBxy+2khCFrV@Mp5Ifm3BxnoEkl0Am>A^BrSAd*3b6gt`* zB1uHDh@=t8Ba%oYlMJaua>LnS!PHxl4m5*NT!igBe_PBjbs~1HNIs8w@80a&|DB9?1E@aDpIb2*WAjXwMPkByqH7338e^+VccCQIInQIaQEz1vy!e zvjsU_8o1rSSHtT*3kNL-T4+stj^p6b+3J3}aZ1x9(^>6(E diff --git a/lib/pytz/zoneinfo/US/East-Indiana b/lib/pytz/zoneinfo/US/East-Indiana deleted file mode 100644 index aa3dfc43730ed25bde9c967039951f5c2fc15cc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1649 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 SOrDgSl9ZjAnw*-P68c?+}V_Y7EM-7G&C- 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 DJ6nx# diff --git a/lib/pytz/zoneinfo/US/Pacific b/lib/pytz/zoneinfo/US/Pacific deleted file mode 100644 index 3b7ce1dceebf9fa9db859068da1fa7eba6df1cfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2819 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 lhz2JUUwbou|j8Z1ia9M1PU`)_Oy`~BM1Zr@g; z{#xT?!eO<@;T}4@G4%ZG(vPQlA|C=hpBEiE*WDiIeZJFoUKNJV$1Wz)<980G<2C(# z1s(l;arfY*P_p$_x_DDT#iilGz>7qYZ=|*8Oa5Ts-MHc6k-Egh$H#{!4fLAem1Cyl z%mEWRyvI!5ztv3HvD!>s-(aS-EHtIDu$exq*pvnRrabSfsjw?_#ixJ{zbWdP(RsgX z#WaviK%$qOttn?FIdE%a)-F;op+1snDwjR^f8wO0x?vrM2yvNL2xzEfm=`ssy z)|mz0Hk;_AP91$&Zx(%Bs~6ubH%mrhI(D&6$M1yn(t~BX_O#N8Z8>^bchD?PzSVVG zzMJ~8M><*e$~4$lbz|uR)A;_OX>zAc)6>gl#p{En`PvcF^7w*I9o=PImdkCqZIA7> zJvkmB+n1ZQ{dqpylRX&iK1Qk1Fn>mMhvkubJNMd7%coSNN{v-2ny@A))zHc_I7Jow zIgeCX#hH0Dk@frid_)H9ExQS(;SLz5aS@$$!{yngV+Z#(4kleF%e=T z#7Kyh5HlfmLJWmi3NaO8E5ulcwGeY5_CgGXSnN2ENKcoOi1&|UPN)3=A97+|CG9Yz83V~DtDFspsq!>swka8gPKnj9X1Sttp z6Qn4IQWc~uhf)`$Fi2&P(jc{2ZkOBR@_21;j@R}{bI#87XYIT(xn4VaFxp*$Dvj~Q z5}o8G(Mf0$o!liliBY1H&?GtuO`?;hL??-5&n3E&%v_@T{rMK6`>*iSzsgg73AJ*b F|0gT@fExe+ diff --git a/lib/pytz/zoneinfo/WET b/lib/pytz/zoneinfo/WET deleted file mode 100644 index 444a1933d72525ab3045980eab2fbf79266cf158..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1873 zcmd7SYfO~|9LMoPjFl|ukH|&2RYYK&;BXBHyo3jafr=afFGLD*NunTP;3d{#&J}aN zHkNb7#Kl;1ioU>l0qC;JXc}v4tWhyHU1gU!H+6IwThI4->nmT?b9VN5cDD2G|NRBF zw>D*Z?s*A|B_4Ro9&PKi$96W@8R_ag5S~VM`r@nYlPmlj8@5rxuX7GEZ^(L{k(A6ln1 z$K$lNDM{=4^X>VP5EVDZ+WO>QJ$pS4{Ff79+YpIAfP6*VRvvpq#)YI^9rn&YMB z8%Nc$*s0d(UcEdY(B6-BsO`%Rd*yJE+DEJG)s{rPb|}X>DhsW%DcWAoNU$#dU-m}0 z$GX!a)qU%l^@J^`=bO*1_vW1Tog20NGZQ*+?2-b<#lcKoUVRK~h0-L6SkTLDE6;K@vhT zLQ+CTSl^j~E| Bn416q diff --git a/lib/pytz/zoneinfo/Zulu b/lib/pytz/zoneinfo/Zulu deleted file mode 100644 index 5583f5b0c6e6949372648a7d75502e4d01b44931..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5Ss -# This file is in the public domain, so clarified as of -# 2009-05-17 by Arthur David Olson. -# ISO 3166 alpha-2 country codes -# -# From Paul Eggert (2006-09-27): -# -# This file contains a table with the following columns: -# 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 Newsletter VI-1 (2007-09-21). See: -# -# ISO 3166 Maintenance agency (ISO 3166/MA) -# . -# 2. The usual English name for the country, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. -# -# Columns are separated by a single tab. -# The table is sorted by country code. -# -# Lines beginning with `#' are comments. -# -# From Arthur David Olson (2011-08-17): -# Resynchronized today with the ISO 3166 site (adding SS for South Sudan). -# -#country- -#code country name -AD Andorra -AE United Arab Emirates -AF Afghanistan -AG Antigua & Barbuda -AI Anguilla -AL Albania -AM Armenia -AO Angola -AQ Antarctica -AR Argentina -AS Samoa (American) -AT Austria -AU Australia -AW Aruba -AX Aaland Islands -AZ Azerbaijan -BA Bosnia & Herzegovina -BB Barbados -BD Bangladesh -BE Belgium -BF Burkina Faso -BG Bulgaria -BH Bahrain -BI Burundi -BJ Benin -BL St Barthelemy -BM Bermuda -BN Brunei -BO Bolivia -BQ Bonaire Sint Eustatius & Saba -BR Brazil -BS Bahamas -BT Bhutan -BV Bouvet Island -BW Botswana -BY Belarus -BZ Belize -CA Canada -CC Cocos (Keeling) Islands -CD Congo (Dem. Rep.) -CF Central African Rep. -CG Congo (Rep.) -CH Switzerland -CI Cote d'Ivoire -CK Cook Islands -CL Chile -CM Cameroon -CN China -CO Colombia -CR Costa Rica -CU Cuba -CV Cape Verde -CW Curacao -CX Christmas Island -CY Cyprus -CZ Czech Republic -DE Germany -DJ Djibouti -DK Denmark -DM Dominica -DO Dominican Republic -DZ Algeria -EC Ecuador -EE Estonia -EG Egypt -EH Western Sahara -ER Eritrea -ES Spain -ET Ethiopia -FI Finland -FJ Fiji -FK Falkland Islands -FM Micronesia -FO Faroe Islands -FR France -GA Gabon -GB Britain (UK) -GD Grenada -GE Georgia -GF French Guiana -GG Guernsey -GH Ghana -GI Gibraltar -GL Greenland -GM Gambia -GN Guinea -GP Guadeloupe -GQ Equatorial Guinea -GR Greece -GS South Georgia & the South Sandwich Islands -GT Guatemala -GU Guam -GW Guinea-Bissau -GY Guyana -HK Hong Kong -HM Heard Island & McDonald Islands -HN Honduras -HR Croatia -HT Haiti -HU Hungary -ID Indonesia -IE Ireland -IL Israel -IM Isle of Man -IN India -IO British Indian Ocean Territory -IQ Iraq -IR Iran -IS Iceland -IT Italy -JE Jersey -JM Jamaica -JO Jordan -JP Japan -KE Kenya -KG Kyrgyzstan -KH Cambodia -KI Kiribati -KM Comoros -KN St Kitts & Nevis -KP Korea (North) -KR Korea (South) -KW Kuwait -KY Cayman Islands -KZ Kazakhstan -LA Laos -LB Lebanon -LC St Lucia -LI Liechtenstein -LK Sri Lanka -LR Liberia -LS Lesotho -LT Lithuania -LU Luxembourg -LV Latvia -LY Libya -MA Morocco -MC Monaco -MD Moldova -ME Montenegro -MF St Martin (French part) -MG Madagascar -MH Marshall Islands -MK Macedonia -ML Mali -MM Myanmar (Burma) -MN Mongolia -MO Macau -MP Northern Mariana Islands -MQ Martinique -MR Mauritania -MS Montserrat -MT Malta -MU Mauritius -MV Maldives -MW Malawi -MX Mexico -MY Malaysia -MZ Mozambique -NA Namibia -NC New Caledonia -NE Niger -NF Norfolk Island -NG Nigeria -NI Nicaragua -NL Netherlands -NO Norway -NP Nepal -NR Nauru -NU Niue -NZ New Zealand -OM Oman -PA Panama -PE Peru -PF French Polynesia -PG Papua New Guinea -PH Philippines -PK Pakistan -PL Poland -PM St Pierre & Miquelon -PN Pitcairn -PR Puerto Rico -PS Palestine -PT Portugal -PW Palau -PY Paraguay -QA Qatar -RE Reunion -RO Romania -RS Serbia -RU Russia -RW Rwanda -SA Saudi Arabia -SB Solomon Islands -SC Seychelles -SD Sudan -SE Sweden -SG Singapore -SH St Helena -SI Slovenia -SJ Svalbard & Jan Mayen -SK Slovakia -SL Sierra Leone -SM San Marino -SN Senegal -SO Somalia -SR Suriname -SS South Sudan -ST Sao Tome & Principe -SV El Salvador -SX Sint Maarten -SY Syria -SZ Swaziland -TC Turks & Caicos Is -TD Chad -TF French Southern & Antarctic Lands -TG Togo -TH Thailand -TJ Tajikistan -TK Tokelau -TL East Timor -TM Turkmenistan -TN Tunisia -TO Tonga -TR Turkey -TT Trinidad & Tobago -TV Tuvalu -TW Taiwan -TZ Tanzania -UA Ukraine -UG Uganda -UM US minor outlying islands -US United States -UY Uruguay -UZ Uzbekistan -VA Vatican City -VC St Vincent -VE Venezuela -VG Virgin Islands (UK) -VI Virgin Islands (US) -VN Vietnam -VU Vanuatu -WF Wallis & Futuna -WS Samoa (western) -YE Yemen -YT Mayotte -ZA South Africa -ZM Zambia -ZW Zimbabwe diff --git a/lib/pytz/zoneinfo/localtime b/lib/pytz/zoneinfo/localtime deleted file mode 100644 index 2ee14295f108ab15ee013cd912e7688407fa3cde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 mcmWHE%1kq2zyORu5fFv}5Ss0stYrjZLKTDXReO=(hY6&_8=4Lyomn)i0TXL?s}c+qA4eD1Km`+c9})T|e~dH(eZ zv|r)jb;drt4=r96E(88$fA$GSD$7alf^Sm=_O;okfpK9)v{r`&GN89RnmQ> zDe*1UEADvDtf(%~pVx_5S&^kzRSh*?6c5s+YacRS=0)k%3!auWnFH0@Y29UALT6Pr zDooZ#+@`+jb5%ApGOE1QAt|rfr#1y%Hk&HfsjrV8FyEB!)fGF+&F0x_^p+*_&DQL> zdRzYMW_wbO-jP1qd>b=DS9+((&XC@ES5%tpx;9+x4vv@I2YadS-Z8ST{UzC_Zs@AX z$IVaizv-V-D$V}3oArU%5_8bANFNHDWe({X`mk@g{IVrO|5{xrzkT+Ws;(F(M+(!G zF80dNtS8j5ycqdCv4c9E)?7{ukJdE_QRa^xq55P*h&k2bqCVZ|f;oNVCw-=-%ADQ5 zUe{KZnRA<~)cMkVViuOE3$xeB#p&}@U3QUN8a-8APRf-lk3Fld#-z%%4pa1>A#rlO z$w+oy4AH7l{1Iu~ zWt(dJ?%i^0=n{47s<|e}%v4SF+tTdNr#g5`rrcJZuR}hYVM0H8Q8zElFt<;AQs0r4 zVD22*QHLc)nijp9>ANDEnwIS%)!j{M%{>j8s(UU5Nvor^s`Za&rOnnoDtz@1a_^$m zs%?(P-1p`j)h^|jX+O49-ygffJTUMB{b1NK6VY*^j__@l$e;aoF&m~A67AWgQUxxma1!Jrs+1}y6T>gXdW8+tBQ^2WFGETp?Wk9Ha%M%);(*^ zn_f4**1ao#G<|+4)^VlhhYwx(l33C>K~IM1N!$< z1L{glLeyxTP&LaW2KUv8YsZ^`we9tw1%>j|{&?k`HckewZ>N$*d1XjZpn5tkMutwV zQNvm{m*kXPD)~m8JQKS@J#!+&j0msPBX(RcBYh=0bxD-h`y`}6h#J!|XHMK0}h3vH+gs|DL>C?Du$howX0|@ATVOT0`?bGJnVfA~T3g zAu@-^BqFnjOd~Rn$V4JD>9kXc%%#&#CNi7IbRzSKOeiv=$dn>;icBgptH`t>^NLI? zGPB6kB6I7slZ(u*(@rlkzsLk5GmK0zGRMdyBeRT5GcwP}L?bheOf@psPCMDiY&-3A zBlC?+xYN!!GUdpeBa@EIIx_9Zydx9uv@?%PJu>&mOg}RJNCJ=yASpm{fFuFQ z0+I$K4@e@AOdzRn+FT&XK(c|P1IY)H5F{f=N|2l&NkOuLqy@>%ku@`ElxydgupY>I#!AxT2Agro_{6Ot$-Q%;*IBv($GEF@bKwMkJ3&B9TlYsYG(= zw8=!W>9pxY@`)rA$taRiB&SGHk*p$VMe>Ry7RfAt!PJ03%X8>{vAm;#b5+G**avC7#0dgWBX9996Am;*dG9YJz)1D5< z`QWrC1ad|=?J0qr6Ua${oE6Avft(k}iGiFM$f<#x8_3CloE=VkdLZYA)1Dy68RE33 z2y%`fCkb+vAg2j(o**X*a;7v0sOLw+zAjlpvvG&`Yz1^d`MR)1!?b -# This file is in the public domain, so clarified as of -# 2009-05-17 by Arthur David Olson. -# -# TZ zone descriptions -# -# From Paul Eggert (1996-08-05): -# -# This file contains a table with the following columns: -# 1. ISO 3166 2-character country code. See the file `iso3166.tab'. -# 2. Latitude and longitude of the zone's principal location -# in ISO 6709 sign-degrees-minutes-seconds format, -# either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS, -# first latitude (+ is north), then longitude (+ is east). -# 3. Zone name used in value of TZ environment variable. -# 4. Comments; present if and only if the country has multiple rows. -# -# Columns are separated by a single tab. -# The table is sorted first by country, then an order within the country that -# (1) makes some geographical sense, and -# (2) puts the most populous zones first, where that does not contradict (1). -# -# Lines beginning with `#' are comments. -# -#country- -#code coordinates TZ comments -AD +4230+00131 Europe/Andorra -AE +2518+05518 Asia/Dubai -AF +3431+06912 Asia/Kabul -AG +1703-06148 America/Antigua -AI +1812-06304 America/Anguilla -AL +4120+01950 Europe/Tirane -AM +4011+04430 Asia/Yerevan -AO -0848+01314 Africa/Luanda -AQ -7750+16636 Antarctica/McMurdo McMurdo Station, Ross Island -AQ -9000+00000 Antarctica/South_Pole Amundsen-Scott Station, South Pole -AQ -6734-06808 Antarctica/Rothera Rothera Station, Adelaide Island -AQ -6448-06406 Antarctica/Palmer Palmer Station, Anvers Island -AQ -6736+06253 Antarctica/Mawson Mawson Station, Holme Bay -AQ -6835+07758 Antarctica/Davis Davis Station, Vestfold Hills -AQ -6617+11031 Antarctica/Casey Casey Station, Bailey Peninsula -AQ -7824+10654 Antarctica/Vostok Vostok Station, Lake Vostok -AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie -AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I -AQ -5430+15857 Antarctica/Macquarie Macquarie Island Station, Macquarie Island -AR -3436-05827 America/Argentina/Buenos_Aires Buenos Aires (BA, CF) -AR -3124-06411 America/Argentina/Cordoba most locations (CB, CC, CN, ER, FM, MN, SE, SF) -AR -2447-06525 America/Argentina/Salta (SA, LP, NQ, RN) -AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) -AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) -AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) -AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) -AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) -AR -3319-06621 America/Argentina/San_Luis San Luis (SL) -AR -5138-06913 America/Argentina/Rio_Gallegos Santa Cruz (SC) -AR -5448-06818 America/Argentina/Ushuaia Tierra del Fuego (TF) -AS -1416-17042 Pacific/Pago_Pago -AT +4813+01620 Europe/Vienna -AU -3133+15905 Australia/Lord_Howe Lord Howe Island -AU -4253+14719 Australia/Hobart Tasmania - most locations -AU -3956+14352 Australia/Currie Tasmania - King Island -AU -3749+14458 Australia/Melbourne Victoria -AU -3352+15113 Australia/Sydney New South Wales - most locations -AU -3157+14127 Australia/Broken_Hill New South Wales - Yancowinna -AU -2728+15302 Australia/Brisbane Queensland - most locations -AU -2016+14900 Australia/Lindeman Queensland - Holiday Islands -AU -3455+13835 Australia/Adelaide South Australia -AU -1228+13050 Australia/Darwin Northern Territory -AU -3157+11551 Australia/Perth Western Australia - most locations -AU -3143+12852 Australia/Eucla Western Australia - Eucla area -AW +1230-06958 America/Aruba -AX +6006+01957 Europe/Mariehamn -AZ +4023+04951 Asia/Baku -BA +4352+01825 Europe/Sarajevo -BB +1306-05937 America/Barbados -BD +2343+09025 Asia/Dhaka -BE +5050+00420 Europe/Brussels -BF +1222-00131 Africa/Ouagadougou -BG +4241+02319 Europe/Sofia -BH +2623+05035 Asia/Bahrain -BI -0323+02922 Africa/Bujumbura -BJ +0629+00237 Africa/Porto-Novo -BL +1753-06251 America/St_Barthelemy -BM +3217-06446 Atlantic/Bermuda -BN +0456+11455 Asia/Brunei -BO -1630-06809 America/La_Paz -BQ +120903-0681636 America/Kralendijk -BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Amapa, E Para -BR -0343-03830 America/Fortaleza NE Brazil (MA, PI, CE, RN, PB) -BR -0803-03454 America/Recife Pernambuco -BR -0712-04812 America/Araguaina Tocantins -BR -0940-03543 America/Maceio Alagoas, Sergipe -BR -1259-03831 America/Bahia Bahia -BR -2332-04637 America/Sao_Paulo S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS) -BR -2027-05437 America/Campo_Grande Mato Grosso do Sul -BR -1535-05605 America/Cuiaba Mato Grosso -BR -0226-05452 America/Santarem W Para -BR -0846-06354 America/Porto_Velho Rondonia -BR +0249-06040 America/Boa_Vista Roraima -BR -0308-06001 America/Manaus E Amazonas -BR -0640-06952 America/Eirunepe W Amazonas -BR -0958-06748 America/Rio_Branco Acre -BS +2505-07721 America/Nassau -BT +2728+08939 Asia/Thimphu -BW -2439+02555 Africa/Gaborone -BY +5354+02734 Europe/Minsk -BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland Time, including SE Labrador -CA +4439-06336 America/Halifax Atlantic Time - Nova Scotia (most places), PEI -CA +4612-05957 America/Glace_Bay Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971 -CA +4606-06447 America/Moncton Atlantic Time - New Brunswick -CA +5320-06025 America/Goose_Bay Atlantic Time - Labrador - most locations -CA +5125-05707 America/Blanc-Sablon Atlantic Standard Time - Quebec - Lower North Shore -CA +4531-07334 America/Montreal Eastern Time - Quebec - most locations -CA +4339-07923 America/Toronto Eastern Time - Ontario - most locations -CA +4901-08816 America/Nipigon Eastern Time - Ontario & Quebec - places that did not observe DST 1967-1973 -CA +4823-08915 America/Thunder_Bay Eastern Time - Thunder Bay, Ontario -CA +6344-06828 America/Iqaluit Eastern Time - east Nunavut - most locations -CA +6608-06544 America/Pangnirtung Eastern Time - Pangnirtung, Nunavut -CA +744144-0944945 America/Resolute Central Standard Time - Resolute, Nunavut -CA +484531-0913718 America/Atikokan Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut -CA +624900-0920459 America/Rankin_Inlet Central Time - central Nunavut -CA +4953-09709 America/Winnipeg Central Time - Manitoba & west Ontario -CA +4843-09434 America/Rainy_River Central Time - Rainy River & Fort Frances, Ontario -CA +5024-10439 America/Regina Central Standard Time - Saskatchewan - most locations -CA +5017-10750 America/Swift_Current Central Standard Time - Saskatchewan - midwest -CA +5333-11328 America/Edmonton Mountain Time - Alberta, east British Columbia & west Saskatchewan -CA +690650-1050310 America/Cambridge_Bay Mountain Time - west Nunavut -CA +6227-11421 America/Yellowknife Mountain Time - central Northwest Territories -CA +682059-1334300 America/Inuvik Mountain Time - west Northwest Territories -CA +4906-11631 America/Creston Mountain Standard Time - Creston, British Columbia -CA +5946-12014 America/Dawson_Creek Mountain Standard Time - Dawson Creek & Fort Saint John, British Columbia -CA +4916-12307 America/Vancouver Pacific Time - west British Columbia -CA +6043-13503 America/Whitehorse Pacific Time - south Yukon -CA +6404-13925 America/Dawson Pacific Time - north Yukon -CC -1210+09655 Indian/Cocos -CD -0418+01518 Africa/Kinshasa west Dem. Rep. of Congo -CD -1140+02728 Africa/Lubumbashi east Dem. Rep. of Congo -CF +0422+01835 Africa/Bangui -CG -0416+01517 Africa/Brazzaville -CH +4723+00832 Europe/Zurich -CI +0519-00402 Africa/Abidjan -CK -2114-15946 Pacific/Rarotonga -CL -3327-07040 America/Santiago most locations -CL -2709-10926 Pacific/Easter Easter Island & Sala y Gomez -CM +0403+00942 Africa/Douala -CN +3114+12128 Asia/Shanghai east China - Beijing, Guangdong, Shanghai, etc. -CN +4545+12641 Asia/Harbin Heilongjiang (except Mohe), Jilin -CN +2934+10635 Asia/Chongqing central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc. -CN +4348+08735 Asia/Urumqi most of Tibet & Xinjiang -CN +3929+07559 Asia/Kashgar west Tibet & Xinjiang -CO +0436-07405 America/Bogota -CR +0956-08405 America/Costa_Rica -CU +2308-08222 America/Havana -CV +1455-02331 Atlantic/Cape_Verde -CW +1211-06900 America/Curacao -CX -1025+10543 Indian/Christmas -CY +3510+03322 Asia/Nicosia -CZ +5005+01426 Europe/Prague -DE +5230+01322 Europe/Berlin -DJ +1136+04309 Africa/Djibouti -DK +5540+01235 Europe/Copenhagen -DM +1518-06124 America/Dominica -DO +1828-06954 America/Santo_Domingo -DZ +3647+00303 Africa/Algiers -EC -0210-07950 America/Guayaquil mainland -EC -0054-08936 Pacific/Galapagos Galapagos Islands -EE +5925+02445 Europe/Tallinn -EG +3003+03115 Africa/Cairo -EH +2709-01312 Africa/El_Aaiun -ER +1520+03853 Africa/Asmara -ES +4024-00341 Europe/Madrid mainland -ES +3553-00519 Africa/Ceuta Ceuta & Melilla -ES +2806-01524 Atlantic/Canary Canary Islands -ET +0902+03842 Africa/Addis_Ababa -FI +6010+02458 Europe/Helsinki -FJ -1808+17825 Pacific/Fiji -FK -5142-05751 Atlantic/Stanley -FM +0725+15147 Pacific/Chuuk Chuuk (Truk) and Yap -FM +0658+15813 Pacific/Pohnpei Pohnpei (Ponape) -FM +0519+16259 Pacific/Kosrae Kosrae -FO +6201-00646 Atlantic/Faroe -FR +4852+00220 Europe/Paris -GA +0023+00927 Africa/Libreville -GB +513030-0000731 Europe/London -GD +1203-06145 America/Grenada -GE +4143+04449 Asia/Tbilisi -GF +0456-05220 America/Cayenne -GG +4927-00232 Europe/Guernsey -GH +0533-00013 Africa/Accra -GI +3608-00521 Europe/Gibraltar -GL +6411-05144 America/Godthab most locations -GL +7646-01840 America/Danmarkshavn east coast, north of Scoresbysund -GL +7029-02158 America/Scoresbysund Scoresbysund / Ittoqqortoormiit -GL +7634-06847 America/Thule Thule / Pituffik -GM +1328-01639 Africa/Banjul -GN +0931-01343 Africa/Conakry -GP +1614-06132 America/Guadeloupe -GQ +0345+00847 Africa/Malabo -GR +3758+02343 Europe/Athens -GS -5416-03632 Atlantic/South_Georgia -GT +1438-09031 America/Guatemala -GU +1328+14445 Pacific/Guam -GW +1151-01535 Africa/Bissau -GY +0648-05810 America/Guyana -HK +2217+11409 Asia/Hong_Kong -HN +1406-08713 America/Tegucigalpa -HR +4548+01558 Europe/Zagreb -HT +1832-07220 America/Port-au-Prince -HU +4730+01905 Europe/Budapest -ID -0610+10648 Asia/Jakarta Java & Sumatra -ID -0002+10920 Asia/Pontianak west & central Borneo -ID -0507+11924 Asia/Makassar east & south Borneo, Sulawesi (Celebes), Bali, Nusa Tengarra, west Timor -ID -0232+14042 Asia/Jayapura west New Guinea (Irian Jaya) & Malukus (Moluccas) -IE +5320-00615 Europe/Dublin -IL +3146+03514 Asia/Jerusalem -IM +5409-00428 Europe/Isle_of_Man -IN +2232+08822 Asia/Kolkata -IO -0720+07225 Indian/Chagos -IQ +3321+04425 Asia/Baghdad -IR +3540+05126 Asia/Tehran -IS +6409-02151 Atlantic/Reykjavik -IT +4154+01229 Europe/Rome -JE +4912-00207 Europe/Jersey -JM +1800-07648 America/Jamaica -JO +3157+03556 Asia/Amman -JP +353916+1394441 Asia/Tokyo -KE -0117+03649 Africa/Nairobi -KG +4254+07436 Asia/Bishkek -KH +1133+10455 Asia/Phnom_Penh -KI +0125+17300 Pacific/Tarawa Gilbert Islands -KI -0308-17105 Pacific/Enderbury Phoenix Islands -KI +0152-15720 Pacific/Kiritimati Line Islands -KM -1141+04316 Indian/Comoro -KN +1718-06243 America/St_Kitts -KP +3901+12545 Asia/Pyongyang -KR +3733+12658 Asia/Seoul -KW +2920+04759 Asia/Kuwait -KY +1918-08123 America/Cayman -KZ +4315+07657 Asia/Almaty most locations -KZ +4448+06528 Asia/Qyzylorda Qyzylorda (Kyzylorda, Kzyl-Orda) -KZ +5017+05710 Asia/Aqtobe Aqtobe (Aktobe) -KZ +4431+05016 Asia/Aqtau Atyrau (Atirau, Gur'yev), Mangghystau (Mankistau) -KZ +5113+05121 Asia/Oral West Kazakhstan -LA +1758+10236 Asia/Vientiane -LB +3353+03530 Asia/Beirut -LC +1401-06100 America/St_Lucia -LI +4709+00931 Europe/Vaduz -LK +0656+07951 Asia/Colombo -LR +0618-01047 Africa/Monrovia -LS -2928+02730 Africa/Maseru -LT +5441+02519 Europe/Vilnius -LU +4936+00609 Europe/Luxembourg -LV +5657+02406 Europe/Riga -LY +3254+01311 Africa/Tripoli -MA +3339-00735 Africa/Casablanca -MC +4342+00723 Europe/Monaco -MD +4700+02850 Europe/Chisinau -ME +4226+01916 Europe/Podgorica -MF +1804-06305 America/Marigot -MG -1855+04731 Indian/Antananarivo -MH +0709+17112 Pacific/Majuro most locations -MH +0905+16720 Pacific/Kwajalein Kwajalein -MK +4159+02126 Europe/Skopje -ML +1239-00800 Africa/Bamako -MM +1647+09610 Asia/Rangoon -MN +4755+10653 Asia/Ulaanbaatar most locations -MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan -MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar -MO +2214+11335 Asia/Macau -MP +1512+14545 Pacific/Saipan -MQ +1436-06105 America/Martinique -MR +1806-01557 Africa/Nouakchott -MS +1643-06213 America/Montserrat -MT +3554+01431 Europe/Malta -MU -2010+05730 Indian/Mauritius -MV +0410+07330 Indian/Maldives -MW -1547+03500 Africa/Blantyre -MX +1924-09909 America/Mexico_City Central Time - most locations -MX +2105-08646 America/Cancun Central Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatan -MX +2540-10019 America/Monterrey Mexican Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas away from US border -MX +2550-09730 America/Matamoros US Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas near US border -MX +2313-10625 America/Mazatlan Mountain Time - S Baja, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mexican Mountain Time - Chihuahua away from US border -MX +2934-10425 America/Ojinaga US Mountain Time - Chihuahua near US border -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana US Pacific Time - Baja California near US border -MX +3018-11452 America/Santa_Isabel Mexican Pacific Time - Baja California away from US border -MX +2048-10515 America/Bahia_Banderas Mexican Central Time - Bahia de Banderas -MY +0310+10142 Asia/Kuala_Lumpur peninsular Malaysia -MY +0133+11020 Asia/Kuching Sabah & Sarawak -MZ -2558+03235 Africa/Maputo -NA -2234+01706 Africa/Windhoek -NC -2216+16627 Pacific/Noumea -NE +1331+00207 Africa/Niamey -NF -2903+16758 Pacific/Norfolk -NG +0627+00324 Africa/Lagos -NI +1209-08617 America/Managua -NL +5222+00454 Europe/Amsterdam -NO +5955+01045 Europe/Oslo -NP +2743+08519 Asia/Kathmandu -NR -0031+16655 Pacific/Nauru -NU -1901-16955 Pacific/Niue -NZ -3652+17446 Pacific/Auckland most locations -NZ -4357-17633 Pacific/Chatham Chatham Islands -OM +2336+05835 Asia/Muscat -PA +0858-07932 America/Panama -PE -1203-07703 America/Lima -PF -1732-14934 Pacific/Tahiti Society Islands -PF -0900-13930 Pacific/Marquesas Marquesas Islands -PF -2308-13457 Pacific/Gambier Gambier Islands -PG -0930+14710 Pacific/Port_Moresby -PH +1435+12100 Asia/Manila -PK +2452+06703 Asia/Karachi -PL +5215+02100 Europe/Warsaw -PM +4703-05620 America/Miquelon -PN -2504-13005 Pacific/Pitcairn -PR +182806-0660622 America/Puerto_Rico -PS +3130+03428 Asia/Gaza Gaza Strip -PS +313200+0350542 Asia/Hebron West Bank -PT +3843-00908 Europe/Lisbon mainland -PT +3238-01654 Atlantic/Madeira Madeira Islands -PT +3744-02540 Atlantic/Azores Azores -PW +0720+13429 Pacific/Palau -PY -2516-05740 America/Asuncion -QA +2517+05132 Asia/Qatar -RE -2052+05528 Indian/Reunion -RO +4426+02606 Europe/Bucharest -RS +4450+02030 Europe/Belgrade -RU +5443+02030 Europe/Kaliningrad Moscow-01 - Kaliningrad -RU +5545+03735 Europe/Moscow Moscow+00 - west Russia -RU +4844+04425 Europe/Volgograd Moscow+00 - Caspian Sea -RU +5312+05009 Europe/Samara Moscow+00 - Samara, Udmurtia -RU +5651+06036 Asia/Yekaterinburg Moscow+02 - Urals -RU +5500+07324 Asia/Omsk Moscow+03 - west Siberia -RU +5502+08255 Asia/Novosibirsk Moscow+03 - Novosibirsk -RU +5345+08707 Asia/Novokuznetsk Moscow+03 - Novokuznetsk -RU +5601+09250 Asia/Krasnoyarsk Moscow+04 - Yenisei River -RU +5216+10420 Asia/Irkutsk Moscow+05 - Lake Baikal -RU +6200+12940 Asia/Yakutsk Moscow+06 - Lena River -RU +4310+13156 Asia/Vladivostok Moscow+07 - Amur River -RU +4658+14242 Asia/Sakhalin Moscow+07 - Sakhalin Island -RU +5934+15048 Asia/Magadan Moscow+08 - Magadan -RU +5301+15839 Asia/Kamchatka Moscow+08 - Kamchatka -RU +6445+17729 Asia/Anadyr Moscow+08 - Bering Sea -RW -0157+03004 Africa/Kigali -SA +2438+04643 Asia/Riyadh -SB -0932+16012 Pacific/Guadalcanal -SC -0440+05528 Indian/Mahe -SD +1536+03232 Africa/Khartoum -SE +5920+01803 Europe/Stockholm -SG +0117+10351 Asia/Singapore -SH -1555-00542 Atlantic/St_Helena -SI +4603+01431 Europe/Ljubljana -SJ +7800+01600 Arctic/Longyearbyen -SK +4809+01707 Europe/Bratislava -SL +0830-01315 Africa/Freetown -SM +4355+01228 Europe/San_Marino -SN +1440-01726 Africa/Dakar -SO +0204+04522 Africa/Mogadishu -SR +0550-05510 America/Paramaribo -SS +0451+03136 Africa/Juba -ST +0020+00644 Africa/Sao_Tome -SV +1342-08912 America/El_Salvador -SX +180305-0630250 America/Lower_Princes -SY +3330+03618 Asia/Damascus -SZ -2618+03106 Africa/Mbabane -TC +2128-07108 America/Grand_Turk -TD +1207+01503 Africa/Ndjamena -TF -492110+0701303 Indian/Kerguelen -TG +0608+00113 Africa/Lome -TH +1345+10031 Asia/Bangkok -TJ +3835+06848 Asia/Dushanbe -TK -0922-17114 Pacific/Fakaofo -TL -0833+12535 Asia/Dili -TM +3757+05823 Asia/Ashgabat -TN +3648+01011 Africa/Tunis -TO -2110-17510 Pacific/Tongatapu -TR +4101+02858 Europe/Istanbul -TT +1039-06131 America/Port_of_Spain -TV -0831+17913 Pacific/Funafuti -TW +2503+12130 Asia/Taipei -TZ -0648+03917 Africa/Dar_es_Salaam -UA +5026+03031 Europe/Kiev most locations -UA +4837+02218 Europe/Uzhgorod Ruthenia -UA +4750+03510 Europe/Zaporozhye Zaporozh'ye, E Lugansk / Zaporizhia, E Luhansk -UA +4457+03406 Europe/Simferopol central Crimea -UG +0019+03225 Africa/Kampala -UM +1645-16931 Pacific/Johnston Johnston Atoll -UM +2813-17722 Pacific/Midway Midway Islands -UM +1917+16637 Pacific/Wake Wake Island -US +404251-0740023 America/New_York Eastern Time -US +421953-0830245 America/Detroit Eastern Time - Michigan - most locations -US +381515-0854534 America/Kentucky/Louisville Eastern Time - Kentucky - Louisville area -US +364947-0845057 America/Kentucky/Monticello Eastern Time - Kentucky - Wayne County -US +394606-0860929 America/Indiana/Indianapolis Eastern Time - Indiana - most locations -US +384038-0873143 America/Indiana/Vincennes Eastern Time - Indiana - Daviess, Dubois, Knox & Martin Counties -US +410305-0863611 America/Indiana/Winamac Eastern Time - Indiana - Pulaski County -US +382232-0862041 America/Indiana/Marengo Eastern Time - Indiana - Crawford County -US +382931-0871643 America/Indiana/Petersburg Eastern Time - Indiana - Pike County -US +384452-0850402 America/Indiana/Vevay Eastern Time - Indiana - Switzerland County -US +415100-0873900 America/Chicago Central Time -US +375711-0864541 America/Indiana/Tell_City Central Time - Indiana - Perry County -US +411745-0863730 America/Indiana/Knox Central Time - Indiana - Starke County -US +450628-0873651 America/Menominee Central Time - Michigan - Dickinson, Gogebic, Iron & Menominee Counties -US +470659-1011757 America/North_Dakota/Center Central Time - North Dakota - Oliver County -US +465042-1012439 America/North_Dakota/New_Salem Central Time - North Dakota - Morton County (except Mandan area) -US +471551-1014640 America/North_Dakota/Beulah Central Time - North Dakota - Mercer County -US +394421-1045903 America/Denver Mountain Time -US +433649-1161209 America/Boise Mountain Time - south Idaho & east Oregon -US +364708-1084111 America/Shiprock Mountain Time - Navajo -US +332654-1120424 America/Phoenix Mountain Standard Time - Arizona -US +340308-1181434 America/Los_Angeles Pacific Time -US +611305-1495401 America/Anchorage Alaska Time -US +581807-1342511 America/Juneau Alaska Time - Alaska panhandle -US +571035-1351807 America/Sitka Alaska Time - southeast Alaska panhandle -US +593249-1394338 America/Yakutat Alaska Time - Alaska panhandle neck -US +643004-1652423 America/Nome Alaska Time - west Alaska -US +515248-1763929 America/Adak Aleutian Islands -US +550737-1313435 America/Metlakatla Metlakatla Time - Annette Island -US +211825-1575130 Pacific/Honolulu Hawaii -UY -3453-05611 America/Montevideo -UZ +3940+06648 Asia/Samarkand west Uzbekistan -UZ +4120+06918 Asia/Tashkent east Uzbekistan -VA +415408+0122711 Europe/Vatican -VC +1309-06114 America/St_Vincent -VE +1030-06656 America/Caracas -VG +1827-06437 America/Tortola -VI +1821-06456 America/St_Thomas -VN +1045+10640 Asia/Ho_Chi_Minh -VU -1740+16825 Pacific/Efate -WF -1318-17610 Pacific/Wallis -WS -1350-17144 Pacific/Apia -YE +1245+04512 Asia/Aden -YT -1247+04514 Indian/Mayotte -ZA -2615+02800 Africa/Johannesburg -ZM -1525+02817 Africa/Lusaka -ZW -1750+03103 Africa/Harare diff --git a/lib/six.py b/lib/six.py deleted file mode 100644 index 34f737fb3db0..000000000000 --- a/lib/six.py +++ /dev/null @@ -1,366 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -import operator -import sys -import types - -__author__ = "Benjamin Peterson " -__version__ = "1.2.0-mpl" - - -# True if we are running on Python 3. -PY3 = sys.version_info[0] == 3 - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform == "java": - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) - # This is a bit ugly, but it avoids running this again. - delattr(tp, self.name) - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - - -class _MovedItems(types.ModuleType): - """Lazy loading of moved objects""" - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("reload_module", "__builtin__", "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("winreg", "_winreg"), -] -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) -del attr - -moves = sys.modules["six.moves"] = _MovedItems("moves") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_code = "__code__" - _func_defaults = "__defaults__" - - _iterkeys = "keys" - _itervalues = "values" - _iteritems = "items" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_code = "func_code" - _func_defaults = "func_defaults" - - _iterkeys = "iterkeys" - _itervalues = "itervalues" - _iteritems = "iteritems" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -if PY3: - def get_unbound_function(unbound): - return unbound - - Iterator = object - - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) -else: - def get_unbound_function(unbound): - return unbound.im_func - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) - - -def iterkeys(d): - """Return an iterator over the keys of a dictionary.""" - return iter(getattr(d, _iterkeys)()) - -def itervalues(d): - """Return an iterator over the values of a dictionary.""" - return iter(getattr(d, _itervalues)()) - -def iteritems(d): - """Return an iterator over the (key, value) pairs of a dictionary.""" - return iter(getattr(d, _iteritems)()) - - -if PY3: - def b(s): - return s.encode("latin-1") - def u(s): - return s - if sys.version_info[1] <= 1: - def int2byte(i): - return bytes((i,)) - else: - # This is about 2x faster than the implementation above on 3.2+ - int2byte = operator.methodcaller("to_bytes", 1, "big") - import io - StringIO = io.StringIO - BytesIO = io.BytesIO -else: - def b(s): - return s - def u(s): - return unicode(s, "unicode_escape") - int2byte = chr - import StringIO - StringIO = BytesIO = StringIO.StringIO -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -if PY3: - import builtins - exec_ = getattr(builtins, "exec") - - - def reraise(tp, value, tb=None): - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - - - print_ = getattr(builtins, "print") - del builtins - -else: - def exec_(code, globs=None, locs=None): - """Execute code in a namespace.""" - if globs is None: - frame = sys._getframe(1) - globs = frame.f_globals - if locs is None: - locs = frame.f_locals - del frame - elif locs is None: - locs = globs - exec("""exec code in globs, locs""") - - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - - def print_(*args, **kwargs): - """The new-style print function.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - def write(data): - if not isinstance(data, basestring): - data = str(data) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - -_add_doc(reraise, """Reraise an exception.""") - - -def with_metaclass(meta, base=object): - """Create a base class with a metaclass.""" - return meta("NewBase", (base,), {}) From 04a73b4d4a961bb415b7e6b24dca0b20a73de3e9 Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 9 Oct 2012 14:28:28 -0400 Subject: [PATCH 03/24] Fix a few bugs in the build. --- lib/matplotlib/fontconfig_pattern.py | 8 +- lib/matplotlib/mathtext.py | 14 +- lib/matplotlib/pyparsing_py2.py | 3791 -------------------------- lib/matplotlib/pyparsing_py3.py | 3682 ------------------------- setup.py | 3 + setupext.py | 5 +- 6 files changed, 12 insertions(+), 7491 deletions(-) delete mode 100644 lib/matplotlib/pyparsing_py2.py delete mode 100644 lib/matplotlib/pyparsing_py3.py diff --git a/lib/matplotlib/fontconfig_pattern.py b/lib/matplotlib/fontconfig_pattern.py index de32d84eafca..f96198a6394c 100644 --- a/lib/matplotlib/fontconfig_pattern.py +++ b/lib/matplotlib/fontconfig_pattern.py @@ -21,12 +21,8 @@ from __future__ import print_function import re, sys -if sys.version_info[0] >= 3: - from matplotlib.pyparsing_py3 import Literal, ZeroOrMore, \ - Optional, Regex, StringEnd, ParseException, Suppress -else: - from matplotlib.pyparsing_py2 import Literal, ZeroOrMore, \ - Optional, Regex, StringEnd, ParseException, Suppress +from pyparsing import Literal, ZeroOrMore, \ + Optional, Regex, StringEnd, ParseException, Suppress family_punc = r'\\\-:,' family_unescape = re.compile(r'\\([%s])' % family_punc).sub diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 3742aecf0e1e..9063b85eb8b6 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -34,16 +34,10 @@ from numpy import inf, isinf import numpy as np -if sys.version_info[0] >= 3: - from matplotlib.pyparsing_py3 import Combine, Group, Optional, Forward, \ - Literal, OneOrMore, ZeroOrMore, ParseException, Empty, \ - ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ - FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException -else: - from matplotlib.pyparsing_py2 import Combine, Group, Optional, Forward, \ - Literal, OneOrMore, ZeroOrMore, ParseException, Empty, \ - ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ - FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException +from pyparsing import Combine, Group, Optional, Forward, \ + Literal, OneOrMore, ZeroOrMore, ParseException, Empty, \ + ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ + FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException # Enable packrat parsing ParserElement.enablePackrat() diff --git a/lib/matplotlib/pyparsing_py2.py b/lib/matplotlib/pyparsing_py2.py deleted file mode 100644 index ac94ff331fbd..000000000000 --- a/lib/matplotlib/pyparsing_py2.py +++ /dev/null @@ -1,3791 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2010 Paul T. McGuire -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -#from __future__ import generators - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form C{", !"}):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word( alphas ) + "," + Word( alphas ) + "!" - - hello = "Hello, World!" - print hello, "->", greet.parseString( hello ) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The parsed results returned from C{parseString()} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments -""" - -__version__ = "1.5.5" -__versionTime__ = "12 Aug 2010 03:56" -__author__ = "Paul McGuire " - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 'Upcase', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'getTokensEndLoc', 'hexnums', -'htmlComment', 'javaStyleComment', 'keepOriginalText', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', -] - -""" -Detect if we are running version 3.X and make appropriate changes -Robert A. Clark -""" -_PY3K = sys.version_info[0] > 2 -if _PY3K: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - _str2dict = set - alphas = string.ascii_lowercase + string.ascii_uppercase -else: - _MAX_INT = sys.maxint - range = xrange - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # The Python docs (http://docs.python.org/ref/customization.html#l2h-182) - # state that "The return value must be a string object". However, does a - # unicode object (being a subclass of basestring) count as a "string - # object"? - # If so, then return a unicode object: - return unicode(obj) - # Else encode it... but how? There are many choices... :) - # Replace unprintables with escape codes? - #return unicode(obj).encode(sys.getdefaultencoding(), 'backslashreplace_errors') - # Replace unprintables with question marks? - #return unicode(obj).encode(sys.getdefaultencoding(), 'replace') - # ... - - def _str2dict(strg): - return dict( [(c,0) for c in strg] ) - - alphas = string.lowercase + string.uppercase - -# build list of single arg builtins, tolerant of Python version, that can be used as parse actions -singleArgBuiltins = [] -import __builtin__ -for fname in "sum len enumerate sorted reversed list tuple set any all".split(): - try: - singleArgBuiltins.append(getattr(__builtin__,fname)) - except AttributeError: - continue - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - from_symbols = '&><"\'' - to_symbols = ['&'+s+';' for s in "amp gt lt quot apos".split()] - for from_,to_ in zip(from_symbols, to_symbols): - data = data.replace(from_, to_) - return data - -class _Constants(object): - pass - -nums = string.digits -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join( [ c for c in string.printable if c not in string.whitespace ] ) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join( [line_str[:line_column], - markerString, line_str[line_column:]]) - return line_str.strip() - def __dir__(self): - return "loc msg pstr parserElement lineno col line " \ - "markInputLine __str__ __repr__".split() - -class ParseException(ParseBaseException): - """exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like C{ParseFatalException}, but thrown internally when an - C{ErrorStop} ('-' operator) indicates that parsing is to stop immediately because - an unbacktrackable syntax error has been found""" - def __init__(self, pe): - super(ParseSyntaxException, self).__init__( - pe.pstr, pe.loc, pe.msg, pe.parserElement) - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by C{validate()} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.}) - """ - #~ __slots__ = ( "__toklist", "__tokdict", "__doinit", "__name", "__parent", "__accumNames", "__weakref__" ) - def __new__(cls, toklist, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist, name=None, asList=True, modal=True, isinstance=isinstance ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - if isinstance(toklist, list): - self.__toklist = toklist[:] - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not toklist in (None,'',[]): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,int): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return len( self.__toklist ) > 0 - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def keys( self ): - """Returns all named result keys.""" - return self.__tokdict.keys() - - def pop( self, index=-1 ): - """Removes and returns item at specified index (default=last). - Will work with either numeric indices or dict-key indicies.""" - ret = self[index] - del self[index] - return ret - - def get(self, key, defaultValue=None): - """Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified.""" - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """Inserts new element at location index in the list of parsed tokens.""" - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name in self.__tokdict: - occurrences = self.__tokdict[name] - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def items( self ): - """Returns all named result keys and values as a list of tuples.""" - return [(k,self[k]) for k in self.__tokdict] - - def values( self ): - """Returns all named result values.""" - return [ v[-1][0] for v in self.__tokdict.values() ] - - def __getattr__( self, name ): - if True: #name not in self.__slots__: - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - return None - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = ( lambda a: (a<0 and offset) or (a+offset) ) - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - return self.copy() - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - out = "[" - sep = "" - for i in self.__toklist: - if isinstance(i, ParseResults): - out += sep + _ustr(i) - else: - out += sep + repr(i) - sep = ", " - out += "]" - return out - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """Returns the parse results as a nested list of matching tokens, all converted to strings.""" - out = [] - for res in self.__toklist: - if isinstance(res,ParseResults): - out.append( res.asList() ) - else: - out.append( res ) - return out - - def asDict( self ): - """Returns the named parse results as dictionary.""" - return dict( self.items() ) - - def copy( self ): - """Returns a new copy of a C{ParseResults} object.""" - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.""" - nl = "\n" - out = [] - namedItems = dict( [ (v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist ] ) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - worklist = self.__toklist - for i,res in enumerate(worklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "" ] - - out += [ nl, indent, "" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - """Returns the results name for this token expression.""" - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - self.__tokdict.values()[0][0][1] in (0,-1)): - return self.__tokdict.keys()[0] - else: - return None - - def dump(self,indent='',depth=0): - """Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data.""" - out = [] - out.append( indent+_ustr(self.asList()) ) - keys = self.items() - keys.sort() - for k,v in keys: - if out: - out.append('\n') - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v.keys(): - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(_ustr(v)) - return "".join(out) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - self.__tokdict, \ - par, \ - inAccumNames, \ - self.__name = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __dir__(self): - return dir(super(ParseResults,self)) + self.keys() - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return (loc} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print ("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - def setDefaultWhitespaceChars( chars ): - """Overrides the default whitespace chars - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - setDefaultWhitespaceChars = staticmethod(setDefaultWhitespaceChars) - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element.""" - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """Define name for this expression, for use in debugging.""" - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - """ - newself = self.copy() - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def _normalizeParseActionArgs( f ): - """Internal method used to decorate parse actions that take fewer than 3 arguments, - so that all parse actions can be called as C{f(s,l,t)}.""" - STAR_ARGS = 4 - - # special handling for single-argument builtins - if (f in singleArgBuiltins): - numargs = 1 - else: - try: - restore = None - if isinstance(f,type): - restore = f - f = f.__init__ - if not _PY3K: - codeObj = f.func_code - else: - codeObj = f.code - if codeObj.co_flags & STAR_ARGS: - return f - numargs = codeObj.co_argcount - if not _PY3K: - if hasattr(f,"im_self"): - numargs -= 1 - else: - if hasattr(f,"__self__"): - numargs -= 1 - if restore: - f = restore - except AttributeError: - try: - if not _PY3K: - call_im_func_code = f.__call__.im_func.func_code - else: - call_im_func_code = f.__code__ - - # not a function, must be a callable object, get info from the - # im_func binding of its bound __call__ method - if call_im_func_code.co_flags & STAR_ARGS: - return f - numargs = call_im_func_code.co_argcount - if not _PY3K: - if hasattr(f.__call__,"im_self"): - numargs -= 1 - else: - if hasattr(f.__call__,"__self__"): - numargs -= 0 - except AttributeError: - if not _PY3K: - call_func_code = f.__call__.func_code - else: - call_func_code = f.__call__.__code__ - # not a bound method, get info directly from __call__ method - if call_func_code.co_flags & STAR_ARGS: - return f - numargs = call_func_code.co_argcount - if not _PY3K: - if hasattr(f.__call__,"im_self"): - numargs -= 1 - else: - if hasattr(f.__call__,"__self__"): - numargs -= 1 - - - #~ print ("adding function %s with %d args" % (f.func_name,numargs)) - if numargs == 3: - return f - else: - if numargs > 3: - def tmp(s,l,t): - return f(f.__call__.__self__, s,l,t) - if numargs == 2: - def tmp(s,l,t): - return f(l,t) - elif numargs == 1: - def tmp(s,l,t): - return f(t) - else: #~ numargs == 0: - def tmp(s,l,t): - return f() - try: - tmp.__name__ = f.__name__ - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - try: - tmp.__doc__ = f.__doc__ - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - try: - tmp.__dict__.update(f.__dict__) - except (AttributeError,TypeError): - # no need for special handling if attribute doesnt exist - pass - return tmp - _normalizeParseActionArgs = staticmethod(_normalizeParseActionArgs) - - def setParseAction( self, *fns, **kwargs ): - """Define action to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a ParseResults object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}} for more information - on parsing strings containing s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - self.parseAction = list(map(self._normalizeParseActionArgs, list(fns))) - self.callDuringTry = ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def addParseAction( self, *fns, **kwargs ): - """Add parse action to expression's list of parse actions. See L{I{setParseAction}}.""" - self.parseAction += list(map(self._normalizeParseActionArgs, list(fns))) - self.callDuringTry = self.callDuringTry or ("callDuringTry" in kwargs and kwargs["callDuringTry"]) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{ParseFatalException} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException: - #~ print ("Exception raised:", err) - err = None - if self.debugActions[2]: - err = sys.exc_info()[1] - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - if err is None: - err = sys.exc_info()[1] - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or loc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - err = sys.exc_info()[1] - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - lookup = (self,instring,loc,callPreParse,doActions) - if lookup in ParserElement._exprArgCache: - value = ParserElement._exprArgCache[ lookup ] - if isinstance(value,Exception): - raise value - return value - else: - try: - value = self._parseNoCache( instring, loc, doActions, callPreParse ) - ParserElement._exprArgCache[ lookup ] = (value[0],value[1].copy()) - return value - except ParseBaseException: - pe = sys.exc_info()[1] - ParserElement._exprArgCache[ lookup ] = pe - raise - - _parse = _parseNoCache - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - _exprArgCache = {} - def resetCache(): - ParserElement._exprArgCache.clear() - resetCache = staticmethod(resetCache) - - _packratEnabled = False - def enablePackrat(): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - ParserElement._parse = ParserElement._parseCache - enablePackrat = staticmethod(enablePackrat) - - def parseString( self, instring, parseAll=False ): - """Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{StringEnd()}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - #loc = self.preParse( instring, loc ) - se = StringEnd() - se._parse( instring, loc ) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT ): - """Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}} for more information on parsing - strings with embedded tabs.""" - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def transformString( self, instring ): - """Extension to C{scanString}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string.""" - out = [] - lastE = 0 - # force preservation of s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - return "".join(map(_ustr,_flatten(out))) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def searchString( self, instring, maxMatches=_MAX_INT ): - """Another extension to C{scanString}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def __add__(self, other ): - """Implementation of + operator - returns And""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """Implementation of + operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """Implementation of - operator, returns C{And} with error stop""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, And._ErrorStop(), other ] ) - - def __rsub__(self, other ): - """Implementation of - operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + ZeroOrMore(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{ZeroOrMore(expr)} - - C{expr*(1,None)} is equivalent to C{OneOrMore(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """Implementation of | operator - returns C{MatchFirst}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """Implementation of | operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """Implementation of ^ operator - returns C{Or}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """Implementation of ^ operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """Implementation of & operator - returns C{Each}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """Implementation of & operator when left operand is not a C{ParserElement}""" - if isinstance( other, basestring ): - other = Literal( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """Implementation of ~ operator - returns C{NotAny}""" - return NotAny( self ) - - def __call__(self, name): - """Shortcut for C{setResultsName}, with C{listAllMatches=default}:: - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - could be written as:: - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - """ - return self.setResultsName(name) - - def suppress( self ): - """Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """Overrides default behavior to expand s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match characters.""" - self.keepTabs = True - return self - - def ignore( self, other ): - """Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - """ - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append( other.copy() ) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """Enable display of debugging messages while doing pattern matching.""" - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable.""" - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """Check defined expressions for valid structure, check for infinite recursive definitions.""" - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - f = open(file_or_filename, "rb") - file_contents = f.read() - f.close() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - exc = sys.exc_info()[1] - raise exc - - def getException(self): - return ParseException("",0,self.errmsg,self) - - def __getattr__(self,aname): - if aname == "myException": - self.myException = ret = self.getException(); - return ret; - else: - raise AttributeError("no such attribute " + aname) - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or self.__dict__ == other.__dict__ - elif isinstance(other, basestring): - try: - self.parseString(_ustr(other), parseAll=True) - return True - except ParseBaseException: - return False - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - -class Token(ParserElement): - """Abstract C{ParserElement} subclass, for defining atomic matching patterns.""" - def __init__( self ): - super(Token,self).__init__( savelist=False ) - #self.myException = ParseException("",0,"",self) - - def setName(self, name): - s = super(Token,self).setName(name) - self.errmsg = "Expected " + self.name - #s.myException.msg = self.errmsg - return s - - -class Empty(Token): - """An empty token, will always match.""" - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """A token that will never match.""" - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - -class Literal(Token): - """Token to exactly match a specified string.""" - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc -_L = Literal - -class Keyword(Token): - """Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{Literal}:: - Literal("if") will match the leading 'if' in 'ifAndOnlyIf'. - Keyword("if") will not; it will only match the leading 'if in 'if x=1', or 'if(y==2)' - Accepts two optional constructor arguments in addition to the keyword string: - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$"; C{caseless} allows case-insensitive - matching, default is False. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=DEFAULT_KEYWORD_CHARS, caseless=False ): - super(Keyword,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = _str2dict(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - setDefaultKeywordChars = staticmethod(setDefaultKeywordChars) - -class CaselessLiteral(Literal): - """Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class CaselessKeyword(Keyword): - def __init__( self, matchString, identChars=Keyword.DEFAULT_KEYWORD_CHARS ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class Word(Token): - """Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False ): - super(Word,self).__init__() - self.initCharsOrig = initChars - self.initChars = _str2dict(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = _str2dict(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = _str2dict(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.bodyCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - return loc,result.group() - - if not(instring[ loc ] in self.initChars): - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - """Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters pattern and flags are passed to the re.compile() function as-is. See the Python re module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if len(pattern) == 0: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - """Token for matching strings that are delimited by quoting characters. - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None): - """ - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=None) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=None) - - multiline - boolean indicating whether quotes can span multiple lines (default=False) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=True) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=None => same as quoteChar) - """ - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if len(quoteChar) == 0: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if len(endQuoteChar) == 0: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join(["%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)]) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern,"\g<1>",ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """Token for matching words composed of characters *not* in a given set. - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - #self.myException.msg = self.errmsg - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{Word} class.""" - whiteStrs = { - " " : "", - "\t": "", - "\n": "", - "\r": "", - "\f": "", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join([c for c in self.whiteChars if c not in self.matchWhite]) ) - #~ self.leaveWhitespace() - self.name = ("".join([White.whiteStrs[c] for c in self.matchWhite])) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - #self.myException.msg = self.errmsg - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - #~ raise ParseException( instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """Token to advance to a specific column of input text; useful for tabular report scraping.""" - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - -class LineStart(_PositionToken): - """Matches if current position is at the beginning of a line within the parse string""" - def __init__( self ): - super(LineStart,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected start of line" - #self.myException.msg = self.errmsg - - def preParse( self, instring, loc ): - preloc = super(LineStart,self).preParse(instring,loc) - if instring[preloc] == "\n": - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - if not( loc==0 or - (loc == self.preParse( instring, 0 )) or - (instring[loc-1] == "\n") ): #col(loc, instring) != 1: - #~ raise ParseException( instring, loc, "Expected start of line" ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - -class LineEnd(_PositionToken): - """Matches if current position is at the end of a line within the parse string""" - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - #self.myException.msg = self.errmsg - - def parseImpl( self, instring, loc, doActions=True ): - if loc len(instring): - return loc, [] - else: - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class WordStart(_PositionToken): - """Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of wordChars - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = _str2dict(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - -class WordEnd(_PositionToken): - """Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of wordChars - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = _str2dict(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - if loc2 > maxMatchLoc: - maxMatchLoc = loc2 - maxMatchExp = e - - if maxMatchLoc < 0: - if maxException is not None: - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - return maxMatchExp._parse( instring, loc, doActions ) - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the '|' operator. - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if exprs: - self.mayReturnEmpty = False - for e in self.exprs: - if e.mayReturnEmpty: - self.mayReturnEmpty = True - break - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException, err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = Literal( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """Requires all given C{ParseExpressions} to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the '&' operator. - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = True - for e in self.exprs: - if not e.mayReturnEmpty: - self.mayReturnEmpty = False - break - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(e) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join( [ _ustr(e) for e in tmpReqd ] ) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = ParseResults([]) - for r in resultlist: - dups = {} - for k in r.keys(): - if k in finalResults.keys(): - tmp = ParseResults(finalResults[k]) - tmp += ParseResults(r[k]) - dups[k] = tmp - finalResults += ParseResults(r) - for k,v in dups.items(): - finalResults[k] = v - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join( [ _ustr(e) for e in self.exprs ] ) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.""" - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - expr = Literal(expr) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """Lookahead matching of the given parse expression. C{FollowedBy} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list.""" - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """Lookahead to disallow matching with the given parse expression. C{NotAny} - does *not* advance the parsing position within the input string, it only - verifies that the specified parse expression does *not* match at the current - position. Also, C{NotAny} does *not* skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator.""" - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - try: - self.expr.tryParse( instring, loc ) - except (ParseException,IndexError): - pass - else: - #~ raise ParseException(instring, loc, self.errmsg ) - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - - -class ZeroOrMore(ParseElementEnhance): - """Optional repetition of zero or more of the given expression.""" - def __init__( self, expr ): - super(ZeroOrMore,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - tokens = [] - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(ZeroOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - - -class OneOrMore(ParseElementEnhance): - """Repetition of one or more of the given expression.""" - def parseImpl( self, instring, loc, doActions=True ): - # must be at least one - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = ( len(self.ignoreExprs) > 0 ) - while 1: - if hasIgnoreExprs: - preloc = self._skipIgnorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self.expr._parse( instring, preloc, doActions ) - if tmptokens or tmptokens.keys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - - def setResultsName( self, name, listAllMatches=False ): - ret = super(OneOrMore,self).setResultsName(name,listAllMatches) - ret.saveAsList = True - return ret - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """Optional matching of the given expression. - A default return string can also be specified, if the optional expression - is not found. - """ - def __init__( self, exprs, default=_optionalNotMatched ): - super(Optional,self).__init__( exprs, savelist=False ) - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - - -class SkipTo(ParseElementEnhance): - """Token for skipping over all undefined text until the matched expression is found. - If C{include} is set to true, the matched expression is also parsed (the skipped text - and matched expression are returned as a 2-element list). The C{ignore} - argument is used to define grammars (typically quoted strings and comments) that - might contain false matches. - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if failOn is not None and isinstance(failOn, basestring): - self.failOn = Literal(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - #self.myException = ParseException("",0,self.errmsg,self) - - def parseImpl( self, instring, loc, doActions=True ): - startLoc = loc - instrlen = len(instring) - expr = self.expr - failParse = False - while loc <= instrlen: - try: - if self.failOn: - try: - self.failOn.tryParse(instring, loc) - except ParseBaseException: - pass - else: - failParse = True - raise ParseException(instring, loc, "Found expression " + str(self.failOn)) - failParse = False - if self.ignoreExpr is not None: - while 1: - try: - loc = self.ignoreExpr.tryParse(instring,loc) - # print "found ignoreExpr, advance to", loc - except ParseBaseException: - break - expr._parse( instring, loc, doActions=False, callPreParse=False ) - skipText = instring[startLoc:loc] - if self.includeMatch: - loc,mat = expr._parse(instring,loc,doActions,callPreParse=False) - if mat: - skipRes = ParseResults( skipText ) - skipRes += mat - return loc, [ skipRes ] - else: - return loc, [ skipText ] - else: - return loc, [ skipText ] - except (ParseException,IndexError): - if failParse: - raise - else: - loc += 1 - exc = self.myException - exc.loc = loc - exc.pstr = instring - raise exc - -class Forward(ParseElementEnhance): - """Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = Literal(other) - self.expr = other - self.mayReturnEmpty = other.mayReturnEmpty - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return None - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret << self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """Abstract subclass of ParseExpression, for converting parsed results.""" - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Upcase(TokenConverter): - """Converter to upper case all matching tokens.""" - def __init__(self, *args): - super(Upcase,self).__init__(*args) - warnings.warn("Upcase class is deprecated, use upcaseTokens parse action instead", - DeprecationWarning,stacklevel=2) - - def postParse( self, instring, loc, tokenlist ): - return list(map( string.upper, tokenlist )) - - -class Combine(TokenConverter): - """Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and len(retToks.keys())>0: - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """Converter to return the matched tokens as a list - useful for returning tokens of ZeroOrMore and OneOrMore expressions.""" - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - """ - def __init__( self, exprs ): - super(Dict,self).__init__( exprs ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.keys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """Converter for ignoring the results of a parsed expression.""" - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """Wrapper for parse actions, to ensure they are only called once.""" - def __init__(self, methodCall): - self.callable = ParserElement._normalizeParseActionArgs(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """Decorator for debugging parse actions.""" - f = ParserElement._normalizeParseActionArgs(f) - def z(*paArgs): - thisFunc = f.func_name - s,l,t = paArgs[-3:] - if len(paArgs)>3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %s)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception: - exc = sys.exc_info()[1] - sys.stderr.write( "<", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join( [ _escapeRegexRangeChars(sym) for sym in symbols] ) ) - else: - return Regex( "|".join( [ re.escape(sym) for sym in symbols] ) ) - except: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst( [ parseElementClass(sym) for sym in symbols ] ) - -def dictOf( key, value ): - """Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{Dict}, C{ZeroOrMore}, and C{Group} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. Simpler to use than the parse action C{keepOriginalText}, and does not - require the inspect module to chase up the call stack. By default, returns a - string containing the original parsed text. - - If the optional C{asString} argument is passed as False, then the return value is a - C{ParseResults} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{originalTextFor} contains expressions with defined - results names, you must set C{asString} to False if you want to preserve those - results name values.""" - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - del t[:] - t.insert(0, s[t._original_start:t._original_end]) - del t["_original_start"] - del t["_original_end"] - matchExpr.setParseAction(extractText) - return matchExpr - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_printables_less_backslash = "".join([ c for c in printables if c not in r"\]" ]) -_escapedHexChar = Combine( Suppress(_bslash + "0x") + Word(hexnums) ).setParseAction(lambda s,l,t:unichr(int(t[0],16))) -_escapedOctChar = Combine( Suppress(_bslash) + Word("0","01234567") ).setParseAction(lambda s,l,t:unichr(int(t[0],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | Word(_printables_less_backslash,exact=1) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -_expanded = lambda p: (isinstance(p,ParseResults) and ''.join([ unichr(c) for c in range(ord(p[0]),ord(p[1])+1) ]) or p) - -def srange(s): - r"""Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be:: - a single character - an escaped character with a leading backslash (such as \- or \]) - an escaped hex character with a leading '\0x' (\0x21, which is a '!' character) - an escaped octal character with a leading '\0' (\041, which is a '!' character) - a range of any of the above, separated by a dash ('a-z', etc.) - any combination of the above ('aeiouy', 'a-zA-Z0-9_$', etc.) - """ - try: - return "".join([_expanded(part) for part in _reBracketExpr.parseString(s).body]) - except: - return "" - -def matchOnlyAtCol(n): - """Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{transformString()}. - """ - def _replFunc(*args): - return [replStr] - return _replFunc - -def removeQuotes(s,l,t): - """Helper parse action for removing quotation marks from parsed quoted strings. - To use, add this parse action to quoted string using:: - quotedString.setParseAction( removeQuotes ) - """ - return t[0][1:-1] - -def upcaseTokens(s,l,t): - """Helper parse action to convert tokens to upper case.""" - return [ tt.upper() for tt in map(_ustr,t) ] - -def downcaseTokens(s,l,t): - """Helper parse action to convert tokens to lower case.""" - return [ tt.lower() for tt in map(_ustr,t) ] - -def keepOriginalText(s,startLoc,t): - """DEPRECATED - use new helper method C{originalTextFor}. - Helper parse action to preserve original parsed text, - overriding any nested parse actions.""" - try: - endloc = getTokensEndLoc() - except ParseException: - raise ParseFatalException("incorrect usage of keepOriginalText - may only be called as a parse action") - del t[:] - t += ParseResults(s[startLoc:endloc]) - return t - -def getTokensEndLoc(): - """Method to be called from within a parse action to determine the end - location of the parsed tokens.""" - import inspect - fstack = inspect.stack() - try: - # search up the stack (through intervening argument normalizers) for correct calling routine - for f in fstack[2:]: - if f[3] == "_parseNoCache": - endloc = f[0].f_locals["loc"] - return endloc - else: - raise ParseFatalException("incorrect usage of getTokensEndLoc - may only be called from within a parse action") - finally: - del fstack - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join( [ c for c in printables if c not in ">" ] ) - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % tagStr) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % tagStr) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """Helper to construct opening and closing tag expressions for HTML, given a tag name""" - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """Helper to construct opening and closing tag expressions for XML, given a tag name""" - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """Helper to create a validating parse action to be used with start tags created - with makeXMLTags or makeHTMLTags. Use withAttribute to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - or