<commit_before>#!/usr/bin/env python

# ===============================================================================
# Copyright 2015 Geoscience Australia
#
# 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.
# ===============================================================================

from __future__ import absolute_import
from __future__ import print_function
import numpy
import numexpr

def bulk_stats(array, no_data=None, double=False, as_bip=False):
    """
    Calculates statistics over the temporal/spectral/z domain
    of a multiband image.

    Calculates statistics over the temporal/spectral/z domain of an array
    containing [z,y,x] data.
    Statistics produced in this order are:
    Sum
    Valid Observations
    Mean
    Variance
    Standard Deviation
    Skewness
    Kurtosis
    Max
    Min
    Median (non-interpolated value)
    Median Index (zero based index)
    1st Quantile (non-interpolated value)
    3rd Quantile (non-interpolated value)
    Geometric Mean

    Median, 1st and 3rd quantiles: For odd length arrays the middle value is
    taken. For even length arrays, the first of the two middle values is taken.
    Either way, no interpolation is used for calculation.
    The median index is the band that the median value came from.

    The numexpr module is used to handle most of the operations. Arrays are
    processed faster while using less memory.
    The moments are calculated using the unbiased method i.e. (n - 1).
    The moments are also calculated direct via the formula rather than built
    in functions. Why?? Because we can recycle previous computations rather
    than recompute, which will make the routine faster.

    :param array:
        A 3D numpy array containing [z,y,x] data.

    :param no_data:
        The data value to ignore for calculations. Default is None.

    :param double:
        If set to True then `array` will be converted to float64 and
        the output will be evaluted in double precision and returned
        as such. Default is False (float32).

    :param as_bip:
        **Experimental**
        If set to True, the array will be transposed to be
        [Lines,Samples,Bands], and processed as such. The default
        is to process the array as [Bands,Lines,Samples], ie False.
        Experimental to see if the computations are quicker after
        transposing the data to be computed along the fastest
        memory access order. No difference maybe apparent as the
        transposed data will just be a view.

    Returns:
        A numpy float32 array, unless `double` is set to True,
        with NaN representing no data values.
    """

    # assuming a 3D array, [bands,rows,cols]
    dims = array.shape
    if len(dims) != 3:
        msg = "Array must be 3D! Received: {}.".format(len(dims))
        raise TypeError(msg)

    bands = dims[0]
    cols = dims[2]
    rows = dims[1]

    # number of bands/stats to be output to be returned
    output_band_count = 14

    # Define our computation datatype
    nan = numpy.float32(numpy.NaN)
    dtype = 'float32'
    if double:
        array = numpy.float64(array)
        nan = numpy.NaN
        dtype = 'float64'

    if no_data:
        wh = numexpr.evaluate("array == no_data")
        array[wh] = nan

    if as_bip:
        # a few transpositions will take place, but they are quick to create
        # and are mostly just views into the data, so no copies are made
        # !!!Hopefully!!!
        # The idea is that it will process the z-axis over the fastest
        # memory access order. But seeing as they're just views, it might not
        # have any effect.
        array_bip = numpy.transpose(array, (1, 2, 0))

        stats = numpy.zeros((output_band_count, rows, cols), dtype=dtype)

        # Sum
        stats[0] = numpy.nansum(array_bip, axis=2)

        # We need to keep an int for the valid observations
        vld_obsv = numpy.sum(numpy.isfinite(array_bip), axis=2)
        stats[2] = vld_obsv

        # Mean
        stats[1] = numexpr.evaluate("fsum / fvld_obsv",
                                    {'fsum': stats[0], 'fvld_obsv': stats[2]})

        residuals = numexpr.evaluate("array - mean", {'mean': stats[1],
                                                      'array': array})
        # Variance
        t_emp = numexpr.evaluate("residuals**2").transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[3] = numexpr.evaluate("nan_sum / (fvld_obsv - 1)",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Stddev
        stats[4] = numexpr.evaluate("sqrt(var)", {'var': stats[3]})

        # Skewness
        t_emp = numexpr.evaluate("(residuals / stddev)**3",
                                 {'stddev': stats[4],
                                  'residuals': residuals}).transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[5] = numexpr.evaluate("nan_sum / fvld_obsv",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Kurtosis
        t_emp = numexpr.evaluate("(residuals / stddev)**4",
                                 {'stddev': stats[4],
                                  'residuals': residuals}).transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[6] = numexpr.evaluate("(nan_sum / fvld_obsv) - 3",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Max and Min
        stats[7] = numpy.nanmax(array_bip, axis=2)
        stats[8] = numpy.nanmin(array_bip, axis=2)

        # 2nd quantile (aka median)
        # Don't want any interpolated values, so can't use the standard
        # numpy.median() function
        # For odd length arrays, the middle value is taken, for even length
        # arrays, the first of the two middle values is taken

        # Sort the array
        flat_sort = numpy.sort(array_bip, axis=2).ravel()

        # q2_offset, median locations
        q2_idx = numexpr.evaluate("((vld_obsv / 2) + ((vld_obsv % 2) - 1))")

        # array offsets
        a_off = numpy.arange(cols * rows).reshape((rows, cols))

        # turn the locations into a useable 1D index
        idx_1D = numexpr.evaluate("(q2_idx + a_off * bands)").astype('int')
        stats[9] = flat_sort[idx_1D]  # get median values

        # now to find the original index of the median value
        sort_orig_idx = numpy.argsort(array_bip, axis=2).ravel()
        stats[10] = sort_orig_idx[idx_1D]

        # 1st quantile
        length = numexpr.evaluate("q2_idx + 1")
        q1_idx = numexpr.evaluate("((length / 2) + ((length % 2) - 1))")
        idx_1D = numexpr.evaluate("(q1_idx + a_off * bands)").astype('int')
        stats[11] = flat_sort[idx_1D]  # get 1st quantile

        # 3rd quantile
        exp = "((q2_idx + q1_idx) + a_off * bands)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[12] = flat_sort[idx_1D]  # get 3rd quantile

        # Geometric Mean
        # need to handle nan's so can't use scipy.stats.gmean ## 28/02/2013
        # x**(1./n) gives nth root
        wh = ~(numpy.isfinite(array_bip))
        array_bip[wh] = 1
        stats[13] = numpy.prod(array_bip, axis=2)**(1. / vld_obsv)

        # Any nan's will evaluate to 1.0, convert back to NaN
        wh = numexpr.evaluate("vld_obsv == 0")
        stats[13][wh] = nan

        # Convert any potential inf values to a NaN for consistancy
        wh = ~(numpy.isfinite(stats))
        stats[wh] = nan

    else:
        stats = numpy.zeros((output_band_count, rows, cols), dtype=dtype)

        # Sum
        stats[0] = numpy.nansum(array, axis=0)

        # We need to keep an int for the valid observations
        vld_obsv = numpy.sum(numpy.isfinite(array), axis=0)
        stats[2] = vld_obsv

        # Mean
        stats[1] = numexpr.evaluate("fsum / fvld_obsv",
                                    {'fsum': stats[0], 'fvld_obsv': stats[2]})

        residuals = numexpr.evaluate("array - mean",
                                     {'mean': stats[1], 'array': array})

        # Variance
        t_emp = numexpr.evaluate("residuals**2")
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[3] = numexpr.evaluate("nan_sum / (fvld_obsv - 1)",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Stddev
        stats[4] = numexpr.evaluate("sqrt(var)", {'var': stats[3]})

        # skewness
        t_emp = numexpr.evaluate("(residuals / stddev)**3",
                                 {'stddev': stats[4], 'residuals': residuals})
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[5] = numexpr.evaluate("nan_sum / fvld_obsv",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Kurtosis
        t_emp = numexpr.evaluate("(residuals / stddev)**4",
                                 {'stddev': stats[4], 'residuals': residuals})
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[6] = numexpr.evaluate("(nan_sum / fvld_obsv) - 3",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # MAx and Min
        stats[7] = numpy.nanmax(array, axis=0)
        stats[8] = numpy.nanmin(array, axis=0)

        # 2nd quantile (aka median)
        # Don't want any interpolated values, so can't use the standard
        # numpy.median() function
        # For odd length arrays, the middle value is taken, for even length
        # arrays, the first of the two middle values is taken

        flat_sort = numpy.sort(array, axis=0).ravel()

        # q2_offset, median locations
        q2_idx = numexpr.evaluate("((vld_obsv / 2) + ((vld_obsv % 2) - 1))")

        # array offsets
        a_off = numpy.arange(cols * rows).reshape((rows, cols))

        # turn the locations into a useable 1D index
        exp = "(q2_idx * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')
        stats[9] = flat_sort[idx_1D]  # get median values

        # now to find the original index of the median value
        sort_orig_idx = numpy.argsort(array, axis=0).ravel()
        stats[10] = sort_orig_idx[idx_1D]

        # 1st quantile
        length = numexpr.evaluate("q2_idx + 1")
        q1_idx = numexpr.evaluate("((length / 2) + ((length % 2) - 1))")
        exp = "(q1_idx * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[11] = flat_sort[idx_1D]  # get 1st quantile

        # 3rd quantile
        exp = "((q2_idx + q1_idx) * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[12] = flat_sort[idx_1D]  # get 3rd quantile

        # Geometric Mean
        # need to handle nan's so can't use scipy.stats.gmean ## 28/02/2013
        # x**(1./n) gives nth root
        wh = ~(numpy.isfinite(array))
        array[wh] = 1
        stats[13] = numpy.prod(array, axis=0)**(1. / vld_obsv)

        # Any nan's will evaluate to 1.0, convert back to NaN
        wh = numexpr.evaluate("vld_obsv == 0")
        stats[13][wh] = nan

        # Convert any potential inf values to a NaN for consistancy
        wh = ~(numpy.isfinite(stats))
        stats[wh] = nan

    return stats
<commit_msg>Added some notes on the skewness and kurtosis formulae.<commit_after>#!/usr/bin/env python

# ===============================================================================
# Copyright 2015 Geoscience Australia
#
# 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.
# ===============================================================================

from __future__ import absolute_import
from __future__ import print_function
import numpy
import numexpr

def bulk_stats(array, no_data=None, double=False, as_bip=False):
    """
    Calculates statistics over the temporal/spectral/z domain
    of a multiband image.

    Calculates statistics over the temporal/spectral/z domain of an array
    containing [z,y,x] data.
    Statistics produced in this order are:
    Sum
    Valid Observations
    Mean
    Variance
    Standard Deviation
    Skewness
    Kurtosis
    Max
    Min
    Median (non-interpolated value)
    Median Index (zero based index)
    1st Quantile (non-interpolated value)
    3rd Quantile (non-interpolated value)
    Geometric Mean

    Median, 1st and 3rd quantiles: For odd length arrays the middle value is
    taken. For even length arrays, the first of the two middle values is taken.
    Either way, no interpolation is used for calculation.
    The median index is the band that the median value came from.

    The numexpr module is used to handle most of the operations. Arrays are
    processed faster while using less memory.
    The moments are calculated using the unbiased method i.e. (n - 1).
    The moments are also calculated direct via the formula rather than built
    in functions. Why?? Because we can recycle previous computations rather
    than recompute, which will make the routine faster.

    :param array:
        A 3D numpy array containing [z,y,x] data.

    :param no_data:
        The data value to ignore for calculations. Default is None.

    :param double:
        If set to True then `array` will be converted to float64 and
        the output will be evaluted in double precision and returned
        as such. Default is False (float32).

    :param as_bip:
        **Experimental**
        If set to True, the array will be transposed to be
        [Lines,Samples,Bands], and processed as such. The default
        is to process the array as [Bands,Lines,Samples], ie False.
        Experimental to see if the computations are quicker after
        transposing the data to be computed along the fastest
        memory access order. No difference maybe apparent as the
        transposed data will just be a view.

    :Returns:
        A numpy float32 array, unless `double` is set to True,
        with NaN representing no data values.

    :Notes:
        The formulae for the skewness and kurtosis are taken from the
        IDL (Exelisvis) help menu. This may differ slightly from the
        scipy formulae, however both forms produce results in the
        expected range.
    """

    # assuming a 3D array, [bands,rows,cols]
    dims = array.shape
    if len(dims) != 3:
        msg = "Array must be 3D! Received: {}.".format(len(dims))
        raise TypeError(msg)

    bands = dims[0]
    cols = dims[2]
    rows = dims[1]

    # number of bands/stats to be output to be returned
    output_band_count = 14

    # Define our computation datatype
    nan = numpy.float32(numpy.NaN)
    dtype = 'float32'
    if double:
        array = numpy.float64(array)
        nan = numpy.NaN
        dtype = 'float64'

    if no_data:
        wh = numexpr.evaluate("array == no_data")
        array[wh] = nan

    if as_bip:
        # a few transpositions will take place, but they are quick to create
        # and are mostly just views into the data, so no copies are made
        # !!!Hopefully!!!
        # The idea is that it will process the z-axis over the fastest
        # memory access order. But seeing as they're just views, it might not
        # have any effect.
        array_bip = numpy.transpose(array, (1, 2, 0))

        stats = numpy.zeros((output_band_count, rows, cols), dtype=dtype)

        # Sum
        stats[0] = numpy.nansum(array_bip, axis=2)

        # We need to keep an int for the valid observations
        vld_obsv = numpy.sum(numpy.isfinite(array_bip), axis=2)
        stats[2] = vld_obsv

        # Mean
        stats[1] = numexpr.evaluate("fsum / fvld_obsv",
                                    {'fsum': stats[0], 'fvld_obsv': stats[2]})

        residuals = numexpr.evaluate("array - mean", {'mean': stats[1],
                                                      'array': array})
        # Variance
        t_emp = numexpr.evaluate("residuals**2").transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[3] = numexpr.evaluate("nan_sum / (fvld_obsv - 1)",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Stddev
        stats[4] = numexpr.evaluate("sqrt(var)", {'var': stats[3]})

        # Skewness
        t_emp = numexpr.evaluate("(residuals / stddev)**3",
                                 {'stddev': stats[4],
                                  'residuals': residuals}).transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[5] = numexpr.evaluate("nan_sum / fvld_obsv",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Kurtosis
        t_emp = numexpr.evaluate("(residuals / stddev)**4",
                                 {'stddev': stats[4],
                                  'residuals': residuals}).transpose(1, 2, 0)
        nan_sum = numpy.nansum(t_emp, axis=2)
        stats[6] = numexpr.evaluate("(nan_sum / fvld_obsv) - 3",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Max and Min
        stats[7] = numpy.nanmax(array_bip, axis=2)
        stats[8] = numpy.nanmin(array_bip, axis=2)

        # 2nd quantile (aka median)
        # Don't want any interpolated values, so can't use the standard
        # numpy.median() function
        # For odd length arrays, the middle value is taken, for even length
        # arrays, the first of the two middle values is taken

        # Sort the array
        flat_sort = numpy.sort(array_bip, axis=2).ravel()

        # q2_offset, median locations
        q2_idx = numexpr.evaluate("((vld_obsv / 2) + ((vld_obsv % 2) - 1))")

        # array offsets
        a_off = numpy.arange(cols * rows).reshape((rows, cols))

        # turn the locations into a useable 1D index
        idx_1D = numexpr.evaluate("(q2_idx + a_off * bands)").astype('int')
        stats[9] = flat_sort[idx_1D]  # get median values

        # now to find the original index of the median value
        sort_orig_idx = numpy.argsort(array_bip, axis=2).ravel()
        stats[10] = sort_orig_idx[idx_1D]

        # 1st quantile
        length = numexpr.evaluate("q2_idx + 1")
        q1_idx = numexpr.evaluate("((length / 2) + ((length % 2) - 1))")
        idx_1D = numexpr.evaluate("(q1_idx + a_off * bands)").astype('int')
        stats[11] = flat_sort[idx_1D]  # get 1st quantile

        # 3rd quantile
        exp = "((q2_idx + q1_idx) + a_off * bands)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[12] = flat_sort[idx_1D]  # get 3rd quantile

        # Geometric Mean
        # need to handle nan's so can't use scipy.stats.gmean ## 28/02/2013
        # x**(1./n) gives nth root
        wh = ~(numpy.isfinite(array_bip))
        array_bip[wh] = 1
        stats[13] = numpy.prod(array_bip, axis=2)**(1. / vld_obsv)

        # Any nan's will evaluate to 1.0, convert back to NaN
        wh = numexpr.evaluate("vld_obsv == 0")
        stats[13][wh] = nan

        # Convert any potential inf values to a NaN for consistancy
        wh = ~(numpy.isfinite(stats))
        stats[wh] = nan

    else:
        stats = numpy.zeros((output_band_count, rows, cols), dtype=dtype)

        # Sum
        stats[0] = numpy.nansum(array, axis=0)

        # We need to keep an int for the valid observations
        vld_obsv = numpy.sum(numpy.isfinite(array), axis=0)
        stats[2] = vld_obsv

        # Mean
        stats[1] = numexpr.evaluate("fsum / fvld_obsv",
                                    {'fsum': stats[0], 'fvld_obsv': stats[2]})

        residuals = numexpr.evaluate("array - mean",
                                     {'mean': stats[1], 'array': array})

        # Variance
        t_emp = numexpr.evaluate("residuals**2")
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[3] = numexpr.evaluate("nan_sum / (fvld_obsv - 1)",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Stddev
        stats[4] = numexpr.evaluate("sqrt(var)", {'var': stats[3]})

        # skewness
        t_emp = numexpr.evaluate("(residuals / stddev)**3",
                                 {'stddev': stats[4], 'residuals': residuals})
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[5] = numexpr.evaluate("nan_sum / fvld_obsv",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # Kurtosis
        t_emp = numexpr.evaluate("(residuals / stddev)**4",
                                 {'stddev': stats[4], 'residuals': residuals})
        nan_sum = numpy.nansum(t_emp, axis=0)
        stats[6] = numexpr.evaluate("(nan_sum / fvld_obsv) - 3",
                                    {'fvld_obsv': stats[2],
                                     'nan_sum': nan_sum})

        # MAx and Min
        stats[7] = numpy.nanmax(array, axis=0)
        stats[8] = numpy.nanmin(array, axis=0)

        # 2nd quantile (aka median)
        # Don't want any interpolated values, so can't use the standard
        # numpy.median() function
        # For odd length arrays, the middle value is taken, for even length
        # arrays, the first of the two middle values is taken

        flat_sort = numpy.sort(array, axis=0).ravel()

        # q2_offset, median locations
        q2_idx = numexpr.evaluate("((vld_obsv / 2) + ((vld_obsv % 2) - 1))")

        # array offsets
        a_off = numpy.arange(cols * rows).reshape((rows, cols))

        # turn the locations into a useable 1D index
        exp = "(q2_idx * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')
        stats[9] = flat_sort[idx_1D]  # get median values

        # now to find the original index of the median value
        sort_orig_idx = numpy.argsort(array, axis=0).ravel()
        stats[10] = sort_orig_idx[idx_1D]

        # 1st quantile
        length = numexpr.evaluate("q2_idx + 1")
        q1_idx = numexpr.evaluate("((length / 2) + ((length % 2) - 1))")
        exp = "(q1_idx * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[11] = flat_sort[idx_1D]  # get 1st quantile

        # 3rd quantile
        exp = "((q2_idx + q1_idx) * cols * rows + a_off)"
        idx_1D = numexpr.evaluate(exp).astype('int')  # 1D index
        stats[12] = flat_sort[idx_1D]  # get 3rd quantile

        # Geometric Mean
        # need to handle nan's so can't use scipy.stats.gmean ## 28/02/2013
        # x**(1./n) gives nth root
        wh = ~(numpy.isfinite(array))
        array[wh] = 1
        stats[13] = numpy.prod(array, axis=0)**(1. / vld_obsv)

        # Any nan's will evaluate to 1.0, convert back to NaN
        wh = numexpr.evaluate("vld_obsv == 0")
        stats[13][wh] = nan

        # Convert any potential inf values to a NaN for consistancy
        wh = ~(numpy.isfinite(stats))
        stats[wh] = nan

    return stats
<|endoftext|>


<commit_before># Django settings for indieitude project.

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@example.com'),
)

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': '',
        'PASSWORD': '',
        'HOST': '',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '',                      # Set to empty string for default.
    }
}

# Hosts/domain names that are valid for this site; required if DEBUG is False
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'America/Chicago'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True

# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/var/www/example.com/media/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://example.com/media/", "http://media.example.com/"
MEDIA_URL = ''

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/"
STATIC_ROOT = ''

# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# Make this unique, and don't share it with anybody.
SECRET_KEY = '9wha-70a!)zowq5(e4pxoa5uxv0(#e%dcv$1^xela9(b+#npi6'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'indieitude.urls'

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'indieitude.wsgi.application'

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    # '/Users/amechiegbe/Desktop/cm_dev/github_cm_dev/indieitude-project/indieitude/templates/admin',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

#Apps for Concepteur Market
    'designers',
    'boutiques',
    'profiles',
    'products',

#Third Party Apps

)

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}
<commit_msg>added host<commit_after># Django settings for indieitude project.

DEBUG = True
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    # ('Your Name', 'your_email@example.com'),
)

MANAGERS = ADMINS

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        # The following settings are not used with sqlite3:
        'USER': '',
        'PASSWORD': '',
        'HOST': '127.0.0.1',                      # Empty for localhost through domain sockets or '127.0.0.1' for localhost through TCP.
        'PORT': '',                      # Set to empty string for default.
    }
}

# Hosts/domain names that are valid for this site; required if DEBUG is False
# See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts
ALLOWED_HOSTS = []

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# In a Windows environment this must be set to your system time zone.
TIME_ZONE = 'America/Chicago'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale.
USE_L10N = True

# If you set this to False, Django will not use timezone-aware datetimes.
USE_TZ = True

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/var/www/example.com/media/"
MEDIA_ROOT = ''

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://example.com/media/", "http://media.example.com/"
MEDIA_URL = ''

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/"
STATIC_ROOT = ''

# URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/"
STATIC_URL = '/static/'

# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
)

# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

# Make this unique, and don't share it with anybody.
SECRET_KEY = '9wha-70a!)zowq5(e4pxoa5uxv0(#e%dcv$1^xela9(b+#npi6'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'indieitude.urls'

# Python dotted path to the WSGI application used by Django's runserver.
WSGI_APPLICATION = 'indieitude.wsgi.application'

TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    # '/Users/amechiegbe/Desktop/cm_dev/github_cm_dev/indieitude-project/indieitude/templates/admin',
)

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',

#Apps for Concepteur Market
    'designers',
    'boutiques',
    'profiles',
    'products',

#Third Party Apps

)

