<commit_before># -*- coding: utf-8 -*-

"""WakaTime plugin for Eric6 and Pymakr."""

from __future__ import unicode_literals

import os
import platform
import re
import shutil
import ssl
import sys
import time
import threading
import traceback
import urllib
from datetime import datetime
from zipfile import ZipFile
try:
    import ConfigParser as configparser
except ImportError:
    import configparser

is_py2 = (sys.version_info[0] == 2)
if is_py2:
    import codecs
    open = codecs.open

from PyQt5.QtGui import QAction, QIcon, QInputDialog, QLineEdit
from PyQt5.QtCore import QObject

from E5Gui.E5Application import e5App
from UI.Info import Program, Version

# Start-Of-Header
name = "WakaTime Plugin"
author = "WakaTime <support@wakatime.com>"
autoactivate = True
deactivateable = False
version = "1.0.1"
pluginType = "viewmanager"
pluginTypename = "WakaTime"
className = "WakaTimePlugin"
packageName = None
shortDescription = "Automatic time tracking and metrics about your IDE usage."
longDescription = "Automatic time tracking and metrics about your IDE usage."
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""

if platform.system() == 'Windows':
    RESOURCES_FOLDER = os.path.join(os.getenv('APPDATA'), 'WakaTime')
else:
    RESOURCES_FOLDER = os.path.join(os.path.expanduser('~'), '.wakatime')
if not os.path.exists(RESOURCES_FOLDER):
    os.makedirs(RESOURCES_FOLDER)

# add wakatime package to path
sys.path.insert(0, os.path.join(RESOURCES_FOLDER, 'wakatime-master'))

HEARTBEAT_FREQUENCY = 2
CLI_LOCATION = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', 'cli.py')
PLUGIN = '{prog}/{progVer} {prog}-wakatime/{pluginVer}'.format(
    prog=Program,
    progVer=Version,
    pluginVer=version,
)
IS_DEBUG_ENABLED = False

# Log Levels
DEBUG = 'DEBUG'
INFO = 'INFO'
WARNING = 'WARNING'
ERROR = 'ERROR'

def getConfigData():
    return {}

def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    pass

class WakaTimePlugin(QObject):
    """
    Class implementing the WakaTime plugin.
    """
    def __init__(self, ui):
        """
        Constructor

        @param ui reference to the user interface object (UI.UserInterface)
        """
        super(WakaTimePlugin, self).__init__(ui)
        self._ui = ui

        try:
            e5App().registerPluginObject(pluginTypename, self)
        except KeyError:
            pass    # ignore duplicate registration

    def getProjectHelper(self):
        """
        Public method to get a reference to the project helper object.

        @return reference to the project helper object
        """
        return self.__projectHelperObject

    def initToolbar(self, ui, toolbarManager):
        """
        Public slot to initialize the VCS toolbar.

        @param ui reference to the main window (UserInterface)
        @param toolbarManager reference to a toolbar manager object
            (E5ToolBarManager)
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.initToolbar(ui, toolbarManager)

    def activate(self):
        global IS_DEBUG_ENABLED
        IS_DEBUG_ENABLED = self._getDebug()

        log(DEBUG, 'Initializing WakaTime v{ver}...'.format(ver=version))

        self._setupCli()

        apiKey = self._getApiKey()
        if not apiKey.strip():
            self._promptForApiKey()

        self._setupEventListeners()

        self._addMenu()

        log(DEBUG, 'Finished initializing WakaTime plugin.')
        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        self.__object = None

        self.action.setVisible(False)
        self.action.setEnabled(False)

    def _setupCli(self):
        if self._isCliLatest():
            return

        thread = DownloadCLI()
        thread.start()

    def _setupEventListeners(self):
        e5App().getObject('ViewManager').cursorChanged.connect(self._cursorChanged)
        e5App().getObject('ViewManager').editorSaved.connect(self._editorSaved)
        #e5App().getObject('Project').projectOpened.connect(self._projectOpened)

    def _addMenu(self):
        """Adds the WakaTime menu item under the File menu."""
        self.action = QAction(QIcon(), 'WakaTime', self)
        self.action.triggered.connect(self._promptForApiKey)
        fileMenu = e5App().getObject('UserInterface').getMenu('file')
        fileMenu.addAction(self.action)

    def _editorSaved(self, fileName):
        self._handleActivity(fileName, isWrite=True)

    def _cursorChanged(self, editor):
        fileName = editor.getFileName()
        self._handleActivity(fileName)

    def _projectOpened(self):
        log(DEBUG, '_projectOpened')

    def _handleActivity(self, fileName, isWrite=False):
        fileName = os.path.abspath(os.path.realpath(fileName))
        if not hasattr(self, '_lastFile'):
            self._lastFile = None
        if fileName != self._lastFile or self._enoughTimePassed(isWrite):
            if not self._shouldExclude(fileName):
                self._sendHeartbeat(fileName, isWrite)

    def _enoughTimePassed(self, isWrite):
        now = time.time()
        if not hasattr(self, '_lastTime'):
            self._lastTime = 0
        if now - self._lastTime > HEARTBEAT_FREQUENCY * 60:
            return True
        if isWrite and now - self._lastTime > 2:
            return True
        return False

    def _shouldExclude(self, fileName):
        return os.path.basename(fileName) == '0.1'

    def _sendHeartbeat(self, fileName, isWrite):
        try:
            from wakatime.main import execute
        except ImportError:
            log(DEBUG, 'Skipping heartbeat because wakatime-cli not found.')
            return
        except:
            log(ERROR, traceback.format_exc())
            return

        self._lastFile = fileName
        self._lastTime = time.time()

        args = ['--entity', fileName, '--plugin', PLUGIN]
        if isWrite:
            args.append('--write')

        log(DEBUG, 'Sending heartbeat:')
        log(DEBUG, ' '.join(args))

        execute(args)

    def _promptForApiKey(self, *args):
        """Prompt the user to enter their api key."""

        ui = e5App().getObject('UserInterface')
        title = 'WakaTime'
        label = '               Enter your WakaTime API Key:               \n' + \
                '               (https://wakatime.com/settings)            '
        default = self._getApiKey()
        text, ok = QInputDialog.getText(ui, title, label, QLineEdit.Normal, default)
        if ok:
            configs = self._parseConfigFile()
            configs.set('settings', 'api_key', text)
            configFile = self._configFile()
            with open(configFile, 'w', encoding='utf-8') as fh:
                configs.write(fh)

    def _createConfigFile(self):
        """Creates the .wakatime.cfg INI file in $HOME directory, if it does
        not already exist.
        """
        configFile = self._configFile()
        try:
            with open(configFile) as fh:
                pass
        except IOError:
            try:
                with open(configFile, 'w') as fh:
                    fh.write("[settings]\n")
                    fh.write("debug = false\n")
                    fh.write("hidefilenames = false\n")
            except IOError:
                pass

    def _getApiKey(self):
        self._createConfigFile()
        key = ''
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'api_key'):
                    key = configs.get('settings', 'api_key')
        except:
            pass
        return key

    def _getDebug(self):
        self._createConfigFile()
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'debug'):
                    return configs.get('settings', 'debug') == 'true'
        except:
            pass
        return False

    def _configFile(self):
        home = os.environ.get('WAKATIME_HOME')
        if home:
            return os.path.join(os.path.expanduser(home), '.wakatime.cfg')

        return os.path.join(os.path.expanduser('~'), '.wakatime.cfg')

    def _parseConfigFile(self):
        """Returns a configparser.SafeConfigParser instance with configs
        read from the config file. Default location of the config file is
        at ~/.wakatime.cfg.
        """

        configFile = self._configFile()

        configs = configparser.SafeConfigParser()
        try:
            with open(configFile, 'r', encoding='utf-8') as fh:
                try:
                    configs.readfp(fh)
                    return configs
                except configparser.Error:
                    log(ERROR, traceback.format_exc())
                    return None
        except IOError:
            log(DEBUG, "Error: Could not read from config file {0}\n".format(configFile))
            return None

    def _isCliLatest(self):
        remoteVer = self._getLatestCliVersion()
        about = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', '__about__.py')
        try:
            with open(about) as fh:
                localVer = self._extractVersion(fh)
            if remoteVer and localVer:
                return remoteVer.strip() == localVer.strip()
        except:
            log(DEBUG, traceback.format_exc())
        return False

    def _getLatestCliVersion(self):
        url = 'https://raw.githubusercontent.com/wakatime/wakatime/master/wakatime/__about__.py'
        try:
            output = os.path.join(RESOURCES_FOLDER, 'remoteVer')
            download(url, output)
            with open(output) as fh:
                return self._extractVersion(fh)
        except:
            return None

    def _extractVersion(self, fh):
        pattern = re.compile(r"^__version_info__ = \('([0-9]+)', '([0-9]+)', '([0-9]+)'\)")
        for line in fh.readlines():
            match = pattern.search(line)
            if match:
                return '{0}.{0}.{0}'.format(match.group(1), match.group(2), match.group(3))
        return None

    def prepareUninstall(self):
        """
        Public method to prepare for an uninstallation.
        """
        e5App().unregisterPluginObject(pluginTypename)

    def prepareUnload(self):
        """
        Public method to prepare for an unload.
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.removeToolbar(
                self.__ui, e5App().getObject("ToolbarManager"))
        e5App().unregisterPluginObject(pluginTypename)

class DownloadCLI(threading.Thread):
    """Non-blocking thread for downloading latest wakatime-cli from GitHub.
    """

    def run(self):
        log(INFO, 'Downloading wakatime-cli...')

        try:
            shutil.rmtree(os.path.join(RESOURCES_FOLDER, 'wakatime-master'))
        except:
            pass

        try:
            url = 'https://github.com/wakatime/wakatime/archive/master.zip'
            zip_file = os.path.join(RESOURCES_FOLDER, 'wakatime.zip')
            download(url, zip_file)

            log(INFO, 'Extracting wakatime-cli...')
            with ZipFile(zip_file) as zf:
                zf.extractall(RESOURCES_FOLDER)
        except:
            log(DEBUG, traceback.format_exc())

        log(INFO, 'Finished extracting wakatime-cli.')

