<commit_before># Copyright (c) IPython Development Team.
# Distributed under the terms of the Modified BSD License.

# Tornado get and post handlers often have different args from their base class methods.
# pylint: disable=W0221

import json
import logging
import os

from subprocess import Popen
from tempfile import TemporaryFile

from pkg_resources import parse_version
from notebook.utils import url_path_join as ujoin
from notebook.base.handlers import IPythonHandler
from tornado import web

from .envmanager import EnvManager, package_map

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)


static = os.path.join(os.path.dirname(__file__), 'static')


class EnvBaseHandler(IPythonHandler):

    @property
    def env_manager(self):
        return self.settings['env_manager']


class MainEnvHandler(EnvBaseHandler):

    @web.authenticated
    def get(self):
        self.finish(json.dumps(self.env_manager.list_envs()))


class EnvHandler(EnvBaseHandler):

    @web.authenticated
    def get(self, env):
        self.finish(json.dumps(self.env_manager.env_packages(env)))


class EnvActionHandler(EnvBaseHandler):

    @web.authenticated
    def get(self, env, action):
        if action == 'export':
            # export environment file
            self.set_header('Content-Disposition', 'attachment; filename="%s"' % (env + '.txt'))
            self.finish(self.env_manager.export_env(env))
        else:
            raise web.HTTPError(400)

    @web.authenticated
    def post(self, env, action):
        if action == 'delete':
            data = self.env_manager.delete_env(env)
        elif action == 'clone':
            name = self.get_argument('name', default=None)
            if not name:
                name = env + '-copy'
            data = self.env_manager.clone_env(env, name)
        elif action == 'update':
            # TODO - some kind of 'check for updates/apply updates' workflow
            raise NotImplementedError
        elif action == 'create':
            env_type = self.get_argument('type', default=None)
            if env_type not in package_map:
                raise web.HTTPError(400)

            data = self.env_manager.create_env(env, env_type)
        self.finish(json.dumps(data))


class EnvPkgActionHandler(EnvBaseHandler):

    @web.authenticated
    def post(self, env, action):
        log.debug('req body: %s', self.request.body)
        packages = self.get_arguments('packages[]')
        if not packages:
            raise web.HTTPError(400)

        if action == 'install':
            resp = self.env_manager.install_packages(env, packages)
        elif action == 'update':
            resp = self.env_manager.update_packages(env, packages)
        elif action == 'check':
            resp = self.env_manager.check_update(env, packages)
        elif action == 'remove':
            resp = self.env_manager.remove_packages(env, packages)
        else:
            raise web.HTTPError(400)

        self.finish(json.dumps(resp))


class CondaSearcher(object):
    def __init__(self):
        self.conda_process = None
        self.conda_temp = None

    def list_available(self):
        if self.conda_process is not None:
            # already running, check for completion
            log.debug('Already running: pid %s', self.conda_process.pid)

            status = self.conda_process.poll()
            log.debug('Status %s', status)

            if status is not None:
                # completed, return the data
                log.debug('Done, reading output')
                self.conda_process = None

                self.conda_temp.seek(0)
                data = json.loads(self.conda_temp.read())
                self.conda_temp = None

                if 'error' in data:
                    # we didn't get back a list of packages, we got a dictionary with error info
                    return data

                packages = []

                for entries in data.values():
                    max_version = None
                    max_version_entry = None

                    for entry in entries:
                        version = parse_version(entry.get('version', ''))

                        if max_version is None or version > max_version:
                            max_version = version
                            max_version_entry = entry

                    packages.append(max_version_entry)

                return sorted(packages, key=lambda entry: entry.get('name'))

        else:
            # Spawn subprocess to get the data
            log.debug('Starting conda process')
            self.conda_temp = TemporaryFile(mode='w+')
            cmdline = 'conda search --json'.split()
            self.conda_process = Popen(cmdline, stdout=self.conda_temp, bufsize=4096)
            log.debug('Started: pid %s', self.conda_process.pid)

        return None

searcher = CondaSearcher()


class AvailablePackagesHandler(EnvBaseHandler):

    @web.authenticated
    def get(self):
        data = searcher.list_available()

        if data is None:
            # tell client to check back later
            self.clear()
            self.set_status(202)  # Accepted
            self.finish('{}')
        else:
            self.finish(json.dumps(data))


class SearchHandler(EnvBaseHandler):

    @web.authenticated
    def get(self):
        q = self.get_argument('q')
        self.finish(json.dumps(self.env_manager.package_search(q)))


# -----------------------------------------------------------------------------
# URL to handler mappings
# -----------------------------------------------------------------------------
<commit_msg>Fix log level, add comments<commit_after>"""
# Copyright (c) 2015-2016 Continuum Analytics.
# See LICENSE.txt for the license.
"""

# Tornado get and post handlers often have different args from their base class methods.
# pylint: disable=W0221

import json
import logging
import os

from subprocess import Popen
from tempfile import TemporaryFile

from pkg_resources import parse_version
from notebook.utils import url_path_join as ujoin
from notebook.base.handlers import IPythonHandler
from tornado import web

from .envmanager import EnvManager, package_map

log = logging.getLogger(__name__)
log_level = logging.DEBUG if os.environ.get('NB_CONDA_DEBUG') else logging.INFO
log.setLevel(log_level)


static = os.path.join(os.path.dirname(__file__), 'static')


