<commit_before># 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.

"""Load data into a repository."""

import functools
import os
import sys
import warnings

from cliff import command
import subunit
import testtools

from stestr import output
from stestr.repository import abstract as repository
from stestr.repository import util
from stestr import results
from stestr import subunit_trace
from stestr import user_config
from stestr import utils

class Load(command.Command):
    """Load a subunit stream into a repository.

    Failing tests are shown on the console and a summary of the stream
    is printed at the end.

    Without --subunit, the process exit code will be non-zero if the test
    run was not successful. With --subunit, the process exit code is
    non-zero if the subunit stream could not be generated successfully.
    The test results and run status are included in the subunit stream, so
    the stream should be used to determining the result of the run instead
    of the exit code when using the --subunit flag.
    """

    def get_parser(self, prog_name):
        parser = super(Load, self).get_parser(prog_name)
        parser.add_argument("files", nargs="*", default=False,
                            help="The subunit v2 stream files to load into the"
                            " repository")
        parser.add_argument("--partial", action="store_true",
                            default=False,
                            help="DEPRECATED: The stream being loaded was a "
                            "partial run. This option is deprecated and no "
                            "does anything. It will be removed in the future")
        parser.add_argument("--force-init", action="store_true",
                            default=False,
                            help="Initialise the repository if it does not "
                            "exist already")
        parser.add_argument("--subunit", action="store_true",
                            default=False,
                            help="Display results in subunit format.")
        parser.add_argument("--id", "-i", default=None,
                            help="Append the stream into an existing entry in "
                            "the repository")
        parser.add_argument("--subunit-trace", action='store_true',
                            default=False,
                            help="Display the loaded stream through the "
                            "subunit-trace output filter")
        parser.add_argument('--color', action='store_true', default=False,
                            help='Enable color output in the subunit-trace '
                            'output, if subunit-trace output is enabled. If '
                            'subunit-trace is disable this does nothing.')
        parser.add_argument('--abbreviate', action='store_true',
                            dest='abbreviate',
                            help='Print one character status for each test')
        parser.add_argument('--suppress-attachments', action='store_true',
                            dest='suppress_attachments',
                            help='If set do not print stdout or stderr '
                            'attachment contents on a successful test '
                            'execution')
        parser.add_argument('--all-attachments', action='store_true',
                            dest='all_attachments',
                            help='If set print all text attachment contents on'
                            ' a successful test execution')
        return parser

    def take_action(self, parsed_args):
        user_conf = user_config.get_user_config(self.app_args.user_config)
        args = parsed_args
        if args.suppress_attachments and args.all_attachments:
            msg = ("The --suppress-attachments and --all-attachments "
                   "options are mutually exclusive, you can not use both "
                   "at the same time")
            print(msg)
            sys.exit(1)
        if getattr(user_conf, 'load', False):
            force_init = args.force_init or user_conf.load.get('force-init',
                                                               False)
            pretty_out = args.subunit_trace or user_conf.load.get(
                'subunit-trace', False)
            color = args.color or user_conf.load.get('color', False)
            abbreviate = args.abbreviate or user_conf.load.get('abbreviate',
                                                               False)
            suppress_attachments_conf = user_conf.run.get(
                'suppress-attachments', False)
            all_attachments_conf = user_conf.run.get(
                'all-attachments', False)
            if not args.suppress_attachments and not args.all_attachments:
                suppress_attachments = suppress_attachments_conf
                all_attachments = all_attachments_conf
            elif args.suppress_attachments:
                all_attachments = False
                suppress_attachments = args.suppress_attachments
            elif args.all_attachments:
                suppress_attachments = False
                all_attachments = args.all_attachments
        else:
            force_init = args.force_init
            pretty_out = args.subunit_trace
            color = args.color
            abbreviate = args.abbreviate
            suppress_attachments = args.suppress_attachments
            all_attachments = args.all_attachments
        verbose_level = self.app.options.verbose_level
        stdout = open(os.devnull, 'w') if verbose_level == 0 else sys.stdout
        load(repo_type=self.app_args.repo_type,
             repo_url=self.app_args.repo_url,
             partial=args.partial, subunit_out=args.subunit,
             force_init=force_init, streams=args.files,
             pretty_out=pretty_out, color=color,
             stdout=stdout, abbreviate=abbreviate,
             suppress_attachments=suppress_attachments, serial=True,
             all_attachments=all_attachments)

def load(force_init=False, in_streams=None,
         partial=False, subunit_out=False, repo_type='file', repo_url=None,
         run_id=None, streams=None, pretty_out=False, color=False,
         stdout=sys.stdout, abbreviate=False, suppress_attachments=False,
         serial=False, all_attachments=False):
    """Load subunit streams into a repository

    This function will load subunit streams into the repository. It will
    output to STDOUT the results from the input stream. Internally this is
    used by the run command to both output the results as well as store the
    result in the repository.

    :param bool force_init: Initialize the specifiedrepository if it hasn't
        been created.
    :param list in_streams: A list of file objects that will be saved into the
        repository
    :param bool partial: DEPRECATED: Specify the input is a partial stream.
        This option is deprecated and no longer does anything. It will be
        removed in the future.
    :param bool subunit_out: Output the subunit stream to stdout
    :param str repo_type: This is the type of repository to use. Valid choices
        are 'file' and 'sql'.
    :param str repo_url: The url of the repository to use.
    :param run_id: The optional run id to save the subunit stream to.
    :param list streams: A list of file paths to read for the input streams.
    :param bool pretty_out: Use the subunit-trace output filter for the loaded
        stream.
    :param bool color: Enabled colorized subunit-trace output
    :param file stdout: The output file to write all output to. By default
        this is sys.stdout
    :param bool abbreviate: Use abbreviated output if set true
    :param bool suppress_attachments: When set true attachments subunit_trace
        will not print attachments on successful test execution.
    :param bool all_attachments: When set true subunit_trace will print all
        text attachments on successful test execution.

    :return return_code: The exit code for the command. 0 for success and > 0
        for failures.
    :rtype: int
    """
    if partial:
        warnings.warn('The partial flag is deprecated and has no effect '
                      'anymore')

    try:
        repo = util.get_repo_open(repo_type, repo_url)
    except repository.RepositoryNotFound:
        if force_init:
            repo = util.get_repo_initialise(repo_type, repo_url)
        else:
            raise
    # Not a full implementation of TestCase, but we only need to iterate
    # back to it. Needs to be a callable - its a head fake for
    # testsuite.add.
    if in_streams:
        streams = utils.iter_streams(in_streams, 'subunit')
    elif streams:
        opener = functools.partial(open, mode='rb')
        streams = map(opener, streams)
    else:
        streams = [sys.stdin]

    def mktagger(pos, result):
        return testtools.StreamTagger([result], add=['worker-%d' % pos])

    def make_tests():
        for pos, stream in enumerate(streams):
            # Calls StreamResult API.
            case = subunit.ByteStreamToStreamResult(
                stream, non_subunit_name='stdout')
            decorate = functools.partial(mktagger, pos)
            case = testtools.DecorateTestCaseResult(case, decorate)
            yield (case, str(pos))
    if not run_id:
        inserter = repo.get_inserter()
    else:
        inserter = repo.get_inserter(run_id=run_id)

    retval = 0
    if serial:
        for stream in streams:
            # Calls StreamResult API.
            case = subunit.ByteStreamToStreamResult(
                stream, non_subunit_name='stdout')
            result = _load_case(inserter, repo, case, subunit_out, pretty_out,
                                color, stdout, abbreviate,
                                suppress_attachments, all_attachments)
            if result or retval:
                retval = 1
            else:
                retval = 0
    else:
        case = testtools.ConcurrentStreamTestSuite(make_tests)
        retval = _load_case(inserter, repo, case, subunit_out, pretty_out,
                            color, stdout, abbreviate, suppress_attachments,
                            all_attachments)

    return retval

def _load_case(inserter, repo, case, subunit_out, pretty_out,
               color, stdout, abbreviate, suppress_attachments,
               all_attachments):
    if subunit_out:
        output_result, summary_result = output.make_result(inserter.get_id,
                                                           output=stdout)
    elif pretty_out:
        outcomes = testtools.StreamToDict(
            functools.partial(subunit_trace.show_outcome, stdout,
                              enable_color=color, abbreviate=abbreviate,
                              suppress_attachments=suppress_attachments,
                              all_attachments=all_attachments))
        summary_result = testtools.StreamSummary()
        output_result = testtools.CopyStreamResult([outcomes, summary_result])
        output_result = testtools.StreamResultRouter(output_result)
        cat = subunit.test_results.CatFiles(stdout)
        output_result.add_rule(cat, 'test_id', test_id=None)
    else:
        try:
            previous_run = repo.get_latest_run()
        except KeyError:
            previous_run = None
        output_result = results.CLITestResult(
            inserter.get_id, stdout, previous_run)
        summary_result = output_result.get_summary()
    result = testtools.CopyStreamResult([inserter, output_result])
    result.startTestRun()
    try:
        case.run(result)
    finally:
        result.stopTestRun()
    if pretty_out and not subunit_out:
        start_times = []
        stop_times = []
        for worker in subunit_trace.RESULTS:
            start_times += [
                x['timestamps'][0] for x in subunit_trace.RESULTS[worker]]
            stop_times += [
                x['timestamps'][1] for x in subunit_trace.RESULTS[worker]]
        if not start_times or not stop_times:
            sys.stderr.write("\nNo tests were successful during the run")
            return 1
        start_time = min(start_times)
        stop_time = max(stop_times)
        elapsed_time = stop_time - start_time
        subunit_trace.print_fails(stdout)
        subunit_trace.print_summary(stdout, elapsed_time)
    if not results.wasSuccessful(summary_result):
        return 1
    else:
        return 0
<commit_msg>Handle NoneType timestamps in subunit results<commit_after># 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.

"""Load data into a repository."""

