<commit_before>from xblock.core import Scope

# A list of metadata that this module can inherit from its parent module
INHERITABLE_METADATA = (
    'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize',
    # TODO (ichuang): used for Fall 2012 xqa server access
    'xqa_key',
    # How many days early to show a course element to beta testers (float)
    # intended to be set per-course, but can be overridden in for specific
    # elements.  Can be a float.
    'days_early_for_beta',
    'giturl',  # for git edit link
    'static_asset_path',	# for static assets placed outside xcontent contentstore
)

def compute_inherited_metadata(descriptor):
    """Given a descriptor, traverse all of its descendants and do metadata
    inheritance.  Should be called on a CourseDescriptor after importing a
    course.

    NOTE: This means that there is no such thing as lazy loading at the
    moment--this accesses all the children."""
    for child in descriptor.get_children():
        inherit_metadata(child, descriptor._model_data)
        compute_inherited_metadata(child)

def inherit_metadata(descriptor, model_data):
    """
    Updates this module with metadata inherited from a containing module.
    Only metadata specified in self.inheritable_metadata will
    be inherited
    """
    # The inherited values that are actually being used.
    if not hasattr(descriptor, '_inherited_metadata'):
        setattr(descriptor, '_inherited_metadata', {})

    # All inheritable metadata values (for which a value exists in model_data).
    if not hasattr(descriptor, '_inheritable_metadata'):
        setattr(descriptor, '_inheritable_metadata', {})

    # Set all inheritable metadata from kwargs that are
    # in self.inheritable_metadata and aren't already set in metadata
    for attr in INHERITABLE_METADATA:
        if attr in model_data:
            descriptor._inheritable_metadata[attr] = model_data[attr]
            if attr not in descriptor._model_data:
                descriptor._inherited_metadata[attr] = model_data[attr]
                descriptor._model_data[attr] = model_data[attr]

def own_metadata(module):
    # IN SPLIT MONGO this is just ['metadata'] as it keeps ['_inherited_metadata'] separate!
    # FIXME move into kvs? will that work for xml mongo?
    """
    Return a dictionary that contains only non-inherited field keys,
    mapped to their values
    """
    inherited_metadata = getattr(module, '_inherited_metadata', {})
    metadata = {}
    for field in module.fields + module.lms.fields:
        # Only save metadata that wasn't inherited
        if field.scope != Scope.settings:
            continue

        if field.name in inherited_metadata and module._model_data.get(field.name) == inherited_metadata.get(field.name):
            continue

        if field.name not in module._model_data:
            continue

        try:
            metadata[field.name] = module._model_data[field.name]
        except KeyError:
            # Ignore any missing keys in _model_data
            pass

    return metadata
<commit_msg>pep8 in inheritance.py<commit_after>from xblock.core import Scope

# A list of metadata that this module can inherit from its parent module
INHERITABLE_METADATA = (
    'graded', 'start', 'due', 'graceperiod', 'showanswer', 'rerandomize',
    # TODO (ichuang): used for Fall 2012 xqa server access
    'xqa_key',
    # How many days early to show a course element to beta testers (float)
    # intended to be set per-course, but can be overridden in for specific
    # elements.  Can be a float.
    'days_early_for_beta',
    'giturl',  # for git edit link
    'static_asset_path',       # for static assets placed outside xcontent contentstore
)

def compute_inherited_metadata(descriptor):
    """Given a descriptor, traverse all of its descendants and do metadata
    inheritance.  Should be called on a CourseDescriptor after importing a
    course.

    NOTE: This means that there is no such thing as lazy loading at the
    moment--this accesses all the children."""
    for child in descriptor.get_children():
        inherit_metadata(child, descriptor._model_data)
        compute_inherited_metadata(child)

def inherit_metadata(descriptor, model_data):
    """
    Updates this module with metadata inherited from a containing module.
    Only metadata specified in self.inheritable_metadata will
    be inherited
    """
    # The inherited values that are actually being used.
    if not hasattr(descriptor, '_inherited_metadata'):
        setattr(descriptor, '_inherited_metadata', {})

    # All inheritable metadata values (for which a value exists in model_data).
    if not hasattr(descriptor, '_inheritable_metadata'):
        setattr(descriptor, '_inheritable_metadata', {})

    # Set all inheritable metadata from kwargs that are
    # in self.inheritable_metadata and aren't already set in metadata
    for attr in INHERITABLE_METADATA:
        if attr in model_data:
            descriptor._inheritable_metadata[attr] = model_data[attr]
            if attr not in descriptor._model_data:
                descriptor._inherited_metadata[attr] = model_data[attr]
                descriptor._model_data[attr] = model_data[attr]

def own_metadata(module):
    # IN SPLIT MONGO this is just ['metadata'] as it keeps ['_inherited_metadata'] separate!
    # FIXME move into kvs? will that work for xml mongo?
    """
    Return a dictionary that contains only non-inherited field keys,
    mapped to their values
    """
    inherited_metadata = getattr(module, '_inherited_metadata', {})
    metadata = {}
    for field in module.fields + module.lms.fields:
        # Only save metadata that wasn't inherited
        if field.scope != Scope.settings:
            continue

        if field.name in inherited_metadata and module._model_data.get(field.name) == inherited_metadata.get(field.name):
            continue

        if field.name not in module._model_data:
            continue

        try:
            metadata[field.name] = module._model_data[field.name]
        except KeyError:
            # Ignore any missing keys in _model_data
            pass

    return metadata
<|endoftext|>


<commit_before>from archetypes.schemaextender.interfaces import IOrderableSchemaExtender
from archetypes.schemaextender.interfaces import ISchemaModifier
from bika.wine import bikaMessageFactory as _
from bika.lims import bikaMessageFactory as _b
from bika.lims.browser.widgets import DateTimeWidget
from bika.lims.browser.widgets import DecimalWidget as bikaDecimalWidget
from bika.lims.fields import *
from bika.lims.interfaces import IBatch
from Products.Archetypes.public import *
from zope.component import adapts
from zope.interface import implements

