<commit_before>import logging
import os
import platform
import requests
import time
import sys


__version__ = '0.3'


logger = logging.getLogger('usagestats')


class Prompt(object):
    def __init__(self, prompt=None, enable=None, disable=None):
        if prompt is not None:
            if enable is not None or disable is not None:
                raise TypeError("Expects either 'prompt' or both 'enable' and "
                                "'disable'")
            self.prompt = prompt
        else:
            if enable is None or disable is None:
                raise TypeError("Expects either 'prompt' or both 'enable' and "
                                "'disable'")
            self.prompt = (
                    "\nUploading usage statistics is currently disabled\n"
                    "Please help us by providing anonymous usage statistics; "
                    "you can enable this\nby running:\n"
                    "    {enable}\n"
                    "If you do not want to see this message again, you can "
                    "run:\n"
                    "    {disable}\n"
                    "Nothing will be uploaded before you opt in.\n".format(
                        enable=enable,
                        disable=disable))


def OPERATING_SYSTEM(stats, info):
    info.append(('architecture', platform.machine().lower()))
    info.append(('distribution',
                 "%s;%s" % (platform.linux_distribution()[0:2])))
    info.append(('system',
                 "%s;%s" % (platform.system(), platform.release())))


def SESSION_TIME(stats, info):
    duration = time.time() - stats.started_time
    secs = int(duration)
    msecs = int((duration - secs) * 1000)
    info.append(('session_time', '%d.%d' % (secs, msecs)))


def PYTHON_VERSION(stats, info):
    # Some versions of Python have a \n in sys.version!
    version = sys.version.replace(' \n', ' ').replace('\n', ' ')
    python = ';'.join([str(c) for c in sys.version_info] + [version])
    info.append(('python', python))


def _encode(s):
    if not isinstance(s, bytes):
        if str == bytes:  # Python 2
            if isinstance(s, unicode):
                s = s.encode('utf-8')
            else:
                s = str(s)
        else:  # Python 3
            if isinstance(s, str):
                s = s.encode('utf-8')
            else:
                s = str(s).encode('utf-8')
    if b'\n' in s:
        s = s.replace(b'\n', b' ')
    return s


class Stats(object):
    ERRORED, DISABLED_ENV, DISABLED, UNSET, ENABLED = range(5)

    @property
    def enabled(self):
        return self.status in (Stats.UNSET, Stats.ENABLED)

    @property
    def enableable(self):
        return self.status is not Stats.ERRORED

    @property
    def disableable(self):
        return self.status is not Stats.ERRORED

    @property
    def recording(self):
        return self.status in (Stats.UNSET, Stats.ENABLED)

    @property
    def sending(self):
        return self.status is Stats.ENABLED

    def __init__(self, location, prompt, drop_point,
                 version, unique_user_id=False,
                 env_var='PYTHON_USAGE_STATS',
                 ssl_verify=None):
        self.started_time = time.time()

        self.ssl_verify = ssl_verify

        env_var = os.environ.get(env_var, '').lower()
        if env_var not in (None, '', '1', 'on', 'enabled', 'yes', 'true'):
            self.status = Stats.DISABLED_ENV
        else:
            self.status = Stats.UNSET
        self.location = os.path.expanduser(location)
        self.drop_point = drop_point
        self.version = version

        if isinstance(prompt, Prompt):
            self.prompt = prompt
        elif isinstance(prompt, basestring):
            self.prompt = Prompt(prompt)
        else:
            raise TypeError("'prompt' should either a Prompt or a string")

        if self.enabled and not os.path.isdir(self.location):
            try:
                os.makedirs(self.location, 0o700)
            except OSError:
                logger.warning("Couldn't create %s, usage statistics won't be "
                               "collected", self.location)
                self.status = Stats.ERRORED

        status_file = os.path.join(self.location, 'status')
        if self.enabled and os.path.exists(status_file):
            with open(status_file, 'r') as fp:
                status = fp.read().strip()
            if status == 'ENABLED':
                self.status = Stats.ENABLED
            elif status == 'DISABLED':
                self.status = Stats.DISABLED

        if self.enabled and unique_user_id:
            user_id_file = os.path.join(self.location, 'user_id')
            if os.path.exists(user_id_file):
                with open(user_id_file, 'r') as fp:
                    self.user_id = fp.read().strip()
            else:
                import uuid
                self.user_id = str(uuid.uuid4())
                with open(user_id_file, 'w') as fp:
                    fp.write(self.user_id)
        else:
            self.user_id = None

        self.notes = []

        self.note([('version', self.version)])

    def enable_reporting(self):
        if not self.enableable:
            logger.critical("Can't enable reporting")
            return
        self.status = Stats.ENABLED
        status_file = os.path.join(self.location, 'status')
        with open(status_file, 'w') as fp:
            fp.write('ENABLED')

    def disable_reporting(self):
        if not self.disableable:
            logger.critical("Can't disable reporting")
            return
        self.status = Stats.DISABLED
        status_file = os.path.join(self.location, 'status')
        with open(status_file, 'w') as fp:
            fp.write('DISABLED')
        if os.path.exists(self.location):
            old_reports = [f for f in os.listdir(self.location)
                           if f.startswith('report_')]
            for old_filename in old_reports:
                fullname = os.path.join(self.location, old_filename)
                os.remove(fullname)
            logger.info("Deleted %d pending reports", len(old_reports))

    @staticmethod
    def _to_notes(info):
        if hasattr(info, 'iteritems'):
            return info.iteritems()
        elif hasattr(info, 'items'):
            return info.items()
        else:
            return info

    def note(self, info):
        if self.recording:
            self.notes.extend(self._to_notes(info))

    def submit(self, info, *flags):
        if not self.recording:
            return

        all_info, self.notes = self.notes, None
        all_info.extend(self._to_notes(info))
        for flag in flags:
            flag(self, all_info)

        now = time.time()
        secs = int(now)
        msecs = int((now - secs) * 1000)
        all_info.insert(0, ('date', '%d.%d' % (secs, msecs)))

        if self.user_id:
            all_info.insert(1, ('user', self.user_id))

        logger.info("Generated report:\n%r", (all_info,))

        # Current report
        def generator():
            for key, value in all_info:
                yield _encode(key) + b':' + _encode(value) + b'\n'
        filename = 'report_%d_%d.txt' % (secs, msecs)

        # Save current report and exit, unless user has opted in
        if not self.sending:<commit_msg>Explicit ValueError if reusing submitted report<commit_after>import logging