import functools
import os
import sys
import warnings

from cliff import command
import subunit
import testtools

from stestr import output
from stestr.repository import abstract as repository
from stestr.repository import util
from stestr import results
from stestr import subunit_trace
from stestr import user_config
from stestr import utils

class Load(command.Command):
    """Load a subunit stream into a repository.

    Failing tests are shown on the console and a summary of the stream
    is printed at the end.

    Without --subunit, the process exit code will be non-zero if the test
    run was not successful. With --subunit, the process exit code is
    non-zero if the subunit stream could not be generated successfully.
    The test results and run status are included in the subunit stream, so
    the stream should be used to determining the result of the run instead
    of the exit code when using the --subunit flag.
    """

    def get_parser(self, prog_name):
        parser = super(Load, self).get_parser(prog_name)
        parser.add_argument("files", nargs="*", default=False,
                            help="The subunit v2 stream files to load into the"
                            " repository")
        parser.add_argument("--partial", action="store_true",
                            default=False,
                            help="DEPRECATED: The stream being loaded was a "
                            "partial run. This option is deprecated and no "
                            "does anything. It will be removed in the future")
        parser.add_argument("--force-init", action="store_true",
                            default=False,
                            help="Initialise the repository if it does not "
                            "exist already")
        parser.add_argument("--subunit", action="store_true",
                            default=False,
                            help="Display results in subunit format.")
        parser.add_argument("--id", "-i", default=None,
                            help="Append the stream into an existing entry in "
                            "the repository")
        parser.add_argument("--subunit-trace", action='store_true',
                            default=False,
                            help="Display the loaded stream through the "
                            "subunit-trace output filter")
        parser.add_argument('--color', action='store_true', default=False,
                            help='Enable color output in the subunit-trace '
                            'output, if subunit-trace output is enabled. If '
                            'subunit-trace is disable this does nothing.')
        parser.add_argument('--abbreviate', action='store_true',
                            dest='abbreviate',
                            help='Print one character status for each test')
        parser.add_argument('--suppress-attachments', action='store_true',
                            dest='suppress_attachments',
                            help='If set do not print stdout or stderr '
                            'attachment contents on a successful test '
                            'execution')
        parser.add_argument('--all-attachments', action='store_true',
                            dest='all_attachments',
                            help='If set print all text attachment contents on'
                            ' a successful test execution')
        return parser

    def take_action(self, parsed_args):
        user_conf = user_config.get_user_config(self.app_args.user_config)
        args = parsed_args
        if args.suppress_attachments and args.all_attachments:
            msg = ("The --suppress-attachments and --all-attachments "
                   "options are mutually exclusive, you can not use both "
                   "at the same time")
            print(msg)
            sys.exit(1)
        if getattr(user_conf, 'load', False):
            force_init = args.force_init or user_conf.load.get('force-init',
                                                               False)
            pretty_out = args.subunit_trace or user_conf.load.get(
                'subunit-trace', False)
            color = args.color or user_conf.load.get('color', False)
            abbreviate = args.abbreviate or user_conf.load.get('abbreviate',
                                                               False)
            suppress_attachments_conf = user_conf.run.get(
                'suppress-attachments', False)
            all_attachments_conf = user_conf.run.get(
                'all-attachments', False)
            if not args.suppress_attachments and not args.all_attachments:
                suppress_attachments = suppress_attachments_conf
                all_attachments = all_attachments_conf
            elif args.suppress_attachments:
                all_attachments = False
                suppress_attachments = args.suppress_attachments
            elif args.all_attachments:
                suppress_attachments = False
                all_attachments = args.all_attachments
        else:
            force_init = args.force_init
            pretty_out = args.subunit_trace
            color = args.color
            abbreviate = args.abbreviate
            suppress_attachments = args.suppress_attachments
            all_attachments = args.all_attachments
        verbose_level = self.app.options.verbose_level
        stdout = open(os.devnull, 'w') if verbose_level == 0 else sys.stdout
        load(repo_type=self.app_args.repo_type,
             repo_url=self.app_args.repo_url,
             partial=args.partial, subunit_out=args.subunit,
             force_init=force_init, streams=args.files,
             pretty_out=pretty_out, color=color,
             stdout=stdout, abbreviate=abbreviate,
             suppress_attachments=suppress_attachments, serial=True,
             all_attachments=all_attachments)

def load(force_init=False, in_streams=None,
         partial=False, subunit_out=False, repo_type='file', repo_url=None,
         run_id=None, streams=None, pretty_out=False, color=False,
         stdout=sys.stdout, abbreviate=False, suppress_attachments=False,
         serial=False, all_attachments=False):
    """Load subunit streams into a repository

    This function will load subunit streams into the repository. It will
    output to STDOUT the results from the input stream. Internally this is
    used by the run command to both output the results as well as store the
    result in the repository.

    :param bool force_init: Initialize the specifiedrepository if it hasn't
        been created.
    :param list in_streams: A list of file objects that will be saved into the
        repository
    :param bool partial: DEPRECATED: Specify the input is a partial stream.
        This option is deprecated and no longer does anything. It will be
        removed in the future.
    :param bool subunit_out: Output the subunit stream to stdout
    :param str repo_type: This is the type of repository to use. Valid choices
        are 'file' and 'sql'.
    :param str repo_url: The url of the repository to use.
    :param run_id: The optional run id to save the subunit stream to.
    :param list streams: A list of file paths to read for the input streams.
    :param bool pretty_out: Use the subunit-trace output filter for the loaded
        stream.
    :param bool color: Enabled colorized subunit-trace output
    :param file stdout: The output file to write all output to. By default
        this is sys.stdout
    :param bool abbreviate: Use abbreviated output if set true
    :param bool suppress_attachments: When set true attachments subunit_trace
        will not print attachments on successful test execution.
    :param bool all_attachments: When set true subunit_trace will print all
        text attachments on successful test execution.

    :return return_code: The exit code for the command. 0 for success and > 0
        for failures.
    :rtype: int
    """
    if partial:
        warnings.warn('The partial flag is deprecated and has no effect '
                      'anymore')

    try:
        repo = util.get_repo_open(repo_type, repo_url)
    except repository.RepositoryNotFound:
        if force_init:
            repo = util.get_repo_initialise(repo_type, repo_url)
        else:
            raise
    # Not a full implementation of TestCase, but we only need to iterate
    # back to it. Needs to be a callable - its a head fake for
    # testsuite.add.
    if in_streams:
        streams = utils.iter_streams(in_streams, 'subunit')
    elif streams:
        opener = functools.partial(open, mode='rb')
        streams = map(opener, streams)
    else:
        streams = [sys.stdin]

    def mktagger(pos, result):
        return testtools.StreamTagger([result], add=['worker-%d' % pos])

    def make_tests():
        for pos, stream in enumerate(streams):
            # Calls StreamResult API.
            case = subunit.ByteStreamToStreamResult(
                stream, non_subunit_name='stdout')
            decorate = functools.partial(mktagger, pos)
            case = testtools.DecorateTestCaseResult(case, decorate)
            yield (case, str(pos))
    if not run_id:
        inserter = repo.get_inserter()
    else:
        inserter = repo.get_inserter(run_id=run_id)

    retval = 0
    if serial:
        for stream in streams:
            # Calls StreamResult API.
            case = subunit.ByteStreamToStreamResult(
                stream, non_subunit_name='stdout')
            result = _load_case(inserter, repo, case, subunit_out, pretty_out,
                                color, stdout, abbreviate,
                                suppress_attachments, all_attachments)
            if result or retval:
                retval = 1
            else:
                retval = 0
    else:
        case = testtools.ConcurrentStreamTestSuite(make_tests)
        retval = _load_case(inserter, repo, case, subunit_out, pretty_out,
                            color, stdout, abbreviate, suppress_attachments,
                            all_attachments)

    return retval

def _load_case(inserter, repo, case, subunit_out, pretty_out,
               color, stdout, abbreviate, suppress_attachments,
               all_attachments):
    if subunit_out:
        output_result, summary_result = output.make_result(inserter.get_id,
                                                           output=stdout)
    elif pretty_out:
        outcomes = testtools.StreamToDict(
            functools.partial(subunit_trace.show_outcome, stdout,
                              enable_color=color, abbreviate=abbreviate,
                              suppress_attachments=suppress_attachments,
                              all_attachments=all_attachments))
        summary_result = testtools.StreamSummary()
        output_result = testtools.CopyStreamResult([outcomes, summary_result])
        output_result = testtools.StreamResultRouter(output_result)
        cat = subunit.test_results.CatFiles(stdout)
        output_result.add_rule(cat, 'test_id', test_id=None)
    else:
        try:
            previous_run = repo.get_latest_run()
        except KeyError:
            previous_run = None
        output_result = results.CLITestResult(
            inserter.get_id, stdout, previous_run)
        summary_result = output_result.get_summary()
    result = testtools.CopyStreamResult([inserter, output_result])
    result.startTestRun()
    try:
        case.run(result)
    finally:
        result.stopTestRun()
    if pretty_out and not subunit_out:
        start_times = []
        stop_times = []
        for worker in subunit_trace.RESULTS:
            for test in subunit_trace.RESULTS[worker]:
                if not test['timestamps'][0] or not test['timestamps'][1]:
                    continue
                start_times.append(test['timestamps'][0])
                stop_times.append(test['timestamps'][1])
        if not start_times or not stop_times:
            sys.stderr.write("\nNo tests were successful during the run")
            return 1
        start_time = min(start_times)
        stop_time = max(stop_times)
        elapsed_time = stop_time - start_time
        subunit_trace.print_fails(stdout)
        subunit_trace.print_summary(stdout, elapsed_time)
    if not results.wasSuccessful(summary_result):
        return 1
    else:
        return 0
<|endoftext|>


<commit_before>from pymks.stats import correlate
from sklearn.base import BaseEstimator
from sklearn.decomposition import TruncatedSVD
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
import numpy as np