class BatchSchemaExtender(object):
    adapts(IBatch)
    implements(IOrderableSchemaExtender)

    fields = [
        ExtStringField(
            'WorksOrderID',
            required=True,
            widget=StringWidget(
                label=_('Works Order ID'),
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
        ExtStringField(
            'BlendNumber',
            required=False,
            widget=StringWidget(
                label=_('Blend Number'),
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
        ExtFloatField(
            'LabelAlcohol',
            required=False,
            validators=('percentvalidator'),
            widget=bikaDecimalWidget(
                label=_('Label Alcohol'),
                unit='%',
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
    ]

    def __init__(self, context):
        self.context = context

    def getOrder(self, schematas):
        default = schematas['default']
        to_insert = [{'name': 'WorksOrderID', 'before': 'description'},
                     {'name': 'BlendNumber', 'before': 'description'},
                     {'name': 'LabelAlcohol', 'before': 'description'}]
        for field in to_insert:
            name = field['name']
            if name in default:
                default.remove(name)
            default.insert(default.index(field['before']), name)
        return schematas

    def getFields(self):
        return self.fields

class BatchSchemaModifier(object):
    adapts(IBatch)
    implements(ISchemaModifier)

    def __init__(self, context):
        self.context = context

    def fiddle(self, schema):
        schema['ClientBatchID'].widget.visible = False
        schema['title'].required = True
        schema['title'].widget.visible = True
        return schema
<commit_msg>Re-order wine/batch fields responds to LIMS-1378<commit_after>from archetypes.schemaextender.interfaces import IOrderableSchemaExtender
from archetypes.schemaextender.interfaces import ISchemaModifier
from bika.wine import bikaMessageFactory as _
from bika.lims import bikaMessageFactory as _b
from bika.lims.browser.widgets import DateTimeWidget
from bika.lims.browser.widgets import DecimalWidget as bikaDecimalWidget
from bika.lims.fields import *
from bika.lims.interfaces import IBatch
from Products.Archetypes.public import *
from zope.component import adapts
from zope.interface import implements

class BatchSchemaExtender(object):
    adapts(IBatch)
    implements(IOrderableSchemaExtender)

    fields = [
        ExtStringField(
            'WorksOrderID',
            required=True,
            widget=StringWidget(
                label=_('Works Order ID'),
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
        ExtStringField(
            'BlendNumber',
            required=False,
            widget=StringWidget(
                label=_('Blend Number'),
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
        ExtFloatField(
            'LabelAlcohol',
            required=False,
            validators=('percentvalidator'),
            widget=bikaDecimalWidget(
                label=_('Label Alcohol'),
                unit='%',
                visible = {'view':'visible',
                           'edit': 'visible'}
            ),
        ),
    ]

    def __init__(self, context):
        self.context = context

    def getOrder(self, schematas):
        default = schematas['default']
        to_insert = [{'name': 'WorksOrderID', 'after': 'description'},
                     {'name': 'BlendNumber', 'after': 'description'},
                     {'name': 'LabelAlcohol', 'after': 'description'}]
        for field in to_insert:
            name = field['name']
            if name in default:
                default.remove(name)
            default.insert(default.index(field['after'])+1, name)
        return schematas

    def getFields(self):
        return self.fields

class BatchSchemaModifier(object):
    adapts(IBatch)
    implements(ISchemaModifier)

    def __init__(self, context):
        self.context = context

    def fiddle(self, schema):
        schema['ClientBatchID'].widget.visible = False
        return schema
<|endoftext|>


<commit_before>import os
import unittest
from tomber import *
from random import randrange
from shutil import rmtree, copyfile

class tomberTester(unittest.TestCase):

    @classmethod
    def setUpClass(self):
        self.pid = str(os.getpid())
        self.tombfile = '.'.join([self.pid, 'tomb'])
        self.keyfile = '.'.join([self.pid, 'key'])
        self.keyfile2 = '.'.join([self.pid, '2ndkey'])
        self.exhumedkey = '.'.join([self.pid, 'exhumed'])
        self.mountpath = './tmptomb'
        # generate a passphrase with spaces
        self.passphrase = str(randrange(2 ** 64)).replace("", " ")[1:-1]
        self.passphrase2 = str(randrange(2 ** 64))
        self.imagefile = '.'.join([self.pid, 'jpg'])
        copyfile(
            '/'.join([os.path.dirname(os.path.abspath(__file__)), 'test.jpg']),
            self.imagefile)

    @classmethod
    def tearDownClass(self):
        os.unlink(self.tombfile)
        os.unlink(self.keyfile)
        os.unlink(self.keyfile2)
        os.unlink(self.imagefile)
        os.unlink(self.exhumedkey)
        rmtree(self.mountpath)

    def test_01_dig(self):
        """ Dig a tomb of 10mb"""
        self.assertTrue(tdig(self.tombfile, 10)[0])

    def test_02_forge(self):
        """ Forge a keyfile and set a passphrase """
        self.assertTrue(tforge(self.keyfile, self.passphrase)[0])

    def test_03_lock(self):
        """ Lock created tomb with forged keyfile """
        self.assertTrue(tlock(self.tombfile, self.keyfile, self.passphrase)[0])

    def test_04_open(self):
        """ Open the created tomb with forged keyfile and passhrase """
        self.assertTrue(topen(
                self.tombfile, self.keyfile, self.passphrase, self.mountpath
                )[0]
            )

    def test_05_close(self):
        """ Close the created tomb """
        self.assertTrue(tclose(self.tombfile.split('.')[0])[0])

    def test_06_resize(self):
        """ Resize created tomb to 12mb """
        self.assertTrue(tresize(
                self.tombfile, self.keyfile, self.passphrase, 12
                )[0]
            )

    def test_07_passwd(self):
        """ Change password in keyfile """
        self.assertTrue(tpasswd(
                self.keyfile, self.passphrase2, self.passphrase
                )[0]
            )

    def test_08_bury(self):
        """ Bury keyfile in a image file """
        self.assertTrue(tbury(
                self.keyfile, self.passphrase2, self.imagefile
                )[0]
            )

    def test_09_exhume(self):
        """ Exhume a key from an image """
        self.assertTrue(texhume(
                self.exhumedkey, self.passphrase2, self.imagefile
                )[0]
            )

    def test_10_setkey(self):
        """ Forge a new key and and set different keyfile to created tomb """
        tforge(self.keyfile2, self.passphrase)
        self.assertTrue(tsetkey(
                self.keyfile,
                self.tombfile,
                self.keyfile2,
                self.passphrase,
                self.passphrase2
                )[0]
            )

    def test_11_slam(self):
        """ Slam open tombs """
        topen(self.tombfile, self.keyfile, self.passphrase2, self.mountpath)
        self.assertTrue(tslam()[0])

if __name__ == '__main__':
    unittest.main()<commit_msg>Fixed bug in test in setkey and slam<commit_after>import os
import unittest
from tomber import *
from random import randrange
from shutil import rmtree, copyfile

class tomberTester(unittest.TestCase):

    @classmethod
    def setUpClass(self):
        self.pid = str(os.getpid())
        self.tombfile = '.'.join([self.pid, 'tomb'])
        self.keyfile = '.'.join([self.pid, 'key'])
        self.keyfile2 = '.'.join([self.pid, '2ndkey'])
        self.exhumedkey = '.'.join([self.pid, 'exhumed'])
        self.mountpath = './tmptomb'
        os.mkdir(self.mountpath)
        # generate a passphrase with spaces
        self.passphrase = str(randrange(2 ** 64)).replace("", " ")[1:-1]
        self.passphrase2 = str(randrange(2 ** 64))
        self.imagefile = '.'.join([self.pid, 'jpg'])
        copyfile(
            '/'.join([os.path.dirname(os.path.abspath(__file__)), 'test.jpg']),
            self.imagefile)

    @classmethod
    def tearDownClass(self):
        os.unlink(self.tombfile)
        os.unlink(self.keyfile)
        os.unlink(self.keyfile2)
        os.unlink(self.imagefile)
        os.unlink(self.exhumedkey)
        rmtree(self.mountpath, ignore_errors=True)

    def test_01_dig(self):
        """ Dig a tomb of 10mb"""
        self.assertTrue(tdig(self.tombfile, 10)[0])

    def test_02_forge(self):
        """ Forge a keyfile and set a passphrase """
        self.assertTrue(tforge(self.keyfile, self.passphrase)[0])

    def test_03_lock(self):
        """ Lock created tomb with forged keyfile """
        self.assertTrue(tlock(self.tombfile, self.keyfile, self.passphrase)[0])

    def test_04_open(self):
        """ Open the created tomb with forged keyfile and passhrase """
        self.assertTrue(topen(
                self.tombfile, self.keyfile, self.passphrase, self.mountpath
                )[0]
            )

    def test_05_close(self):
        """ Close the created tomb """
        self.assertTrue(tclose(self.tombfile.split('.')[0])[0])

    def test_06_resize(self):
        """ Resize created tomb to 12mb """
        self.assertTrue(tresize(
                self.tombfile, self.keyfile, self.passphrase, 12
                )[0]
            )

    def test_07_passwd(self):
        """ Change password in keyfile """
        self.assertTrue(tpasswd(
                self.keyfile, self.passphrase2, self.passphrase
                )[0]
            )

    def test_08_bury(self):
        """ Bury keyfile in a image file """
        self.assertTrue(tbury(
                self.keyfile, self.passphrase2, self.imagefile
                )[0]
            )

    def test_09_exhume(self):
        """ Exhume a key from an image """
        self.assertTrue(texhume(
                self.exhumedkey, self.passphrase2, self.imagefile
                )[0]
            )

    def test_10_setkey(self):
        """ Forge a new key and and set different keyfile to created tomb """
        tforge(self.keyfile2, self.passphrase)
        self.assertTrue(tsetkey(
                self.keyfile,
                self.tombfile,
                self.keyfile2,
                self.passphrase2,
                self.passphrase
                )[0]
            )

    def test_11_slam(self):
        """ Slam open tombs """
        topen(self.tombfile, self.keyfile2, self.passphrase, self.mountpath)
        self.assertTrue(tslam()[0])

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before>"""
.. See the NOTICE file distributed with this work for additional information
   regarding copyright ownership.

   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 print_function

import sys
from sys import stdout
from subprocess import PIPE, Popen
import os
from cPickle import load

from utils import logger

from pytadbit.parsers.hic_bam_parser import write_matrix
from pytadbit import Chromosome
from pytadbit.parsers.hic_parser import load_hic_data_from_bam
from pytadbit.mapping.analyze import hic_map

try:
    if hasattr(sys, '_run_from_cmdl') is True:
        raise ImportError
    from pycompss.api.parameter import FILE_IN, FILE_OUT, FILE_INOUT, IN
    from pycompss.api.task import task
    from pycompss.api.api import compss_wait_on
    # from pycompss.api.constraint import constraint
except ImportError:
    logger.info("[Warning] Cannot import \"pycompss\" API packages.")
    logger.info("          Using mock decorators.")

    from utils.dummy_pycompss import FILE_IN, FILE_OUT, IN # pylint: disable=ungrouped-imports
    from utils.dummy_pycompss import task # pylint: disable=ungrouped-imports
    from utils.dummy_pycompss import compss_wait_on # pylint: disable=ungrouped-imports
    # from utils.dummy_pycompss import constraint # pylint: disable=ungrouped-imports

from basic_modules.tool import Tool

# ------------------------------------------------------------------------------

class tbBinTool(Tool):
    """
    Tool for binning an adjacency matrix
    """

    def __init__(self):
        """
        Init function
        """
        logger.info("TADbit - Bin")
        Tool.__init__(self)

    @task(bamin=FILE_IN, biases=FILE_IN, resolution=IN, coord1=IN, coord2=IN,
          norm=IN, workdir=IN, raw_matrix=FILE_OUT, raw_fig=FILE_OUT,
          nrm_matrix=FILE_OUT, nrm_fig=FILE_OUT, json_matrix=FILE_OUT)
    # @constraint(ProcessorCoreCount=16)
    def tb_bin(self, bamin, biases, resolution, coord1, coord2, norm, workdir, ncpus="1", metadata=None):
        """
        Function to bin to a given resolution the Hi-C
        matrix

        Parameters
        ----------
        bamin : str
            Location of the tadbit bam paired reads
        biases : str
            Location of the pickle hic biases
        resolution : int
            Resolution of the Hi-C
        coord1 : str
            Coordinate of the region to retrieve. By default all genome,
            arguments can be either one chromosome name, or the coordinate in
            the form: "-c chr3:110000000-120000000"
        coord2 : str
            Coordinate of a second region to retrieve the matrix in the
            intersection with the first region.
        norm : list
            [['raw']] normalization(s) to apply. Order matters. Choices: [norm,
            decay, raw]
        workdir : str
            Location of working directory
        ncpus : int
            Number of cpus to use

        Returns
        -------
        hic_contacts_matrix_raw : str
            Location of HiC raw matrix in text format
        hic_contacts_matrix_nrm : str
            Location of HiC normalized matrix in text format
        hic_contacts_matrix_raw_fig : str
            Location of HiC raw matrix in png format
        hic_contacts_matrix_norm_fig : str
            Location of HiC normalized matrix in png format

        """
        logger.info("TB BIN: {0}, {1}, {2}".format(bamin, resolution, workdir))

        output_metadata = {}

        if coord2 and not coord1:
            coord1, coord2 = coord2, coord1

        if not coord1:
            region1 = None
            start1 = None
            end1 = None
            region2 = None
            start2 = None
            end2 = None
        else:
            try:
                crm1, pos1 = coord1.split(':')
                start1, end1 = pos1.split('-')
                region1 = crm1
                start1 = int(start1)
                end1 = int(end1)
            except ValueError:
                region1 = coord1
                start1 = None
                end1 = None
            if coord2:
                try:
                    crm2, pos2 = coord2.split(':')
                    start2, end2 = pos2.split('-')
                    region2 = crm2
                    start2 = int(start2)
                    end2 = int(end2)
                except ValueError:
                    region2 = coord2
                    start2 = None
                    end2 = None
            else:
                region2 = None
                start2 = None
                end2 = None

        if region1:
            if region1:
                stdout.write('\nExtraction of %s' % (region1))
                if start1:
                    stdout.write(':%s-%s' % (start1, end1))
                else:
                    stdout.write(' (full chromosome)')
                if region2:
                    stdout.write(' intersection with %s' % (region2))
                    if start2:
                        stdout.write(':%s-%s\n' % (start2, end2))
                    else:
                        stdout.write(' (full chromosome)\n')
                else:
                    stdout.write('\n')
        else:
            stdout.write('\nExtraction of full genome\n')

        out_files = write_matrix(
            bamin, resolution,
            load(open(biases)) if biases else None,
            workdir, filter_exclude=[],
            normalizations=norm, half_matrix=True,
            region1=region1, start1=start1, end1=end1,
            region2=region2, start2=start2, end2=end2,
            tmpdir=workdir, append_to_tar=None, ncpus=ncpus,
            verbose=True)
        output_files = [out_files['RAW']]
        imx = load_hic_data_from_bam(bamin, resolution, biases=biases if biases else None, ncpus=ncpus, tmpdir=workdir)
        hic_contacts_matrix_raw_fig = workdir+"/genomic_maps_raw.png"
        focus = None
        by_chrom = None
        if start1 is not None:
            focus = ((start1/resolution) if start1 != 0 else 1, (end1/resolution))
        else:
            if region1 is not None:
                focus = region1
            else:
                by_chrom = 'all'
                hic_contacts_matrix_raw_fig = workdir+"/genomic_maps_raw"
        hic_map(imx, resolution, savefig=hic_contacts_matrix_raw_fig, normalized=False, by_chrom=by_chrom, focus=focus)
        if by_chrom == 'all':
            hic_map(imx, resolution, savefig=hic_contacts_matrix_raw_fig+"/full_map.png", normalized=False, by_chrom=None, focus=focus)
        output_files.append(hic_contacts_matrix_raw_fig)

        if len(norm) > 1:
            output_files.append(out_files['NRM'])
            hic_contacts_matrix_norm_fig = workdir+"/genomic_maps_nrm.png"
            if by_chrom == 'all':
                hic_contacts_matrix_norm_fig = workdir+"/genomic_maps_nrm"
            hic_map(imx, resolution, savefig=hic_contacts_matrix_norm_fig, normalized=True, by_chrom=by_chrom, focus=focus)
            if by_chrom == 'all':
                hic_map(imx, resolution, savefig=hic_contacts_matrix_norm_fig+"/full_map.png", normalized=True, by_chrom=None, focus=focus)
            output_files.append(hic_contacts_matrix_norm_fig)

        json_chr = Chromosome(name="VRE Chromosome", species=metadata["species"], assembly=metadata["assembly"], max_tad_size=260000)
        json_chr.add_experiment(
            "exp1", resolution,
            hic_data=imx,
            silent=True)

        exp = json_chr.experiments[0]
        json_file_name = out_files['RAW'].replace(".abc", ".json")
        if start1 is not None:
            if focus[1]-focus[0] > 1200:
                logger.info("TADkit json too big, limiting to 1200 bins")
                focus = (focus[0], focus[0]+1200)
        else:
            if exp.size > 1200:
                logger.info("TADkit json too big, limiting to 1200 bins")
                focus = (1, 1200)
        exp.write_json(json_file_name, focus=focus)
        output_files.append(json_file_name)

        return (output_files, output_metadata)

    def run(self, input_files, output_files, metadata=None):
        """
        The main function to the predict TAD sites for a given resolution from
        the Hi-C matrix

        Parameters
        ----------
        input_files : list
            bamin : str
                Location of the tadbit bam paired reads
            biases : str
                Location of the pickle hic biases
        metadata : dict
            resolution : int
                Resolution of the Hi-C
            coord1 : str
                Coordinate of the region to retrieve. By default all genome,
                arguments can be either one chromosome name, or the coordinate in
                the form: "-c chr3:110000000-120000000"
            coord2 : str
                Coordinate of a second region to retrieve the matrix in the
                intersection with the first region.
            norm : str
                [['raw']] normalization(s) to apply. Order matters. Choices: [norm,
                decay, raw]
            workdir : str
                Location of working directory
            ncpus : int
                Number of cpus to use

        Returns
        -------
        output_files : list
            List of locations for the output files.
        output_metadata : list
            List of matching metadata dict objects

        """

        bamin = input_files[0]

        if not os.path.isfile(bamin.replace('.bam', '.bam.bai')):
            logger.info('Creating bam index')
            _cmd = ['samtools', 'index', bamin]
            out, err = Popen(_cmd, stdout=PIPE, stderr=PIPE).communicate()
            logger.info(out)
            logger.info(err)

        biases = None
        if len(input_files) > 1:
            biases = input_files[1]
        resolution = 100000
        if 'resolution' in metadata:
            resolution = int(metadata['resolution'])

        coord1 = coord2 = norm = None
        ncpus = 1
        if 'ncpus' in metadata:
            ncpus = metadata['ncpus']

        if 'coord1' in metadata:
            coord1 = metadata['coord1']
        if 'coord2' in metadata:
            coord2 = metadata['coord2']
        if 'norm' in metadata:
            norm = metadata['norm']

        root_name = os.path.dirname(os.path.abspath(bamin))
        if 'workdir' in metadata:
            root_name = metadata['workdir']

        # input and output share most metadata
        project_metadata = {}
        project_metadata["species"] = metadata["species"]
        project_metadata["assembly"] = metadata["assembly"]

        output_files, output_metadata = self.tb_bin(bamin, biases, resolution, coord1, coord2, norm, root_name, ncpus, project_metadata)

        return (output_files, output_metadata)

# ------------------------------------------------------------------------------
<commit_msg>Fix focus in tadbit bin<commit_after>"""
.. See the NOTICE file distributed with this work for additional information
   regarding copyright ownership.

   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 print_function

import sys
from sys import stdout
from subprocess import PIPE, Popen
import os
from cPickle import load

from utils import logger

from pytadbit.parsers.hic_bam_parser import write_matrix
from pytadbit import Chromosome
from pytadbit.parsers.hic_parser import load_hic_data_from_bam
from pytadbit.mapping.analyze import hic_map

try:
    if hasattr(sys, '_run_from_cmdl') is True:
        raise ImportError
    from pycompss.api.parameter import FILE_IN, FILE_OUT, FILE_INOUT, IN
    from pycompss.api.task import task
    from pycompss.api.api import compss_wait_on
    # from pycompss.api.constraint import constraint
except ImportError:
    logger.info("[Warning] Cannot import \"pycompss\" API packages.")
    logger.info("          Using mock decorators.")

    from utils.dummy_pycompss import FILE_IN, FILE_OUT, IN # pylint: disable=ungrouped-imports
    from utils.dummy_pycompss import task # pylint: disable=ungrouped-imports
    from utils.dummy_pycompss import compss_wait_on # pylint: disable=ungrouped-imports
    # from utils.dummy_pycompss import constraint # pylint: disable=ungrouped-imports

from basic_modules.tool import Tool

# ------------------------------------------------------------------------------

class tbBinTool(Tool):
    """
    Tool for binning an adjacency matrix
    """

    def __init__(self):
        """
        Init function
        """
        logger.info("TADbit - Bin")
        Tool.__init__(self)

    @task(bamin=FILE_IN, biases=FILE_IN, resolution=IN, coord1=IN, coord2=IN,
          norm=IN, workdir=IN, raw_matrix=FILE_OUT, raw_fig=FILE_OUT,
          nrm_matrix=FILE_OUT, nrm_fig=FILE_OUT, json_matrix=FILE_OUT)
    # @constraint(ProcessorCoreCount=16)
    def tb_bin(self, bamin, biases, resolution, coord1, coord2, norm, workdir, ncpus="1", metadata=None):
        """
        Function to bin to a given resolution the Hi-C
        matrix

        Parameters
        ----------
        bamin : str
            Location of the tadbit bam paired reads
        biases : str
            Location of the pickle hic biases
        resolution : int
            Resolution of the Hi-C
        coord1 : str
            Coordinate of the region to retrieve. By default all genome,
            arguments can be either one chromosome name, or the coordinate in
            the form: "-c chr3:110000000-120000000"
        coord2 : str
            Coordinate of a second region to retrieve the matrix in the
            intersection with the first region.
        norm : list
            [['raw']] normalization(s) to apply. Order matters. Choices: [norm,
            decay, raw]
        workdir : str
            Location of working directory
        ncpus : int
            Number of cpus to use

        Returns
        -------
        hic_contacts_matrix_raw : str
            Location of HiC raw matrix in text format
        hic_contacts_matrix_nrm : str
            Location of HiC normalized matrix in text format
        hic_contacts_matrix_raw_fig : str
            Location of HiC raw matrix in png format
        hic_contacts_matrix_norm_fig : str
            Location of HiC normalized matrix in png format

        """
        logger.info("TB BIN: {0}, {1}, {2}".format(bamin, resolution, workdir))

        output_metadata = {}

        if coord2 and not coord1:
            coord1, coord2 = coord2, coord1

        if not coord1:
            region1 = None
            start1 = None
            end1 = None
            region2 = None
            start2 = None
            end2 = None
        else:
            try:
                crm1, pos1 = coord1.split(':')
                start1, end1 = pos1.split('-')
                region1 = crm1
                start1 = int(start1)
                end1 = int(end1)
            except ValueError:
                region1 = coord1
                start1 = None
                end1 = None
            if coord2:
                try:
                    crm2, pos2 = coord2.split(':')
                    start2, end2 = pos2.split('-')
                    region2 = crm2
                    start2 = int(start2)
                    end2 = int(end2)
                except ValueError:
                    region2 = coord2
                    start2 = None
                    end2 = None
            else:
                region2 = None
                start2 = None
                end2 = None

        if region1:
            if region1:
                stdout.write('\nExtraction of %s' % (region1))
                if start1:
                    stdout.write(':%s-%s' % (start1, end1))
                else:
                    stdout.write(' (full chromosome)')
                if region2:
                    stdout.write(' intersection with %s' % (region2))
                    if start2:
                        stdout.write(':%s-%s\n' % (start2, end2))
                    else:
                        stdout.write(' (full chromosome)\n')
                else:
                    stdout.write('\n')
        else:
            stdout.write('\nExtraction of full genome\n')

        out_files = write_matrix(
            bamin, resolution,
            load(open(biases)) if biases else None,
            workdir, filter_exclude=[],
            normalizations=norm, half_matrix=True,
            region1=region1, start1=start1, end1=end1,
            region2=region2, start2=start2, end2=end2,
            tmpdir=workdir, append_to_tar=None, ncpus=ncpus,
            verbose=True)
        output_files = [out_files['RAW']]
        imx = load_hic_data_from_bam(bamin, resolution,
                                     biases=biases if biases else None,
                                     region=region1,
                                     ncpus=ncpus, tmpdir=workdir)
        hic_contacts_matrix_raw_fig = workdir+"/genomic_maps_raw.png"
        focus = None
        by_chrom = None
        if start1 is not None:
            focus = ((start1/resolution) if start1 != 0 else 1, (end1/resolution))
        else:
            if region1 is not None:
                focus = region1
            else:
                by_chrom = 'all'
                hic_contacts_matrix_raw_fig = workdir+"/genomic_maps_raw"
        hic_map(imx, resolution, savefig=hic_contacts_matrix_raw_fig, normalized=False, by_chrom=by_chrom, focus=focus)
        if by_chrom == 'all':
            hic_map(imx, resolution, savefig=hic_contacts_matrix_raw_fig+"/full_map.png", normalized=False, by_chrom=None, focus=focus)
        output_files.append(hic_contacts_matrix_raw_fig)

        if len(norm) > 1:
            output_files.append(out_files['NRM'])
            hic_contacts_matrix_norm_fig = workdir+"/genomic_maps_nrm.png"
            if by_chrom == 'all':
                hic_contacts_matrix_norm_fig = workdir+"/genomic_maps_nrm"
            hic_map(imx, resolution, savefig=hic_contacts_matrix_norm_fig, normalized=True, by_chrom=by_chrom, focus=focus)
            if by_chrom == 'all':
                hic_map(imx, resolution, savefig=hic_contacts_matrix_norm_fig+"/full_map.png", normalized=True, by_chrom=None, focus=focus)
            output_files.append(hic_contacts_matrix_norm_fig)

        json_chr = Chromosome(name="VRE Chromosome", species=metadata["species"], assembly=metadata["assembly"], max_tad_size=260000)
        json_chr.add_experiment(
            "exp1", resolution,
            hic_data=imx,
            silent=True)

        exp = json_chr.experiments[0]
        json_file_name = out_files['RAW'].replace(".abc", ".json")
        if start1 is not None:
            if focus[1]-focus[0] > 1200:
                logger.info("TADkit json too big, limiting to 1200 bins")
                focus = (focus[0], focus[0]+1200)
        else:
            if exp.size > 1200:
                logger.info("TADkit json too big, limiting to 1200 bins")
                focus = (1, 1200)
        exp.write_json(json_file_name, focus=focus)
        output_files.append(json_file_name)

        return (output_files, output_metadata)

    def run(self, input_files, output_files, metadata=None):
        """
        The main function to the predict TAD sites for a given resolution from
        the Hi-C matrix

        Parameters
        ----------
        input_files : list
            bamin : str
                Location of the tadbit bam paired reads
            biases : str
                Location of the pickle hic biases
        metadata : dict
            resolution : int
                Resolution of the Hi-C
            coord1 : str
                Coordinate of the region to retrieve. By default all genome,
                arguments can be either one chromosome name, or the coordinate in
                the form: "-c chr3:110000000-120000000"
            coord2 : str
                Coordinate of a second region to retrieve the matrix in the
                intersection with the first region.
            norm : str
                [['raw']] normalization(s) to apply. Order matters. Choices: [norm,
                decay, raw]
            workdir : str
                Location of working directory
            ncpus : int
                Number of cpus to use

        Returns
        -------
        output_files : list
            List of locations for the output files.
        output_metadata : list
            List of matching metadata dict objects

        """

        bamin = input_files[0]

        if not os.path.isfile(bamin.replace('.bam', '.bam.bai')):
            logger.info('Creating bam index')
            _cmd = ['samtools', 'index', bamin]
            out, err = Popen(_cmd, stdout=PIPE, stderr=PIPE).communicate()
            logger.info(out)
            logger.info(err)

        biases = None
        if len(input_files) > 1:
            biases = input_files[1]
        resolution = 100000
        if 'resolution' in metadata:
            resolution = int(metadata['resolution'])

        coord1 = coord2 = norm = None
        ncpus = 1
        if 'ncpus' in metadata:
            ncpus = metadata['ncpus']

        if 'coord1' in metadata:
            coord1 = metadata['coord1']
        if 'coord2' in metadata:
            coord2 = metadata['coord2']
        if 'norm' in metadata:
            norm = metadata['norm']

        root_name = os.path.dirname(os.path.abspath(bamin))
        if 'workdir' in metadata:
            root_name = metadata['workdir']

        # input and output share most metadata
        project_metadata = {}
        project_metadata["species"] = metadata["species"]
        project_metadata["assembly"] = metadata["assembly"]

        output_files, output_metadata = self.tb_bin(bamin, biases, resolution, coord1, coord2, norm, root_name, ncpus, project_metadata)

        return (output_files, output_metadata)

# ------------------------------------------------------------------------------
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Bok choy acceptance tests for problems in the LMS

See also old lettuce tests in lms/djangoapps/courseware/features/problems.feature
"""
from textwrap import dedent
from flaky import flaky

from ..helpers import UniqueCourseTest
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.lms.courseware import CoursewarePage
from ...pages.lms.problem import ProblemPage
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ..helpers import EventsTestMixin

class ProblemsTest(UniqueCourseTest):
    """
    Base class for tests of problems in the LMS.
    """
    USERNAME = "joe_student"
    EMAIL = "joe@example.com"

    def setUp(self):
        super(ProblemsTest, self).setUp()

        self.xqueue_grade_response = None

        self.courseware_page = CoursewarePage(self.browser, self.course_id)

        # Install a course with a hierarchy and problems
        course_fixture = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )

        problem = self.get_problem()
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection').add_children(problem)
            )
        ).install()

        # Auto-auth register for the course.
        AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL,
                     course_id=self.course_id, staff=False).visit()

    def get_problem(self):
        """ Subclasses should override this to complete the fixture """
        raise NotImplementedError()

class ProblemClarificationTest(ProblemsTest):
    """
    Tests the <clarification> element that can be used in problem XML.
    """

    def get_problem(self):
        """
        Create a problem with a <clarification>
        """
        xml = dedent("""
            <problem markdown="null">
                <text>

                        Given the data in Table 7 <clarification>Table 7: "Example PV Installation Costs",
                        Page 171 of Roberts textbook</clarification>, compute the ROI
                        <clarification>Return on Investment (per year)</clarification> over 20 years.

                    <numericalresponse answer="6.5">
                        <textline label="Enter the annual ROI" trailing_text="%" />
                    </numericalresponse>
                </text>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'TOOLTIP TEST PROBLEM', data=xml)

    def test_clarification(self):
        """
        Test that we can see the <clarification> tooltips.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, 'TOOLTIP TEST PROBLEM')
        problem_page.click_clarification(0)
        self.assertIn('"Example PV Installation Costs"', problem_page.visible_tooltip_text)
        problem_page.click_clarification(1)
        tooltip_text = problem_page.visible_tooltip_text
        self.assertIn('Return on Investment', tooltip_text)
        self.assertIn('per year', tooltip_text)
        self.assertNotIn('strong', tooltip_text)

class ProblemExtendedHintTest(ProblemsTest, EventsTestMixin):
    """
    Test that extended hint features plumb through to the page html and tracking log.
    """

    def get_problem(self):
        """
        Problem with extended hint features.
        """
        xml = dedent("""
            <problem>

question text

            <stringresponse answer="A">
                <stringequalhint answer="B">hint</stringequalhint>
                <textline size="20"/>
            </stringresponse>
            <demandhint>
              <hint>demand-hint1</hint>
              <hint>demand-hint2</hint>
            </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'TITLE', data=xml)

    def test_check_hint(self):
        """
        Test clicking Check shows the extended hint in the problem message.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_text[0], u'question text')
        problem_page.fill_answer('B')
        problem_page.click_check()
        self.assertEqual(problem_page.message_text, u'Incorrect: hint')
        # Check for corresponding tracking event
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.feedback_displayed'},
            number_of_matches=1
        )
        self.assert_events_match(
            [{'event': {'hint_label': u'Incorrect',
                        'trigger_type': 'single',
                        'student_answer': [u'B'],
                        'correctness': False,
                        'question_type': 'stringresponse',
                        'hints': [{'text': 'hint'}]}}],
            actual_events)

    def test_demand_hint(self):
        """
        Test clicking hint button shows the demand hint in its div.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): demand-hint1')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (2 of 2): demand-hint2')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): demand-hint1')
        # Check corresponding tracking events
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.demandhint_displayed'},
            number_of_matches=3
        )
        self.assert_events_match(
            [
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'demand-hint1'}},
                {'event': {u'hint_index': 1, u'hint_len': 2, u'hint_text': u'demand-hint2'}},
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'demand-hint1'}}
            ],
            actual_events)