def download(url, filePath):
    try:
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)
    except IOError:
        ssl._create_default_https_context = ssl._create_unverified_context
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)

def log(lvl, msg, *args, **kwargs):
    if lvl == DEBUG and not IS_DEBUG_ENABLED:
        return
    if len(args) > 0:
        msg = msg.format(*args)
    elif len(kwargs) > 0:
        msg = msg.format(**kwargs)
    date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    try:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg))
    except UnicodeDecodeError:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg.decode('utf8', 'replace')))
<commit_msg>Support for Eric6 with Python3.6<commit_after># -*- coding: utf-8 -*-

"""WakaTime plugin for Eric6 and Pymakr."""

from __future__ import unicode_literals

import os
import platform
import re
import shutil
import ssl
import sys
import time
import threading
import traceback
from datetime import datetime
from zipfile import ZipFile
try:
    import ConfigParser as configparser
except ImportError:
    import configparser
try:
    from urllib2 import urlretrieve
except ImportError:
    from urllib.request import urlretrieve

is_py2 = (sys.version_info[0] == 2)
if is_py2:
    import codecs
    open = codecs.open

from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QObject
try:
    from PyQt5.QtGui import QAction, QInputDialog, QLineEdit
except ImportError:
    from PyQt5.QtWidgets import QAction, QInputDialog, QLineEdit

from E5Gui.E5Application import e5App
from UI.Info import Program, Version

# Start-Of-Header
name = "WakaTime Plugin"
author = "WakaTime <support@wakatime.com>"
autoactivate = True
deactivateable = False
version = "1.0.1"
pluginType = "viewmanager"
pluginTypename = "WakaTime"
className = "WakaTimePlugin"
packageName = None
shortDescription = "Automatic time tracking and metrics about your IDE usage."
longDescription = "Automatic time tracking and metrics about your IDE usage."
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""

if platform.system() == 'Windows':
    RESOURCES_FOLDER = os.path.join(os.getenv('APPDATA'), 'WakaTime')
else:
    RESOURCES_FOLDER = os.path.join(os.path.expanduser('~'), '.wakatime')
if not os.path.exists(RESOURCES_FOLDER):
    os.makedirs(RESOURCES_FOLDER)

# add wakatime package to path
sys.path.insert(0, os.path.join(RESOURCES_FOLDER, 'wakatime-master'))

HEARTBEAT_FREQUENCY = 2
CLI_LOCATION = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', 'cli.py')
PLUGIN = '{prog}/{progVer} {prog}-wakatime/{pluginVer}'.format(
    prog=Program,
    progVer=Version,
    pluginVer=version,
)
IS_DEBUG_ENABLED = False

# Log Levels
DEBUG = 'DEBUG'
INFO = 'INFO'
WARNING = 'WARNING'
ERROR = 'ERROR'

def getConfigData():
    return {}

def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    pass

class WakaTimePlugin(QObject):
    """
    Class implementing the WakaTime plugin.
    """
    def __init__(self, ui):
        """
        Constructor

        @param ui reference to the user interface object (UI.UserInterface)
        """
        super(WakaTimePlugin, self).__init__(ui)
        self._ui = ui

        try:
            e5App().registerPluginObject(pluginTypename, self)
        except KeyError:
            pass    # ignore duplicate registration

    def getProjectHelper(self):
        """
        Public method to get a reference to the project helper object.

        @return reference to the project helper object
        """
        return self.__projectHelperObject

    def initToolbar(self, ui, toolbarManager):
        """
        Public slot to initialize the VCS toolbar.

        @param ui reference to the main window (UserInterface)
        @param toolbarManager reference to a toolbar manager object
            (E5ToolBarManager)
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.initToolbar(ui, toolbarManager)

    def activate(self):
        global IS_DEBUG_ENABLED
        IS_DEBUG_ENABLED = self._getDebug()

        log(DEBUG, 'Initializing WakaTime v{ver}...'.format(ver=version))

        self._setupCli()

        apiKey = self._getApiKey()
        if not apiKey.strip():
            self._promptForApiKey()

        self._setupEventListeners()

        self._addMenu()

        log(DEBUG, 'Finished initializing WakaTime plugin.')
        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        self.__object = None

        self.action.setVisible(False)
        self.action.setEnabled(False)

    def _setupCli(self):
        if self._isCliLatest():
            return

        thread = DownloadCLI()
        thread.start()

    def _setupEventListeners(self):
        e5App().getObject('ViewManager').cursorChanged.connect(self._cursorChanged)
        e5App().getObject('ViewManager').editorSaved.connect(self._editorSaved)
        #e5App().getObject('Project').projectOpened.connect(self._projectOpened)

    def _addMenu(self):
        """Adds the WakaTime menu item under the File menu."""
        self.action = QAction(QIcon(), 'WakaTime', self)
        self.action.triggered.connect(self._promptForApiKey)
        fileMenu = e5App().getObject('UserInterface').getMenu('file')
        fileMenu.addAction(self.action)

    def _editorSaved(self, fileName):
        self._handleActivity(fileName, isWrite=True)

    def _cursorChanged(self, editor):
        fileName = editor.getFileName()
        self._handleActivity(fileName)

    def _projectOpened(self):
        log(DEBUG, '_projectOpened')

    def _handleActivity(self, fileName, isWrite=False):
        fileName = os.path.abspath(os.path.realpath(fileName))
        if not hasattr(self, '_lastFile'):
            self._lastFile = None
        if fileName != self._lastFile or self._enoughTimePassed(isWrite):
            if not self._shouldExclude(fileName):
                self._sendHeartbeat(fileName, isWrite)

    def _enoughTimePassed(self, isWrite):
        now = time.time()
        if not hasattr(self, '_lastTime'):
            self._lastTime = 0
        if now - self._lastTime > HEARTBEAT_FREQUENCY * 60:
            return True
        if isWrite and now - self._lastTime > 2:
            return True
        return False

    def _shouldExclude(self, fileName):
        return os.path.basename(fileName) == '0.1'

    def _sendHeartbeat(self, fileName, isWrite):
        try:
            from wakatime.main import execute
        except ImportError:
            log(DEBUG, 'Skipping heartbeat because wakatime-cli not found.')
            return
        except:
            log(ERROR, traceback.format_exc())
            return

        self._lastFile = fileName
        self._lastTime = time.time()

        args = ['--entity', fileName, '--plugin', PLUGIN]
        if isWrite:
            args.append('--write')

        log(DEBUG, 'Sending heartbeat:')
        log(DEBUG, ' '.join(args))

        execute(args)

    def _promptForApiKey(self, *args):
        """Prompt the user to enter their api key."""

        ui = e5App().getObject('UserInterface')
        title = 'WakaTime'
        label = '               Enter your WakaTime API Key:               \n' + \
                '               (https://wakatime.com/settings)            '
        default = self._getApiKey()
        text, ok = QInputDialog.getText(ui, title, label, QLineEdit.Normal, default)
        if ok:
            configs = self._parseConfigFile()
            configs.set('settings', 'api_key', text)
            configFile = self._configFile()
            with open(configFile, 'w', encoding='utf-8') as fh:
                configs.write(fh)

    def _createConfigFile(self):
        """Creates the .wakatime.cfg INI file in $HOME directory, if it does
        not already exist.
        """
        configFile = self._configFile()
        try:
            with open(configFile) as fh:
                pass
        except IOError:
            try:
                with open(configFile, 'w') as fh:
                    fh.write("[settings]\n")
                    fh.write("debug = false\n")
                    fh.write("hidefilenames = false\n")
            except IOError:
                pass

    def _getApiKey(self):
        self._createConfigFile()
        key = ''
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'api_key'):
                    key = configs.get('settings', 'api_key')
        except:
            pass
        return key

    def _getDebug(self):
        self._createConfigFile()
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'debug'):
                    return configs.get('settings', 'debug') == 'true'
        except:
            pass
        return False

    def _configFile(self):
        home = os.environ.get('WAKATIME_HOME')
        if home:
            return os.path.join(os.path.expanduser(home), '.wakatime.cfg')

        return os.path.join(os.path.expanduser('~'), '.wakatime.cfg')

    def _parseConfigFile(self):
        """Returns a configparser.SafeConfigParser instance with configs
        read from the config file. Default location of the config file is
        at ~/.wakatime.cfg.
        """

        configFile = self._configFile()

        configs = configparser.SafeConfigParser()
        try:
            with open(configFile, 'r', encoding='utf-8') as fh:
                try:
                    configs.readfp(fh)
                    return configs
                except configparser.Error:
                    log(ERROR, traceback.format_exc())
                    return None
        except IOError:
            log(DEBUG, "Error: Could not read from config file {0}\n".format(configFile))
            return None

    def _isCliLatest(self):
        remoteVer = self._getLatestCliVersion()
        about = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', '__about__.py')
        try:
            with open(about) as fh:
                localVer = self._extractVersion(fh)
            if remoteVer and localVer:
                return remoteVer.strip() == localVer.strip()
        except:
            log(DEBUG, traceback.format_exc())
        return False

    def _getLatestCliVersion(self):
        url = 'https://raw.githubusercontent.com/wakatime/wakatime/master/wakatime/__about__.py'
        try:
            output = os.path.join(RESOURCES_FOLDER, 'remoteVer')
            download(url, output)
            with open(output) as fh:
                return self._extractVersion(fh)
        except:
            return None

    def _extractVersion(self, fh):
        pattern = re.compile(r"^__version_info__ = \('([0-9]+)', '([0-9]+)', '([0-9]+)'\)")
        for line in fh.readlines():
            match = pattern.search(line)
            if match:
                return '{0}.{0}.{0}'.format(match.group(1), match.group(2), match.group(3))
        return None

    def prepareUninstall(self):
        """
        Public method to prepare for an uninstallation.
        """
        e5App().unregisterPluginObject(pluginTypename)

    def prepareUnload(self):
        """
        Public method to prepare for an unload.
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.removeToolbar(
                self.__ui, e5App().getObject("ToolbarManager"))
        e5App().unregisterPluginObject(pluginTypename)