SESSION_SERIALIZER = 'django.contrib.sessions.serializers.JSONSerializer'

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}
<|endoftext|>


<commit_before>import csv
import os

# helper function for extracting score data
def get_scores(filedata):
    # Given a score file, extract the last element of each row
    # (expected to be a float) and remove the last 2 chars (a newline)
    assert len(filedata) == 6
    return [filedata[i].split(" ")[-1][:-1] for i in xrange(4)]

# point to score files
score_file_directory = "results\\"  # TODO make passable arg
score_files = os.listdir(score_file_directory)

# csv prep
header = ['PAM_1','PAM_2','PAM_3','Tool','Init FA','Init DNA','Final FA','Final DNA']
categories = ['3DNA', 'Chimera']
csv_dict = {elem:csv.writer(open('%s.csv' % elem,'a'),lineterminator='\n') for elem in categories}
for elem in categories:
    filename = '%s.csv' % elem
    if os.stat(filename).st_size == 0:  # if file empty, write header
        print "%s is empty, adding header" % filename
        csv_dict[elem].writerow(header)
    else:
        print "%s already exists" % filename

# append all data to csv
for i, score_file in enumerate(score_files):

    # get textfile classifiers (PAM and category)
    pam, pam_tool_txt = score_file.split("_")
    pam_tool = pam_tool_txt.split(".")[0]
    assert pam_tool in categories

    # read contents of textfile
    with open(score_file_directory + score_file) as f:
        filedata = f.readlines()

    # format row and append to csv
    scores = get_scores(filedata)
    row = [pam[0], pam[1], pam[2], pam_tool] + scores
    csv_dict[pam_tool].writerow(row)