class MKSHomogenizationModel(BaseEstimator):

    '''
    The `MKSHomogenizationModel` takes in microstructures and a their
    associated macroscopic property, and created a low dimensional structure
    property linkage. The `MKSHomogenizationModel` model is designed to
    integrate with dimensionality reduction techniques and predictive models.

    Below is an examlpe of using MKSHomogenizationModel to predict the type of
    microstructure using PCA and Logistic Regression.

    >>> n_states = 3
    >>> domain = [-1, 1]

    >>> from .bases import LegendreBasis
    >>> basis = LegendreBasis(n_states=n_states, domain=domain)
    >>> from sklearn.decomposition import PCA
    >>> from sklearn.linear_model import LogisticRegression
    >>> reducer = PCA(n_components=3)
    >>> linker = LogisticRegression()
    >>> model = MKSHomogenizationModel(basis=basis, dimension_reducer=reducer,
    ...                                property_linker=linker)

    >>> from .datasets import make_cahn_hilliard
    >>> X0, X1 = make_cahn_hilliard(n_samples=25)
    >>> y0 = np.zeros(X0.shape[0])
    >>> y1 = np.ones(X1.shape[0])

    >>> X = np.concatenate((X0, X1))
    >>> y = np.concatenate((y0, y1))

    >>> model.fit(X, y)

    >>> X0_test, X1_test = make_cahn_hilliard(n_samples=3)
    >>> y0_test = model.predict(X0_test)
    >>> y1_test = model.predict(X1_test)
    >>> assert np.allclose(y0_test, [0, 0, 0])
    >>> assert np.allclose(y1_test, [1, 1, 1])

    '''

    def __init__(self, basis, n_components=None, poly_order=1,
                 dimension_reducer=None, property_linker=None):
        '''
        Create an instance of a `MKSHomogenizationModel`.

        Args:
            basis: an instance of a bases class.
            dimension_reducer: an instance of a dimensionality reduction
                class with a fit_transform method.
            property_linker: an instance for a machine learning class with fit
                and predict methods.
        '''

        self.basis = basis
        self.dimension_reducer = dimension_reducer
        if self.dimension_reducer is None:
            self.dimension_reducer = TruncatedSVD()
        if n_components is None:
            n_components = self.dimension_reducer.n_components
        if property_linker is None:
            property_linker = LinearRegression()
        self.linker = Pipeline([('poly', PolynomialFeatures(degree=1)),
                                ('linker', property_linker)])
        self._check_methods
        self.poly_order = poly_order
        self.n_components = n_components

    @property
    def n_components(self):
        return self._n_components

    @n_components.setter
    def n_components(self, value):
        self._n_components = value
        self.dimension_reducer.n_components = value

    @property
    def poly_order(self):
        return self._poly_order

    @poly_order.setter
    def poly_order(self, value):
        self._poly_order = value
        self.linker.set_params(poly__degree=value)

    def _check_methods(self):
        '''
        Helper function to make check that the dimensionality reduction and
        property linking methods have the appropriate methods.
        '''
        if not callable(getattr(self.dimension_reducer,
                                "fit_transform", None)):
            raise RuntimeError(
                "dimension_reducer does not have fit_transform() method.")
        if not callable(getattr(self.dimension_reducer, "transform", None)):
            raise RuntimeError(
                "dimension_reducer does not have transform() method.")
        if not callable(getattr(self.linker, "fit", None)):
            raise RuntimeError(
                "property_linker does not have fit() method.")
        if not callable(getattr(self.linker, "predict", None)):
            raise RuntimeError(
                "property_linker does not have predict() method.")

    def fit(self, X, y, X_reduce_label=None,
            periodic_axes=[], probability_mask=None, size=None):
        '''
        Fits data by calculating 2-point statistics from X, preforming
        dimension reduction using dimension_reducer, and fitting the reduced
        data with the property_linker.

        >>> from sklearn.decomposition import PCA
        >>> from sklearn.linear_model import LinearRegression
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> from pymks.stats import correlate

        >>> reducer = PCA(n_components=2)
        >>> linker = LinearRegression()
        >>> dbasis = DiscreteIndicatorBasis(n_states=2, domain=[0, 1])
        >>> model = MKSHomogenizationModel(dbasis,
        ...                                dimension_reducer=reducer,
        ...                                property_linker=linker)
        >>> np.random.seed(99)
        >>> X = np.random.randint(2, size=(3, 15))
        >>> y = np.array([1, 2, 3])
        >>> model.fit(X, y)
        >>> X_ = dbasis.discretize(X)
        >>> X_corr = correlate(X_)
        >>> X_reshaped = X_corr.reshape((X_corr.shape[0], X_corr[0].size))
        >>> X_pca = reducer.fit_transform(X_reshaped - np.mean(X_reshaped,
        ...                               axis=1)[:, None])
        >>> assert np.allclose(model.fit_data, X_pca)

        Args:
          X: The microstructure, an `(S, N, ...)` shaped
             array where `S` is the number of samples and `N` is the
             spatial discretization.
          y: The material property associated with `X`.
          reducer_label: label for X used during the fit_transform method
             for the `dimension_reducer`.
          periodic_axes: axes that are periodic. (0, 2) would indicate
              that axes x and z are periodic in a 3D microstrucure.
          probability_mask: array with same shape as X used to assign a
              confidence value for each data point.
        '''
        if size is not None:
            new_shape = (X.shape[0],) + size
            X = X.reshape(new_shape)
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.fit_transform(X_preped,
                                                         X_reduce_label)
        self.linker.fit(X_reduced, y)
        self.fit_data = X_reduced

    def predict(self, X, periodic_axes=[], probability_mask=None):
        '''Predicts macroscopic property for the microstructures `X`.

        >>> from sklearn.manifold import LocallyLinearEmbedding
        >>> from sklearn.linear_model import BayesianRidge
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> np.random.seed(99)
        >>> X = np.random.randint(2, size=(50, 100))
        >>> y = np.random.random(50)
        >>> reducer = LocallyLinearEmbedding()
        >>> linker = BayesianRidge()
        >>> basis = DiscreteIndicatorBasis(2, domain=[0, 1])
        >>> model = MKSHomogenizationModel(basis, n_components=2,
        ...                                dimension_reducer=reducer,
        ...                                property_linker=linker)
        >>> model.fit(X, y)
        >>> X_test = np.random.randint(2, size=(1, 100))
        >>> assert np.allclose(model.predict(X_test), 0.53031958)

        Args:
            X: The microstructre, an `(S, N, ...)` shaped array where `S` is
               the number of samples and `N` is the spatial discretization.
            periodic_axes: axes that are periodic. (0, 2) would indicate
                that axes x and z are periodic in a 3D microstrucure.
            probability_mask: array with same shape as X used to assign a
                confidence value for each data point.
        Returns:
            The predicted macroscopic property for `X`.
        '''
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.transform(X_preped)
        self.predict_data = X_reduced
        return self.linker.predict(X_reduced)

    def _X_prep(self, X, periodic_axes=[], probability_mask=None):
        '''
        Helper function used to calculated 2-point statistics from `X` and
        reshape them appropriately for fit and predict methods.

        >>> from sklearn.manifold import Isomap
        >>> from sklearn.linear_model import ARDRegression
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> reducer = Isomap()
        >>> linker = ARDRegression()
        >>> basis = DiscreteIndicatorBasis(2, [0, 1])
        >>> model = MKSHomogenizationModel(basis, reducer, linker)
        >>> X = np.array([[0, 1],
        ...               [1, 0]])
        >>> X_prep = model._X_prep(X, [], None)
        >>> X_test = np.array([[-1 / 6., -1 / 6., -1 / 6.,
        ...                      1 / 3., 1 / 3., -1 / 6.],
        ...                    [-1 / 3., -1 / 3., 2 / 3.,
        ...                      1 / 6., 1 / 6., -1 / 3.]])
        >>> assert np.allclose(X_test, X_prep)

        Args:
            X: The microstructre, an `(S, N, ...)` shaped array where `S` is
               the number of samples and `N` is the spatial discretization.
            periodic_axes: axes that are periodic. (0, 2) would indicate
                that axes x and z are periodic in a 3D microstrucure.
            probability_mask: array with same shape as X used to assign a
                confidence value for each data point.
        Returns:
           Spatial correlations for each sample formated with dimensions
           (n_samples, n_features).
        '''
        X_ = self.basis.discretize(X)
        X_corr = correlate(X_, periodic_axes=periodic_axes,
                           probability_mask=probability_mask)
        X_reshaped = X_corr.reshape((X_corr.shape[0], X_corr[0].size))
        return X_reshaped - np.mean(X_reshaped, axis=1)[:, None]

    def score(self, X, y, periodic_axes=[], probability_mask=None):
        '''
        The score function for the MKSHomogenizationModel. It formats the
        data and uses the score method from the property_linker.
        '''
        if not callable(getattr(self.linker, "score", None)):
            raise RuntimeError(
                "property_linker does not have score() method.")
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.transform(X_preped)
        return self.linker.score(X_reduced, y)
<commit_msg>Change poly_order to degree<commit_after>from pymks.stats import correlate
from sklearn.base import BaseEstimator
from sklearn.decomposition import TruncatedSVD
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
import numpy as np