class DownloadCLI(threading.Thread):
    """Non-blocking thread for downloading latest wakatime-cli from GitHub.
    """

    def run(self):
        log(INFO, 'Downloading wakatime-cli...')

        try:
            shutil.rmtree(os.path.join(RESOURCES_FOLDER, 'wakatime-master'))
        except:
            pass

        try:
            url = 'https://github.com/wakatime/wakatime/archive/master.zip'
            zip_file = os.path.join(RESOURCES_FOLDER, 'wakatime.zip')
            download(url, zip_file)

            log(INFO, 'Extracting wakatime-cli...')
            with ZipFile(zip_file) as zf:
                zf.extractall(RESOURCES_FOLDER)
        except:
            log(DEBUG, traceback.format_exc())

        log(INFO, 'Finished extracting wakatime-cli.')

def download(url, filePath):
    try:
        urlretrieve(url, filePath)
    except IOError:
        ssl._create_default_https_context = ssl._create_unverified_context
        urlretrieve(url, filePath)

def log(lvl, msg, *args, **kwargs):
    if lvl == DEBUG and not IS_DEBUG_ENABLED:
        return
    if len(args) > 0:
        msg = msg.format(*args)
    elif len(kwargs) > 0:
        msg = msg.format(**kwargs)
    date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    try:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg))
    except UnicodeDecodeError:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg.decode('utf8', 'replace')))
<|endoftext|>


<commit_before>import numpy as np

def standardize(x):
    """Standardize the original data set."""
    mean_x = np.mean(x)
    x = x - mean_x
    std_x = np.std(x)
    x = x / std_x
    return x, mean_x, std_x

def binarize_categorical_feature(f):
    """ return binary columns for each feature value """
    values = sorted(list(set(f[:,0])))
    x = np.zeros((f.shape[0], 1))
    for v in values:
        x = np.hstack((x, f == v))
    return x[:,1:]

def binarize_categorical(x, ids):
    """ replace categorical feature with multiple binary ones """
    x_ = np.zeros((x.shape[0], 1))
    for idx in ids:
        x_ = np.hstack((x_, binarize_categorical_feature(x[:, idx:idx+1])))
    x = np.delete(x, ids, axis=1)
    x = np.hstack((x, x_[:, 1:]))
    return x

def impute_with_mean(X_, ids, missing_val = -999):
    """ replace missing_val with mean value on columns ids """
    X_ = np.copy(X_)
    X = X_[:, ids]
    X[X == missing_val] = None
    nan_mean = np.nanmean(X, axis = 0)
    inds = np.where(np.isnan(X))
    X[inds] = np.take(nan_mean, inds[1])
    X_[:, ids] = X
    return X_

def add_polynomial(X, ids, max_degrees = 2):
    """ add constant feature and degrees of features ids up to selected degree """
    if type(max_degrees) == type(int):
        max_degrees = np.ones((len(ids))) * max_degrees
    X_orig = X
    X = np.copy(X)
    X = np.hstack((np.ones((X.shape[0], 1)), X))
    for i, idx in enumerate(ids):
        for degree in range(2, max_degrees[i] + 1):
            X = np.hstack((X, np.power(X_orig[:, idx:idx+1], degree)))
    return X

def indicator_missing(X, ids, missing_val = -999.):
    """ add binary feature indicating if original feature was missing """
    X = np.copy(X)
    for idx in ids:
        f_miss = 1. * (X[:, idx:idx + 1] == missing_val)
        X = np.hstack((X, f_miss))
    return X

### TESTING SECTION

def test_binarize_1():
    x = np.array([[1,2,2,4]]).T
    x_copy = np.copy(x)
    x_ = np.array([[1,0,0],[0,1,0],[0,1,0],[0,0,1]])
    assert np.all(x_ == binarize_categorical_feature(x)), "binarize_categorical_feature"
    assert np.all(x == x_copy), "copy"

def test_binarize_2():
    x = np.array([[1,2,2,4],[0.1,0.2,0.3,0.4],[1,-1,1,1]]).T
    x_copy = np.copy(x)
    x_ = np.array([[0.1,1,0,0,0,1],[0.2,0,1,0,1,0],[0.3,0,1,0,0,1],[0.4,0,0,1,0,1]])
    assert np.all(x_ == binarize_categorical(x, [0,2])), "binarize_categorical"
    assert np.all(x == x_copy), "copy"

def test_impute_1():
    X_ = np.array([[0,1,1],[3,4,0],[0,0,-999]], dtype=np.float64)
    X_copy = np.copy(X_)
    X__ = np.array([[ 0. ,  1. ,  1. ], [ 3. ,  4. ,  0. ], [ 0. ,  0. ,  0.5]])
    assert np.all(X__ == impute_with_mean(X_, [2], missing_val=-999)), "impute_with_mean"
    assert np.all(X_ == X_copy), "copy"

def test_poly_1():
    X = np.array([[0,1,2],[3,4,5],[0.5,0.6,0.7]])
    X_copy = np.copy(X)

    X_ans = np.array([[  1.   ,   0.   ,   1.   ,   2.   ,   0.   ,   0.   ,   4.   ],
           [  1.   ,   3.   ,   4.   ,   5.   ,   9.   ,  27.   ,  25.   ],
           [  1.   ,   0.5  ,   0.6  ,   0.7  ,   0.25 ,   0.125,   0.49 ]])
    assert np.allclose(X_ans, add_polynomial(X, [0,2], max_degrees = [3,2])), "add_polynomial"
    assert np.all(X_copy == X), "copy"

def test_missing_1():
    X = [[0,1,2],[3,-999,5],[0,3,-999]]
    X_copy = np.copy(X)
    X_ans = np.array([[   0.,    1.,    2.,    0.,    0.],
           [   3., -999.,    5.,    1.,    0.],
           [   0.,    3., -999.,    0.,    1.]])
    assert np.allclose(X_ans, indicator_missing(X, [1,2], missing_val = -999.)), "indicator_missing"
    assert np.all(X_copy == X), "copy"

def test_all():
    test_binarize_1()
    test_binarize_2()
    test_impute_1()
    test_poly_1()
    test_missing_1()
    return 1

if __name__ == "__main__":
    if test_all():
        print("Tests passed")
<commit_msg>Fix add_polynomial on scalar max_degrees<commit_after>import numpy as np

def standardize(x):
    """Standardize the original data set."""
    mean_x = np.mean(x)
    x = x - mean_x
    std_x = np.std(x)
    x = x / std_x
    return x, mean_x, std_x

def binarize_categorical_feature(f):
    """ return binary columns for each feature value """
    values = sorted(list(set(f[:,0])))
    assert len(values) < 10, "too many categories"
    x = np.zeros((f.shape[0], 1))
    for v in values:
        x = np.hstack((x, f == v))
    return x[:,1:]

def binarize_categorical(x, ids):
    """ replace categorical feature with multiple binary ones """
    x_ = np.zeros((x.shape[0], 1))
    for idx in ids:
        x_ = np.hstack((x_, binarize_categorical_feature(x[:, idx:idx+1])))
    x = np.delete(x, ids, axis=1)
    x = np.hstack((x, x_[:, 1:]))
    return x

def impute_with_mean(X_, ids, missing_val = -999):
    """ replace missing_val with mean value on columns ids """
    X_ = np.copy(X_)
    X = X_[:, ids]
    X[X == missing_val] = None
    nan_mean = np.nanmean(X, axis = 0)
    inds = np.where(np.isnan(X))
    X[inds] = np.take(nan_mean, inds[1])
    X_[:, ids] = X
    return X_

def add_polynomial(X, ids, max_degrees = 2):
    """ add constant feature and degrees of features ids up to selected degree """
    if type(max_degrees) == int:
        max_degrees = [max_degrees] * len(ids)
    X_orig = X
    X = np.copy(X)
    X = np.hstack((np.ones((X.shape[0], 1)), X))
    for i, idx in enumerate(ids):
        for degree in range(2, max_degrees[i] + 1):
            X = np.hstack((X, np.power(X_orig[:, idx:idx+1], degree)))
    return X

def indicator_missing(X, ids, missing_val = -999.):
    """ add binary feature indicating if original feature was missing """
    X = np.copy(X)
    for idx in ids:
        f_miss = 1. * (X[:, idx:idx + 1] == missing_val)
        X = np.hstack((X, f_miss))
    return X

### TESTING SECTION

def test_binarize_1():
    x = np.array([[1,2,2,4]]).T
    x_copy = np.copy(x)
    x_ = np.array([[1,0,0],[0,1,0],[0,1,0],[0,0,1]])
    assert np.all(x_ == binarize_categorical_feature(x)), "binarize_categorical_feature"
    assert np.all(x == x_copy), "copy"

def test_binarize_2():
    x = np.array([[1,2,2,4],[0.1,0.2,0.3,0.4],[1,-1,1,1]]).T
    x_copy = np.copy(x)
    x_ = np.array([[0.1,1,0,0,0,1],[0.2,0,1,0,1,0],[0.3,0,1,0,0,1],[0.4,0,0,1,0,1]])
    assert np.all(x_ == binarize_categorical(x, [0,2])), "binarize_categorical"
    assert np.all(x == x_copy), "copy"

def test_impute_1():
    X_ = np.array([[0,1,1],[3,4,0],[0,0,-999]], dtype=np.float64)
    X_copy = np.copy(X_)
    X__ = np.array([[ 0. ,  1. ,  1. ], [ 3. ,  4. ,  0. ], [ 0. ,  0. ,  0.5]])
    assert np.all(X__ == impute_with_mean(X_, [2], missing_val=-999)), "impute_with_mean"
    assert np.all(X_ == X_copy), "copy"

