<commit_before>import os
import json
import requests
import six
from retrying import retry
from datetime import datetime

from wargaming.exceptions import RequestError, ValidationError
from wargaming.settings import ALLOWED_GAMES, ALLOWED_REGIONS, HTTP_USER_AGENT_HEADER, RETRY_COUNT


def check_allowed_game(game):
    if game not in ALLOWED_GAMES:
        raise ValidationError("Game '%s' is not allowed list: %s" %
                              (game, ', '.join(ALLOWED_GAMES)))


def check_allowed_region(region):
    if region not in ALLOWED_REGIONS:
        raise ValidationError("Region %s is not allowed list: %s" %
                              (region, ', '.join(ALLOWED_REGIONS)))


def region_url(region, game):
    check_allowed_game(game)
    check_allowed_region(region)

    # all api calls for all project goes to api.worldoftanks.*
    # maybe WG would move this api to api.wargaming.net
    return 'https://api.worldoftanks.%s/%s/' % (region, game)


@six.python_2_unicode_compatible
class WGAPI(object):
    """Result from WG API request"""

    def __init__(self, url, stop_max_attempt_number=RETRY_COUNT, **kwargs):
        self.url = url
        for name, value in kwargs.items():
            if isinstance(value, list) or isinstance(value, tuple):
                kwargs[name] = ','.join(str(i) for i in value)
            elif isinstance(value, datetime):
                kwargs[name] = value.isoformat()
        self.params = kwargs
        self._data = None
        self.error = None
        self._iter = None
        self.stop_max_attempt_number = stop_max_attempt_number
        self._fetch_data = retry(
            stop_max_attempt_number=stop_max_attempt_number,
            retry_on_exception=lambda ex: isinstance(ex, RequestError)
        )(self._fetch_data)

    def _fetch_data(self):
        if not self._data:
            self.response = response = requests.get(self.url, params=self.params, headers={
                'User-Agent': HTTP_USER_AGENT_HEADER,
            }).json()

            if response.get('status', '') == 'error':
                self.error = response['error']
                raise RequestError(**self.error)

            self._data = response.get('data', response)
        return self._data

    @property
    def data(self):
        return self._fetch_data()

    @data.setter
    def data(self, value):
        """setter is used if needed to fake response or reset data"""
        self._data = value

    def __len__(self):
        return len(self.data)

    def __str__(self):
        return str(self.data)

    def __iter__(self):
        return iter(self.data)

    def keys(self):
        return self.data.keys()

    def items(self):
        return self.data.items()

    def values(self):
        return self.data.values()

    def __getitem__(self, item):
        """__getitem__ with smart type detection
        would try to lookup data['123']
        if not found would try data[123] and vise versa
        """
        data = self.data
        try:
            return data[item]
        except KeyError:
            item = int(item) if type(item) == str and item.isdigit() else str(item)
            return data[item]

    def __repr__(self):
        res = str(self.data)
        return res[0:200] + ('...' if len(res) > 200 else '')


class ModuleAPI(object):
    _module_dict = {}

    def __init__(self, application_id, language, base_url):
        """
        :param application_id: WG application id
        :param language: default language param
        :param base_url: base url of module api
        """
        self.application_id = application_id
        self.language = language
        self.base_url = base_url


class BaseAPI(object):
    _module_dict = {}

    def __init__(self, application_id, language, region):
        """
        :param application_id: WG application id
        :param language: default language param
        :param region: game geo region short name
        """
        self.application_id = application_id
        self.language = language
        self.region = region
        self.base_url = region_url(region, self.__class__.__name__.lower())
        for k, v in self._module_dict.items():
            setattr(self, k, v(application_id, language, self.base_url))


