<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import with_statement, print_function, division, unicode_literals

import sys
import os.path as op
from functools import wraps
import datetime
from datetime import timedelta
from collections import defaultdict, namedtuple
from zipfile import ZipFile
from io import BytesIO

# We could have used "six", but like this we have no dependency
if sys.version_info[0] < 3:
    range = xrange
    from itertools import izip as zip
    from urllib2 import urlopen

    def iteritems(d):
        return d.iteritems()

    def itervalues(d):
        return d.itervalues()


else:
    from urllib.request import urlopen

    def iteritems(d):
        return d.items()

    def itervalues(d):
        return d.values()


_DIRNAME = op.realpath(op.dirname(__file__))
CURRENCY_FILE = op.join(_DIRNAME, 'eurofxref-hist.zip')

Bounds = namedtuple('Bounds', 'first_date last_date')

__all__ = ['CurrencyConverter',
           'S3CurrencyConverter',
           'RateNotFoundError', ]


def memoize(function):
    memo = {}

    @wraps(function)
    def wrapper(*args):
        if args not in memo:
            memo[args] = function(*args)
        return memo[args]
    return wrapper


@memoize
def list_dates_between(first_date, last_date):
    """Returns all dates from first to last included."""
    return [first_date + timedelta(days=n)
            for n in range(1 + (last_date - first_date).days)]


@memoize
def parse_date(s):
    """Fast %Y-%m-%d parsing."""
    try:
        return datetime.date(int(s[:4]), int(s[5:7]), int(s[8:10]))
    except ValueError:  # other accepted format used in one-day data set
        return datetime.datetime.strptime(s, '%d %B %Y').date()


def get_lines_from_zip(zip_str):
    zip_file = ZipFile(BytesIO(zip_str))
    for name in zip_file.namelist():
        for line in zip_file.read(name).decode('utf-8').splitlines():
            yield line


class RateNotFoundError(Exception):
    """Custom exception when data is missing in the rates file."""
    pass


class CurrencyConverter(object):
    """
    At init, load the historic currencies (since 1999) from the ECB.
    The rates are EUR foreign exchange reference rates:

    Date,USD,JPY,BGN,CYP,CZK,...
    2014-03-28,1.3759,140.9,1.9558,N/A,27.423,...
    2014-03-27,1.3758,...

    ``_rates`` is a dictionary with:
    + currencies as keys
    + {date: rate, ...} as values.

    ``currencies`` is a set of all available currencies.
    ``bounds`` is a dict if first and last date available per currency.
    """
    def __init__(self,
                 currency_file=CURRENCY_FILE,
                 fallback_on_wrong_date=False,
                 fallback_on_missing_rate=False,
                 ref_currency='EUR',
                 na_values=frozenset(['', 'N/A']),
                 verbose=False):

        # Global options
        self.fallback_on_wrong_date = fallback_on_wrong_date
        self.fallback_on_missing_rate = fallback_on_missing_rate
        self.ref_currency = ref_currency  # reference currency of rates
        self.na_values = na_values        # missing values
        self.verbose = verbose

        # Will be filled once the file is loaded
        self._rates = None
        self.bounds = None
        self.currencies = None

        if currency_file is not None:
            self.load_file(currency_file)<commit_msg>Add docstring to CurrencyConverter.__init__<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import with_statement, print_function, division, unicode_literals

import sys
import os.path as op
from functools import wraps
import datetime
from datetime import timedelta
from collections import defaultdict, namedtuple
from zipfile import ZipFile
from io import BytesIO

# We could have used "six", but like this we have no dependency
if sys.version_info[0] < 3:
    range = xrange
    from itertools import izip as zip
    from urllib2 import urlopen

    def iteritems(d):
        return d.iteritems()

    def itervalues(d):
        return d.itervalues()


else:
    from urllib.request import urlopen

    def iteritems(d):
        return d.items()

    def itervalues(d):
        return d.values()