def test_poly_1():
    X = np.array([[0,1,2],[3,4,5],[0.5,0.6,0.7]])
    X_copy = np.copy(X)

    X_ans = np.array([[  1.   ,   0.   ,   1.   ,   2.   ,   0.   ,   0.   ,   4.   ],
           [  1.   ,   3.   ,   4.   ,   5.   ,   9.   ,  27.   ,  25.   ],
           [  1.   ,   0.5  ,   0.6  ,   0.7  ,   0.25 ,   0.125,   0.49 ]])
    assert np.allclose(X_ans, add_polynomial(X, [0,2], max_degrees = [3,2])), "add_polynomial"
    assert np.all(X_copy == X), "copy"

def test_poly_2():
    X = np.array([[0,1,2],[3,4,5],[0.5,0.6,0.7]])
    X_copy = np.copy(X)

    X_ans = np.array([[  1.   ,   0.   ,   1.   ,   2.   ,   0.   ,     4.   ],
           [  1.   ,   3.   ,   4.   ,   5.   ,   9.   ,  25.   ],
           [  1.   ,   0.5  ,   0.6  ,   0.7  ,   0.25 ,   0.49 ]])
    assert np.allclose(X_ans, add_polynomial(X, [0,2], max_degrees = 2)), "add_polynomial"
    assert np.all(X_copy == X), "copy"

def test_missing_1():
    X = [[0,1,2],[3,-999,5],[0,3,-999]]
    X_copy = np.copy(X)
    X_ans = np.array([[   0.,    1.,    2.,    0.,    0.],
           [   3., -999.,    5.,    1.,    0.],
           [   0.,    3., -999.,    0.,    1.]])
    assert np.allclose(X_ans, indicator_missing(X, [1,2], missing_val = -999.)), "indicator_missing"
    assert np.all(X_copy == X), "copy"

def test_all():
    test_binarize_1()
    test_binarize_2()
    test_impute_1()
    test_poly_1()
    test_poly_2()
    test_missing_1()
    return 1