class MKSHomogenizationModel(BaseEstimator):

    '''
    The `MKSHomogenizationModel` takes in microstructures and a their
    associated macroscopic property, and created a low dimensional structure
    property linkage. The `MKSHomogenizationModel` model is designed to
    integrate with dimensionality reduction techniques and predictive models.

    Below is an examlpe of using MKSHomogenizationModel to predict the type of
    microstructure using PCA and Logistic Regression.

    >>> n_states = 3
    >>> domain = [-1, 1]

    >>> from .bases import LegendreBasis
    >>> basis = LegendreBasis(n_states=n_states, domain=domain)
    >>> from sklearn.decomposition import PCA
    >>> from sklearn.linear_model import LogisticRegression
    >>> reducer = PCA(n_components=3)
    >>> linker = LogisticRegression()
    >>> model = MKSHomogenizationModel(basis=basis, dimension_reducer=reducer,
    ...                                property_linker=linker)

    >>> from .datasets import make_cahn_hilliard
    >>> X0, X1 = make_cahn_hilliard(n_samples=25)
    >>> y0 = np.zeros(X0.shape[0])
    >>> y1 = np.ones(X1.shape[0])

    >>> X = np.concatenate((X0, X1))
    >>> y = np.concatenate((y0, y1))

    >>> model.fit(X, y)

    >>> X0_test, X1_test = make_cahn_hilliard(n_samples=3)
    >>> y0_test = model.predict(X0_test)
    >>> y1_test = model.predict(X1_test)
    >>> assert np.allclose(y0_test, [0, 0, 0])
    >>> assert np.allclose(y1_test, [1, 1, 1])

    '''

    def __init__(self, basis, n_components=None, degree=1,
                 dimension_reducer=None, property_linker=None):
        '''
        Create an instance of a `MKSHomogenizationModel`.

        Args:
            basis: an instance of a bases class.
            dimension_reducer: an instance of a dimensionality reduction
                class with a fit_transform method.
            property_linker: an instance for a machine learning class with fit
                and predict methods.
            n_components: number of components kept by the dimension_reducer
            degree: degree of the polynomial used by property_linker.
        '''

        self.basis = basis
        self.dimension_reducer = dimension_reducer
        if self.dimension_reducer is None:
            self.dimension_reducer = TruncatedSVD()
        if n_components is None:
            n_components = self.dimension_reducer.n_components
        if property_linker is None:
            property_linker = LinearRegression()
        self.linker = Pipeline([('poly', PolynomialFeatures(degree=degree)),
                                ('linker', property_linker)])
        self._check_methods
        self.degree = degree
        self.n_components = n_components

    @property
    def n_components(self):
        return self._n_components

    @n_components.setter
    def n_components(self, value):
        self._n_components = value
        self.dimension_reducer.n_components = value

    @property
    def degree(self):
        return self._degree

    @degree.setter
    def degree(self, value):
        self._degree = value
        self.linker.set_params(poly__degree=value)

    def _check_methods(self):
        '''
        Helper function to make check that the dimensionality reduction and
        property linking methods have the appropriate methods.
        '''
        if not callable(getattr(self.dimension_reducer,
                                "fit_transform", None)):
            raise RuntimeError(
                "dimension_reducer does not have fit_transform() method.")
        if not callable(getattr(self.dimension_reducer, "transform", None)):
            raise RuntimeError(
                "dimension_reducer does not have transform() method.")
        if not callable(getattr(self.linker, "fit", None)):
            raise RuntimeError(
                "property_linker does not have fit() method.")
        if not callable(getattr(self.linker, "predict", None)):
            raise RuntimeError(
                "property_linker does not have predict() method.")

    def fit(self, X, y, X_reduce_label=None,
            periodic_axes=[], probability_mask=None, size=None):
        '''
        Fits data by calculating 2-point statistics from X, preforming
        dimension reduction using dimension_reducer, and fitting the reduced
        data with the property_linker.

        >>> from sklearn.decomposition import PCA
        >>> from sklearn.linear_model import LinearRegression
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> from pymks.stats import correlate

        >>> reducer = PCA(n_components=2)
        >>> linker = LinearRegression()
        >>> dbasis = DiscreteIndicatorBasis(n_states=2, domain=[0, 1])
        >>> model = MKSHomogenizationModel(dbasis,
        ...                                dimension_reducer=reducer,
        ...                                property_linker=linker)
        >>> np.random.seed(99)
        >>> X = np.random.randint(2, size=(3, 15))
        >>> y = np.array([1, 2, 3])
        >>> model.fit(X, y)
        >>> X_ = dbasis.discretize(X)
        >>> X_corr = correlate(X_)
        >>> X_reshaped = X_corr.reshape((X_corr.shape[0], X_corr[0].size))
        >>> X_pca = reducer.fit_transform(X_reshaped - np.mean(X_reshaped,
        ...                               axis=1)[:, None])
        >>> assert np.allclose(model.fit_data, X_pca)

        Args:
          X: The microstructure, an `(S, N, ...)` shaped
             array where `S` is the number of samples and `N` is the
             spatial discretization.
          y: The material property associated with `X`.
          reducer_label: label for X used during the fit_transform method
             for the `dimension_reducer`.
          periodic_axes: axes that are periodic. (0, 2) would indicate
              that axes x and z are periodic in a 3D microstrucure.
          probability_mask: array with same shape as X used to assign a
              confidence value for each data point.
        '''
        if size is not None:
            new_shape = (X.shape[0],) + size
            X = X.reshape(new_shape)
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.fit_transform(X_preped,
                                                         X_reduce_label)
        self.linker.fit(X_reduced, y)
        self.fit_data = X_reduced

    def predict(self, X, periodic_axes=[], probability_mask=None):
        '''Predicts macroscopic property for the microstructures `X`.

        >>> from sklearn.manifold import LocallyLinearEmbedding
        >>> from sklearn.linear_model import BayesianRidge
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> np.random.seed(99)
        >>> X = np.random.randint(2, size=(50, 100))
        >>> y = np.random.random(50)
        >>> reducer = LocallyLinearEmbedding()
        >>> linker = BayesianRidge()
        >>> basis = DiscreteIndicatorBasis(2, domain=[0, 1])
        >>> model = MKSHomogenizationModel(basis, n_components=2,
        ...                                dimension_reducer=reducer,
        ...                                property_linker=linker)
        >>> model.fit(X, y)
        >>> X_test = np.random.randint(2, size=(1, 100))
        >>> assert np.allclose(model.predict(X_test), 0.53031958)

        Args:
            X: The microstructre, an `(S, N, ...)` shaped array where `S` is
               the number of samples and `N` is the spatial discretization.
            periodic_axes: axes that are periodic. (0, 2) would indicate
                that axes x and z are periodic in a 3D microstrucure.
            probability_mask: array with same shape as X used to assign a
                confidence value for each data point.
        Returns:
            The predicted macroscopic property for `X`.
        '''
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.transform(X_preped)
        self.predict_data = X_reduced
        return self.linker.predict(X_reduced)

    def _X_prep(self, X, periodic_axes=[], probability_mask=None):
        '''
        Helper function used to calculated 2-point statistics from `X` and
        reshape them appropriately for fit and predict methods.

        >>> from sklearn.manifold import Isomap
        >>> from sklearn.linear_model import ARDRegression
        >>> from pymks.bases import DiscreteIndicatorBasis
        >>> reducer = Isomap()
        >>> linker = ARDRegression()
        >>> basis = DiscreteIndicatorBasis(2, [0, 1])
        >>> model = MKSHomogenizationModel(basis, reducer, linker)
        >>> X = np.array([[0, 1],
        ...               [1, 0]])
        >>> X_prep = model._X_prep(X, [], None)
        >>> X_test = np.array([[-1 / 6., -1 / 6., -1 / 6.,
        ...                      1 / 3., 1 / 3., -1 / 6.],
        ...                    [-1 / 3., -1 / 3., 2 / 3.,
        ...                      1 / 6., 1 / 6., -1 / 3.]])
        >>> assert np.allclose(X_test, X_prep)

        Args:
            X: The microstructre, an `(S, N, ...)` shaped array where `S` is
               the number of samples and `N` is the spatial discretization.
            periodic_axes: axes that are periodic. (0, 2) would indicate
                that axes x and z are periodic in a 3D microstrucure.
            probability_mask: array with same shape as X used to assign a
                confidence value for each data point.
        Returns:
           Spatial correlations for each sample formated with dimensions
           (n_samples, n_features).
        '''
        X_ = self.basis.discretize(X)
        X_corr = correlate(X_, periodic_axes=periodic_axes,
                           probability_mask=probability_mask)
        X_reshaped = X_corr.reshape((X_corr.shape[0], X_corr[0].size))
        return X_reshaped - np.mean(X_reshaped, axis=1)[:, None]

    def score(self, X, y, periodic_axes=[], probability_mask=None):
        '''
        The score function for the MKSHomogenizationModel. It formats the
        data and uses the score method from the property_linker.
        '''
        if not callable(getattr(self.linker, "score", None)):
            raise RuntimeError(
                "property_linker does not have score() method.")
        X_preped = self._X_prep(X, periodic_axes, probability_mask)
        X_reduced = self.dimension_reducer.transform(X_preped)
        return self.linker.score(X_reduced, y)
<|endoftext|>


<commit_before>import requests
from .common import Provider