# close csvs
for elem in categories:
    with open('%s.csv' % elem) as f: f.close()
    with open('%s.csv' % elem) as f:
        print f.readlines()
print "csv writing complete"
<commit_msg>unnecessary printing, suppress<commit_after>import csv
import os

# helper function for extracting score data
def get_scores(filedata):
    # Given a score file, extract the last element of each row
    # (expected to be a float) and remove the last 2 chars (a newline)
    assert len(filedata) == 6
    return [filedata[i].split(" ")[-1][:-1] for i in xrange(4)]

# point to score files
score_file_directory = "results\\"  # TODO make passable arg
score_files = os.listdir(score_file_directory)

# csv prep
header = ['PAM_1','PAM_2','PAM_3','Tool','Init FA','Init DNA','Final FA','Final DNA']
categories = ['3DNA', 'Chimera']
csv_dict = {elem:csv.writer(open('%s.csv' % elem,'a'),lineterminator='\n') for elem in categories}
for elem in categories:
    filename = '%s.csv' % elem
    if os.stat(filename).st_size == 0:  # if file empty, write header
        print "%s is empty, adding header" % filename
        csv_dict[elem].writerow(header)
    else:
        print "%s already exists" % filename

# append all data to csv
for i, score_file in enumerate(score_files):

    # get textfile classifiers (PAM and category)
    pam, pam_tool_txt = score_file.split("_")
    pam_tool = pam_tool_txt.split(".")[0]
    assert pam_tool in categories

    # read contents of textfile
    with open(score_file_directory + score_file) as f:
        filedata = f.readlines()

    # format row and append to csv
    scores = get_scores(filedata)
    row = [pam[0], pam[1], pam[2], pam_tool] + scores
    csv_dict[pam_tool].writerow(row)

# close csvs
for elem in categories:
    with open('%s.csv' % elem) as f: f.close()
print "csv writing complete"
<|endoftext|>


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

from __future__ import absolute_import

import logging
import oauth2 as oauth
import requests

from django.apps import apps
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.http import HttpResponse, QueryDict
from django.shortcuts import get_object_or_404
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import View, RedirectView, TemplateView

from xml.etree import cElementTree as ET

from . import conf as settings

DEFAULT_TYPE = "MERCHANT"
app_name, model_name = settings.PESAPAL_TRANSACTION_MODEL.split('.')
Transaction = apps.get_model(app_label=app_name, model_name=model_name)

logger = logging.getLogger(__name__)