if __name__ == "__main__":
    if test_all():
        print("Tests passed")
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""WakaTime plugin for Eric6 and Pymakr."""

from __future__ import unicode_literals

import os
import platform
import re
import shutil
import ssl
import sys
import tempfile
import time
import threading
import traceback
import urllib
from datetime import datetime
from zipfile import ZipFile
try:
    import ConfigParser as configparser
except ImportError:
    import configparser

is_py2 = (sys.version_info[0] == 2)
if is_py2:
    import codecs
    open = codecs.open

from PyQt5.QtGui import QAction, QIcon, QInputDialog, QLineEdit
from PyQt5.QtCore import QObject

from E5Gui.E5Application import e5App
from UI.Info import Program, Version

# Start-Of-Header
name = "WakaTime Plugin"
author = "WakaTime <support@wakatime.com>"
autoactivate = True
deactivateable = False
version = "1.0.0"
pluginType = "viewmanager"
pluginTypename = "WakaTime"
className = "WakaTimePlugin"
packageName = None
shortDescription = "Automatic time tracking and metrics about your IDE usage."
longDescription = "Automatic time tracking and metrics about your IDE usage."
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""

if platform.system() == 'Windows':
    RESOURCES_FOLDER = os.path.join(os.getenv('APPDATA'), 'WakaTime')
else:
    RESOURCES_FOLDER = os.path.join(os.path.expanduser('~'), '.wakatime')
if not os.path.exists(RESOURCES_FOLDER):
    os.makedirs(RESOURCES_FOLDER)

# add wakatime package to path
sys.path.insert(0, os.path.join(RESOURCES_FOLDER, 'wakatime-master'))

HEARTBEAT_FREQUENCY = 2
CLI_LOCATION = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', 'cli.py')
PLUGIN = '{prog}/{progVer} {prog}-wakatime/{pluginVer}'.format(
    prog=Program,
    progVer=Version,
    pluginVer=version,
)
IS_DEBUG_ENABLED = False

# Log Levels
DEBUG = 'DEBUG'
INFO = 'INFO'
WARNING = 'WARNING'
ERROR = 'ERROR'

def getConfigData():
    return {}

def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    pass

class WakaTimePlugin(QObject):
    """
    Class implementing the WakaTime plugin.
    """
    def __init__(self, ui):
        """
        Constructor

        @param ui reference to the user interface object (UI.UserInterface)
        """
        super(WakaTimePlugin, self).__init__(ui)
        self._ui = ui

        try:
            e5App().registerPluginObject(pluginTypename, self)
        except KeyError:
            pass    # ignore duplicate registration

    def getProjectHelper(self):
        """
        Public method to get a reference to the project helper object.

        @return reference to the project helper object
        """
        return self.__projectHelperObject

    def initToolbar(self, ui, toolbarManager):
        """
        Public slot to initialize the VCS toolbar.

        @param ui reference to the main window (UserInterface)
        @param toolbarManager reference to a toolbar manager object
            (E5ToolBarManager)
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.initToolbar(ui, toolbarManager)

    def activate(self):
        global IS_DEBUG_ENABLED
        IS_DEBUG_ENABLED = self._getDebug()

        log(DEBUG, 'Initializing WakaTime v{ver}...'.format(ver=version))

        self._setupCli()

        apiKey = self._getApiKey()
        if not apiKey.strip():
            self._promptForApiKey()

        self._setupEventListeners()

        self._addMenu()

        log(DEBUG, 'Finished initializing WakaTime plugin.')
        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        self.__object = None

        self.action.setVisible(False)
        self.action.setEnabled(False)

    def _setupCli(self):
        if self._isCliLatest():
            return

        thread = DownloadCLI()
        thread.start()

    def _setupEventListeners(self):
        e5App().getObject('ViewManager').cursorChanged.connect(self._cursorChanged)
        e5App().getObject('ViewManager').editorSaved.connect(self._editorSaved)
        #e5App().getObject('Project').projectOpened.connect(self._projectOpened)

    def _addMenu(self):
        """Adds the WakaTime menu item under the File menu."""
        self.action = QAction(QIcon(), 'WakaTime', self)
        self.action.triggered.connect(self._promptForApiKey)
        fileMenu = e5App().getObject('UserInterface').getMenu('file')
        fileMenu.addAction(self.action)

    def _editorSaved(self, fileName):
        self._handleActivity(fileName, isWrite=True)

    def _cursorChanged(self, editor):
        fileName = editor.getFileName()
        self._handleActivity(fileName)

    def _projectOpened(self):
        log(DEBUG, '_projectOpened')

    def _handleActivity(self, fileName, isWrite=False):
        fileName = os.path.abspath(os.path.realpath(fileName))
        if not hasattr(self, '_lastFile'):
            self._lastFile = None
        if fileName != self._lastFile or self._enoughTimePassed(isWrite):
            if not self._shouldExclude(fileName):
                self._sendHeartbeat(fileName, isWrite)

    def _enoughTimePassed(self, isWrite):
        now = time.time()
        if not hasattr(self, '_lastTime'):
            self._lastTime = 0
        if now - self._lastTime > HEARTBEAT_FREQUENCY * 60:
            return True
        if isWrite and now - self._lastTime > 2:
            return True
        return False

    def _shouldExclude(self, fileName):
        return os.path.basename(fileName) == '0.1'

    def _sendHeartbeat(self, fileName, isWrite):
        try:
            from wakatime.main import execute
        except ImportError:
            log(DEBUG, 'Skipping heartbeat because wakatime-cli not found.')
            return
        except:
            log(ERROR, traceback.format_exc())
            return

        self._lastFile = fileName
        self._lastTime = time.time()

        args = ['--entity', fileName, '--plugin', PLUGIN]
        if isWrite:
            args.append('--write')

        log(DEBUG, 'Sending heartbeat:')
        log(DEBUG, ' '.join(args))

        execute(args)

    def _promptForApiKey(self, *args):
        """Prompt the user to enter their api key."""

        ui = e5App().getObject('UserInterface')
        title = 'WakaTime'
        label = '               Enter your WakaTime API Key:               \n' + \
                '               (https://wakatime.com/settings)            '
        default = self._getApiKey()
        text, ok = QInputDialog.getText(ui, title, label, QLineEdit.Normal, default)
        if ok:
            configs = self._parseConfigFile()
            configs.set('settings', 'api_key', text)
            configFile = self._configFile()
            with open(configFile, 'w', encoding='utf-8') as fh:
                configs.write(fh)

    def _createConfigFile(self):
        """Creates the .wakatime.cfg INI file in $HOME directory, if it does
        not already exist.
        """
        configFile = self._configFile()
        try:
            with open(configFile) as fh:
                pass
        except IOError:
            try:
                with open(configFile, 'w') as fh:
                    fh.write("[settings]\n")
                    fh.write("debug = false\n")
                    fh.write("hidefilenames = false\n")
            except IOError:
                pass

    def _getApiKey(self):
        self._createConfigFile()
        key = ''
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'api_key'):
                    key = configs.get('settings', 'api_key')
        except:
            pass
        return key

    def _getDebug(self):
        self._createConfigFile()
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'debug'):
                    return configs.get('settings', 'debug') == 'true'
        except:
            pass
        return False

    def _configFile(self):
        home = os.environ.get('WAKATIME_HOME')
        if home:
            return os.path.join(os.path.expanduser(home), '.wakatime.cfg')

        return os.path.join(os.path.expanduser('~'), '.wakatime.cfg')

    def _parseConfigFile(self):
        """Returns a configparser.SafeConfigParser instance with configs
        read from the config file. Default location of the config file is
        at ~/.wakatime.cfg.
        """

        configFile = self._configFile()

        configs = configparser.SafeConfigParser()
        try:
            with open(configFile, 'r', encoding='utf-8') as fh:
                try:
                    configs.readfp(fh)
                    return configs
                except configparser.Error:
                    log(ERROR, traceback.format_exc())
                    return None
        except IOError:
            log(DEBUG, "Error: Could not read from config file {0}\n".format(configFile))
            return None

    def _isCliLatest(self):
        remoteVer = self._getLatestCliVersion()
        about = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', '__about__.py')
        try:
            with open(about) as fh:
                localVer = self._extractVersion(fh)
            if remoteVer and localVer:
                return remoteVer.strip() == localVer.strip()
        except:
            log(ERROR, traceback.format_exc())
        return False

    def _getLatestCliVersion(self):
        url = 'https://raw.githubusercontent.com/wakatime/wakatime/master/wakatime/__about__.py'
        try:
            with tempfile.NamedTemporaryFile() as tmp:
                output = tmp.name
                download(url, output)

                with open(output) as fh:
                    return self._extractVersion(fh)
        except:
            return None

    def _extractVersion(self, fh):
        pattern = re.compile(r"^__version_info__ = \('([0-9]+)', '([0-9]+)', '([0-9]+)'\)")
        for line in fh.readlines():
            match = pattern.search(line)
            if match:
                return '{0}.{0}.{0}'.format(match.group(1), match.group(2), match.group(3))
        return None

    def prepareUninstall(self):
        """
        Public method to prepare for an uninstallation.
        """
        e5App().unregisterPluginObject(pluginTypename)

    def prepareUnload(self):
        """
        Public method to prepare for an unload.
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.removeToolbar(
                self.__ui, e5App().getObject("ToolbarManager"))
        e5App().unregisterPluginObject(pluginTypename)

class DownloadCLI(threading.Thread):
    """Non-blocking thread for downloading latest wakatime-cli from GitHub.
    """

    def run(self):
        log(INFO, 'Downloading wakatime-cli...')

        try:
            shutil.rmtree(os.path.join(RESOURCES_FOLDER, 'wakatime-master'))
        except:
            pass

        with tempfile.NamedTemporaryFile() as fh:
            zip_file = fh.name

            url = 'https://github.com/wakatime/wakatime/archive/master.zip'
            download(url, zip_file)

            log(INFO, 'Extracting wakatime-cli...')
            with ZipFile(zip_file) as zf:
                zf.extractall(RESOURCES_FOLDER)

        log(INFO, 'Finished extracting wakatime-cli.')

def download(url, filePath):
    try:
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)
    except IOError:
        ssl._create_default_https_context = ssl._create_unverified_context
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)

def log(lvl, msg, *args, **kwargs):
    if lvl == DEBUG and not IS_DEBUG_ENABLED:
        return
    if len(args) > 0:
        msg = msg.format(*args)
    elif len(kwargs) > 0:
        msg = msg.format(**kwargs)
    date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    try:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg))
    except UnicodeDecodeError:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg.decode('utf8', 'replace')))
<commit_msg>temp files not available on Windows platform<commit_after># -*- coding: utf-8 -*-

"""WakaTime plugin for Eric6 and Pymakr."""

from __future__ import unicode_literals

import os
import platform
import re
import shutil
import ssl
import sys
import time
import threading
import traceback
import urllib
from datetime import datetime
from zipfile import ZipFile
try:
    import ConfigParser as configparser
except ImportError:
    import configparser

is_py2 = (sys.version_info[0] == 2)
if is_py2:
    import codecs
    open = codecs.open

from PyQt5.QtGui import QAction, QIcon, QInputDialog, QLineEdit
from PyQt5.QtCore import QObject

from E5Gui.E5Application import e5App
from UI.Info import Program, Version

# Start-Of-Header
name = "WakaTime Plugin"
author = "WakaTime <support@wakatime.com>"
autoactivate = True
deactivateable = False
version = "1.0.0"
pluginType = "viewmanager"
pluginTypename = "WakaTime"
className = "WakaTimePlugin"
packageName = None
shortDescription = "Automatic time tracking and metrics about your IDE usage."
longDescription = "Automatic time tracking and metrics about your IDE usage."
pyqtApi = 2
python2Compatible = True
# End-Of-Header

error = ""

if platform.system() == 'Windows':
    RESOURCES_FOLDER = os.path.join(os.getenv('APPDATA'), 'WakaTime')
else:
    RESOURCES_FOLDER = os.path.join(os.path.expanduser('~'), '.wakatime')
if not os.path.exists(RESOURCES_FOLDER):
    os.makedirs(RESOURCES_FOLDER)

# add wakatime package to path
sys.path.insert(0, os.path.join(RESOURCES_FOLDER, 'wakatime-master'))

HEARTBEAT_FREQUENCY = 2
CLI_LOCATION = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', 'cli.py')
PLUGIN = '{prog}/{progVer} {prog}-wakatime/{pluginVer}'.format(
    prog=Program,
    progVer=Version,
    pluginVer=version,
)
IS_DEBUG_ENABLED = False

# Log Levels
DEBUG = 'DEBUG'
INFO = 'INFO'
WARNING = 'WARNING'
ERROR = 'ERROR'

def getConfigData():
    return {}

def prepareUninstall():
    """
    Module function to prepare for an uninstallation.
    """
    pass

class WakaTimePlugin(QObject):
    """
    Class implementing the WakaTime plugin.
    """
    def __init__(self, ui):
        """
        Constructor

        @param ui reference to the user interface object (UI.UserInterface)
        """
        super(WakaTimePlugin, self).__init__(ui)
        self._ui = ui

        try:
            e5App().registerPluginObject(pluginTypename, self)
        except KeyError:
            pass    # ignore duplicate registration

    def getProjectHelper(self):
        """
        Public method to get a reference to the project helper object.

        @return reference to the project helper object
        """
        return self.__projectHelperObject

    def initToolbar(self, ui, toolbarManager):
        """
        Public slot to initialize the VCS toolbar.

        @param ui reference to the main window (UserInterface)
        @param toolbarManager reference to a toolbar manager object
            (E5ToolBarManager)
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.initToolbar(ui, toolbarManager)

    def activate(self):
        global IS_DEBUG_ENABLED
        IS_DEBUG_ENABLED = self._getDebug()

        log(DEBUG, 'Initializing WakaTime v{ver}...'.format(ver=version))

        self._setupCli()

        apiKey = self._getApiKey()
        if not apiKey.strip():
            self._promptForApiKey()

        self._setupEventListeners()

        self._addMenu()

        log(DEBUG, 'Finished initializing WakaTime plugin.')
        return None, True

    def deactivate(self):
        """
        Public method to deactivate this plugin.
        """
        self.__object = None

        self.action.setVisible(False)
        self.action.setEnabled(False)

    def _setupCli(self):
        if self._isCliLatest():
            return

        thread = DownloadCLI()
        thread.start()

    def _setupEventListeners(self):
        e5App().getObject('ViewManager').cursorChanged.connect(self._cursorChanged)
        e5App().getObject('ViewManager').editorSaved.connect(self._editorSaved)
        #e5App().getObject('Project').projectOpened.connect(self._projectOpened)

    def _addMenu(self):
        """Adds the WakaTime menu item under the File menu."""
        self.action = QAction(QIcon(), 'WakaTime', self)
        self.action.triggered.connect(self._promptForApiKey)
        fileMenu = e5App().getObject('UserInterface').getMenu('file')
        fileMenu.addAction(self.action)

    def _editorSaved(self, fileName):
        self._handleActivity(fileName, isWrite=True)

    def _cursorChanged(self, editor):
        fileName = editor.getFileName()
        self._handleActivity(fileName)

    def _projectOpened(self):
        log(DEBUG, '_projectOpened')

    def _handleActivity(self, fileName, isWrite=False):
        fileName = os.path.abspath(os.path.realpath(fileName))
        if not hasattr(self, '_lastFile'):
            self._lastFile = None
        if fileName != self._lastFile or self._enoughTimePassed(isWrite):
            if not self._shouldExclude(fileName):
                self._sendHeartbeat(fileName, isWrite)

    def _enoughTimePassed(self, isWrite):
        now = time.time()
        if not hasattr(self, '_lastTime'):
            self._lastTime = 0
        if now - self._lastTime > HEARTBEAT_FREQUENCY * 60:
            return True
        if isWrite and now - self._lastTime > 2:
            return True
        return False

    def _shouldExclude(self, fileName):
        return os.path.basename(fileName) == '0.1'

    def _sendHeartbeat(self, fileName, isWrite):
        try:
            from wakatime.main import execute
        except ImportError:
            log(DEBUG, 'Skipping heartbeat because wakatime-cli not found.')
            return
        except:
            log(ERROR, traceback.format_exc())
            return

        self._lastFile = fileName
        self._lastTime = time.time()

        args = ['--entity', fileName, '--plugin', PLUGIN]
        if isWrite:
            args.append('--write')

        log(DEBUG, 'Sending heartbeat:')
        log(DEBUG, ' '.join(args))

        execute(args)

    def _promptForApiKey(self, *args):
        """Prompt the user to enter their api key."""

        ui = e5App().getObject('UserInterface')
        title = 'WakaTime'
        label = '               Enter your WakaTime API Key:               \n' + \
                '               (https://wakatime.com/settings)            '
        default = self._getApiKey()
        text, ok = QInputDialog.getText(ui, title, label, QLineEdit.Normal, default)
        if ok:
            configs = self._parseConfigFile()
            configs.set('settings', 'api_key', text)
            configFile = self._configFile()
            with open(configFile, 'w', encoding='utf-8') as fh:
                configs.write(fh)

    def _createConfigFile(self):
        """Creates the .wakatime.cfg INI file in $HOME directory, if it does
        not already exist.
        """
        configFile = self._configFile()
        try:
            with open(configFile) as fh:
                pass
        except IOError:
            try:
                with open(configFile, 'w') as fh:
                    fh.write("[settings]\n")
                    fh.write("debug = false\n")
                    fh.write("hidefilenames = false\n")
            except IOError:
                pass

    def _getApiKey(self):
        self._createConfigFile()
        key = ''
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'api_key'):
                    key = configs.get('settings', 'api_key')
        except:
            pass
        return key

    def _getDebug(self):
        self._createConfigFile()
        try:
            configs = self._parseConfigFile()
            if configs is not None:
                if configs.has_option('settings', 'debug'):
                    return configs.get('settings', 'debug') == 'true'
        except:
            pass
        return False

    def _configFile(self):
        home = os.environ.get('WAKATIME_HOME')
        if home:
            return os.path.join(os.path.expanduser(home), '.wakatime.cfg')

        return os.path.join(os.path.expanduser('~'), '.wakatime.cfg')

    def _parseConfigFile(self):
        """Returns a configparser.SafeConfigParser instance with configs
        read from the config file. Default location of the config file is
        at ~/.wakatime.cfg.
        """

        configFile = self._configFile()

        configs = configparser.SafeConfigParser()
        try:
            with open(configFile, 'r', encoding='utf-8') as fh:
                try:
                    configs.readfp(fh)
                    return configs
                except configparser.Error:
                    log(ERROR, traceback.format_exc())
                    return None
        except IOError:
            log(DEBUG, "Error: Could not read from config file {0}\n".format(configFile))
            return None

    def _isCliLatest(self):
        remoteVer = self._getLatestCliVersion()
        about = os.path.join(RESOURCES_FOLDER, 'wakatime-master', 'wakatime', '__about__.py')
        try:
            with open(about) as fh:
                localVer = self._extractVersion(fh)
            if remoteVer and localVer:
                return remoteVer.strip() == localVer.strip()
        except:
            log(DEBUG, traceback.format_exc())
        return False

    def _getLatestCliVersion(self):
        url = 'https://raw.githubusercontent.com/wakatime/wakatime/master/wakatime/__about__.py'
        try:
            output = os.path.join(RESOURCES_FOLDER, 'remoteVer')
            download(url, output)
            with open(output) as fh:
                return self._extractVersion(fh)
        except:
            return None

    def _extractVersion(self, fh):
        pattern = re.compile(r"^__version_info__ = \('([0-9]+)', '([0-9]+)', '([0-9]+)'\)")
        for line in fh.readlines():
            match = pattern.search(line)
            if match:
                return '{0}.{0}.{0}'.format(match.group(1), match.group(2), match.group(3))
        return None

    def prepareUninstall(self):
        """
        Public method to prepare for an uninstallation.
        """
        e5App().unregisterPluginObject(pluginTypename)

    def prepareUnload(self):
        """
        Public method to prepare for an unload.
        """
        if self.__projectHelperObject:
            self.__projectHelperObject.removeToolbar(
                self.__ui, e5App().getObject("ToolbarManager"))
        e5App().unregisterPluginObject(pluginTypename)