class ProblemHintWithHtmlTest(ProblemsTest, EventsTestMixin):
    """
    Tests that hints containing html get rendered properly
    """

    def get_problem(self):
        """
        Problem with extended hint features.
        """
        xml = dedent("""
            <problem>

question text

            <stringresponse answer="A">
                <stringequalhint answer="B">aa bb cc</stringequalhint>
                <stringequalhint answer="C">aa bb cc</stringequalhint>
                <textline size="20"/>
            </stringresponse>
            <demandhint>
              <hint>aa bb cc</hint>
              <hint>dd  ee ff</hint>
            </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'PROBLEM HTML HINT TEST', data=xml)

    @flaky  # TODO fix this, see TNL-3183
    def test_check_hint(self):
        """
        Test clicking Check shows the extended hint in the problem message.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_text[0], u'question text')
        problem_page.fill_answer('B')
        problem_page.click_check()
        self.assertEqual(problem_page.message_text, u'Incorrect: aa bb cc')
        problem_page.fill_answer('C')
        problem_page.click_check()
        self.assertEqual(problem_page.message_text, u'Incorrect: aa bb cc')
        # Check for corresponding tracking event
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.feedback_displayed'},
            number_of_matches=2
        )
        self.assert_events_match(
            [{'event': {'hint_label': u'Incorrect',
                        'trigger_type': 'single',
                        'student_answer': [u'B'],
                        'correctness': False,
                        'question_type': 'stringresponse',
                        'hints': [{'text': 'aa bb cc'}]}},
             {'event': {'hint_label': u'Incorrect',
                        'trigger_type': 'single',
                        'student_answer': [u'C'],
                        'correctness': False,
                        'question_type': 'stringresponse',
                        'hints': [{'text': 'aa bb cc'}]}}],
            actual_events)

    def test_demand_hint(self):
        """
        Test clicking hint button shows the demand hint in its div.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): aa bb cc')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (2 of 2): dd ee ff')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): aa bb cc')
        # Check corresponding tracking events
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.demandhint_displayed'},
            number_of_matches=3
        )
        self.assert_events_match(
            [
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'aa bb cc'}},
                {'event': {u'hint_index': 1, u'hint_len': 2, u'hint_text': u'dd  ee ff'}},
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'aa bb cc'}}
            ],
            actual_events)

class ProblemWithMathjax(ProblemsTest):
    """
    Tests the <MathJax> used in problem
    """

    def get_problem(self):
        """
        Create a problem with a <MathJax> in body and hint
        """
        xml = dedent(r"""
            <problem>