class PaymentRequestMixin(object):

    def sign_request(self, params, url_to_sign):
        token = None

        # Default signature method is SignatureMethod_HMAC_SHA1
        signature_method = getattr(
            oauth, settings.PESAPAL_OAUTH_SIGNATURE_METHOD)()

        consumer = oauth.Consumer(
            settings.PESAPAL_CONSUMER_KEY, settings.PESAPAL_CONSUMER_SECRET)
        signed_request = oauth.Request.from_consumer_and_token(
            consumer, http_url=url_to_sign, parameters=params,
            is_form_encoded=True)
        signed_request.sign_request(signature_method, consumer, token)
        return signed_request

    def build_signed_request(self, payload):
        '''
        Returns a signed OAuth request. Assumes http protocol if request
        parameter is not provided.
        Otherwise it tries to figure out the url using the request object.
        '''

        if self.request:
            callback_url = self.request.build_absolute_uri(
                reverse(settings.PESAPAL_OAUTH_CALLBACK_URL)
            )
        else:
            current_site = Site.objects.get_current()
            protocol = 'http' if settings.PESAPAL_DEMO else 'https'
            callback_url = '{0}://{1}{2}'.format(
                protocol, current_site.domain,
                reverse(settings.PESAPAL_OAUTH_CALLBACK_URL)
            )

        params = {
            'oauth_callback': callback_url,
            'pesapal_request_data': payload,
        }

        signed_request = self.sign_request(params, settings.PESAPAL_IFRAME_LINK)

        return signed_request

    def generate_payload(self, **kwargs):
        '''
        Generates the XML payload required by Pesapal
        '''
        defaults = {
            'amount': 0,
            'description': '',
            'reference': '',
            'first_name': '',
            'last_name': '',
            'email': '',
            'type': DEFAULT_TYPE,
        }

        defaults.update(kwargs)

        xml_doc = ET.Element('PesapalDirectOrderInfo')
        xml_doc.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
        xml_doc.set('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
        xml_doc.set('xmlns', 'http://www.pesapal.com')

        for k, v in defaults.items():
            # convert keys into pesapal properties format e.g. first_name --> FirstName
            key_items = [str(x).title() for x in k.split('_')]
            k = ''.join(key_items)
            xml_doc.set(k, str(v))

        pesapal_request_data = ET.tostring(xml_doc)
        return pesapal_request_data

    def get_payment_url(self, **kwargs):
        '''
        Use the computed order information to generate a url for the
        Pesapal iframe.

        Params should include the following keys:
            Required params: `amount`, `description`, `reference`, `email`
            Optional params: `first_name`, `last_name`, `type`
        '''
        # assert type(params) == type({}), "Params must be of type 'dict'"

        # generate xml order
        payload = self.generate_payload(**kwargs)

        # generate iframe url
        signed_request = self.build_signed_request(payload)
        return signed_request.to_url()

    def get_payment_status(self, **kwargs):

        '''
        Query the payment status from pesapal using the `transaction_id`
        and the `merchant_reference_id`

        Params should include the following keys:
            Required params: `pesapal_merchant_reference`,
            `pesapal_transaction_tracking_id`
        '''

        params = {
            'pesapal_merchant_reference': '',
            'pesapal_transaction_tracking_id': '',
        }

        params.update(**kwargs)

        signed_request = self.sign_request(
            params, settings.PESAPAL_QUERY_STATUS_LINK)

        url = signed_request.to_url()

        response = requests.get(url, headers={
            'content-type': 'text/namevalue; charset=utf-8'
        })
        if response.status_code != requests.codes.ok:
            logger.error(
                'Unable to complete payment status request with'
                'error response code {0}'.format(response.status_code))
            comm_status = False
        else:
            comm_status = True

        response_data = {}
        response_data['raw_request'] = url
        response_data['raw_response'] = response.text
        response_data['comm_success'] = comm_status

        _, values = response.text.split('=')
        _, payment_method, status, _ = values.split(',')
        response_data['payment_status'] = status
        response_data['payment_method'] = payment_method

        return response_data

class PaymentResponseMixin(object):

    def build_url_params(self):
        url_params = QueryDict('', mutable=True)
        url_params.update({
            'pesapal_merchant_reference': self.transaction.merchant_reference,
            'pesapal_transaction_tracking_id': self.transaction.pesapal_transaction,
            }
        )
        url_params = '?' + url_params.urlencode()
        return url_params

    def get_payment_status_url(self):
        status_url = reverse('transaction_status')
        status_url += self.build_url_params()
        return status_url

    def get_order_completion_url(self):
        completed_url = reverse(settings.PESAPAL_TRANSACTION_DEFAULT_REDIRECT_URL)
        completed_url += self.build_url_params()
        return completed_url

class TransactionCompletedView(PaymentResponseMixin, TemplateView):

    '''
    After Pesapal processes the transaction this will save the transaction and
    then redirect to whatever redirect URL in your settings as
    `PESAPAL_TRANSACTION_DEFAULT_REDIRECT_URL`.

    For further processing just create a `post_save` signal on the
    `Transaction` model.
    '''

    template_name = 'django_pesapal/post_payment.html'

    def get(self, request, *args, **kwargs):

        transaction_id = request.GET.get('pesapal_transaction_tracking_id', 0)
        merchant_reference = request.GET.get('pesapal_merchant_reference', 0)

        if transaction_id and merchant_reference:
            self.transaction, created = Transaction.objects.get_or_create(
                merchant_reference=merchant_reference,
                pesapal_transaction=transaction_id
            )

        return super(TransactionCompletedView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):

        ctx = super(TransactionCompletedView, self).get_context_data(**kwargs)

        ctx['transaction_completed_url'] = self.get_order_completion_url()
        ctx['transaction_status_url'] = self.get_payment_status_url()
        ctx['payment_status'] = self.transaction.payment_status

        if self.transaction.payment_status == Transaction.PENDING:
            message = _(
                'Your payment is being processed. We will notify you'
                'once it has completed'
            )
            ctx['payment_pending'] = True
        else:
            if self.transaction.payment_status == Transaction.COMPLETED:
                message = mark_safe(
                    _('Your payment has been successfully processed.'
                      'The page should automatically redirect in'
                      '3 seconds.'
                      )
                )
            elif self.transaction.payment_status == Transaction.FAILED:
                message = _('The processing of your payment failed. '
                            'Please contact the system administrator.')
            else:
                # INVALID
                message = _('The transaction details provided were invalid.')

        ctx['message'] = message
        return ctx

class UpdatePaymentStatusMixin(PaymentRequestMixin):

    def get_params(self):
        self.merchant_reference = self.request.GET.get(
            'pesapal_merchant_reference', 0)
        self.transaction_id = self.request.GET.get(
            'pesapal_transaction_tracking_id', None)

        params = {
            'pesapal_merchant_reference': self.merchant_reference,
            'pesapal_transaction_tracking_id': self.transaction_id,
        }

        return params

    def process_payment_status(self):
        params = self.get_params()

        self.transaction = get_object_or_404(
            Transaction,
            merchant_reference=self.merchant_reference,
            pesapal_transaction=self.transaction_id
        )

        # check status from pesapal server
        response = self.get_payment_status(**params)

        if response['payment_status'] == 'COMPLETED':
            self.transaction.payment_status = Transaction.COMPLETED
            self.transaction.payment_method = response['payment_method']
        elif response['payment_status'] == 'FAILED':
            self.transaction.payment_status = Transaction.FAILED
            self.transaction.payment_method = response['payment_method']
            logger.error('Failed Transaction: {}'.format(self.transaction))
        elif response['payment_status'] == 'INVALID':
            self.transaction.payment_status = Transaction.INVALID
            logger.error('Invalid Transaction: {}'.format(self.transaction))

        self.transaction.save()

class TransactionStatusView(UpdatePaymentStatusMixin, RedirectView):

    permanent = False
    url = None

    def get_redirect_url(self, *args, **kwargs):

        params = self.get_params()
        self.process_payment_status()

        # redirect back to Transaction completed view
        url = reverse('transaction_completed')

        query_dict = QueryDict('', mutable=True)
        query_dict.update(params)
        url += '?' + query_dict.urlencode()

        return url

class IPNCallbackView(UpdatePaymentStatusMixin, PaymentResponseMixin, View):

    def build_ipn_response(self):
        params = self.get_params()
        params['pesapal_notification_type'] = self.request.GET.get(
            'pesapal_notification_type')

        query_dict = QueryDict('', mutable=True)
        query_dict.update(params)
        response = query_dict.urlencode()
        return HttpResponse(response)

    def get(self, request, *args, **kwargs):
        self.process_payment_status()
        response = self.build_ipn_response()
        return response
<commit_msg>Fix displayed message<commit_after># -*- coding: utf-8 -*-

from __future__ import absolute_import

import logging
import oauth2 as oauth
import requests

from django.apps import apps
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.http import HttpResponse, QueryDict
from django.shortcuts import get_object_or_404
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import View, RedirectView, TemplateView

from xml.etree import cElementTree as ET

from . import conf as settings

DEFAULT_TYPE = "MERCHANT"
app_name, model_name = settings.PESAPAL_TRANSACTION_MODEL.split('.')
Transaction = apps.get_model(app_label=app_name, model_name=model_name)

logger = logging.getLogger(__name__)

class PaymentRequestMixin(object):

    def sign_request(self, params, url_to_sign):
        token = None

        # Default signature method is SignatureMethod_HMAC_SHA1
        signature_method = getattr(
            oauth, settings.PESAPAL_OAUTH_SIGNATURE_METHOD)()

        consumer = oauth.Consumer(
            settings.PESAPAL_CONSUMER_KEY, settings.PESAPAL_CONSUMER_SECRET)
        signed_request = oauth.Request.from_consumer_and_token(
            consumer, http_url=url_to_sign, parameters=params,
            is_form_encoded=True)
        signed_request.sign_request(signature_method, consumer, token)
        return signed_request

    def build_signed_request(self, payload):
        '''
        Returns a signed OAuth request. Assumes http protocol if request
        parameter is not provided.
        Otherwise it tries to figure out the url using the request object.
        '''

        if self.request:
            callback_url = self.request.build_absolute_uri(
                reverse(settings.PESAPAL_OAUTH_CALLBACK_URL)
            )
        else:
            current_site = Site.objects.get_current()
            protocol = 'http' if settings.PESAPAL_DEMO else 'https'
            callback_url = '{0}://{1}{2}'.format(
                protocol, current_site.domain,
                reverse(settings.PESAPAL_OAUTH_CALLBACK_URL)
            )

        params = {
            'oauth_callback': callback_url,
            'pesapal_request_data': payload,
        }

        signed_request = self.sign_request(params, settings.PESAPAL_IFRAME_LINK)

        return signed_request

    def generate_payload(self, **kwargs):
        '''
        Generates the XML payload required by Pesapal
        '''
        defaults = {
            'amount': 0,
            'description': '',
            'reference': '',
            'first_name': '',
            'last_name': '',
            'email': '',
            'type': DEFAULT_TYPE,
        }

        defaults.update(kwargs)

        xml_doc = ET.Element('PesapalDirectOrderInfo')
        xml_doc.set('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
        xml_doc.set('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
        xml_doc.set('xmlns', 'http://www.pesapal.com')

        for k, v in defaults.items():
            # convert keys into pesapal properties format e.g. first_name --> FirstName
            key_items = [str(x).title() for x in k.split('_')]
            k = ''.join(key_items)
            xml_doc.set(k, str(v))

        pesapal_request_data = ET.tostring(xml_doc)
        return pesapal_request_data

    def get_payment_url(self, **kwargs):
        '''
        Use the computed order information to generate a url for the
        Pesapal iframe.

        Params should include the following keys:
            Required params: `amount`, `description`, `reference`, `email`
            Optional params: `first_name`, `last_name`, `type`
        '''
        # assert type(params) == type({}), "Params must be of type 'dict'"

        # generate xml order
        payload = self.generate_payload(**kwargs)

        # generate iframe url
        signed_request = self.build_signed_request(payload)
        return signed_request.to_url()

    def get_payment_status(self, **kwargs):

        '''
        Query the payment status from pesapal using the `transaction_id`
        and the `merchant_reference_id`

        Params should include the following keys:
            Required params: `pesapal_merchant_reference`,
            `pesapal_transaction_tracking_id`
        '''

        params = {
            'pesapal_merchant_reference': '',
            'pesapal_transaction_tracking_id': '',
        }

        params.update(**kwargs)

        signed_request = self.sign_request(
            params, settings.PESAPAL_QUERY_STATUS_LINK)

        url = signed_request.to_url()

        response = requests.get(url, headers={
            'content-type': 'text/namevalue; charset=utf-8'
        })
        if response.status_code != requests.codes.ok:
            logger.error(
                'Unable to complete payment status request with'
                'error response code {0}'.format(response.status_code))
            comm_status = False
        else:
            comm_status = True

        response_data = {}
        response_data['raw_request'] = url
        response_data['raw_response'] = response.text
        response_data['comm_success'] = comm_status

        _, values = response.text.split('=')
        _, payment_method, status, _ = values.split(',')
        response_data['payment_status'] = status
        response_data['payment_method'] = payment_method

        return response_data

class PaymentResponseMixin(object):

    def build_url_params(self):
        url_params = QueryDict('', mutable=True)
        url_params.update({
            'pesapal_merchant_reference': self.transaction.merchant_reference,
            'pesapal_transaction_tracking_id': self.transaction.pesapal_transaction,
            }
        )
        url_params = '?' + url_params.urlencode()
        return url_params

    def get_payment_status_url(self):
        status_url = reverse('transaction_status')
        status_url += self.build_url_params()
        return status_url

    def get_order_completion_url(self):
        completed_url = reverse(settings.PESAPAL_TRANSACTION_DEFAULT_REDIRECT_URL)
        completed_url += self.build_url_params()
        return completed_url

class TransactionCompletedView(PaymentResponseMixin, TemplateView):

    '''
    After Pesapal processes the transaction this will save the transaction and
    then redirect to whatever redirect URL in your settings as
    `PESAPAL_TRANSACTION_DEFAULT_REDIRECT_URL`.

    For further processing just create a `post_save` signal on the
    `Transaction` model.
    '''

    template_name = 'django_pesapal/post_payment.html'

    def get(self, request, *args, **kwargs):

        transaction_id = request.GET.get('pesapal_transaction_tracking_id', 0)
        merchant_reference = request.GET.get('pesapal_merchant_reference', 0)

        if transaction_id and merchant_reference:
            self.transaction, created = Transaction.objects.get_or_create(
                merchant_reference=merchant_reference,
                pesapal_transaction=transaction_id
            )

        return super(TransactionCompletedView, self).get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):

        ctx = super(TransactionCompletedView, self).get_context_data(**kwargs)

        ctx['transaction_completed_url'] = self.get_order_completion_url()
        ctx['transaction_status_url'] = self.get_payment_status_url()
        ctx['payment_status'] = self.transaction.payment_status

        if self.transaction.payment_status == Transaction.PENDING:
            message = _(
                'Your payment is being processed. We will notify you '
                'once it has completed'
            )
            ctx['payment_pending'] = True
        else:
            if self.transaction.payment_status == Transaction.COMPLETED:
                message = mark_safe(
                    _('Your payment has been successfully processed. '
                      'The page should automatically redirect in '
                      '3 seconds.'
                      )
                )
            elif self.transaction.payment_status == Transaction.FAILED:
                message = _('The processing of your payment failed. '
                            'Please contact the system administrator.')
            else:
                # INVALID
                message = _('The transaction details provided were invalid.')

        ctx['message'] = message
        return ctx

class UpdatePaymentStatusMixin(PaymentRequestMixin):

    def get_params(self):
        self.merchant_reference = self.request.GET.get(
            'pesapal_merchant_reference', 0)
        self.transaction_id = self.request.GET.get(
            'pesapal_transaction_tracking_id', None)

        params = {
            'pesapal_merchant_reference': self.merchant_reference,
            'pesapal_transaction_tracking_id': self.transaction_id,
        }

        return params

    def process_payment_status(self):
        params = self.get_params()

        self.transaction = get_object_or_404(
            Transaction,
            merchant_reference=self.merchant_reference,
            pesapal_transaction=self.transaction_id
        )

        # check status from pesapal server
        response = self.get_payment_status(**params)

        if response['payment_status'] == 'COMPLETED':
            self.transaction.payment_status = Transaction.COMPLETED
            self.transaction.payment_method = response['payment_method']
        elif response['payment_status'] == 'FAILED':
            self.transaction.payment_status = Transaction.FAILED
            self.transaction.payment_method = response['payment_method']
            logger.error('Failed Transaction: {}'.format(self.transaction))
        elif response['payment_status'] == 'INVALID':
            self.transaction.payment_status = Transaction.INVALID
            logger.error('Invalid Transaction: {}'.format(self.transaction))

        self.transaction.save()

class TransactionStatusView(UpdatePaymentStatusMixin, RedirectView):

    permanent = False
    url = None

    def get_redirect_url(self, *args, **kwargs):

        params = self.get_params()
        self.process_payment_status()

        # redirect back to Transaction completed view
        url = reverse('transaction_completed')

        query_dict = QueryDict('', mutable=True)
        query_dict.update(params)
        url += '?' + query_dict.urlencode()

        return url

class IPNCallbackView(UpdatePaymentStatusMixin, PaymentResponseMixin, View):

    def build_ipn_response(self):
        params = self.get_params()
        params['pesapal_notification_type'] = self.request.GET.get(
            'pesapal_notification_type')

        query_dict = QueryDict('', mutable=True)
        query_dict.update(params)
        response = query_dict.urlencode()
        return HttpResponse(response)

    def get(self, request, *args, **kwargs):
        self.process_payment_status()
        response = self.build_ipn_response()
        return response
<|endoftext|>


<commit_before>import sublime, sublime_plugin
import re
import time
try:
    # Python 3.x
    from . import context
    from .salesforce.metadata import apex_completions
except:
    # Python 2.x
    import context
    from salesforce.metadata import apex_completions

class SobjectCompletions(sublime_plugin.EventListener):
    """
    When you refresh all, your sobject completions will updated at the same time

    when you input a variable, this part will get the variable type by the variable
    and then get the field information according to the variable type
    """

    def on_query_completions(self, view, prefix, locations):
        if not view.match_selector(locations[0], "source.java"):
            return []

        # Load sobjects compoletions
        setting = sublime.load_settings("sobjects_completion.sublime-settings")

        # Load sobjects field meatadata
        toolingapi_settings = context.get_toolingapi_settings()
        username = toolingapi_settings["username"]

        # If current username is in settings, it means project is initiated
        if not setting.has(username):
            return

        location = locations[0]
        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))

        if ch != ".":
            return

        # Get the variable name
        pt = pt - 1
        variable_name = view.substr(view.word(pt))

        # Get the matched region by variable name
        matched_regions = view.find_all("\\w+\\s+" + variable_name + "\\s*[:;=]")
        if len(matched_regions) == 0: return
        matched_block = view.substr(matched_regions[0])

        # Get the matched variable type
        sobject = matched_block.split(" ")[0]

        # If username is in settings, get the sobject fields describe dict
        metadata = setting.get(username)
        completion_list = []
        if sobject in metadata:
            fields = metadata.get(sobject)
        elif sobject.capitalize() in metadata:
            fields = metadata.get(sobject.lower().capitalize())
        else:
            return

        for key in fields.keys():
            completion_list.append((sobject + "." + key, fields[key]))

        return (completion_list, sublime.INHIBIT_WORD_COMPLETIONS or sublime.INHIBIT_EXPLICIT_COMPLETIONS)