class DownloadCLI(threading.Thread):
    """Non-blocking thread for downloading latest wakatime-cli from GitHub.
    """

    def run(self):
        log(INFO, 'Downloading wakatime-cli...')

        try:
            shutil.rmtree(os.path.join(RESOURCES_FOLDER, 'wakatime-master'))
        except:
            pass

        try:
            url = 'https://github.com/wakatime/wakatime/archive/master.zip'
            zip_file = os.path.join(RESOURCES_FOLDER, 'wakatime.zip')
            download(url, zip_file)

            log(INFO, 'Extracting wakatime-cli...')
            with ZipFile(zip_file) as zf:
                zf.extractall(RESOURCES_FOLDER)
        except:
            log(DEBUG, traceback.format_exc())

        log(INFO, 'Finished extracting wakatime-cli.')

def download(url, filePath):
    try:
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)
    except IOError:
        ssl._create_default_https_context = ssl._create_unverified_context
        try:
            urllib.urlretrieve(url, filePath)
        except AttributeError:
            urllib.request.urlretrieve(url, filePath)

def log(lvl, msg, *args, **kwargs):
    if lvl == DEBUG and not IS_DEBUG_ENABLED:
        return
    if len(args) > 0:
        msg = msg.format(*args)
    elif len(kwargs) > 0:
        msg = msg.format(**kwargs)
    date = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    try:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg))
    except UnicodeDecodeError:
        print('[WakaTime] [{date}] [{lvl}] {msg}'.format(lvl=lvl, date=date, msg=msg.decode('utf8', 'replace')))
<|endoftext|>


<commit_before>"""
sentry.plugins.bases.issue
~~~~~~~~~~~~~~~~~~~~~~~~~~

:copyright: (c) 2010-2013 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from sentry.conf import settings
from sentry.models import GroupMeta
from sentry.plugins import Plugin
from django import forms
from django.core.urlresolvers import reverse
from django.utils.html import escape
from django.utils.safestring import mark_safe
from social_auth.models import UserSocialAuth
from sentry.utils.auth import get_auth_providers
from sentry.utils.http import absolute_uri

class NewIssueForm(forms.Form):
    title = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class': 'span9'}))
    description = forms.CharField(widget=forms.Textarea(attrs={'class': 'span9'}))

class IssuePlugin(Plugin):
    # project_conf_form = BaseIssueOptionsForm
    new_issue_form = NewIssueForm

    create_issue_template = 'sentry/plugins/bases/issue/create_issue.html'
    not_configured_template = 'sentry/plugins/bases/issue/not_configured.html'
    needs_auth_template = 'sentry/plugins/bases/issue/needs_auth.html'
    auth_provider = None

    def __init__(self, *args, **kwargs):
        super(IssuePlugin, self).__init__(*args, **kwargs)
        self._cache = {}

    def _get_group_body(self, request, group, event, **kwargs):
        interface = event.interfaces.get('sentry.interfaces.Stacktrace')
        if interface:
            return interface.to_string(event)
        return

    def _get_group_description(self, request, group, event):
        output = [
            absolute_uri(reverse('sentry-group', kwargs={
                'project_id': group.project.slug,
                'team_slug': group.team.slug,
                'group_id': group.id,
            })),
        ]
        body = self._get_group_body(request, group, event)
        if body:
            output.extend([
                '',
                '```',
                body,
                '```',
            ])
        return '\n'.join(output)

    def _get_group_title(self, request, group, event):
        return event.error()

    def is_configured(self, request, project, **kwargs):
        raise NotImplementedError

    def get_auth_for_user(self, user, **kwargs):
        """
        Return a ``UserSocialAuth`` object for the given user based on this plugins ``auth_provider``.
        """
        assert self.auth_provider, 'There is no auth provider configured for this plugin.'

        if not user.is_authenticated():
            return None

        try:
            return UserSocialAuth.objects.filter(user=user, provider=self.auth_provider)[0]
        except IndexError:
            return None

    def needs_auth(self, request, project, **kwargs):
        """
        Return ``True`` if the authenticated user needs to associate an auth service before
        performing actions with this plugin.
        """
        if self.auth_provider is None:
            return False

        if not request.user.is_authenticated():
            return True

        return bool(not UserSocialAuth.objects.filter(user=request.user, provider=self.auth_provider).exists())

    def get_new_issue_title(self, **kwargs):
        """
        Return a string for the "Create new issue" action label.
        """
        return 'Create %s Issue' % self.get_title()

    def get_issue_url(self, group, issue_id, **kwargs):
        """
        Given an issue_id (string) return an absolute URL to the issue's details
        page.
        """
        raise NotImplementedError

    def get_issue_label(self, group, issue_id, **kwargs):
        """
        Given an issue_id (string) return a string representing the issue.

        e.g. GitHub represents issues as GH-XXX
        """
        return '#%s' % issue_id

    def create_issue(self, request, group, form_data, **kwargs):
        """
        Creates the issue on the remote service and returns an issue ID.
        """
        raise NotImplementedError

    def get_initial_form_data(self, request, group, event, **kwargs):
        return {
            'description': self._get_group_description(request, group, event),
            'title': self._get_group_title(request, group, event),
        }

    def has_auth_configured(self, **kwargs):
        if not self.auth_provider:
            return True

        return self.auth_provider in get_auth_providers()

    def view(self, request, group, **kwargs):
        has_auth_configured = self.has_auth_configured()
        if not (has_auth_configured and self.is_configured(project=group.project, request=request)):
            if self.auth_provider:
                required_auth_settings = settings.AUTH_PROVIDERS[self.auth_provider]
            else:
                required_auth_settings = None

            return self.render(self.not_configured_template, {
                'title': self.get_title(),
                'project': group.project,
                'has_auth_configured': has_auth_configured,
                'required_auth_settings': required_auth_settings,
            })

        if self.needs_auth(project=group.project, request=request):
            return self.render(self.needs_auth_template, {
                'title': self.get_title(),
                'project': group.project,
            })

        if GroupMeta.objects.get_value(group, '%s:tid' % self.get_conf_key(), None):
            return None

        prefix = self.get_conf_key()
        event = group.get_latest_event()

        form = self.new_issue_form(request.POST or None, initial=self.get_initial_form_data(request, group, event))
        if form.is_valid():
            try:
                issue_id = self.create_issue(
                    group=group,
                    form_data=form.cleaned_data,
                    request=request,
                )
            except forms.ValidationError, e:
                form.errors['__all__'] = [u'Error creating issue: %s' % e]
            else:
                issue_information = {
                    'title': form.cleaned_data['title'],
                    'provider': self.get_title(),
                    'location': self.get_issue_url(group, issue_id),
                }
                Activity.objects.create(
                    project=group.project,
                    group=group,
                    type=Activity.CREATE_ISSUE,
                    user=request.user,
                    data=issue_information,
                    )

        if form.is_valid():
            GroupMeta.objects.set_value(group, '%s:tid' % prefix, issue_id)

            return self.redirect(reverse('sentry-group', args=[group.team.slug, group.project_id, group.pk]))

        context = {
            'form': form,
            'title': self.get_new_issue_title(),
        }

        return self.render(self.create_issue_template, context)

    def actions(self, request, group, action_list, **kwargs):
        if not self.is_configured(request=request, project=group.project):
            return action_list
        prefix = self.get_conf_key()
        if not GroupMeta.objects.get_value(group, '%s:tid' % prefix, None):
            action_list.append((self.get_new_issue_title(), self.get_url(group)))
        return action_list

    def before_events(self, request, event_list, **kwargs):
        if event_list and self.is_configured(request=request, project=event_list[0].project):
            prefix = self.get_conf_key()
            self._cache = GroupMeta.objects.get_value_bulk(event_list, '%s:tid' % prefix)

    def tags(self, request, group, tag_list, **kwargs):
        if not self.is_configured(request=request, project=group.project):
            return tag_list

        issue_id = self._cache.get(group.pk)
        if not issue_id:
            return tag_list

        tag_list.append(mark_safe('%s' % (
            self.get_issue_url(group=group, issue_id=issue_id),
            escape(self.get_issue_label(group=group, issue_id=issue_id)),
        )))

        return tag_list
<commit_msg>Moved activity creation down.<commit_after>"""
sentry.plugins.bases.issue
~~~~~~~~~~~~~~~~~~~~~~~~~~