Check mathjax has rendered [mathjax]E=mc^2[/mathjax]

                <multiplechoiceresponse>
                  <choicegroup label="Answer this?" type="MultipleChoice">
                    <choice correct="true">Choice1 <choicehint>Correct choice message</choicehint></choice>
                    <choice correct="false">Choice2<choicehint>Wrong choice message</choicehint></choice>
                  </choicegroup>
                </multiplechoiceresponse>
                <demandhint>
                        <hint>mathjax should work1 \(E=mc^2\) </hint>
                        <hint>mathjax should work2 [mathjax]E=mc^2[/mathjax]</hint>
                </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'MATHJAX TEST PROBLEM', data=xml)

    def test_mathjax_in_hint(self):
        """
        Test that MathJax have successfully rendered in problem hint
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, "MATHJAX TEST PROBLEM")

        # Verify Mathjax have been rendered
        self.assertTrue(problem_page.mathjax_rendered_in_problem, "MathJax did not rendered in body")

        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertIn("Hint (1 of 2): mathjax should work1", problem_page.hint_text)
        self.assertTrue(problem_page.mathjax_rendered_in_hint, "MathJax did not rendered in problem hint")

        # Rotate the hint and check the problem hint
        problem_page.click_hint()

        self.assertIn("Hint (2 of 2): mathjax should work2", problem_page.hint_text)
        self.assertTrue(problem_page.mathjax_rendered_in_hint, "MathJax did not rendered in problem hint")

class ProblemPartialCredit(ProblemsTest):
    """
    Makes sure that the partial credit is appearing properly.
    """
    def get_problem(self):
        """
        Create a problem with partial credit.
        """
        xml = dedent("""
            <problem>