class Cryptoid(Provider):

    '''API wrapper for http://chainz.cryptoid.info blockexplorer.'''

    @classmethod
    def __init__(self, network: str):
        """
        : network = peercoin [ppc], peercoin-testnet [tppc] ...
        """

        self.net = self._netname(network)['short']

    key = '7547f94398e3'
    api_calls = ('getblockcount', 'getdifficulty', 'getbalance',
                 'getreceivedbyaddress', 'listunspent')
    private = ('getbalance', 'unspent')
    explorer_url = 'https://chainz.cryptoid.info/explorer/'
    api_session = requests.Session()

    @staticmethod
    def format_name(net: str) -> str:
        '''take care of specifics of cryptoid naming system'''

        if net.startswith('t') or 'testnet' in net:
            net = net[1:] + '-test'
        else:
            net = net

        return net

    @classmethod
    def api_req(self, query: str) -> dict:

        api_url = 'https://chainz.cryptoid.info/{net}/api.dws'.format(
                                                               net=self.format_name(self.net))

        if (p in self.api_calls for p in query):
            query = api_url + "?q=" + query

            if (p in self.private for p in query):
                query += "&key=" + self.key

            response = self.api_session.get(query)

        assert response.status_code == 200, {'error': 'API error: ' + str(response.status_code)}
        return response.json()

    @classmethod
    def block_req(self, query: str) -> dict:

        response = self.api_session.get(query)
        assert response.status_code == 200, {'error': 'API error: ' + str(response.status_code)}
        return response.json()

    @classmethod
    def getblockcount(cls) -> int:

        return cls.api_req('getblockcount')

    @classmethod
    def getblock(cls, blockhash: str) -> dict:
        '''query block using <blockhash> as key.'''

        query = cls.block_url(cls.net) + '&hash={blockhash}'.format(net=cls.net,
                                                                    blockhash=blockhash)
        return cls.block_req(query)

    @classmethod
    def getblockhash(cls, blocknum: int) -> str:
        '''get blockhash'''

        query = cls.block_url(cls.net) + '&id={blocknum}'.format(net=cls.net,
                                                                 blocknum=blocknum)
        return cls.block_req(query)['hash']

    @classmethod
    def getdifficulty(cls) -> float:

        return cls.api_req('getdifficulty')

    @classmethod
    def getbalance(cls, address: str) -> float:

        return float(cls.api_req('getbalance' + "&a=" + address))

    @classmethod
    def getreceivedbyaddress(cls, address: str) -> float:

        return float(cls.api_req('getreceivedbyaddress' + "&a=" + address))

    @classmethod
    def listunspent(cls, address: str) -> list:

        return cls.api_req('unspent' + "&active=" + address)['unspent_outputs']

    @classmethod
    def getrawtransaction(cls, txid: str) -> dict:

        query = cls.explorer_url + 'tx.raw.dws?coin={net}&id={txid}'.format(net=cls.format_name(cls.net),
                                                                            txid=txid)
        return cls.block_req(query)

    @classmethod
    def listtransactions(cls, address: str) -> list:

        query = cls.block_url
        query = cls.explorer_url + 'address.summary.dws?coin={net}&id={addr}'.format(net=cls.format_name(cls.net),
                                                                                addr=address)
        resp = cls.block_req(query)
        return [i[1].lower() for i in resp['tx']]
<commit_msg>cryptoid added proper getblockhash api method.<commit_after>import requests
from .common import Provider

class Cryptoid(Provider):

    '''API wrapper for http://chainz.cryptoid.info blockexplorer.'''

    @classmethod
    def __init__(self, network: str):
        """
        : network = peercoin [ppc], peercoin-testnet [tppc] ...
        """

        self.net = self._netname(network)['short']

    key = '7547f94398e3'
    api_calls = ('getblockcount', 'getdifficulty', 'getbalance',
                 'getreceivedbyaddress', 'listunspent')
    private = ('getbalance', 'unspent')
    explorer_url = 'https://chainz.cryptoid.info/explorer/'
    api_session = requests.Session()

    @staticmethod
    def format_name(net: str) -> str:
        '''take care of specifics of cryptoid naming system'''

        if net.startswith('t') or 'testnet' in net:
            net = net[1:] + '-test'
        else:
            net = net

        return net

    @classmethod
    def api_req(self, query: str) -> dict:

        api_url = 'https://chainz.cryptoid.info/{net}/api.dws'.format(
                                                               net=self.format_name(self.net))

        if (p in self.api_calls for p in query):
            query = api_url + "?q=" + query

            if (p in self.private for p in query):
                query += "&key=" + self.key

            response = self.api_session.get(query)

        assert response.status_code == 200, {'error': 'API error: ' + str(response.status_code)}
        return response.json()

    @classmethod
    def block_req(self, query: str) -> dict:

        response = self.api_session.get(query)
        assert response.status_code == 200, {'error': 'API error: ' + str(response.status_code)}
        return response.json()

    @classmethod
    def getblockcount(cls) -> int:

        return cls.api_req('getblockcount')

    @classmethod
    def getblock(cls, blockhash: str) -> dict:
        '''query block using <blockhash> as key.'''

        query = cls.block_url(cls.net) + '&hash={blockhash}'.format(net=cls.net,
                                                                    blockhash=blockhash)
        return cls.block_req(query)

    @classmethod
    def getblockhash(cls, blocknum: int) -> str:
        '''get blockhash'''

        return cls.api_req('getblockhash' + '&height=' + str(blocknum))

    @classmethod
    def getdifficulty(cls) -> float:

        return cls.api_req('getdifficulty')

    @classmethod
    def getbalance(cls, address: str) -> float:

        return float(cls.api_req('getbalance' + "&a=" + address))

    @classmethod
    def getreceivedbyaddress(cls, address: str) -> float:

        return float(cls.api_req('getreceivedbyaddress' + "&a=" + address))

    @classmethod
    def listunspent(cls, address: str) -> list:

        return cls.api_req('unspent' + "&active=" + address)['unspent_outputs']

    @classmethod
    def getrawtransaction(cls, txid: str) -> dict:

        query = cls.explorer_url + 'tx.raw.dws?coin={net}&id={txid}'.format(net=cls.format_name(cls.net),
                                                                            txid=txid)
        return cls.block_req(query)

    @classmethod
    def listtransactions(cls, address: str) -> list:

        query = cls.block_url
        query = cls.explorer_url + 'address.summary.dws?coin={net}&id={addr}'.format(net=cls.format_name(cls.net),
                                                                                addr=address)
        resp = cls.block_req(query)
        return [i[1].lower() for i in resp['tx']]
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
""" Contains smart indent modes """
import re
from pyqode.qt.QtGui import QTextCursor
from pyqode.core.modes.autoindent import AutoIndentMode