:copyright: (c) 2010-2013 by the Sentry Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from sentry.conf import settings
from sentry.models import GroupMeta
from sentry.plugins import Plugin
from django import forms
from django.core.urlresolvers import reverse
from django.utils.html import escape
from django.utils.safestring import mark_safe
from social_auth.models import UserSocialAuth
from sentry.utils.auth import get_auth_providers
from sentry.utils.http import absolute_uri

class NewIssueForm(forms.Form):
    title = forms.CharField(max_length=200, widget=forms.TextInput(attrs={'class': 'span9'}))
    description = forms.CharField(widget=forms.Textarea(attrs={'class': 'span9'}))

class IssuePlugin(Plugin):
    # project_conf_form = BaseIssueOptionsForm
    new_issue_form = NewIssueForm

    create_issue_template = 'sentry/plugins/bases/issue/create_issue.html'
    not_configured_template = 'sentry/plugins/bases/issue/not_configured.html'
    needs_auth_template = 'sentry/plugins/bases/issue/needs_auth.html'
    auth_provider = None

    def __init__(self, *args, **kwargs):
        super(IssuePlugin, self).__init__(*args, **kwargs)
        self._cache = {}

    def _get_group_body(self, request, group, event, **kwargs):
        interface = event.interfaces.get('sentry.interfaces.Stacktrace')
        if interface:
            return interface.to_string(event)
        return

    def _get_group_description(self, request, group, event):
        output = [
            absolute_uri(reverse('sentry-group', kwargs={
                'project_id': group.project.slug,
                'team_slug': group.team.slug,
                'group_id': group.id,
            })),
        ]
        body = self._get_group_body(request, group, event)
        if body:
            output.extend([
                '',
                '```',
                body,
                '```',
            ])
        return '\n'.join(output)

    def _get_group_title(self, request, group, event):
        return event.error()

    def is_configured(self, request, project, **kwargs):
        raise NotImplementedError

    def get_auth_for_user(self, user, **kwargs):
        """
        Return a ``UserSocialAuth`` object for the given user based on this plugins ``auth_provider``.
        """
        assert self.auth_provider, 'There is no auth provider configured for this plugin.'

        if not user.is_authenticated():
            return None

        try:
            return UserSocialAuth.objects.filter(user=user, provider=self.auth_provider)[0]
        except IndexError:
            return None

    def needs_auth(self, request, project, **kwargs):
        """
        Return ``True`` if the authenticated user needs to associate an auth service before
        performing actions with this plugin.
        """
        if self.auth_provider is None:
            return False

        if not request.user.is_authenticated():
            return True

        return bool(not UserSocialAuth.objects.filter(user=request.user, provider=self.auth_provider).exists())

    def get_new_issue_title(self, **kwargs):
        """
        Return a string for the "Create new issue" action label.
        """
        return 'Create %s Issue' % self.get_title()

    def get_issue_url(self, group, issue_id, **kwargs):
        """
        Given an issue_id (string) return an absolute URL to the issue's details
        page.
        """
        raise NotImplementedError

    def get_issue_label(self, group, issue_id, **kwargs):
        """
        Given an issue_id (string) return a string representing the issue.

        e.g. GitHub represents issues as GH-XXX
        """
        return '#%s' % issue_id

    def create_issue(self, request, group, form_data, **kwargs):
        """
        Creates the issue on the remote service and returns an issue ID.
        """
        raise NotImplementedError

    def get_initial_form_data(self, request, group, event, **kwargs):
        return {
            'description': self._get_group_description(request, group, event),
            'title': self._get_group_title(request, group, event),
        }

    def has_auth_configured(self, **kwargs):
        if not self.auth_provider:
            return True

        return self.auth_provider in get_auth_providers()

    def view(self, request, group, **kwargs):
        has_auth_configured = self.has_auth_configured()
        if not (has_auth_configured and self.is_configured(project=group.project, request=request)):
            if self.auth_provider:
                required_auth_settings = settings.AUTH_PROVIDERS[self.auth_provider]
            else:
                required_auth_settings = None

            return self.render(self.not_configured_template, {
                'title': self.get_title(),
                'project': group.project,
                'has_auth_configured': has_auth_configured,
                'required_auth_settings': required_auth_settings,
            })

        if self.needs_auth(project=group.project, request=request):
            return self.render(self.needs_auth_template, {
                'title': self.get_title(),
                'project': group.project,
            })

        if GroupMeta.objects.get_value(group, '%s:tid' % self.get_conf_key(), None):
            return None

        prefix = self.get_conf_key()
        event = group.get_latest_event()

        form = self.new_issue_form(request.POST or None, initial=self.get_initial_form_data(request, group, event))
        if form.is_valid():
            try:
                issue_id = self.create_issue(
                    group=group,
                    form_data=form.cleaned_data,
                    request=request,
                )
            except forms.ValidationError, e:
                form.errors['__all__'] = [u'Error creating issue: %s' % e]

        if form.is_valid():
            GroupMeta.objects.set_value(group, '%s:tid' % prefix, issue_id)

            issue_information = {
                'title': form.cleaned_data['title'],
                'provider': self.get_title(),
                'location': self.get_issue_url(group, issue_id),
            }
            Activity.objects.create(
                project=group.project,
                group=group,
                type=Activity.CREATE_ISSUE,
                user=request.user,
                data=issue_information,
                )

            return self.redirect(reverse('sentry-group', args=[group.team.slug, group.project_id, group.pk]))

        context = {
            'form': form,
            'title': self.get_new_issue_title(),
        }

        return self.render(self.create_issue_template, context)

    def actions(self, request, group, action_list, **kwargs):
        if not self.is_configured(request=request, project=group.project):
            return action_list
        prefix = self.get_conf_key()
        if not GroupMeta.objects.get_value(group, '%s:tid' % prefix, None):
            action_list.append((self.get_new_issue_title(), self.get_url(group)))
        return action_list

    def before_events(self, request, event_list, **kwargs):
        if event_list and self.is_configured(request=request, project=event_list[0].project):
            prefix = self.get_conf_key()
            self._cache = GroupMeta.objects.get_value_bulk(event_list, '%s:tid' % prefix)

    def tags(self, request, group, tag_list, **kwargs):
        if not self.is_configured(request=request, project=group.project):
            return tag_list

        issue_id = self._cache.get(group.pk)
        if not issue_id:
            return tag_list

        tag_list.append(mark_safe('%s' % (
            self.get_issue_url(group=group, issue_id=issue_id),
            escape(self.get_issue_label(group=group, issue_id=issue_id)),
        )))

        return tag_list
<|endoftext|>


<commit_before># All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import datetime

from webob import exc
import wsme
from wsme import types as wtypes

from ironic.common.i18n import _

class APIBase(wtypes.Base):

    created_at = wsme.wsattr(datetime.datetime, readonly=True)
    """The time in UTC at which the object is created"""

    updated_at = wsme.wsattr(datetime.datetime, readonly=True)
    """The time in UTC at which the object is updated"""

    def as_dict(self):
        """Render this object as a dict of its fields."""
        return dict((k, getattr(self, k))
                    for k in self.fields
                    if hasattr(self, k) and
                    getattr(self, k) != wsme.Unset)

    def unset_fields_except(self, except_list=None):
        """Unset fields so they don't appear in the message body.

        :param except_list: A list of fields that won't be touched.

        """
        if except_list is None:
            except_list = []

        for k in self.as_dict():
            if k not in except_list:
                setattr(self, k, wsme.Unset)

class Version(object):
    """API Version object."""

    string = 'X-OpenStack-Ironic-API-Version'
    """HTTP Header string carrying the requested version"""

    min_string = 'X-OpenStack-Ironic-API-Minimum-Version'
    """HTTP reponse header"""

    max_string = 'X-OpenStack-Ironic-API-Maximum-Version'
    """HTTP response header"""

    def __init__(self, headers, min=None, max=None):
        """Create an API Version object from the supplied headers.

        :param headers: webob headers
        """
        (self.major, self.minor) = Version.parse_headers(headers)
        self.min = min
        self.max = max

    def __repr__(self):
        return '%s.%s' % (self.major, self.minor)

    @staticmethod
    def parse_headers(headers):
        """Determine the API version requested based on the headers supplied.

        :param headers: webob headers
        :returns: a tupe of (major, minor) version numbers
        :raises: webob.HTTPNotAcceptable
        """
        try:
            version = tuple(int(i) for i in headers.get(
                    Version.string, '1.0').split('.'))
        except ValueError:
            version = ()
        if len(version) != 2:
            raise exc.HTTPNotAcceptable(_(
                "Invalid value for X-OpenStack-Ironic-API-Version "
                "header."))
        return version

    def set_min_max(self, min, max):
        """Set or update the min and max versions.

        This is useful if the specific min and max are not known when
        the Version object is instantiated, eg. because it was created
        in the root controller.
        """
        self.min = min
        self.max = max
<commit_msg>Add :raises: for Version constructor docstring<commit_after># All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import datetime

from webob import exc
import wsme
from wsme import types as wtypes

from ironic.common.i18n import _

class APIBase(wtypes.Base):

    created_at = wsme.wsattr(datetime.datetime, readonly=True)
    """The time in UTC at which the object is created"""

    updated_at = wsme.wsattr(datetime.datetime, readonly=True)
    """The time in UTC at which the object is updated"""

    def as_dict(self):
        """Render this object as a dict of its fields."""
        return dict((k, getattr(self, k))
                    for k in self.fields
                    if hasattr(self, k) and
                    getattr(self, k) != wsme.Unset)

    def unset_fields_except(self, except_list=None):
        """Unset fields so they don't appear in the message body.

        :param except_list: A list of fields that won't be touched.

        """
        if except_list is None:
            except_list = []

        for k in self.as_dict():
            if k not in except_list:
                setattr(self, k, wsme.Unset)