The answer is 1. Partial credit for -1.

                <numericalresponse answer="1" partial_credit="list">
                    <formulaequationinput label="How many miles away from Earth is the sun? Use scientific notation to answer." />
                    <responseparam type="tolerance" default="0.01" />
                    <responseparam partial_answers="-1" />
                </numericalresponse>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'PARTIAL CREDIT TEST PROBLEM', data=xml)

    def test_partial_credit(self):
        """
        Test that we can see the partial credit value and feedback.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, 'PARTIAL CREDIT TEST PROBLEM')
        problem_page.fill_answer_numerical('-1')
        problem_page.click_check()
        self.assertTrue(problem_page.simpleprob_is_partially_correct())
<commit_msg>Addresses TNL-3183<commit_after># -*- coding: utf-8 -*-
"""
Bok choy acceptance tests for problems in the LMS

See also old lettuce tests in lms/djangoapps/courseware/features/problems.feature
"""
from textwrap import dedent

from ..helpers import UniqueCourseTest
from ...pages.studio.auto_auth import AutoAuthPage
from ...pages.lms.courseware import CoursewarePage
from ...pages.lms.problem import ProblemPage
from ...fixtures.course import CourseFixture, XBlockFixtureDesc
from ..helpers import EventsTestMixin

class ProblemsTest(UniqueCourseTest):
    """
    Base class for tests of problems in the LMS.
    """
    USERNAME = "joe_student"
    EMAIL = "joe@example.com"

    def setUp(self):
        super(ProblemsTest, self).setUp()

        self.xqueue_grade_response = None

        self.courseware_page = CoursewarePage(self.browser, self.course_id)

        # Install a course with a hierarchy and problems
        course_fixture = CourseFixture(
            self.course_info['org'], self.course_info['number'],
            self.course_info['run'], self.course_info['display_name']
        )

        problem = self.get_problem()
        course_fixture.add_children(
            XBlockFixtureDesc('chapter', 'Test Section').add_children(
                XBlockFixtureDesc('sequential', 'Test Subsection').add_children(problem)
            )
        ).install()

        # Auto-auth register for the course.
        AutoAuthPage(self.browser, username=self.USERNAME, email=self.EMAIL,
                     course_id=self.course_id, staff=False).visit()

    def get_problem(self):
        """ Subclasses should override this to complete the fixture """
        raise NotImplementedError()

class ProblemClarificationTest(ProblemsTest):
    """
    Tests the <clarification> element that can be used in problem XML.
    """

    def get_problem(self):
        """
        Create a problem with a <clarification>
        """
        xml = dedent("""
            <problem markdown="null">
                <text>

                        Given the data in Table 7 <clarification>Table 7: "Example PV Installation Costs",
                        Page 171 of Roberts textbook</clarification>, compute the ROI
                        <clarification>Return on Investment (per year)</clarification> over 20 years.

                    <numericalresponse answer="6.5">
                        <textline label="Enter the annual ROI" trailing_text="%" />
                    </numericalresponse>
                </text>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'TOOLTIP TEST PROBLEM', data=xml)

    def test_clarification(self):
        """
        Test that we can see the <clarification> tooltips.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, 'TOOLTIP TEST PROBLEM')
        problem_page.click_clarification(0)
        self.assertIn('"Example PV Installation Costs"', problem_page.visible_tooltip_text)
        problem_page.click_clarification(1)
        tooltip_text = problem_page.visible_tooltip_text
        self.assertIn('Return on Investment', tooltip_text)
        self.assertIn('per year', tooltip_text)
        self.assertNotIn('strong', tooltip_text)

class ProblemExtendedHintTest(ProblemsTest, EventsTestMixin):
    """
    Test that extended hint features plumb through to the page html and tracking log.
    """

    def get_problem(self):
        """
        Problem with extended hint features.
        """
        xml = dedent("""
            <problem>