_DIRNAME = op.realpath(op.dirname(__file__))
CURRENCY_FILE = op.join(_DIRNAME, 'eurofxref-hist.zip')

Bounds = namedtuple('Bounds', 'first_date last_date')

__all__ = ['CurrencyConverter',
           'S3CurrencyConverter',
           'RateNotFoundError', ]


def memoize(function):
    memo = {}

    @wraps(function)
    def wrapper(*args):
        if args not in memo:
            memo[args] = function(*args)
        return memo[args]
    return wrapper


@memoize
def list_dates_between(first_date, last_date):
    """Returns all dates from first to last included."""
    return [first_date + timedelta(days=n)
            for n in range(1 + (last_date - first_date).days)]


@memoize
def parse_date(s):
    """Fast %Y-%m-%d parsing."""
    try:
        return datetime.date(int(s[:4]), int(s[5:7]), int(s[8:10]))
    except ValueError:  # other accepted format used in one-day data set
        return datetime.datetime.strptime(s, '%d %B %Y').date()


def get_lines_from_zip(zip_str):
    zip_file = ZipFile(BytesIO(zip_str))
    for name in zip_file.namelist():
        for line in zip_file.read(name).decode('utf-8').splitlines():
            yield line


class RateNotFoundError(Exception):
    """Custom exception when data is missing in the rates file."""
    pass


class CurrencyConverter(object):
    """
    At init, load the historic currencies (since 1999) from the ECB.
    The rates are EUR foreign exchange reference rates:

    Date,USD,JPY,BGN,CYP,CZK,...
    2014-03-28,1.3759,140.9,1.9558,N/A,27.423,...
    2014-03-27,1.3758,...

    ``_rates`` is a dictionary with:
    + currencies as keys
    + {date: rate, ...} as values.

    ``currencies`` is a set of all available currencies.
    ``bounds`` is a dict if first and last date available per currency.
    """
    def __init__(self,
                 currency_file=CURRENCY_FILE,
                 fallback_on_wrong_date=False,
                 fallback_on_missing_rate=False,
                 ref_currency='EUR',
                 na_values=frozenset(['', 'N/A']),
                 verbose=False):
        """Instantiate a CurrencyConverter.

        :param str currency_file: Path to the source data. Can be a local path,
            or an URL starting with 'http://' or 'https://'. Defaults to the
            European Central Bank historical rates file included in the package.
        :param bool fallback_on_wrong_date: Set to False (default) to raise a
            RateNotFoundError when dates are requested outside the data's range.
            Set to True to extrapolate rates for dates outside the source data's
            range. The extrapolation is done by falling back to the first or
            last data point, for dates before and after the data's range,
            respectively.
        :param bool fallback_on_missing_rate: Set to True to linearly
            interpolate missing rates by their two closest valid rates. This
            only affects dates within the source data's range. Default False.
        :param str ref_currency: Three-letter currency code for the currency
            that the source data is oriented towards. This is EUR for the
            default European Central Bank data, and so the default is 'EUR'.
        :param iterable na_values: What to interpret as missing values in the
            source data.
        :param verbose: Set to True to print what is going on under the hood.
        """
        # Global options
        self.fallback_on_wrong_date = fallback_on_wrong_date
        self.fallback_on_missing_rate = fallback_on_missing_rate
        self.ref_currency = ref_currency  # reference currency of rates
        self.na_values = na_values        # missing values
        self.verbose = verbose

        # Will be filled once the file is loaded
        self._rates = None
        self.bounds = None
        self.currencies = None

        if currency_file is not None:
            self.load_file(currency_file)
{'fraction_non_alphanumeric': 0.09292089497493582, 'fraction_numerical': 0.013938134246240371, 'mean_word_length': 2.658318425760286, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '118393', 'n_tokens_mistral': 2527, 'n_tokens_neox': 2376, 'n_words': 771}