class PyAutoIndentMode(AutoIndentMode):
    """
    Customised :class:`pyqode.core.AutoIndentMode` for python, the indentation
    level is based on the previous line indent but is automatically incremented
    after a *:* and decremented after *pass* or *return*
    """
    #: Mode identifier
    IDENTIFIER = "pyAutoIndentMode"
    #: Mode description
    _DESCRIPTION = """ This mode provides python specific auto indentation. """

    def __init__(self):
        super(PyAutoIndentMode, self).__init__()

    def isOperator(self, word):
        operators = ['.', ',', '+', '-', '/', '*', 'or', 'and', "=", "%", "=="]
        return word in operators

    def twoPrevEmptyLine(self, tc):
        ln = tc.blockNumber()
        limit = ln - 1
        while ln > limit:
            if self.editor.lineText(ln).strip() != "":
                return False
            ln -= 1
        return True

    def isStringBetweenParams(self, tc):
        ln = tc.blockNumber()
        while ln >= 0:
            line = self.editor.lineText(ln)
            if line.count("(") > line.count(")"):
                return True
            ln -= 1
        return False

    def inStringDef(self, fullLine, column):
        count = 0
        for i in range(len(fullLine)):
            if fullLine[i] == "'" or fullLine[i] == '"':
                count += 1
        count_after_col = 0
        for i in range(column, len(fullLine)):
            if fullLine[i] == "'" or fullLine[i] == '"':
                count_after_col += 1
        return count % 2 == 0 and count_after_col == 1

    def isOpenParen(self, paren):
        return (paren.character == "(" or paren.character == "["
                or paren.character == '{')

    def isClosedParen(self, paren):
        return (paren.character == ")" or paren.character == "]"
                or paren.character == '}')

    def getfullLine(self, tc):
        tc2 = QTextCursor(tc)
        tc2.select(QTextCursor.LineUnderCursor)
        full_line = tc2.selectedText()
        return full_line

    def betweenParen(self, tc, col):
        data = tc.block().userData()
        nb_open = 0
        nb_closed = 0
        lists = [data.parentheses, data.braces, data.squareBrackets]
        for symbols in lists:
            for paren in symbols:
                if paren.position >= col:
                    break
                if self.isOpenParen(paren):
                    nb_open += 1
                if self.isClosedParen(paren):
                    nb_closed += 1
        return nb_open > nb_closed

    def inComment(self, column, tc, fullLine):
        useParentImpl = False
        usd = tc.block().userData()
        for start, end in usd.cc_disabled_zones:
            if start < column < end:
                string = fullLine[start:end]
                if not ((string.startswith("'") or
                        string.startswith('"')) and
                        (string.endswith("'") or
                         string.endswith('"'))):
                    useParentImpl = True
                    break
        return useParentImpl

    def getLastWord(self, tc):
        tc2 = QTextCursor(tc)
        tc2.movePosition(QTextCursor.WordLeft)
        tc2.select(QTextCursor.WordUnderCursor)
        return tc2.selectedText().strip()

    def getIndentOfOpeningParen(self, tc, column):
        # find last closed paren
        pos = None
        data = tc.block().userData()
        tc2 = QTextCursor(tc)
        tc2.movePosition(tc2.StartOfLine, tc2.MoveAnchor)
        for paren in reversed(data.parentheses):
            if paren.character == ')':
                column = paren.position
                pos = tc2.position() + column + 1
                break
        if pos:
            tc2 = QTextCursor(tc)
            tc2.setPosition(pos)
            oL, oC = self.editor.symbolMatcherMode.getSymbolPos(
                tc2, '(', 0)
            line = self.editor.lineText(oL)
            return len(line) - len(line.lstrip())
        return None

    def getLastOpenParenPos(self, tc, column):
        ln = tc.blockNumber() + 1
        tc2 = QTextCursor(tc)
        tc2.movePosition(tc2.StartOfLine, tc2.MoveAnchor)
        pos = None
        char = None
        data = tc.block().userData()
        lists = [data.parentheses, data.braces, data.squareBrackets]
        for symbols in lists:
            for paren in reversed(symbols):
                if paren.position < column:
                    if self.isOpenParen(paren):
                        column = paren.position
                        pos = tc2.position() + column
                        char = paren.character
                        # ensure it does not have a closing paren on the same
                        # line
                        tc3 = QTextCursor(tc)
                        tc3.setPosition(pos)
                        # ensure we don't have a closing paren on the same line
                        l, c = self.editor.symbolMatcherMode.getSymbolPos(tc3)
                        if l == ln:
                            continue
                        break
        return pos, char

    def getParenPos(self, tc, column):
        pos, char = self.getLastOpenParenPos(tc, column)
        if char == '(':
            pType = 0
            closingChar = ')'
        elif char == '[':
            pType = 1
            closingChar = ']'
        elif char == '{':
            pType = 2
            closingChar = '}'
        tc2 = QTextCursor(tc)
        tc2.setPosition(pos)
        oL, oC = self.editor.symbolMatcherMode.getSymbolPos(
            tc2, char, pType)
        cL, cC = self.editor.symbolMatcherMode.getSymbolPos(
            tc2, closingChar, pType)
        return (oL, oC), (cL, cC)

    def handleIndentAfterParen(self, column, line, fullLine, tc):
        # elements might be separated by ',' 'or' 'and'
        (oL, oC), (cL, cC) = self.getParenPos(tc, column)
        closingLine = self.editor.lineText(cL)
        openingLine = self.editor.lineText(oL)
        openingIndent = len(openingLine) - len(openingLine.lstrip())
        tokens = [t.strip() for t in re.split(', |and |or ',
                                              line[oC:column]) if t]
        if tokens:
            # align with first token pos
            if len(closingLine) > cC and closingLine[cC] == ":":
                post = openingIndent * " " + 8 * " "
            else:
                post = oC * " "
        else:
            if len(closingLine) > cC and closingLine[cC] == ":":
                post = openingIndent * " " + 8 * " "
            else:
                post = openingIndent * " " + 4 * " "
        pre = ""
        if self.inStringDef(fullLine, column):
            pre = '"'
            post += '"'
        return pre, post

    def _getIndent(self, tc):
        pos = tc.position()
        ln, column = self.editor.cursorPosition
        fullLine = self.getfullLine(tc)
        line = fullLine[:column]
        if pos == 0 or column == 0:
            return "", ""
        pre, post = AutoIndentMode._getIndent(self, tc)
        lastWord = self.getLastWord(tc)
        if self.inComment(column, tc, fullLine):
            if line.strip().startswith("#") and column != len(fullLine):
                post = post + '#'
            return pre, post
        elif self.betweenParen(tc, column):
            pre, post = self.handleIndentAfterParen(column, line, fullLine, tc)
        else:
            if self.inStringDef(fullLine, column):
                # the string might be between paren if multiline
                # check if there a at least a non closed paren on the previous
                # lines
                if self.isStringBetweenParams(tc):
                    pre = '"'
                    post += '"'
                else:
                    pre = '" \\'
                    post += 4 * ' ' + '"'
            elif fullLine.endswith(":"):
                try:
                    indent = self.getIndentOfOpeningParen(tc, column) + 4
                    if indent:
                        post = indent * " "
                except TypeError:
                    kw = ["if", "class", "def", "while", "for", "else", "elif", "except", "finally"]
                    l = fullLine
                    print(fullLine)
                    ln = tc.blockNumber()
                    def check_kw_in_line(kws, l):
                        for kw in kws:
                            if kw in l:
                                return True
                        return False
                    while not check_kw_in_line(kw, l) and ln:
                        ln -= 1
                        l = self.editor.lineText(ln)
                    print(l)
                    indent = (len(l) - len(l.lstrip())) * " "
                    post = indent + 4 * " "
                    print(len(post))
            elif fullLine.endswith("\\"):
                # increment indent
                post = post + 4 * " "
            elif fullLine.endswith(")"):
                # find line where the open braces can be found and align with
                # that line
                indent = self.getIndentOfOpeningParen(tc, column)
                if indent:
                    post = indent * " "
            elif (lastWord == "return" or lastWord == "pass" or
                    self.twoPrevEmptyLine(tc)):
                post = post[:-4]

        return pre, post

        #     if full_line.endswith(":"):
        #         kw = ["if", "def", "while", "for", "else", "elif", "except", "finally"]
        #         l = full_line
        #         ln = tc.blockNumber() + 1
        #
        #         def check_kw_in_line(kws, l):
        #             for kw in kws:
        #                 if kw in l:
        #                     return True
        #             return False
        #
        #         while not check_kw_in_line(kw, l) and ln:
        #             ln -= 1
        #             l = self.editor.lineText(ln)
        #         indent = (len(l) - len(l.lstrip())) * " "
        #         indent += 4 * " "
        #     # si dans un string
        #     if line.endswith("\\"):
        #         indent += 4 * " "
        #     elif last_word in ["return", "pass"]:
        #         indent = indent[4:]
        #     if line.startswith("#"):
        #         indent += "# "
        #     if line.endswith(")"):
        #         # find the indent of the line where the opening brace can be found.
        #         if hasattr(self.editor, "symbolMatcherMode"):
        #             ln, cn = self.editor.symbolMatcherMode.getOpeningSymbolPos(
        #                 self.editor.textCursor())
        #             if ln and cn:
        #                 l = self.editor.lineText(ln)
        #                 indent = (len(l) - len(l.lstrip())) * " "
        #     data = tc.block().userData()
        #     nb_open = 0
        #     nb_closed = 0
        #     lists = [data.parentheses, data.braces, data.squareBrackets]
        #     for symbols in lists:
        #         for paren in symbols:
        #             if paren.position >= col:
        #                 break
        #             if self.isOpenParen(paren):
        #                 nb_open += 1
        #             if self.isClosedParen(paren):
        #                 nb_closed += 1
        #     if nb_open > nb_closed:
        #         # align with first parameter
        #         if nb_open - nb_closed != 0 and ("," in line or "=" in line
        #                                          or last_word == "%"):
        #             paren_pos = self.getLastOpenParenPos(data, col)
        #             if ',' in line and paren_pos > line.rfind(","):
        #                 indent += 4 * " "
        #             else:
        #                 indent = (paren_pos + 1) * " "
        #         # no parameters declare, indent normally
        #         else:
        #             indent += 4 * " "
        #     elif ((nb_open == nb_closed or nb_closed == 0) and
        #           (len(full_line) - len(line) > 0)):
        #         if (not "\\" in full_line and not "#" in full_line and
        #                 self.isOperator(last_word)):
        #             pre += "\\"
        #             indent += 4 * " "
        #
        #     for symbols in lists:
        #         for paren in symbols:
        #             if self.isClosedParen(paren):
        #                 nb_closed += 1
        #     inString, lastChar = self.inStringDef(full_line, col)
        #     if inString:
        #         if nb_open == 0 and nb_closed == 0:
        #             pre += "\\"
        #             indent += 4 * " "
        #         pre = lastChar + pre
        #         indent = indent + lastChar
        #     tc.setPosition(pos)
        #     return pre, indent
        # return "", ""
<commit_msg>#17 Try statement were left<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
""" Contains smart indent modes """
import re
from pyqode.qt.QtGui import QTextCursor
from pyqode.core.modes.autoindent import AutoIndentMode