question text

            <stringresponse answer="A">
                <stringequalhint answer="B">hint</stringequalhint>
                <textline size="20"/>
            </stringresponse>
            <demandhint>
              <hint>demand-hint1</hint>
              <hint>demand-hint2</hint>
            </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'TITLE', data=xml)

    def test_check_hint(self):
        """
        Test clicking Check shows the extended hint in the problem message.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_text[0], u'question text')
        problem_page.fill_answer('B')
        problem_page.click_check()
        self.assertEqual(problem_page.message_text, u'Incorrect: hint')
        # Check for corresponding tracking event
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.feedback_displayed'},
            number_of_matches=1
        )
        self.assert_events_match(
            [{'event': {'hint_label': u'Incorrect',
                        'trigger_type': 'single',
                        'student_answer': [u'B'],
                        'correctness': False,
                        'question_type': 'stringresponse',
                        'hints': [{'text': 'hint'}]}}],
            actual_events)

    def test_demand_hint(self):
        """
        Test clicking hint button shows the demand hint in its div.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): demand-hint1')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (2 of 2): demand-hint2')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): demand-hint1')
        # Check corresponding tracking events
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.demandhint_displayed'},
            number_of_matches=3
        )
        self.assert_events_match(
            [
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'demand-hint1'}},
                {'event': {u'hint_index': 1, u'hint_len': 2, u'hint_text': u'demand-hint2'}},
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'demand-hint1'}}
            ],
            actual_events)

class ProblemHintWithHtmlTest(ProblemsTest, EventsTestMixin):
    """
    Tests that hints containing html get rendered properly
    """

    def get_problem(self):
        """
        Problem with extended hint features.
        """
        xml = dedent("""
            <problem>

question text

            <stringresponse answer="A">
                <stringequalhint answer="C">aa bb cc</stringequalhint>
                <textline size="20"/>
            </stringresponse>
            <demandhint>
              <hint>aa bb cc</hint>
              <hint>dd  ee ff</hint>
            </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'PROBLEM HTML HINT TEST', data=xml)

    def test_check_hint(self):
        """
        Test clicking Check shows the extended hint in the problem message.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_text[0], u'question text')
        problem_page.fill_answer('C')
        problem_page.click_check()
        self.assertEqual(problem_page.message_text, u'Incorrect: aa bb cc')
        # Check for corresponding tracking event
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.feedback_displayed'},
            number_of_matches=1
        )
        self.assert_events_match(
            [{'event': {'hint_label': u'Incorrect',
                        'trigger_type': 'single',
                        'student_answer': [u'C'],
                        'correctness': False,
                        'question_type': 'stringresponse',
                        'hints': [{'text': 'aa bb cc'}]}}],
            actual_events)

    def test_demand_hint(self):
        """
        Test clicking hint button shows the demand hint in its div.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): aa bb cc')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (2 of 2): dd ee ff')
        problem_page.click_hint()
        self.assertEqual(problem_page.hint_text, u'Hint (1 of 2): aa bb cc')
        # Check corresponding tracking events
        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.problem.hint.demandhint_displayed'},
            number_of_matches=3
        )
        self.assert_events_match(
            [
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'aa bb cc'}},
                {'event': {u'hint_index': 1, u'hint_len': 2, u'hint_text': u'dd  ee ff'}},
                {'event': {u'hint_index': 0, u'hint_len': 2, u'hint_text': u'aa bb cc'}}
            ],
            actual_events)

class ProblemWithMathjax(ProblemsTest):
    """
    Tests the <MathJax> used in problem
    """

    def get_problem(self):
        """
        Create a problem with a <MathJax> in body and hint
        """
        xml = dedent(r"""
            <problem>