class ApexCompletions(sublime_plugin.EventListener):
    def on_query_completions(self, view, prefix, locations):
        if not view.match_selector(locations[0], "source.java"):
            return []

        location = locations[0]
        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))

        if ch != ".":
            return

        # Get the variable name
        # Get the variable name
        pt = pt - 1
        variable_name = view.substr(view.word(pt))
        print (variable_name)

        # Get the matched variable type
        matched_regions = view.find_all("\\w+\\s+" + variable_name + "\\s*[:;=]")
        variable_type = ""
        if len(matched_regions) > 0:
            matched_block = view.substr(matched_regions[0])
            variable_type = matched_block.split(" ")[0]

        print (variable_name, variable_type)
        completion_list = []
        if variable_name in apex_completions:
            methods = apex_completions.get(variable_name)
        elif variable_name.capitalize() in apex_completions:
            methods = apex_completions.get(variable_name.capitalize())
        elif variable_type in apex_completions:
            methods = apex_completions.get(variable_type)
        elif variable_type.capitalize() in apex_completions:
            methods = apex_completions.get(variable_type.capitalize())
        else:
            return

        for key in methods.keys():
            completion_list.append((key, methods[key]))

        return (completion_list, sublime.INHIBIT_WORD_COMPLETIONS or sublime.INHIBIT_EXPLICIT_COMPLETIONS)