class MetaAPI(type):
    """MetaClass Loads current scheme from schema.json file
    and creates API structure based on scheme.

    Scheme format:
    {'module_name': {                         # account, globalmap, etc
        'function_name': {                    # list, provinces, etc
            '__doc__': description,           # text description<commit_msg>Add __repr__ for BaseAPI<commit_after>import os
import json
import requests
import six
from retrying import retry
from datetime import datetime

from wargaming.exceptions import RequestError, ValidationError
from wargaming.settings import ALLOWED_GAMES, ALLOWED_REGIONS, HTTP_USER_AGENT_HEADER, RETRY_COUNT


def check_allowed_game(game):
    if game not in ALLOWED_GAMES:
        raise ValidationError("Game '%s' is not allowed list: %s" %
                              (game, ', '.join(ALLOWED_GAMES)))


def check_allowed_region(region):
    if region not in ALLOWED_REGIONS:
        raise ValidationError("Region %s is not allowed list: %s" %
                              (region, ', '.join(ALLOWED_REGIONS)))


def region_url(region, game):
    check_allowed_game(game)
    check_allowed_region(region)

    # all api calls for all project goes to api.worldoftanks.*
    # maybe WG would move this api to api.wargaming.net
    return 'https://api.worldoftanks.%s/%s/' % (region, game)


@six.python_2_unicode_compatible
class WGAPI(object):
    """Result from WG API request"""

    def __init__(self, url, stop_max_attempt_number=RETRY_COUNT, **kwargs):
        self.url = url
        for name, value in kwargs.items():
            if isinstance(value, list) or isinstance(value, tuple):
                kwargs[name] = ','.join(str(i) for i in value)
            elif isinstance(value, datetime):
                kwargs[name] = value.isoformat()
        self.params = kwargs
        self._data = None
        self.error = None
        self._iter = None
        self.stop_max_attempt_number = stop_max_attempt_number
        self._fetch_data = retry(
            stop_max_attempt_number=stop_max_attempt_number,
            retry_on_exception=lambda ex: isinstance(ex, RequestError)
        )(self._fetch_data)

    def _fetch_data(self):
        if not self._data:
            self.response = response = requests.get(self.url, params=self.params, headers={
                'User-Agent': HTTP_USER_AGENT_HEADER,
            }).json()

            if response.get('status', '') == 'error':
                self.error = response['error']
                raise RequestError(**self.error)

            self._data = response.get('data', response)
        return self._data

    @property
    def data(self):
        return self._fetch_data()

    @data.setter
    def data(self, value):
        """setter is used if needed to fake response or reset data"""
        self._data = value

    def __len__(self):
        return len(self.data)

    def __str__(self):
        return str(self.data)

    def __iter__(self):
        return iter(self.data)

    def keys(self):
        return self.data.keys()

    def items(self):
        return self.data.items()

    def values(self):
        return self.data.values()

    def __getitem__(self, item):
        """__getitem__ with smart type detection
        would try to lookup data['123']
        if not found would try data[123] and vise versa
        """
        data = self.data
        try:
            return data[item]
        except KeyError:
            item = int(item) if type(item) == str and item.isdigit() else str(item)
            return data[item]

    def __repr__(self):
        res = str(self.data)
        return res[0:200] + ('...' if len(res) > 200 else '')


class ModuleAPI(object):
    _module_dict = {}

    def __init__(self, application_id, language, base_url):
        """
        :param application_id: WG application id
        :param language: default language param
        :param base_url: base url of module api
        """
        self.application_id = application_id
        self.language = language
        self.base_url = base_url


class BaseAPI(object):
    _module_dict = {}

    def __init__(self, application_id, language, region):
        """
        :param application_id: WG application id
        :param language: default language param
        :param region: game geo region short name
        """
        self.application_id = application_id
        self.language = language
        self.region = region
        self.base_url = region_url(region, self.__class__.__name__.lower())
        for k, v in self._module_dict.items():
            setattr(self, k, v(application_id, language, self.base_url))

    def __repr__(self):
        return str("<%s at %s, language=%s>" % (self.__class__.__name__, self.base_url, self.language))


class MetaAPI(type):
    """MetaClass Loads current scheme from schema.json file
    and creates API structure based on scheme.

    Scheme format:
    {'module_name': {                         # account, globalmap, etc
        'function_name': {                    # list, provinces, etc
            '__doc__': description,           # text description
{'fraction_non_alphanumeric': 0.0990025466893039, 'fraction_numerical': 0.0029711375212224107, 'mean_word_length': 2.3421985815602837, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 6, 'https://': 2, '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': '3578216', 'n_tokens_mistral': 2740, 'n_tokens_neox': 2624, 'n_words': 750}