class PyAutoIndentMode(AutoIndentMode):
    """
    Customised :class:`pyqode.core.AutoIndentMode` for python, the indentation
    level is based on the previous line indent but is automatically incremented
    after a *:* and decremented after *pass* or *return*
    """
    #: Mode identifier
    IDENTIFIER = "pyAutoIndentMode"
    #: Mode description
    _DESCRIPTION = """ This mode provides python specific auto indentation. """

    def __init__(self):
        super(PyAutoIndentMode, self).__init__()

    def isOperator(self, word):
        operators = ['.', ',', '+', '-', '/', '*', 'or', 'and', "=", "%", "=="]
        return word in operators

    def twoPrevEmptyLine(self, tc):
        ln = tc.blockNumber()
        limit = ln - 1
        while ln > limit:
            if self.editor.lineText(ln).strip() != "":
                return False
            ln -= 1
        return True

    def isStringBetweenParams(self, tc):
        ln = tc.blockNumber()
        while ln >= 0:
            line = self.editor.lineText(ln)
            if line.count("(") > line.count(")"):
                return True
            ln -= 1
        return False

    def inStringDef(self, fullLine, column):
        count = 0
        for i in range(len(fullLine)):
            if fullLine[i] == "'" or fullLine[i] == '"':
                count += 1
        count_after_col = 0
        for i in range(column, len(fullLine)):
            if fullLine[i] == "'" or fullLine[i] == '"':
                count_after_col += 1
        return count % 2 == 0 and count_after_col == 1

    def isOpenParen(self, paren):
        return (paren.character == "(" or paren.character == "["
                or paren.character == '{')

    def isClosedParen(self, paren):
        return (paren.character == ")" or paren.character == "]"
                or paren.character == '}')

    def getfullLine(self, tc):
        tc2 = QTextCursor(tc)
        tc2.select(QTextCursor.LineUnderCursor)
        full_line = tc2.selectedText()
        return full_line

    def betweenParen(self, tc, col):
        data = tc.block().userData()
        nb_open = 0
        nb_closed = 0
        lists = [data.parentheses, data.braces, data.squareBrackets]
        for symbols in lists:
            for paren in symbols:
                if paren.position >= col:
                    break
                if self.isOpenParen(paren):
                    nb_open += 1
                if self.isClosedParen(paren):
                    nb_closed += 1
        return nb_open > nb_closed

    def inComment(self, column, tc, fullLine):
        useParentImpl = False
        usd = tc.block().userData()
        for start, end in usd.cc_disabled_zones:
            if start < column < end:
                string = fullLine[start:end]
                if not ((string.startswith("'") or
                        string.startswith('"')) and
                        (string.endswith("'") or
                         string.endswith('"'))):
                    useParentImpl = True
                    break
        return useParentImpl

    def getLastWord(self, tc):
        tc2 = QTextCursor(tc)
        tc2.movePosition(QTextCursor.WordLeft)
        tc2.select(QTextCursor.WordUnderCursor)
        return tc2.selectedText().strip()

    def getIndentOfOpeningParen(self, tc, column):
        # find last closed paren
        pos = None
        data = tc.block().userData()
        tc2 = QTextCursor(tc)
        tc2.movePosition(tc2.StartOfLine, tc2.MoveAnchor)
        for paren in reversed(data.parentheses):
            if paren.character == ')':
                column = paren.position
                pos = tc2.position() + column + 1
                break
        if pos:
            tc2 = QTextCursor(tc)
            tc2.setPosition(pos)
            oL, oC = self.editor.symbolMatcherMode.getSymbolPos(
                tc2, '(', 0)
            line = self.editor.lineText(oL)
            return len(line) - len(line.lstrip())
        return None

    def getLastOpenParenPos(self, tc, column):
        ln = tc.blockNumber() + 1
        tc2 = QTextCursor(tc)
        tc2.movePosition(tc2.StartOfLine, tc2.MoveAnchor)
        pos = None
        char = None
        data = tc.block().userData()
        lists = [data.parentheses, data.braces, data.squareBrackets]
        for symbols in lists:
            for paren in reversed(symbols):
                if paren.position < column:
                    if self.isOpenParen(paren):
                        column = paren.position
                        pos = tc2.position() + column
                        char = paren.character
                        # ensure it does not have a closing paren on the same
                        # line
                        tc3 = QTextCursor(tc)
                        tc3.setPosition(pos)
                        # ensure we don't have a closing paren on the same line
                        l, c = self.editor.symbolMatcherMode.getSymbolPos(tc3)
                        if l == ln:
                            continue
                        break
        return pos, char

    def getParenPos(self, tc, column):
        pos, char = self.getLastOpenParenPos(tc, column)
        if char == '(':
            pType = 0
            closingChar = ')'
        elif char == '[':
            pType = 1
            closingChar = ']'
        elif char == '{':
            pType = 2
            closingChar = '}'
        tc2 = QTextCursor(tc)
        tc2.setPosition(pos)
        oL, oC = self.editor.symbolMatcherMode.getSymbolPos(
            tc2, char, pType)
        cL, cC = self.editor.symbolMatcherMode.getSymbolPos(
            tc2, closingChar, pType)
        return (oL, oC), (cL, cC)

    def handleIndentAfterParen(self, column, line, fullLine, tc):
        # elements might be separated by ',' 'or' 'and'
        (oL, oC), (cL, cC) = self.getParenPos(tc, column)
        closingLine = self.editor.lineText(cL)
        openingLine = self.editor.lineText(oL)
        openingIndent = len(openingLine) - len(openingLine.lstrip())
        tokens = [t.strip() for t in re.split(', |and |or ',
                                              line[oC:column]) if t]
        if tokens:
            # align with first token pos
            if len(closingLine) > cC and closingLine[cC] == ":":
                post = openingIndent * " " + 8 * " "
            else:
                post = oC * " "
        else:
            if len(closingLine) > cC and closingLine[cC] == ":":
                post = openingIndent * " " + 8 * " "
            else:
                post = openingIndent * " " + 4 * " "
        pre = ""
        if self.inStringDef(fullLine, column):
            pre = '"'
            post += '"'
        return pre, post

    def _getIndent(self, tc):
        pos = tc.position()
        ln, column = self.editor.cursorPosition
        fullLine = self.getfullLine(tc)
        line = fullLine[:column]
        if pos == 0 or column == 0:
            return "", ""
        pre, post = AutoIndentMode._getIndent(self, tc)
        lastWord = self.getLastWord(tc)
        if self.inComment(column, tc, fullLine):
            if line.strip().startswith("#") and column != len(fullLine):
                post = post + '#'
            return pre, post
        elif self.betweenParen(tc, column):
            pre, post = self.handleIndentAfterParen(column, line, fullLine, tc)
        else:
            if self.inStringDef(fullLine, column):
                # the string might be between paren if multiline
                # check if there a at least a non closed paren on the previous
                # lines
                if self.isStringBetweenParams(tc):
                    pre = '"'
                    post += '"'
                else:
                    pre = '" \\'
                    post += 4 * ' ' + '"'
            elif fullLine.endswith(":"):
                try:
                    indent = self.getIndentOfOpeningParen(tc, column) + 4
                    if indent:
                        post = indent * " "
                except TypeError:
                    kw = ["if", "class", "def", "while", "for", "else", "elif", "except", "finally", "try"]
                    l = fullLine
                    print(fullLine)
                    ln = tc.blockNumber()
                    def check_kw_in_line(kws, l):
                        for kw in kws:
                            if kw in l:
                                return True
                        return False
                    while not check_kw_in_line(kw, l) and ln:
                        ln -= 1
                        l = self.editor.lineText(ln)
                    print(l)
                    indent = (len(l) - len(l.lstrip())) * " "
                    post = indent + 4 * " "
                    print(len(post))
            elif fullLine.endswith("\\"):
                # increment indent
                post = post + 4 * " "
            elif fullLine.endswith(")"):
                # find line where the open braces can be found and align with
                # that line
                indent = self.getIndentOfOpeningParen(tc, column)
                if indent:
                    post = indent * " "
            elif (lastWord == "return" or lastWord == "pass" or
                    self.twoPrevEmptyLine(tc)):
                post = post[:-4]

        return pre, post

        #     if full_line.endswith(":"):
        #         kw = ["if", "def", "while", "for", "else", "elif", "except", "finally"]
        #         l = full_line
        #         ln = tc.blockNumber() + 1
        #
        #         def check_kw_in_line(kws, l):
        #             for kw in kws:
        #                 if kw in l:
        #                     return True
        #             return False
        #
        #         while not check_kw_in_line(kw, l) and ln:
        #             ln -= 1
        #             l = self.editor.lineText(ln)
        #         indent = (len(l) - len(l.lstrip())) * " "
        #         indent += 4 * " "
        #     # si dans un string
        #     if line.endswith("\\"):
        #         indent += 4 * " "
        #     elif last_word in ["return", "pass"]:
        #         indent = indent[4:]
        #     if line.startswith("#"):
        #         indent += "# "
        #     if line.endswith(")"):
        #         # find the indent of the line where the opening brace can be found.
        #         if hasattr(self.editor, "symbolMatcherMode"):
        #             ln, cn = self.editor.symbolMatcherMode.getOpeningSymbolPos(
        #                 self.editor.textCursor())
        #             if ln and cn:
        #                 l = self.editor.lineText(ln)
        #                 indent = (len(l) - len(l.lstrip())) * " "
        #     data = tc.block().userData()
        #     nb_open = 0
        #     nb_closed = 0
        #     lists = [data.parentheses, data.braces, data.squareBrackets]
        #     for symbols in lists:
        #         for paren in symbols:
        #             if paren.position >= col:
        #                 break
        #             if self.isOpenParen(paren):
        #                 nb_open += 1
        #             if self.isClosedParen(paren):
        #                 nb_closed += 1
        #     if nb_open > nb_closed:
        #         # align with first parameter
        #         if nb_open - nb_closed != 0 and ("," in line or "=" in line
        #                                          or last_word == "%"):
        #             paren_pos = self.getLastOpenParenPos(data, col)
        #             if ',' in line and paren_pos > line.rfind(","):
        #                 indent += 4 * " "
        #             else:
        #                 indent = (paren_pos + 1) * " "
        #         # no parameters declare, indent normally
        #         else:
        #             indent += 4 * " "
        #     elif ((nb_open == nb_closed or nb_closed == 0) and
        #           (len(full_line) - len(line) > 0)):
        #         if (not "\\" in full_line and not "#" in full_line and
        #                 self.isOperator(last_word)):
        #             pre += "\\"
        #             indent += 4 * " "
        #
        #     for symbols in lists:
        #         for paren in symbols:
        #             if self.isClosedParen(paren):
        #                 nb_closed += 1
        #     inString, lastChar = self.inStringDef(full_line, col)
        #     if inString:
        #         if nb_open == 0 and nb_closed == 0:
        #             pre += "\\"
        #             indent += 4 * " "
        #         pre = lastChar + pre
        #         indent = indent + lastChar
        #     tc.setPosition(pos)
        #     return pre, indent
        # return "", ""
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
"""
Contains the quick documentation panel
"""
import jedi
from pyqode.core import get_server
from pyqode.core.system import driftColor
import pyqode.core
from pyqode.qt import QtGui

class JediDocWorker(object):
    _slot = "jedi"

    def __init__(self, code, line, col, path, encoding):
        self.code = code
        self.line = line
        self.col = col
        self.path = path
        self.encoding = encoding

    def __call__(self, client, caller_id, *args, **kwargs):
        script = jedi.Script(self.code, self.line, self.col, self.path,
                             self.encoding)
        try:
            definitions = script.goto_definitions()
        except jedi.api.NotFoundError:
            return []
        else:
            ret_val = [d.doc for d in definitions]
            return ret_val