# Extends Sublime Text autocompletion to find matches in all open
# files. By default, Sublime only considers words from the current file.

# limits to prevent bogging down the system
MIN_WORD_SIZE = 3
MAX_WORD_SIZE = 30

MAX_VIEWS = 20
MAX_WORDS_PER_VIEW = 100
MAX_FIX_TIME_SECS_PER_VIEW = 0.01

class CrossViewCompletions(sublime_plugin.EventListener):
    """
    https://github.com/alienhard/SublimeAllAutocomplete/blob/master/all_views_completions.py
    """

    def on_query_completions(self, view, prefix, locations):
        words = []

        # Limit number of views but always include the active view. This
        # view goes first to prioritize matches close to cursor position.
        other_views = [v for v in sublime.active_window().views() if v.id != view.id]
        views = [view] + other_views
        views = views[0:MAX_VIEWS]

        for v in views:
            if len(locations) > 0 and v.id == view.id:
                view_words = v.extract_completions(prefix, locations[0])
            else:
                view_words = v.extract_completions(prefix)

            view_words = [w for w in view_words]
            view_words = self.filter_words(view_words)
            view_words = self.fix_truncation(v, view_words)
            words += view_words

        words = self.without_duplicates(words)
        matches = [(w, w) for w in words]
        return matches

    def filter_words(self, words):
        words = words[0:MAX_WORDS_PER_VIEW]
        return [w for w in words if MIN_WORD_SIZE <= len(w) <= MAX_WORD_SIZE]

    # keeps first instance of every word and retains the original order
    # (n^2 but should not be a problem as len(words) <= MAX_VIEWS*MAX_WORDS_PER_VIEW)
    def without_duplicates(self, words):
        result = []
        for w in words:
            if w not in result:
                result.append(w)
        return result

    # Ugly workaround for truncation bug in Sublime when using view.extract_completions()
    # in some types of files.
    def fix_truncation(self, view, words):
        fixed_words = []
        start_time = time.time()

        for i, w in enumerate(words):
            #The word is truncated if and only if it cannot be found with a word boundary before and after

            # this fails to match strings with trailing non-alpha chars, like
            # 'foo?' or 'bar!', which are common for instance in Ruby.
            truncated = view.find(r'\b' + re.escape(w) + r'\b', 0) is None
            if truncated:
                #Truncation is always by a single character, so we extend the word by one word character before a word boundary
                extended_words = []
                view.find_all(r'\b' + re.escape(w) + r'\w\b', 0, "$0", extended_words)
                if len(extended_words) > 0:
                    fixed_words += extended_words
                else:
                    # to compensate for the missing match problem mentioned above, just
                    # use the old word if we didn't find any extended matches
                    fixed_words.append(w)
            else:
                #Pass through non-truncated words
                fixed_words.append(w)

            # if too much time is spent in here, bail out,
            # and don't bother fixing the remaining words
            if time.time() - start_time > MAX_FIX_TIME_SECS_PER_VIEW:
                return fixed_words + words[i+1:]

        return fixed_words