class EnvBaseHandler(IPythonHandler):
    """
    Base request handler class. Just maintains a reference to the
    'env_manager' which implements all of the conda functions.
    """
    @property
    def env_manager(self):
        """Return our env_manager instance"""
        return self.settings['env_manager']


class MainEnvHandler(EnvBaseHandler):
    """
    Handler for `GET /environments` which lists the environments.
    """
    @web.authenticated
    def get(self):
        self.finish(json.dumps(self.env_manager.list_envs()))


class EnvHandler(EnvBaseHandler):
    """
    Handler for `GET /environments/<name>` which lists
    the packages in the specified environment.
    """
    @web.authenticated
    def get(self, env):
        self.finish(json.dumps(self.env_manager.env_packages(env)))


class EnvActionHandler(EnvBaseHandler):
    """
    Handler for `GET /environments/<name>/export` which
    exports the specified environment, and
    `POST /environments/<name>/{delete,clone,create}`
    which performs the requested action on the environment.
    """
    @web.authenticated
    def get(self, env, action):
        if action == 'export':
            # export environment file
            self.set_header('Content-Disposition', 'attachment; filename="%s"' % (env + '.txt'))
            self.finish(self.env_manager.export_env(env))
        else:
            raise web.HTTPError(400)

    @web.authenticated
    def post(self, env, action):
        if action == 'delete':
            data = self.env_manager.delete_env(env)
        elif action == 'clone':
            name = self.get_argument('name', default=None)
            if not name:
                name = env + '-copy'
            data = self.env_manager.clone_env(env, name)
        elif action == 'create':
            env_type = self.get_argument('type', default=None)
            if env_type not in package_map:
                raise web.HTTPError(400)

            data = self.env_manager.create_env(env, env_type)
        self.finish(json.dumps(data))


class EnvPkgActionHandler(EnvBaseHandler):
    """
    Handler for `POST /environments/<name>/packages/{install,update,check,remove}`
    which performs the requested action on the packages in the specified environment.
    """
    @web.authenticated
    def post(self, env, action):
        log.debug('req body: %s', self.request.body)
        packages = self.get_arguments('packages[]')
        if not packages:
            raise web.HTTPError(400)

        if action == 'install':
            resp = self.env_manager.install_packages(env, packages)
        elif action == 'update':
            resp = self.env_manager.update_packages(env, packages)
        elif action == 'check':
            resp = self.env_manager.check_update(env, packages)
        elif action == 'remove':
            resp = self.env_manager.remove_packages(env, packages)
        else:
            raise web.HTTPError(400)

        self.finish(json.dumps(resp))


class CondaSearcher(object):
    """
    Helper object that runs `conda search` to retrieve the
    list of packages available in the current conda channels.
    """
    def __init__(self):
        self.conda_process = None
        self.conda_temp = None

    def list_available(self):
        """
        List the available conda packages by kicking off a background
        conda process. Will return None. Call again to poll the process
        status. When the process completes, a list of packages will be
        returned upon success. On failure, the results of `conda search --json`
        will be returned (this will be a dict containing error information).
        TODO - break up this method.
        """
        if self.conda_process is not None:
            # already running, check for completion
            log.debug('Already running: pid %s', self.conda_process.pid)

            status = self.conda_process.poll()
            log.debug('Status %s', status)

            if status is not None:
                # completed, return the data
                log.debug('Done, reading output')
                self.conda_process = None

                self.conda_temp.seek(0)
                data = json.loads(self.conda_temp.read())
                self.conda_temp = None

                if 'error' in data:
                    # we didn't get back a list of packages, we got a dictionary with error info
                    return data

                packages = []

                for entries in data.values():
                    max_version = None
                    max_version_entry = None

                    for entry in entries:
                        version = parse_version(entry.get('version', ''))

                        if max_version is None or version > max_version:
                            max_version = version
                            max_version_entry = entry

                    packages.append(max_version_entry)

                return sorted(packages, key=lambda entry: entry.get('name'))

        else:
            # Spawn subprocess to get the data
            log.debug('Starting conda process')
            self.conda_temp = TemporaryFile(mode='w+')
            cmdline = 'conda search --json'.split()
            self.conda_process = Popen(cmdline, stdout=self.conda_temp, bufsize=4096)
            log.debug('Started: pid %s', self.conda_process.pid)

        return None

searcher = CondaSearcher()


class AvailablePackagesHandler(EnvBaseHandler):
    """
    Handler for `GET /packages/available`, which uses CondaSearcher
    to list the packages available for installation.
    """
    @web.authenticated
    def get(self):
        data = searcher.list_available()

        if data is None:
            # tell client to check back later
            self.clear()
            self.set_status(202)  # Accepted
            self.finish('{}')
        else:
            self.finish(json.dumps(data))


class SearchHandler(EnvBaseHandler):
    """
    Handler for `GET /packages/search?q=<query>`, which uses CondaSearcher
    to search the available conda packages. Note, this is pretty slow
    and the nb_conda UI doesn't call it.
    """
    @web.authenticated
    def get(self):
        q = self.get_argument('q')
        self.finish(json.dumps(self.env_manager.package_search(q)))


# -----------------------------------------------------------------------------
# URL to handler mappings
# -----------------------------------------------------------------------------

{'fraction_non_alphanumeric': 0.1158220502901354, 'fraction_numerical': 0.004332688588007737, 'mean_word_length': 2.0644855381697487, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2114534', 'n_tokens_mistral': 3565, 'n_tokens_neox': 3411, 'n_words': 952}