Check mathjax has rendered [mathjax]E=mc^2[/mathjax]

                <multiplechoiceresponse>
                  <choicegroup label="Answer this?" type="MultipleChoice">
                    <choice correct="true">Choice1 <choicehint>Correct choice message</choicehint></choice>
                    <choice correct="false">Choice2<choicehint>Wrong choice message</choicehint></choice>
                  </choicegroup>
                </multiplechoiceresponse>
                <demandhint>
                        <hint>mathjax should work1 \(E=mc^2\) </hint>
                        <hint>mathjax should work2 [mathjax]E=mc^2[/mathjax]</hint>
                </demandhint>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'MATHJAX TEST PROBLEM', data=xml)

    def test_mathjax_in_hint(self):
        """
        Test that MathJax have successfully rendered in problem hint
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, "MATHJAX TEST PROBLEM")

        # Verify Mathjax have been rendered
        self.assertTrue(problem_page.mathjax_rendered_in_problem, "MathJax did not rendered in body")

        # The hint button rotates through multiple hints
        problem_page.click_hint()
        self.assertIn("Hint (1 of 2): mathjax should work1", problem_page.hint_text)
        self.assertTrue(problem_page.mathjax_rendered_in_hint, "MathJax did not rendered in problem hint")

        # Rotate the hint and check the problem hint
        problem_page.click_hint()

        self.assertIn("Hint (2 of 2): mathjax should work2", problem_page.hint_text)
        self.assertTrue(problem_page.mathjax_rendered_in_hint, "MathJax did not rendered in problem hint")

class ProblemPartialCredit(ProblemsTest):
    """
    Makes sure that the partial credit is appearing properly.
    """
    def get_problem(self):
        """
        Create a problem with partial credit.
        """
        xml = dedent("""
            <problem>

The answer is 1. Partial credit for -1.

                <numericalresponse answer="1" partial_credit="list">
                    <formulaequationinput label="How many miles away from Earth is the sun? Use scientific notation to answer." />
                    <responseparam type="tolerance" default="0.01" />
                    <responseparam partial_answers="-1" />
                </numericalresponse>
            </problem>
        """)
        return XBlockFixtureDesc('problem', 'PARTIAL CREDIT TEST PROBLEM', data=xml)

    def test_partial_credit(self):
        """
        Test that we can see the partial credit value and feedback.
        """
        self.courseware_page.visit()
        problem_page = ProblemPage(self.browser)
        self.assertEqual(problem_page.problem_name, 'PARTIAL CREDIT TEST PROBLEM')
        problem_page.fill_answer_numerical('-1')
        problem_page.click_check()
        self.assertTrue(problem_page.simpleprob_is_partially_correct())
<|endoftext|>


<commit_before>from dimagi.utils.queryable_set import QueryableList

class PathfinderPatientGroup(QueryableList):
    def __init__(self):

        self._new = lambda x: x['registered_this_month']
        self._followup = lambda x: x['followup_this_month']

        self._f = lambda x: x['followup_this_month'] and (x['registration_and_followup_hiv'] == 'continuing' or x['registration_and_followup_hiv'] == '')

        self._0to14 = lambda x: 0 <= x['age'] <= 14
        self._15to24 = lambda x: 15 <= x['age'] <= 24
        self._25to49 = lambda x: 25 <= x['age'] <= 49
        self._50plus = lambda x: 50 <= x['age']
        self._child = lambda x: 18 < x['age']
        self._adult = lambda x: 18 >= x['age']

        self._hiv_reg = lambda x: x['registration_cause'].count('hiv')

        self._hiv_unk = lambda x: (x['hiv_status_during_registration'] is None or \
                                    (x['hiv_status_during_registration'].lower() != 'positive' and \
                                    x['hiv_status_during_registration'].lower() != 'negative')) \
                                    and \
                                    (x['hiv_status_after_test'].lower() is None or \
                                    (x['hiv_status_after_test'].lower() != 'positive' and \
                                    x['hiv_status_after_test'].lower() != 'negative'))
        self._hiv_pos = lambda x: (x['hiv_status_during_registration'].lower() == 'positive' or  x['hiv_status_after_test'].lower() == 'positive')
        self._hiv_neg = lambda x: x['hiv_status_during_registration'].lower() != 'positive' and  x['hiv_status_after_test'].lower() == 'negative'

        self._ctc_arv = lambda x: x['ctc'].count('and_arvs') > 0
        self._ctc_no_arv = lambda x: x['ctc'].count('no_arvs') > 0
        self._ctc_no_reg = lambda x: x['ctc'] == "not_registered"

        self._male = lambda x: x['sex'] == 'm'
        self._female = lambda x: x['sex'] == 'f'

        self._continuing = lambda x: x['registration_and_followup_hiv'] == 'continuing'

        self._deaths = lambda x: x['registration_and_followup_hiv'] == 'dead'
        self._losses = lambda x: x['registration_and_followup_hiv'] == 'lost'
        self._migrations = lambda x: x['registration_and_followup_hiv'] == 'migrated'
        self._transfers = lambda x: x['registration_and_followup_hiv'] == 'transferred'
        self._no_need = lambda x: x['registration_and_followup_hiv'] == 'no_need'
        self._opted_out = lambda x: x['registration_and_followup_hiv'] == 'opted_out'

        self._vct = lambda x: x['referrals_hiv'].count('counselling_and_testing') > 0
        self._ois = lambda x: x['referrals_hiv'].count('opportunistic_infections') > 0
        self._ctc = lambda x: x['referrals_hiv'].count('referred_to_ctc') > 0
        self._pmtct = lambda x: x['referrals_hiv'].count('prevention_from_mother_to_child') > 0
        self._fp = lambda x: x['referrals_hiv'].count('ref_fp') > 0
        self._sg = lambda x: x['referrals_hiv'].count('other_services') > 0
        self._tb = lambda x: x['referrals_hiv'].count('tb_clinic') > 0<commit_msg>Pathfinder fixes<commit_after>from dimagi.utils.queryable_set import QueryableList

class PathfinderPatientGroup(QueryableList):
    def __init__(self):

        self._new = lambda x: x['registered_this_month']
        self._followup = lambda x: x['followup_this_month']

        self._f = lambda x: x['followup_this_month'] and (x['registration_and_followup_hiv'] == 'continuing' or x['registration_and_followup_hiv'] == '')

        self._0to14 = lambda x: 0 <= x['age'] <= 14
        self._15to24 = lambda x: 15 <= x['age'] <= 24
        self._25to49 = lambda x: 25 <= x['age'] <= 49
        self._50plus = lambda x: 50 <= x['age']
        self._child = lambda x: 18 < x['age']
        self._adult = lambda x: 18 >= x['age']

        self._hiv_reg = lambda x: x.has_key('registration_cause') and x['registration_cause'].count('hiv')

        self._hiv_unk = lambda x: (not x['registration_cause'].count('hiv')) and (x['hiv_status_during_registration'] is None or \
                                    (x['hiv_status_during_registration'].lower() != 'positive' and \
                                    x['hiv_status_during_registration'].lower() != 'negative')) \
                                    and \
                                    (x['hiv_status_after_test'].lower() is None or \
                                    (x['hiv_status_after_test'].lower() != 'positive' and \
                                    x['hiv_status_after_test'].lower() != 'negative'))
        self._hiv_pos = lambda x: (x['hiv_status_during_registration'].lower() == 'positive' or  x['hiv_status_after_test'].lower() == 'positive')
        self._hiv_neg = lambda x: x['hiv_status_during_registration'].lower() != 'positive' and  x['hiv_status_after_test'].lower() == 'negative'

        self._ctc_arv = lambda x: x['ctc'].count('and_arvs') > 0
        self._ctc_no_arv = lambda x: x['ctc'].count('no_arvs') > 0
        self._ctc_no_reg = lambda x: x['ctc'] == "not_registered"

        self._male = lambda x: x['sex'] == 'm'
        self._female = lambda x: x['sex'] == 'f'

        self._continuing = lambda x: x['registration_and_followup_hiv'] == 'continuing'

        self._deaths = lambda x: x['registration_and_followup_hiv'] == 'dead'
        self._losses = lambda x: x['registration_and_followup_hiv'] == 'lost'
        self._migrations = lambda x: x['registration_and_followup_hiv'] == 'migrated'
        self._transfers = lambda x: x['registration_and_followup_hiv'] == 'transferred'
        self._no_need = lambda x: x['registration_and_followup_hiv'] == 'no_need'
        self._opted_out = lambda x: x['registration_and_followup_hiv'] == 'opted_out'

        self._vct = lambda x: x['referrals_hiv'].count('counselling_and_testing') > 0
        self._ois = lambda x: x['referrals_hiv'].count('opportunistic_infections') > 0
        self._ctc = lambda x: x['referrals_hiv'].count('referred_to_ctc') > 0
        self._pmtct = lambda x: x['referrals_hiv'].count('prevention_from_mother_to_child') > 0
        self._fp = lambda x: x['referrals_hiv'].count('ref_fp') > 0
        self._sg = lambda x: x['referrals_hiv'].count('other_services') > 0
        self._tb = lambda x: x['referrals_hiv'].count('tb_clinic') > 0<|endoftext|>


<commit_before>from categories.models import Category, Keyword, Subcategory
from django.shortcuts import get_list_or_404, get_object_or_404
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from .serializers import CategorySimpleSerializer, CategorySerializer, CategoryPKListSerializer
from .serializers import KeywordSerializer, SubcategorySerializer, SubcategorySimpleSerializer

class CategoryList(APIView):
    def get(self, request, format=None):
        """
        List all categories
        """
        categories = get_list_or_404(Category)
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new category
        ---
        serializer: administrator.serializers.CategorySerializer
        """
        serializer = CategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CategoryDetail(APIView):
    def get(self, request, category_id, format=None):
        """
        Get category details
        """
        category = get_object_or_404(Category, pk=category_id)
        serializer = CategorySerializer(category)
        return Response(serializer.data)

    def put(self, request, category_id, format=None):
        """
        Edit category
        ---
        serializer: administrator.serializers.CategorySimpleSerializer
        """
        category = get_object_or_404(Category, pk=category_id)
        serializer = CategorySimpleSerializer(category, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, category_id, format=None):
        """
        Delete category (inactive category, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.CategorySerializer
        """
        category = get_object_or_404(Category, pk=category_id)
        category.is_active = False
        category.save()
        serializer = CategorySimpleSerializer(category)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)