import os
import platform
import requests
import time
import sys


__version__ = '0.3'


logger = logging.getLogger('usagestats')


class Prompt(object):
    def __init__(self, prompt=None, enable=None, disable=None):
        if prompt is not None:
            if enable is not None or disable is not None:
                raise TypeError("Expects either 'prompt' or both 'enable' and "
                                "'disable'")
            self.prompt = prompt
        else:
            if enable is None or disable is None:
                raise TypeError("Expects either 'prompt' or both 'enable' and "
                                "'disable'")
            self.prompt = (
                    "\nUploading usage statistics is currently disabled\n"
                    "Please help us by providing anonymous usage statistics; "
                    "you can enable this\nby running:\n"
                    "    {enable}\n"
                    "If you do not want to see this message again, you can "
                    "run:\n"
                    "    {disable}\n"
                    "Nothing will be uploaded before you opt in.\n".format(
                        enable=enable,
                        disable=disable))


def OPERATING_SYSTEM(stats, info):
    info.append(('architecture', platform.machine().lower()))
    info.append(('distribution',
                 "%s;%s" % (platform.linux_distribution()[0:2])))
    info.append(('system',
                 "%s;%s" % (platform.system(), platform.release())))


def SESSION_TIME(stats, info):
    duration = time.time() - stats.started_time
    secs = int(duration)
    msecs = int((duration - secs) * 1000)
    info.append(('session_time', '%d.%d' % (secs, msecs)))


def PYTHON_VERSION(stats, info):
    # Some versions of Python have a \n in sys.version!
    version = sys.version.replace(' \n', ' ').replace('\n', ' ')
    python = ';'.join([str(c) for c in sys.version_info] + [version])
    info.append(('python', python))


def _encode(s):
    if not isinstance(s, bytes):
        if str == bytes:  # Python 2
            if isinstance(s, unicode):
                s = s.encode('utf-8')
            else:
                s = str(s)
        else:  # Python 3
            if isinstance(s, str):
                s = s.encode('utf-8')
            else:
                s = str(s).encode('utf-8')
    if b'\n' in s:
        s = s.replace(b'\n', b' ')
    return s