class QuickDocPanel(pyqode.core.Panel):
    """
    This panel quickly shows the documentation of the symbol under
    cursor.
    """
    STYLESHEET = """

    QTextEdit
    {
        background-color: %(tooltip)s;
        color: %(color)s;
    }

    QPushButton
    {
        color: %(color)s;
        background-color: transparent;
        padding: 5px;
        border: none;
    }

    QPushButton:hover
    {
        background-color: %(highlight)s;
        border: none;
        border-radius: 5px;
        color: %(color)s;
    }

    QPushButton:pressed, QCheckBox:pressed
    {
        border: 1px solid %(bck)s;
    }

    QPushButton:disabled
    {
        color: %(highlight)s;
    }
    """

    _KEYS = ["panelBackground", "background", "panelForeground",
             "panelHighlight"]

    #: Mode identifier
    IDENTIFIER = "quickDocPanel"

    #: Mode description
    DESCRIPTION = __doc__

    def __init__(self):
        super(QuickDocPanel, self).__init__()
        # layouts
        layout = QtGui.QHBoxLayout()
        self.setLayout(layout)
        child_layout = QtGui.QVBoxLayout()

        # A QTextEdit to show the doc
        self.textEdit = QtGui.QTextEdit()
        self.textEdit.setReadOnly(True)
        self.textEdit.setAcceptRichText(True)
        layout.addWidget(self.textEdit)

        # A QPushButton (inside a child layout for a better alignment)
        # to close the panel
        self.btClose = QtGui.QPushButton()
        self.btClose.setIcon(QtGui.QIcon.fromTheme(
            "application-exit", QtGui.QIcon(":/pyqode-icons/rc/close.png")))
        self.btClose.clicked.connect(self.hide)
        child_layout.addWidget(self.btClose)
        child_layout.addStretch()
        layout.addLayout(child_layout)

        # Action
        self.aQuickDoc = QtGui.QAction("Show documentation", self)
        self.aQuickDoc.setShortcut("Alt+Q")

        self.aQuickDoc.triggered.connect(self._onQuickDoc_triggered)

    def _resetStylesheet(self):
        highlight = driftColor(self.editor.palette().window().color())
        stylesheet = self.STYLESHEET % {
            "tooltip": self.editor.palette().toolTipBase().color().name(),
            "bck": self.editor.palette().window().color().name(),
            "color": self.editor.palette().windowText().color().name(),
            "highlight": highlight.name()}
        self.setStyleSheet(stylesheet)

    def _onInstall(self, editor):
        super(QuickDocPanel, self)._onInstall(editor)
        self._resetStylesheet()
        self.setVisible(False)

    def _onStateChanged(self, state):
        super(QuickDocPanel, self)._onStateChanged(state)
        srv = get_server()
        if state:
            if srv:
                srv.signals.workCompleted.connect(self._onWorkCompleted)
            if hasattr(self.editor, "codeCompletionMode"):
                self.editor.codeCompletionMode.preLoadStarted.connect(
                    self._onPreloadStarted)
                self.editor.codeCompletionMode.preLoadCompleted.connect(
                    self._onPreloadCompleted)
            self.editor.addAction(self.aQuickDoc)
        else:
            if srv:
                srv.signals.workCompleted.disconnect(self._onWorkCompleted)
            self.editor.removeAction(self.aQuickDoc)
            if hasattr(self.editor, "codeCompletionMode"):
                self.editor.codeCompletionMode.preLoadStarted.disconnect(
                    self._onPreloadStarted)
                self.editor.codeCompletionMode.preLoadCompleted.disconnect(
                    self._onPreloadCompleted)

    def _onPreloadStarted(self):
        self.aQuickDoc.setDisabled(True)

    def _onPreloadCompleted(self):
        self.aQuickDoc.setEnabled(True)

    def _onStyleChanged(self, section, key):
        super(QuickDocPanel, self)._onStyleChanged(section, key)
        if key in self._KEYS or not key:
            self._resetStylesheet()

    def _onQuickDoc_triggered(self):
        tc = self.editor.selectWordUnderCursor(selectWholeWord=True)
        assert isinstance(tc, QtGui.QTextCursor)
        w = JediDocWorker(self.editor.toPlainText(), tc.blockNumber() + 1,
                    tc.columnNumber(), self.editor.filePath, self.editor.fileEncoding)
        get_server().requestWork(self, w)

    def _onWorkCompleted(self, caller_id, worker, results):
        if caller_id == id(self) and isinstance(worker, JediDocWorker):
            self.setVisible(True)
            if results:
                if len(results) and results[0] != "":
                    string = "\n\n".join(results)
                    if string:
                        self.textEdit.setText(string)
                else:
                    self.textEdit.setText("Documentation not found")
            else:
                self.textEdit.setText("Documentation not found")
<commit_msg>Improve quick dock panel<commit_after># -*- coding: utf-8 -*-
#
#The MIT License (MIT)
#
#Copyright (c) <2013-2014> <Colin Duquesnoy and others, see AUTHORS.txt>
#
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
#
"""
Contains the quick documentation panel
"""
from docutils.core import publish_parts
import jedi
import pyqode.core
from pyqode.core import get_server
from pyqode.core.system import driftColor
from pyqode.qt import QtGui

class JediDocWorker(object):
    _slot = "jedi"

    def __init__(self, code, line, col, path, encoding):
        self.code = code
        self.line = line
        self.col = col
        self.path = path
        self.encoding = encoding

    def __call__(self, client, caller_id, *args, **kwargs):
        script = jedi.Script(self.code, self.line, self.col, self.path,
                             self.encoding)
        try:
            definitions = script.goto_definitions()
        except jedi.api.NotFoundError:
            return []
        else:
            ret_val = [d.doc for d in definitions]
            return ret_val

class QuickDocPanel(pyqode.core.Panel):
    """
    This panel quickly shows the documentation of the symbol under
    cursor.
    """
    STYLESHEET = """

    QTextEdit
    {
        background-color: %(tooltip)s;
        color: %(color)s;
    }

    QPushButton
    {
        color: %(color)s;
        background-color: transparent;
        padding: 5px;
        border: none;
    }

    QPushButton:hover
    {
        background-color: %(highlight)s;
        border: none;
        border-radius: 5px;
        color: %(color)s;
    }

    QPushButton:pressed, QCheckBox:pressed
    {
        border: 1px solid %(bck)s;
    }

    QPushButton:disabled
    {
        color: %(highlight)s;
    }
    """

    _KEYS = ["panelBackground", "background", "panelForeground",
             "panelHighlight"]

    #: Mode identifier
    IDENTIFIER = "quickDocPanel"

    #: Mode description
    DESCRIPTION = __doc__

    def __init__(self):
        super(QuickDocPanel, self).__init__()
        # layouts
        layout = QtGui.QHBoxLayout()
        self.setLayout(layout)
        child_layout = QtGui.QVBoxLayout()

        # A QTextEdit to show the doc
        self.textEdit = QtGui.QTextEdit()
        self.textEdit.setReadOnly(True)
        self.textEdit.setAcceptRichText(True)
        layout.addWidget(self.textEdit)

        # A QPushButton (inside a child layout for a better alignment)
        # to close the panel
        self.btClose = QtGui.QPushButton()
        self.btClose.setIcon(QtGui.QIcon.fromTheme(
            "application-exit", QtGui.QIcon(":/pyqode-icons/rc/close.png")))
        self.btClose.clicked.connect(self.hide)
        child_layout.addWidget(self.btClose)
        child_layout.addStretch()
        layout.addLayout(child_layout)

        # Action
        self.aQuickDoc = QtGui.QAction("Show documentation", self)
        self.aQuickDoc.setShortcut("Alt+Q")

        self.aQuickDoc.triggered.connect(self._onQuickDoc_triggered)

    def _resetStylesheet(self):
        highlight = driftColor(self.editor.palette().window().color())
        stylesheet = self.STYLESHEET % {
            "tooltip": self.editor.palette().toolTipBase().color().name(),
            "bck": self.editor.palette().window().color().name(),
            "color": self.editor.palette().windowText().color().name(),
            "highlight": highlight.name()}
        self.setStyleSheet(stylesheet)

    def _onInstall(self, editor):
        super(QuickDocPanel, self)._onInstall(editor)
        self._resetStylesheet()
        self.setVisible(False)

    def _onStateChanged(self, state):
        super(QuickDocPanel, self)._onStateChanged(state)
        srv = get_server()
        if state:
            if srv:
                srv.signals.workCompleted.connect(self._onWorkCompleted)
            if hasattr(self.editor, "codeCompletionMode"):
                self.editor.codeCompletionMode.preLoadStarted.connect(
                    self._onPreloadStarted)
                self.editor.codeCompletionMode.preLoadCompleted.connect(
                    self._onPreloadCompleted)
            self.editor.addAction(self.aQuickDoc)
        else:
            if srv:
                srv.signals.workCompleted.disconnect(self._onWorkCompleted)
            self.editor.removeAction(self.aQuickDoc)
            if hasattr(self.editor, "codeCompletionMode"):
                self.editor.codeCompletionMode.preLoadStarted.disconnect(
                    self._onPreloadStarted)
                self.editor.codeCompletionMode.preLoadCompleted.disconnect(
                    self._onPreloadCompleted)

    def _onPreloadStarted(self):
        self.aQuickDoc.setDisabled(True)

    def _onPreloadCompleted(self):
        self.aQuickDoc.setEnabled(True)

    def _onStyleChanged(self, section, key):
        super(QuickDocPanel, self)._onStyleChanged(section, key)
        if key in self._KEYS or not key:
            self._resetStylesheet()

    def _onQuickDoc_triggered(self):
        tc = self.editor.selectWordUnderCursor(selectWholeWord=True)
        assert isinstance(tc, QtGui.QTextCursor)
        w = JediDocWorker(self.editor.toPlainText(), tc.blockNumber() + 1,
                    tc.columnNumber(), self.editor.filePath, self.editor.fileEncoding)
        get_server().requestWork(self, w)

    def _onWorkCompleted(self, caller_id, worker, results):
        if caller_id == id(self) and isinstance(worker, JediDocWorker):
            self.setVisible(True)
            if results:
                if len(results) and results[0] != "":
                    string = "\n\n".join(results)
                    string = publish_parts(
                        string, writer_name='html',
                        settings_overrides={'output_encoding': 'unicode'})['html_body']
                    string = string.replace('colspan="2"', 'colspan="0"')
                    string = string.replace("<th ", '<th align="left" ')
                    string = string.replace('
\n
 	',
                                            '')
                    if string:
                        self.textEdit.setText(string)

                else:
                    self.textEdit.setText("Documentation not found")
            else:
                self.textEdit.setText("Documentation not found")
<|endoftext|>