class PageCompletions(sublime_plugin.EventListener):
    """
    Provide completions that match just after typing an opening angle bracket
    https://github.com/jairzh/sublime-sfdc-assist/blob/master/visualforce_completions.py
    """

    def on_query_completions(self, view, prefix, locations):
        # Only trigger within HTML
        if not view.match_selector(locations[0],
                "text.html - source"):
            return []

        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))
        if ch != '<':
            return []

        # Not include chart component
        return ([
            ('apex:actionFunction\tVF', 'apex:actionFunction name="$1" action="$2" rerender="$3" status="$4"/>'),
            ('apex:actionPoller\tVF', 'apex:actionPoller action="$1" rerender="$2" interval="$3"/>'),
            ('apex:actionRegion\tVF', 'apex:actionRegion>\n\t$1\n</apex:actionRegion>'),
            ('apex:actionStatus\tVF', 'apex:actionStatus id="$1"/>'),
            ('apex:actionSupport\tVF', 'apex:actionSupport event="$1" action="$2" rerender="$3" status="$4"/>'),
            ('apex:attribute\tVF', 'apex:attribute name="$1" description="$2" type="$3" required=\"${4:true}\"/>'),
            ('apex:column\tVF', 'apex:column value="$1"/>'),
            ('apex:commandButton\tVF', 'apex:commandButton action="$1" value="$2" id="$3"/>'),
            ('apex:commandLink\tVF', 'apex:commandLink action="$1" value="$2" id="$3"/>'),
            ('apex:component\tVF', 'apex:component>\n\t$1\n</apex:component>'),
            ('apex:componentBody\tVF', 'apex:componentBody />'),
            ('apex:composition\tVF', 'apex:composition template="$1">\n\t$2\n</apex:composition>'),
            ('apex:dataList\tVF', 'apex:dataList value="$1" var="$2" id="$3">\n\t$4\n</apex:dataList>'),
            ('apex:dataTable\tVF', 'apex:dataTable value="$1" var="$2" id="$3">\n\t$4\n</apex:dataTable>'),
            ('apex:define\tVF', 'apex:define name="$1"/>'),
            ('apex:detail\tVF', 'apex:detail subject="$1" relatedList=\"${2:false}\" title=\"${3:false}\"/>'),
            ('apex:dynamicComponent\tVF', 'apex:dynamicComponent componentValue="$1"/>'),
            ('apex:emailPublisher\tVF', 'apex:emailPublisher />'),
            ('apex:enhancedList\tVF', 'apex:enhancedList type="$1" height="$2" rowsPerPage="$3" id="$4"/>'),
            ('apex:facet\tVF', 'apex:facet name="$1">$2<apex:facet/>'),
            ('apex:flash\tVF', 'apex:flash src="$1" height="$2" width="$3"/>'),
            ('apex:form\tVF', 'apex:form id="$1">\n\t$2\n</apex:form>'),
            ('apex:iframe\tVF', 'apex:iframe src="$1" scrolling="$2" id="$3"/>'),
            ('apex:image\tVF', 'apex:image id="$1" value="$2" width="$3" height="$4"/>'),
            ('apex:include\tVF', 'apex:include pageName="$1"/>'),
            ('apex:includeScript\tVF', 'apex:includeScript value="$1"/>'),
            ('apex:inlineEditSupport\tVF', 'apex:inlineEditSupport showOnEdit="$1" cancelButton="$2" hideOnEdit="$3" event="$4"/>'),
            ('apex:inputCheckbox\tVF', 'apex:inputCheckbox value="$1"/>'),
            ('apex:inputField\tVF', 'apex:inputField value="$1"/>'),
            ('apex:inputHidden\tVF', 'apex:inputHidden value="$1"/>'),
            ('apex:inputSecret\tVF', 'apex:inputSecret value="$1"/>'),
            ('apex:inputText\tVF', 'apex:inputText value="$1"/>'),
            ('apex:inputTextarea\tVF', 'apex:inputTextarea value="$1"/>'),
            ('apex:insert\tVF', 'apex:insert name="$1"/>'),
            ('apex:listViews\tVF', 'apex:listViews name="$1"/>'),
            ('apex:message\tVF', 'apex:message for="$1"/>'),
            ('apex:messages\tVF', 'apex:messages />'),
            ('apex:outputField\tVF', 'apex:outputField value="$1"/>'),
            ('apex:outputLabel\tVF', 'apex:outputLabel value="$1" for="$2"/>'),
            ('apex:outputLink\tVF', 'apex:outputLink value="$1"/>'),
            ('apex:outputPanel\tVF', 'apex:outputPanel id="$1">\n\t$2\n</apex:outputPanel>'),
            ('apex:outputText\tVF', 'apex:outputText value="$1"/>'),
            ('apex:page\tVF', 'apex:page id="$1">\n\t$2\n</apex:page>'),
            ('apex:pageBlock\tVF', 'apex:pageBlock mode=\"${1:detail}\">\n\t$2\n</apex:pageBlock>'),
            ('apex:pageBlockButtons\tVF', 'apex:pageBlockButtons>\n\t$1\n</apex:pageBlockButtons>'),
            ('apex:pageBlockSection\tVF', 'apex:pageBlockSection title="$1" columns="$2">\n\t$3\n</apex:pageBlockSection>'),
            ('apex:pageBlockSectionItem\tVF', 'apex:pageBlockSectionItem>\n\t$1\n</apex:pageBlockSectionItem>'),
            ('apex:pageBlockTable\tVF', 'apex:pageBlockTable value="$1" var="$2">\n\t$3\n</apex:pageBlockTable>'),
            ('apex:pageMessage\tVF', 'apex:pageMessage summary="$1" serverity="$2" strength=\"${3:3}\"/>'),
            ('apex:pageMessages\tVF', 'apex:pageMessages />'),
            ('apex:panelBar\tVF', 'apex:panelBar>\n\t$1\n</apex:panelBar>'),
            ('apex:panelBarItem\tVF', 'apex:panelBarItem label="$1">$2<apex:panelBarItem/>'),
            ('apex:panelGrid\tVF', 'apex:panelGrid columns="$1">\n\t$2\n</apex:panelGrid>'),
            ('apex:panelGroup\tVF', 'apex:panelGroup id="$1">\n\t$2\n</apex:panelGroup>'),
            ('apex:param\tVF', 'apex:param value="$1"/>'),
            ('apex:relatedList\tVF', 'apex:relatedList list="$1"/>'),
            ('apex:repeat\tVF', 'apex:repeat value="$1" var="$2">\n\t$3\n</apex:repeat>'),
            ('apex:selectCheckboxes\tVF', 'apex:selectCheckboxes value="$1">\n\t$2\n</apex:selectCheckboxes>'),
            ('apex:selectList\tVF', 'apex:selectList value="$1" size="$2">\n\t$3\n</apex:selectList>'),
            ('apex:selectOption\tVF', 'apex:selectOption itemValue="$1" itemLabel="$2"/>'),
            ('apex:selectOptions\tVF', 'apex:selectOptions value="$1"/>'),
            ('apex:selectRadio\tVF', 'apex:selectRadio value="$1">\n\t$2\n</apex:selectRadio>'),
            ('apex:stylesheet\tVF', 'apex:stylesheet value="$1"/>'),
            ('apex:tab\tVF', 'apex:tab label="$1" name="$2"/>'),
            ('apex:tabPanel\tVF', 'apex:tabPanel>\n\t$2\n</apex:tabPanel>'),
            ('apex:toolbarGroup\tVF', 'apex:toolbarGroup itemSeparator="$1" id="$2">\n\t$3\n</apex:toolbarGroup>'),
            ('apex:variable\tVF', 'apex:variable var="$1" value="$2"/>'),
            ('apex:vote\tVF', 'apex:vote objectId="$1"/>')

        ], sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)<commit_msg>Account.N should have completions<commit_after>import sublime, sublime_plugin
import re
import time
try:
    # Python 3.x
    from . import context
    from .salesforce.metadata import apex_completions
except:
    # Python 2.x
    import context
    from salesforce.metadata import apex_completions

class SobjectCompletions(sublime_plugin.EventListener):
    """
    When you refresh all, your sobject completions will updated at the same time

    when you input a variable, this part will get the variable type by the variable
    and then get the field information according to the variable type
    """

    def on_query_completions(self, view, prefix, locations):
        if not view.match_selector(locations[0], "source.java"):
            return []

        # Load sobjects compoletions
        setting = sublime.load_settings("sobjects_completion.sublime-settings")

        # Load sobjects field meatadata
        toolingapi_settings = context.get_toolingapi_settings()
        username = toolingapi_settings["username"]

        # If current username is in settings, it means project is initiated
        if not setting.has(username):
            return

        location = locations[0]
        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))

        if ch != ".":
            return

        # Get the variable name
        pt = pt - 1
        variable_name = view.substr(view.word(pt))

        # Get the matched region by variable name
        matched_regions = view.find_all("\\w+\\s+" + variable_name + "\\s*[:;=]")
        sobject = ""
        if len(matched_regions) > 0:
            matched_block = view.substr(matched_regions[0])
            sobject = matched_block.split(" ")[0]

        # If username is in settings, get the sobject fields describe dict
        metadata = setting.get(username)
        completion_list = []
        if sobject in metadata:
            fields = metadata.get(sobject)
        elif sobject.capitalize() in metadata:
            fields = metadata.get(sobject.lower().capitalize())
        elif variable_name in metadata:
            fields = metadata.get(variable_name)
        elif variable_name.capitalize() in metadata:
            fields = metadata.get(variable_name.lower().capitalize())
        else:
            return

        for key in fields.keys():
            completion_list.append((sobject + "." + key, fields[key]))

        return (completion_list, sublime.INHIBIT_WORD_COMPLETIONS or sublime.INHIBIT_EXPLICIT_COMPLETIONS)

class ApexCompletions(sublime_plugin.EventListener):
    def on_query_completions(self, view, prefix, locations):
        if not view.match_selector(locations[0], "source.java"):
            return []

        location = locations[0]
        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))

        if ch != ".":
            return

        # Get the variable name
        # Get the variable name
        pt = pt - 1
        variable_name = view.substr(view.word(pt))
        print (variable_name)

        # Get the matched variable type
        matched_regions = view.find_all("\\w+\\s+" + variable_name + "\\s*[:;=]")
        variable_type = ""
        if len(matched_regions) > 0:
            matched_block = view.substr(matched_regions[0])
            variable_type = matched_block.split(" ")[0]

        print (variable_name, variable_type)
        completion_list = []
        if variable_name in apex_completions:
            methods = apex_completions.get(variable_name)
        elif variable_name.capitalize() in apex_completions:
            methods = apex_completions.get(variable_name.capitalize())
        elif variable_type in apex_completions:
            methods = apex_completions.get(variable_type)
        elif variable_type.capitalize() in apex_completions:
            methods = apex_completions.get(variable_type.capitalize())
        else:
            return

        for key in methods.keys():
            completion_list.append((key, methods[key]))

        return (completion_list, sublime.INHIBIT_WORD_COMPLETIONS or sublime.INHIBIT_EXPLICIT_COMPLETIONS)

# Extends Sublime Text autocompletion to find matches in all open
# files. By default, Sublime only considers words from the current file.

# limits to prevent bogging down the system
MIN_WORD_SIZE = 3
MAX_WORD_SIZE = 30

MAX_VIEWS = 20
MAX_WORDS_PER_VIEW = 100
MAX_FIX_TIME_SECS_PER_VIEW = 0.01

class CrossViewCompletions(sublime_plugin.EventListener):
    """
    https://github.com/alienhard/SublimeAllAutocomplete/blob/master/all_views_completions.py
    """

    def on_query_completions(self, view, prefix, locations):
        words = []

        # Limit number of views but always include the active view. This
        # view goes first to prioritize matches close to cursor position.
        other_views = [v for v in sublime.active_window().views() if v.id != view.id]
        views = [view] + other_views
        views = views[0:MAX_VIEWS]

        for v in views:
            if len(locations) > 0 and v.id == view.id:
                view_words = v.extract_completions(prefix, locations[0])
            else:
                view_words = v.extract_completions(prefix)

            view_words = [w for w in view_words]
            view_words = self.filter_words(view_words)
            view_words = self.fix_truncation(v, view_words)
            words += view_words

        words = self.without_duplicates(words)
        matches = [(w, w) for w in words]
        return matches

    def filter_words(self, words):
        words = words[0:MAX_WORDS_PER_VIEW]
        return [w for w in words if MIN_WORD_SIZE <= len(w) <= MAX_WORD_SIZE]

    # keeps first instance of every word and retains the original order
    # (n^2 but should not be a problem as len(words) <= MAX_VIEWS*MAX_WORDS_PER_VIEW)
    def without_duplicates(self, words):
        result = []
        for w in words:
            if w not in result:
                result.append(w)
        return result

    # Ugly workaround for truncation bug in Sublime when using view.extract_completions()
    # in some types of files.
    def fix_truncation(self, view, words):
        fixed_words = []
        start_time = time.time()

        for i, w in enumerate(words):
            #The word is truncated if and only if it cannot be found with a word boundary before and after

            # this fails to match strings with trailing non-alpha chars, like
            # 'foo?' or 'bar!', which are common for instance in Ruby.
            truncated = view.find(r'\b' + re.escape(w) + r'\b', 0) is None
            if truncated:
                #Truncation is always by a single character, so we extend the word by one word character before a word boundary
                extended_words = []
                view.find_all(r'\b' + re.escape(w) + r'\w\b', 0, "$0", extended_words)
                if len(extended_words) > 0:
                    fixed_words += extended_words
                else:
                    # to compensate for the missing match problem mentioned above, just
                    # use the old word if we didn't find any extended matches
                    fixed_words.append(w)
            else:
                #Pass through non-truncated words
                fixed_words.append(w)

            # if too much time is spent in here, bail out,
            # and don't bother fixing the remaining words
            if time.time() - start_time > MAX_FIX_TIME_SECS_PER_VIEW:
                return fixed_words + words[i+1:]

        return fixed_words