class Stats(object):
    ERRORED, DISABLED_ENV, DISABLED, UNSET, ENABLED = range(5)

    @property
    def enabled(self):
        return self.status in (Stats.UNSET, Stats.ENABLED)

    @property
    def enableable(self):
        return self.status is not Stats.ERRORED

    @property
    def disableable(self):
        return self.status is not Stats.ERRORED

    @property
    def recording(self):
        return self.status in (Stats.UNSET, Stats.ENABLED)

    @property
    def sending(self):
        return self.status is Stats.ENABLED

    def __init__(self, location, prompt, drop_point,
                 version, unique_user_id=False,
                 env_var='PYTHON_USAGE_STATS',
                 ssl_verify=None):
        self.started_time = time.time()

        self.ssl_verify = ssl_verify

        env_var = os.environ.get(env_var, '').lower()
        if env_var not in (None, '', '1', 'on', 'enabled', 'yes', 'true'):
            self.status = Stats.DISABLED_ENV
        else:
            self.status = Stats.UNSET
        self.location = os.path.expanduser(location)
        self.drop_point = drop_point
        self.version = version

        if isinstance(prompt, Prompt):
            self.prompt = prompt
        elif isinstance(prompt, basestring):
            self.prompt = Prompt(prompt)
        else:
            raise TypeError("'prompt' should either a Prompt or a string")

        if self.enabled and not os.path.isdir(self.location):
            try:
                os.makedirs(self.location, 0o700)
            except OSError:
                logger.warning("Couldn't create %s, usage statistics won't be "
                               "collected", self.location)
                self.status = Stats.ERRORED

        status_file = os.path.join(self.location, 'status')
        if self.enabled and os.path.exists(status_file):
            with open(status_file, 'r') as fp:
                status = fp.read().strip()
            if status == 'ENABLED':
                self.status = Stats.ENABLED
            elif status == 'DISABLED':
                self.status = Stats.DISABLED

        if self.enabled and unique_user_id:
            user_id_file = os.path.join(self.location, 'user_id')
            if os.path.exists(user_id_file):
                with open(user_id_file, 'r') as fp:
                    self.user_id = fp.read().strip()
            else:
                import uuid
                self.user_id = str(uuid.uuid4())
                with open(user_id_file, 'w') as fp:
                    fp.write(self.user_id)
        else:
            self.user_id = None

        self.notes = []

        self.note([('version', self.version)])

    def enable_reporting(self):
        if not self.enableable:
            logger.critical("Can't enable reporting")
            return
        self.status = Stats.ENABLED
        status_file = os.path.join(self.location, 'status')
        with open(status_file, 'w') as fp:
            fp.write('ENABLED')

    def disable_reporting(self):
        if not self.disableable:
            logger.critical("Can't disable reporting")
            return
        self.status = Stats.DISABLED
        status_file = os.path.join(self.location, 'status')
        with open(status_file, 'w') as fp:
            fp.write('DISABLED')
        if os.path.exists(self.location):
            old_reports = [f for f in os.listdir(self.location)
                           if f.startswith('report_')]
            for old_filename in old_reports:
                fullname = os.path.join(self.location, old_filename)
                os.remove(fullname)
            logger.info("Deleted %d pending reports", len(old_reports))

    @staticmethod
    def _to_notes(info):
        if hasattr(info, 'iteritems'):
            return info.iteritems()
        elif hasattr(info, 'items'):
            return info.items()
        else:
            return info

    def note(self, info):
        if self.recording:
            if self.notes is None:
                raise ValueError("This report has already been submitted")
            self.notes.extend(self._to_notes(info))

    def submit(self, info, *flags):
        if not self.recording:
            return

        if self.notes is None:
            raise ValueError("This report has already been submitted")

        all_info, self.notes = self.notes, None
        all_info.extend(self._to_notes(info))
        for flag in flags:
            flag(self, all_info)

        now = time.time()
        secs = int(now)
        msecs = int((now - secs) * 1000)
        all_info.insert(0, ('date', '%d.%d' % (secs, msecs)))

        if self.user_id:
            all_info.insert(1, ('user', self.user_id))

        logger.info("Generated report:\n%r", (all_info,))

        # Current report
        def generator():
            for key, value in all_info:
                yield _encode(key) + b':' + _encode(value) + b'\n'
        filename = 'report_%d_%d.txt' % (secs, msecs)

        # Save current report and exit, unless user has opted in
        if not self.sending:
{'fraction_non_alphanumeric': 0.11420146102808122, 'fraction_numerical': 0.0034850211111855773, 'mean_word_length': 1.7803242034656233, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, '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': '565824', 'n_tokens_mistral': 4450, 'n_tokens_neox': 4242, 'n_words': 1110}