class Version(object):
    """API Version object."""

    string = 'X-OpenStack-Ironic-API-Version'
    """HTTP Header string carrying the requested version"""

    min_string = 'X-OpenStack-Ironic-API-Minimum-Version'
    """HTTP reponse header"""

    max_string = 'X-OpenStack-Ironic-API-Maximum-Version'
    """HTTP response header"""

    def __init__(self, headers, min=None, max=None):
        """Create an API Version object from the supplied headers.

        :param headers: webob headers
        :raises: webob.HTTPNotAcceptable
        """
        (self.major, self.minor) = Version.parse_headers(headers)
        self.min = min
        self.max = max

    def __repr__(self):
        return '%s.%s' % (self.major, self.minor)

    @staticmethod
    def parse_headers(headers):
        """Determine the API version requested based on the headers supplied.

        :param headers: webob headers
        :returns: a tupe of (major, minor) version numbers
        :raises: webob.HTTPNotAcceptable
        """
        try:
            version = tuple(int(i) for i in headers.get(
                    Version.string, '1.0').split('.'))
        except ValueError:
            version = ()
        if len(version) != 2:
            raise exc.HTTPNotAcceptable(_(
                "Invalid value for X-OpenStack-Ironic-API-Version "
                "header."))
        return version

    def set_min_max(self, min, max):
        """Set or update the min and max versions.

        This is useful if the specific min and max are not known when
        the Version object is instantiated, eg. because it was created
        in the root controller.
        """
        self.min = min
        self.max = max
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from flask import Blueprint, request, render_template, g, url_for
from flask.ext.babel import gettext
from sqlalchemy import func, distinct
from werkzeug import urls

from dataviva import db, view_cache
from dataviva.attrs import models as attrs
from dataviva.rais import models as rais
from dataviva.secex import models as secex

from dataviva.general.models import Plan
from dataviva.attrs.models import Bra, Cnae, Cbo, Hs, Wld, University, Course_hedu, Course_sc
from dataviva.rais.models import Ybi, Ybo, Yio

from dataviva.utils.cached_query import cached_query, make_cache_key, api_cache_key

from dataviva.utils.gzip_data import gzipped

from dataviva.profiles import models as profileModels

import time

mod = Blueprint('profiles', __name__, url_prefix='/profiles')

@mod.before_request
def before_request():
    g.page_type = mod.name
    g.path = request.path

    g.color = "#e0902d"

@mod.route('/')
@mod.route('/<category>/select/')
@view_cache.cached(timeout=604800, key_prefix=make_cache_key)
def index(category = None, id = None):
    selector = category

    article = None

    if category == "cbo":
        article = gettext(u"an occupation")
    elif category == "cnae":
        article = gettext(u"an industry")
    elif category == "hs":
        article = gettext(u"a product")
    elif category == "bra":
        article = gettext(u"a location")
    elif category == "wld":
        article = gettext(u"a country")
    elif category == "university":
        article = gettext(u"a university")
    elif category == "course_hedu":
        article = gettext(u"a course")
    elif category == "course_sc":
        article = gettext(u"a course")

    if category:
        page = "general/selector.html"
    else:
        page = "profiles/index.html"

    return render_template(page,
        selector = selector,
        article = article)

@mod.route('/<category>/<id>/')
# @view_cache.cached(timeout=604800, key_prefix=api_cache_key("profiles"))
@gzipped
def profiles(category = None, id = None):

    if category == "bra" and id == "all":
        item = Wld.query.get("sabra")
    else:
        item = globals()[category.capitalize()].query.get_or_404(id)

    profile = getattr(profileModels, category.capitalize())(category, item)
    builds = profile.builds()

    start = request.args.get("app", 1)

    return render_template("profiles/profile.html",
                category=category, item=item,
                starting_app = start, builds=builds)
<commit_msg>added info for profile landing page<commit_after># -*- coding: utf-8 -*-
from flask import Blueprint, request, render_template, g, url_for
from flask.ext.babel import gettext
from sqlalchemy import func, distinct
from werkzeug import urls
import time

from dataviva import db, view_cache
from dataviva.attrs import models as attrs
from dataviva.rais import models as rais
from dataviva.secex import models as secex

from dataviva.general.models import Plan
from dataviva.attrs.models import Bra, Cnae, Cbo, Hs, Wld, University, Course_hedu, Course_sc
from dataviva.secex.models import Ymb, Ymp, Ymw
from dataviva.rais.models import Ybi, Ybo, Yio, Yi, Yo
from dataviva.hedu.models import Yu, Yc_hedu
from dataviva.sc.models import Yc_sc

from dataviva.utils.cached_query import cached_query, make_cache_key, api_cache_key
from dataviva.utils.gzip_data import gzipped
from dataviva.profiles import models as profileModels

from dataviva import __year_range__
from dataviva.stats.util import parse_year

mod = Blueprint('profiles', __name__, url_prefix='/profiles')

@mod.before_request
def before_request():
    g.page_type = mod.name
    g.path = request.path

    g.color = "#e0902d"

@mod.route('/')
@view_cache.cached(timeout=604800, key_prefix=make_cache_key)
def index():

    profile_types = []

    # Bra
    most_recent_year = parse_year(__year_range__["secex"][-1])
    top = Ymb.query.filter_by(year=most_recent_year, month=0, bra_id_len=9).order_by(Ymb.export_val.desc()).limit(10).all()
    top = [t.bra for t in top]
    profile_types.append({
        "summary": "Showing exports, employment and education data, statistics and visualizations about the chosen Brazilian location.",
        "top": top,
        "top_title": gettext(u"Top Locations"),
        "type": "bra"
    })

    # Occupations
    most_recent_year = parse_year(__year_range__["rais"][-1])
    top = Yo.query.filter_by(year=most_recent_year, cbo_id_len=4).order_by(Yo.num_emp.desc()).limit(10).all()
    top = [t.cbo for t in top]
    profile_types.append({
        "summary": "Showing industries and locations that employ the selected occupation.",
        "top": top,
        "top_title": gettext(u"Top Occupations"),
        "type": "cbo"
    })

    # Industries
    top = Yi.query.filter_by(year=most_recent_year, cnae_id_len=6).order_by(Yi.num_emp.desc()).limit(10).all()
    top = [t.cnae for t in top]
    profile_types.append({
        "summary": "Showing the occupations and locations with employees in the selected industry.",
        "top": top,
        "top_title": gettext(u"Top Industries"),
        "type": "cnae"
    })

    # Prods
    most_recent_year = parse_year(__year_range__["secex"][-1])
    top = Ymp.query.filter_by(year=most_recent_year, month=0, hs_id_len=6).order_by(Ymp.export_val.desc()).limit(10).all()
    top = [t.hs for t in top]
    profile_types.append({
        "summary": "Showing locations in Brazil that export and import the selected product and their destinations and origins.",
        "top": top,
        "top_title": gettext(u"Top Products"),
        "type": "hs"
    })

    # Countries
    top = Ymw.query.filter_by(year=most_recent_year, month=0, wld_id_len=5).order_by(Ymw.export_val.desc()).limit(10).all()
    top = [t.wld for t in top]
    profile_types.append({
        "summary": "Showing locations in brazil that trade with the selected country and the products they export and import from them.",
        "top": top,
        "top_title": gettext(u"Top Trade Partners"),
        "type": "wld"
    })

    # Universities
    most_recent_year = parse_year(__year_range__["hedu"][-1])
    top = Yu.query.filter_by(year=most_recent_year).order_by(Yu.enrolled.desc()).limit(10).all()
    top = [t.university for t in top]
    profile_types.append({
        "summary": "Showing the majors found in the selected univserity.",
        "top": top,
        "top_title": gettext(u"Top Universities"),
        "type": "university"
    })

    # Majors
    top = Yc_hedu.query.filter_by(year=most_recent_year).order_by(Yc_hedu.enrolled.desc()).limit(10).all()
    top = [t.course_hedu for t in top]
    profile_types.append({
        "summary": "Showing the university and locations in Brazil where the selected major is found.",
        "top": top,
        "top_title": gettext(u"Top Majors"),
        "type": "course_hedu"
    })

    # Vocations
    most_recent_year = parse_year(__year_range__["sc"][-1])
    top = Yc_sc.query.filter_by(year=most_recent_year).order_by(Yc_sc.enrolled.desc()).limit(10).all()
    top = [t.course_sc for t in top]
    profile_types.append({
        "summary": "Showing ...",
        "top": top,
        "top_title": gettext(u"Top Vocations"),
        "type": "course_sc"
    })

    return render_template("profiles/index.html", profile_types=profile_types)

@mod.route('/<category>/select/')
@view_cache.cached(timeout=604800, key_prefix=make_cache_key)
def index_selector(category = None, id = None):
    selector = category

    article = None

    if category == "cbo":
        article = gettext(u"an occupation")
    elif category == "cnae":
        article = gettext(u"an industry")
    elif category == "hs":
        article = gettext(u"a product")
    elif category == "bra":
        article = gettext(u"a location")
    elif category == "wld":
        article = gettext(u"a country")
    elif category == "university":
        article = gettext(u"a university")
    elif category == "course_hedu":
        article = gettext(u"a course")
    elif category == "course_sc":
        article = gettext(u"a course")

    if category:
        page = "general/selector.html"
    else:
        page = "profiles/index.html"

    return render_template(page,
        selector = selector,
        article = article)

@mod.route('/<category>/<id>/')
# @view_cache.cached(timeout=604800, key_prefix=api_cache_key("profiles"))
@gzipped
def profiles(category = None, id = None):

    if category == "bra" and id == "all":
        item = Wld.query.get("sabra")
    else:
        item = globals()[category.capitalize()].query.get_or_404(id)

    profile = getattr(profileModels, category.capitalize())(category, item)
    builds = profile.builds()

    start = request.args.get("app", 1)

    return render_template("profiles/profile.html",
                category=category, item=item,
                starting_app = start, builds=builds)
<|endoftext|>