class PageCompletions(sublime_plugin.EventListener):
    """
    Provide completions that match just after typing an opening angle bracket
    https://github.com/jairzh/sublime-sfdc-assist/blob/master/visualforce_completions.py
    """

    def on_query_completions(self, view, prefix, locations):
        # Only trigger within HTML
        if not view.match_selector(locations[0],
                "text.html - source"):
            return []

        pt = locations[0] - len(prefix) - 1
        ch = view.substr(sublime.Region(pt, pt + 1))
        if ch != '<':
            return []

        # Not include chart component
        return ([
            ('apex:actionFunction\tVF', 'apex:actionFunction name="$1" action="$2" rerender="$3" status="$4"/>'),
            ('apex:actionPoller\tVF', 'apex:actionPoller action="$1" rerender="$2" interval="$3"/>'),
            ('apex:actionRegion\tVF', 'apex:actionRegion>\n\t$1\n</apex:actionRegion>'),
            ('apex:actionStatus\tVF', 'apex:actionStatus id="$1"/>'),
            ('apex:actionSupport\tVF', 'apex:actionSupport event="$1" action="$2" rerender="$3" status="$4"/>'),
            ('apex:attribute\tVF', 'apex:attribute name="$1" description="$2" type="$3" required=\"${4:true}\"/>'),
            ('apex:column\tVF', 'apex:column value="$1"/>'),
            ('apex:commandButton\tVF', 'apex:commandButton action="$1" value="$2" id="$3"/>'),
            ('apex:commandLink\tVF', 'apex:commandLink action="$1" value="$2" id="$3"/>'),
            ('apex:component\tVF', 'apex:component>\n\t$1\n</apex:component>'),
            ('apex:componentBody\tVF', 'apex:componentBody />'),
            ('apex:composition\tVF', 'apex:composition template="$1">\n\t$2\n</apex:composition>'),
            ('apex:dataList\tVF', 'apex:dataList value="$1" var="$2" id="$3">\n\t$4\n</apex:dataList>'),
            ('apex:dataTable\tVF', 'apex:dataTable value="$1" var="$2" id="$3">\n\t$4\n</apex:dataTable>'),
            ('apex:define\tVF', 'apex:define name="$1"/>'),
            ('apex:detail\tVF', 'apex:detail subject="$1" relatedList=\"${2:false}\" title=\"${3:false}\"/>'),
            ('apex:dynamicComponent\tVF', 'apex:dynamicComponent componentValue="$1"/>'),
            ('apex:emailPublisher\tVF', 'apex:emailPublisher />'),
            ('apex:enhancedList\tVF', 'apex:enhancedList type="$1" height="$2" rowsPerPage="$3" id="$4"/>'),
            ('apex:facet\tVF', 'apex:facet name="$1">$2<apex:facet/>'),
            ('apex:flash\tVF', 'apex:flash src="$1" height="$2" width="$3"/>'),
            ('apex:form\tVF', 'apex:form id="$1">\n\t$2\n</apex:form>'),
            ('apex:iframe\tVF', 'apex:iframe src="$1" scrolling="$2" id="$3"/>'),
            ('apex:image\tVF', 'apex:image id="$1" value="$2" width="$3" height="$4"/>'),
            ('apex:include\tVF', 'apex:include pageName="$1"/>'),
            ('apex:includeScript\tVF', 'apex:includeScript value="$1"/>'),
            ('apex:inlineEditSupport\tVF', 'apex:inlineEditSupport showOnEdit="$1" cancelButton="$2" hideOnEdit="$3" event="$4"/>'),
            ('apex:inputCheckbox\tVF', 'apex:inputCheckbox value="$1"/>'),
            ('apex:inputField\tVF', 'apex:inputField value="$1"/>'),
            ('apex:inputHidden\tVF', 'apex:inputHidden value="$1"/>'),
            ('apex:inputSecret\tVF', 'apex:inputSecret value="$1"/>'),
            ('apex:inputText\tVF', 'apex:inputText value="$1"/>'),
            ('apex:inputTextarea\tVF', 'apex:inputTextarea value="$1"/>'),
            ('apex:insert\tVF', 'apex:insert name="$1"/>'),
            ('apex:listViews\tVF', 'apex:listViews name="$1"/>'),
            ('apex:message\tVF', 'apex:message for="$1"/>'),
            ('apex:messages\tVF', 'apex:messages />'),
            ('apex:outputField\tVF', 'apex:outputField value="$1"/>'),
            ('apex:outputLabel\tVF', 'apex:outputLabel value="$1" for="$2"/>'),
            ('apex:outputLink\tVF', 'apex:outputLink value="$1"/>'),
            ('apex:outputPanel\tVF', 'apex:outputPanel id="$1">\n\t$2\n</apex:outputPanel>'),
            ('apex:outputText\tVF', 'apex:outputText value="$1"/>'),
            ('apex:page\tVF', 'apex:page id="$1">\n\t$2\n</apex:page>'),
            ('apex:pageBlock\tVF', 'apex:pageBlock mode=\"${1:detail}\">\n\t$2\n</apex:pageBlock>'),
            ('apex:pageBlockButtons\tVF', 'apex:pageBlockButtons>\n\t$1\n</apex:pageBlockButtons>'),
            ('apex:pageBlockSection\tVF', 'apex:pageBlockSection title="$1" columns="$2">\n\t$3\n</apex:pageBlockSection>'),
            ('apex:pageBlockSectionItem\tVF', 'apex:pageBlockSectionItem>\n\t$1\n</apex:pageBlockSectionItem>'),
            ('apex:pageBlockTable\tVF', 'apex:pageBlockTable value="$1" var="$2">\n\t$3\n</apex:pageBlockTable>'),
            ('apex:pageMessage\tVF', 'apex:pageMessage summary="$1" serverity="$2" strength=\"${3:3}\"/>'),
            ('apex:pageMessages\tVF', 'apex:pageMessages />'),
            ('apex:panelBar\tVF', 'apex:panelBar>\n\t$1\n</apex:panelBar>'),
            ('apex:panelBarItem\tVF', 'apex:panelBarItem label="$1">$2<apex:panelBarItem/>'),
            ('apex:panelGrid\tVF', 'apex:panelGrid columns="$1">\n\t$2\n</apex:panelGrid>'),
            ('apex:panelGroup\tVF', 'apex:panelGroup id="$1">\n\t$2\n</apex:panelGroup>'),
            ('apex:param\tVF', 'apex:param value="$1"/>'),
            ('apex:relatedList\tVF', 'apex:relatedList list="$1"/>'),
            ('apex:repeat\tVF', 'apex:repeat value="$1" var="$2">\n\t$3\n</apex:repeat>'),
            ('apex:selectCheckboxes\tVF', 'apex:selectCheckboxes value="$1">\n\t$2\n</apex:selectCheckboxes>'),
            ('apex:selectList\tVF', 'apex:selectList value="$1" size="$2">\n\t$3\n</apex:selectList>'),
            ('apex:selectOption\tVF', 'apex:selectOption itemValue="$1" itemLabel="$2"/>'),
            ('apex:selectOptions\tVF', 'apex:selectOptions value="$1"/>'),
            ('apex:selectRadio\tVF', 'apex:selectRadio value="$1">\n\t$2\n</apex:selectRadio>'),
            ('apex:stylesheet\tVF', 'apex:stylesheet value="$1"/>'),
            ('apex:tab\tVF', 'apex:tab label="$1" name="$2"/>'),
            ('apex:tabPanel\tVF', 'apex:tabPanel>\n\t$2\n</apex:tabPanel>'),
            ('apex:toolbarGroup\tVF', 'apex:toolbarGroup itemSeparator="$1" id="$2">\n\t$3\n</apex:toolbarGroup>'),
            ('apex:variable\tVF', 'apex:variable var="$1" value="$2"/>'),
            ('apex:vote\tVF', 'apex:vote objectId="$1"/>')

        ], sublime.INHIBIT_WORD_COMPLETIONS | sublime.INHIBIT_EXPLICIT_COMPLETIONS)<|endoftext|>