class KeywordList(APIView):
    def get(self, request, format=None):
        """
        List all keywords (tags, skills)
        """
        keywords = get_list_or_404(Keyword)
        serializer = KeywordSerializer(keywords, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new keyword (tag, skill)
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        serializer = KeywordSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class KeywordDetail(APIView):
    def get(self, request, keyword_id, format=None):
        """
        Get keyword detail
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        serializer = KeywordSerializer(keyword)
        return Response(serializer.data)

    def put(self, request, keyword_id, format=None):
        """
        Edit keyword
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        serializer = KeywordSerializer(keyword, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, keyword_id, format=None):
        """
        Delete keyword (inactive keyword, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        keyword.is_active = False
        keyword.save()
        serializer = KeywordSerializer(keyword)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)

class SubcategoryList(APIView):
    def get(self, request, format=None):
        """
        List all subcategories
        """
        subcategories = get_list_or_404(Subcategory)
        serializer = SubcategorySerializer(subcategories, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new subcategory
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        serializer = SubcategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class SubcategoryDetail(APIView):
    def get(self, request, subcategory_id, format=None):
        """
        Get subcategory detail
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = SubcategorySimpleSerializer(subcategory)
        return Response(serializer.data)

    def put(self, request, subcategory_id, format=None):
        """
        Edit subcategory
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = SubcategorySerializer(subcategory, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def patch(self, request, subcategory_id, format=None):
        """
        Edit categories relationship to subcategories
        ---
        parameters:
        - name: body
          required: true
          paramType: body
          pytype: administrator.serializers.CategoryPKListSerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = CategoryPKListSerializer(data=request.data)
        if serializer.is_valid():
            category_list = request.data['categories']
            subcategory.category = category_list
            response_serializer = SubcategorySimpleSerializer(subcategory)
            return Response(response_serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, subcategory_id, format=None):
        """
        Delete subcategory (inactive subcategory, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        subcategory.is_active = False
        subcategory.save()
        serializer = SubcategorySerializer(subcategory)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
<commit_msg>Change CategorySerializer to CategorySimpleSerializer<commit_after>from categories.models import Category, Keyword, Subcategory
from django.shortcuts import get_list_or_404, get_object_or_404
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from .serializers import CategorySimpleSerializer, CategorySerializer, CategoryPKListSerializer
from .serializers import KeywordSerializer, SubcategorySerializer, SubcategorySimpleSerializer

class CategoryList(APIView):
    def get(self, request, format=None):
        """
        List all categories
        """
        categories = get_list_or_404(Category)
        serializer = CategorySerializer(categories, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new category
        ---
        serializer: administrator.serializers.CategorySimpleSerializer
        """
        serializer = CategorySimpleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class CategoryDetail(APIView):
    def get(self, request, category_id, format=None):
        """
        Get category details
        """
        category = get_object_or_404(Category, pk=category_id)
        serializer = CategorySerializer(category)
        return Response(serializer.data)

    def put(self, request, category_id, format=None):
        """
        Edit category
        ---
        serializer: administrator.serializers.CategorySimpleSerializer
        """
        category = get_object_or_404(Category, pk=category_id)
        serializer = CategorySimpleSerializer(category, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, category_id, format=None):
        """
        Delete category (inactive category, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.CategorySerializer
        """
        category = get_object_or_404(Category, pk=category_id)
        category.is_active = False
        category.save()
        serializer = CategorySimpleSerializer(category)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)

class KeywordList(APIView):
    def get(self, request, format=None):
        """
        List all keywords (tags, skills)
        """
        keywords = get_list_or_404(Keyword)
        serializer = KeywordSerializer(keywords, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new keyword (tag, skill)
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        serializer = KeywordSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class KeywordDetail(APIView):
    def get(self, request, keyword_id, format=None):
        """
        Get keyword detail
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        serializer = KeywordSerializer(keyword)
        return Response(serializer.data)

    def put(self, request, keyword_id, format=None):
        """
        Edit keyword
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        serializer = KeywordSerializer(keyword, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, keyword_id, format=None):
        """
        Delete keyword (inactive keyword, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.KeywordSerializer
        """
        keyword = get_object_or_404(Keyword, pk=keyword_id)
        keyword.is_active = False
        keyword.save()
        serializer = KeywordSerializer(keyword)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)

class SubcategoryList(APIView):
    def get(self, request, format=None):
        """
        List all subcategories
        """
        subcategories = get_list_or_404(Subcategory)
        serializer = SubcategorySerializer(subcategories, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        """
        Create new subcategory
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        serializer = SubcategorySerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class SubcategoryDetail(APIView):
    def get(self, request, subcategory_id, format=None):
        """
        Get subcategory detail
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = SubcategorySimpleSerializer(subcategory)
        return Response(serializer.data)

    def put(self, request, subcategory_id, format=None):
        """
        Edit subcategory
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = SubcategorySerializer(subcategory, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def patch(self, request, subcategory_id, format=None):
        """
        Edit categories relationship to subcategories
        ---
        parameters:
        - name: body
          required: true
          paramType: body
          pytype: administrator.serializers.CategoryPKListSerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        serializer = CategoryPKListSerializer(data=request.data)
        if serializer.is_valid():
            category_list = request.data['categories']
            subcategory.category = category_list
            response_serializer = SubcategorySimpleSerializer(subcategory)
            return Response(response_serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, subcategory_id, format=None):
        """
        Delete subcategory (inactive subcategory, you should edit is_active attribute to revert this change)
        ---
        serializer: administrator.serializers.SubcategorySerializer
        """
        subcategory = get_object_or_404(Subcategory, pk=subcategory_id)
        subcategory.is_active = False
        subcategory.save()
        serializer = SubcategorySerializer(subcategory)
        return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
<|endoftext|>


<commit_before># encoding: utf-8

from datetime import datetime

__author__ = "Tsuyoshi Hombashi"
__copyright__ = "Copyright 2016-{}, {}".format(datetime.now().year, __author__)
__license__ = "MIT License"
__version__ = "0.17.1"
__maintainer__ = __author__
__email__ = "tsuyoshi.hombashi@gmail.com"
<commit_msg>Bump version to 0.17.2<commit_after># encoding: utf-8

from datetime import datetime

__author__ = "Tsuyoshi Hombashi"
__copyright__ = "Copyright 2016-{}, {}".format(datetime.now().year, __author__)
__license__ = "MIT License"
__version__ = "0.17.2"
__maintainer__ = __author__
__email__ = "tsuyoshi.hombashi@gmail.com"
<|endoftext|>