<commit_before>"""ParametricJobs Table."""
import os
import re
import time
import json
import logging
import calendar
from datetime import datetime

import cherrypy
from sqlalchemy import Column, SmallInteger, Integer, Boolean, String, PickleType, TIMESTAMP, ForeignKey, Enum, CheckConstraint
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound

from lzproduction.rpc.DiracRPCClient import dirac_api_client, ParametricDiracJobClient
from lzproduction.utils.collections import list_splitter
from lzproduction.utils.tempfile_utils import temporary_runscript, temporary_macro
from ..utils import db_session
from ..statuses import LOCALSTATUS
from .SQLTableBase import SQLTableBase
from .JSONTableEncoder import JSONTableEncoder
from .DiracJobs import DiracJobs

logger = logging.getLogger(__name__)  # pylint: disable=invalid-name
UNIXDATE = re.compile(r'(?P<month>[0-9]{2})-(?P<day>[0-9]{2})-(?P<year>[0-9]{4})$')

@cherrypy.expose
class ParametricJobs(SQLTableBase):
    """Jobs SQL Table."""

    __tablename__ = 'parametricjobs'
    id = Column(Integer, primary_key=True)  # pylint: disable=invalid-name
    priority = Column(SmallInteger, CheckConstraint('priority >= 0 and priority < 10'), nullable=False, default=3)
    app = Column(String(250))
    app_version = Column(String(250))
    site = Column(String(250), nullable=False, default='ANY')
    sim_lfn_outputdir = Column(String(250))
    mctruth_lfn_outputdir = Column(String(250))
    macro = Column(String(250))
    tag = Column(String(250))
    njobs = Column(Integer)
    nevents = Column(Integer)
    seed = Column(Integer)
    fastnest_version = Column(String(250))
    reduction_version = Column(String(250))
    reduction_lfn_inputdir = Column(String(250))
    reduction_lfn_outputdir = Column(String(250))
    der_version = Column(String(250))
    der_lfn_inputdir = Column(String(250))
    der_lfn_outputdir = Column(String(250))
    lzap_version = Column(String(250))
    lzap_lfn_inputdir = Column(String(250))
    lzap_lfn_outputdir = Column(String(250))
    request_id = Column(Integer, ForeignKey('requests.id'), nullable=False)
    request = relationship("Requests", back_populates="parametricjobs")
    status = Column(Enum(LOCALSTATUS), nullable=False)
    reschedule = Column(Boolean, nullable=False, default=False)
    timestamp = Column(TIMESTAMP, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
    num_completed = Column(Integer, nullable=False, default=0)
    num_failed = Column(Integer, nullable=False, default=0)
    num_submitted = Column(Integer, nullable=False, default=0)
    num_running = Column(Integer, nullable=False, default=0)
    diracjobs = relationship("DiracJobs", back_populates="parametricjob")

    @hybrid_property
    def num_other(self):
        """Return the number of jobs in states other than the known ones."""
        return self.njobs - (self.num_submitted + self.num_running + self.num_failed + self.num_completed)

    def submit(self):
        """Submit parametric job."""
        # problems here if not running simulation, there will be no macro so
        # everything including context needs reworking.
#        lfn_root = os.path.join('/lz/user/l/lzproduser.grid.hep.ph.ic.ac.uk', '_'.join(('-'.join((self.app, self.app_version)),
#                                                           '-'.join(('DER', self.der_version)))))

        parametric_job = ParametricDiracJobClient()
        dirac_ids = set()
        if self.app_version is not None:

            macro_name = os.path.splitext(os.path.basename(self.macro or ''))[0]
            livetime_sec_per_beamon = 0.1132698957
            livetimeperjob = str((self.nevents or 1) * livetime_sec_per_beamon)
            unixtime = time.time()
            match = UNIXDATE.search(macro_name)
            if match is not None:
                month, day, year = match.groups()
                unixtime = str(int(calendar.timegm(datetime(int(year), int(month), int(day), 0, 0).utctimetuple())))
            with temporary_runscript(root_version='5.34.32',
                                     root_arch='slc6_gcc44_x86_64',
                                     g4_version='4.10.03.p02',
                                     physics_version='1.4.0',
                                     se='UKI-LT2-IC-HEP-disk',
                                     unixtime=unixtime,
                                     livetimeperjob=livetimeperjob, **self) as runscript,\
                 temporary_macro(self.tag, self.macro or '', self.app, self.app_version, self.nevents) as macro:
                logger.info("Submitting ParametricJob %s, macro: %s to DIRAC", self.id, self.macro)
                for sublist in list_splitter(range(self.seed, self.seed + self.njobs), 1000):
                    with parametric_job as j:
                        j.setName(os.path.splitext(os.path.basename(macro))[0] + '-%(args)s')
                        j.setPriority(self.priority)
                        j.setPlatform('ANY')
                        j.setExecutable(os.path.basename(runscript),
                                        os.path.basename(macro) + ' %(args)s' + ' %s' % self.nevents,
                                        'lzproduction_output.log')
                        j.setInputSandbox([runscript, macro])
                        if self.site.endswith('2Processors'):
                            j.setDestination("LCG.UKI-LT2-IC-HEP.uk")
                            j.setTag('2Processors')
                        else:
                            j.setDestination(self.site)
                        j.setBannedSites(['LCG.UKI-LT2-Brunel.uk', 'LCG.UKI-NORTHGRID-LANCS-HEP.uk', 'LCG.UKI-SOUTHGRID-BRIS-HEP.uk'])
                        j.setParameterSequence('args', sublist, addToWorkflow=False)
                    dirac_ids.update(parametric_job.subjob_ids)
        else:
            with temporary_runscript(root_version='5.34.32',
                                     root_arch='slc6_gcc44_x86_64',
                                     g4_version='4.10.03.p02',
                                     physics_version='1.4.0',
                                     se='UKI-LT2-IC-HEP-disk', **self) as runscript:
                logger.info("Submitting ParametricJob %s, inputdir: %s to DIRAC", self.id, self.reduction_lfn_inputdir or self.der_lfn_inputdir or self.lzap_lfn_inputdir)

                input_lfn_dir=self.reduction_lfn_inputdir or\
                               self.der_lfn_inputdir or \
                               self.lzap_lfn_inputdir
                for sublist in list_splitter(list_lfns(input_lfn_dir), 1000):
                    with parametric_job as j:
                        j.setName("%(args)s")
                        j.setPriority(self.priority)
                        j.setPlatform('ANY')
                        j.setExecutable(os.path.basename(runscript),
                                        '%(args)s',
                                        'lzanalysis_output.log')
                        j.setInputSandbox([runscript])
                        if self.site.endswith('2Processors'):
                            j.setDestination("LCG.UKI-LT2-IC-HEP.uk")
                            j.setTag('2Processors')
                        else:
                            j.setDestination(self.site)
                        j.setBannedSites(['LCG.UKI-LT2-Brunel.uk', 'LCG.UKI-NORTHGRID-LANCS-HEP.uk', 'LCG.UKI-SOUTHGRID-BRIS-HEP.uk')
                        j.setParameterSequence('InputData', sublist, addToWorkflow='ParametricInputData')
                        j.setParameterSequence('args',
                                               [os.path.basename(l) for l in sublist],
                                               addToWorkflow=False)
                    dirac_ids.update(parametric_job.subjob_ids)

        with db_session() as session:
            session.bulk_insert_mappings(DiracJobs, [{'id': i, 'parametricjob_id': self.id}
                                                     for i in dirac_ids])

    def reset(self):
        """Reset parametric job."""
        with db_session(reraise=False) as session:
            dirac_jobs = session.query(DiracJobs).filter_by(parametricjob_id=self.id)
            dirac_job_ids = [j.id for j in dirac_jobs.all()]
            dirac_jobs.delete(synchronize_session=False)
        with dirac_api_client() as dirac:
            logger.info("Removing Dirac jobs %s from ParametricJob %s", dirac_job_ids, self.id)
            dirac.kill(dirac_job_ids)
            dirac.delete(dirac_job_ids)

    def delete_dirac_jobs(self, session):
        """Delete associated DIRAC jobs."""
        logger.info("Deleting DiracJobs for ParametricJob id: %s", self.id)
        session.query(DiracJobs)\
               .filter_by(parametricjob_id=self.id)\
               .delete(synchronize_session=False)

    def update_status(self):
        """Update the status of parametric job."""
        local_statuses = DiracJobs.update_status(self)
        # could just have DiracJobs return this... maybe better
#        local_statuses = Counter(status.local_status for status in dirac_statuses.elements())
        status = max(local_statuses or [self.status])
        with db_session() as session:
            this = session.merge(self)
            this.status = status
            this.num_completed = local_statuses[LOCALSTATUS.Completed]
            this.num_failed = local_statuses[LOCALSTATUS.Failed]
            this.num_submitted = local_statuses[LOCALSTATUS.Submitted]
            this.num_running = local_statuses[LOCALSTATUS.Running]
            this.reschedule = False
        return status

    @staticmethod
    def GET(reqid):  # pylint: disable=invalid-name
        """
        REST Get method.

        Returns all ParametricJobs for a given request id.
        """
        logger.debug("In GET: reqid = %s", reqid)
        requester = cherrypy.request.verified_user
        with db_session() as session:
            user_requests = session.query(ParametricJobs)\
                                   .filter_by(request_id=reqid)
            if not requester.admin:
                user_requests = user_requests.join(ParametricJobs.request)\
                                             .filter_by(requester_id=requester.id)
            return json.dumps({'data': user_requests.all()}, cls=JSONTableEncoder)

    @staticmethod
    def PUT(jobid, reschedule=False):  # pylint: disable=invalid-name
        """REST Put method."""
        logger.debug("In PUT: jobid = %s, reschedule = %s", jobid, reschedule)
        requester = cherrypy.request.verified_user
        with db_session() as session:
            query = session.query(ParametricJobs).filter_by(id=jobid)
            if not requester.admin:
                query = query.join(ParametricJobs.request)\
                             .filter_by(requester_id=requester.id)
            try:
                job = query.one()
            except NoResultFound:
                logger.error("No ParametricJobs found with id: %s", jobid)
            except MultipleResultsFound:
                logger.error("Multiple ParametricJobs found with id: %s", jobid)
            else:
                if reschedule and not job.reschedule:
                    job.reschedule = True
                    job.status = LOCALSTATUS.Submitting

<commit_msg>fixup! Banned sites and 2 cores<commit_after>"""ParametricJobs Table."""
import os
import re
import time
import json
import logging
import calendar
from datetime import datetime

import cherrypy
from sqlalchemy import Column, SmallInteger, Integer, Boolean, String, PickleType, TIMESTAMP, ForeignKey, Enum, CheckConstraint
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship
from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound

from lzproduction.rpc.DiracRPCClient import dirac_api_client, ParametricDiracJobClient
from lzproduction.utils.collections import list_splitter
from lzproduction.utils.tempfile_utils import temporary_runscript, temporary_macro
from ..utils import db_session
from ..statuses import LOCALSTATUS
from .SQLTableBase import SQLTableBase
from .JSONTableEncoder import JSONTableEncoder
from .DiracJobs import DiracJobs

logger = logging.getLogger(__name__)  # pylint: disable=invalid-name
UNIXDATE = re.compile(r'(?P<month>[0-9]{2})-(?P<day>[0-9]{2})-(?P<year>[0-9]{4})$')

@cherrypy.expose
class ParametricJobs(SQLTableBase):
    """Jobs SQL Table."""

    __tablename__ = 'parametricjobs'
    id = Column(Integer, primary_key=True)  # pylint: disable=invalid-name
    priority = Column(SmallInteger, CheckConstraint('priority >= 0 and priority < 10'), nullable=False, default=3)
    app = Column(String(250))
    app_version = Column(String(250))
    site = Column(String(250), nullable=False, default='ANY')
    sim_lfn_outputdir = Column(String(250))
    mctruth_lfn_outputdir = Column(String(250))
    macro = Column(String(250))
    tag = Column(String(250))
    njobs = Column(Integer)
    nevents = Column(Integer)
    seed = Column(Integer)
    fastnest_version = Column(String(250))
    reduction_version = Column(String(250))
    reduction_lfn_inputdir = Column(String(250))
    reduction_lfn_outputdir = Column(String(250))
    der_version = Column(String(250))
    der_lfn_inputdir = Column(String(250))
    der_lfn_outputdir = Column(String(250))
    lzap_version = Column(String(250))
    lzap_lfn_inputdir = Column(String(250))
    lzap_lfn_outputdir = Column(String(250))
    request_id = Column(Integer, ForeignKey('requests.id'), nullable=False)
    request = relationship("Requests", back_populates="parametricjobs")
    status = Column(Enum(LOCALSTATUS), nullable=False)
    reschedule = Column(Boolean, nullable=False, default=False)
    timestamp = Column(TIMESTAMP, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
    num_completed = Column(Integer, nullable=False, default=0)
    num_failed = Column(Integer, nullable=False, default=0)
    num_submitted = Column(Integer, nullable=False, default=0)
    num_running = Column(Integer, nullable=False, default=0)
    diracjobs = relationship("DiracJobs", back_populates="parametricjob")

    @hybrid_property
    def num_other(self):
        """Return the number of jobs in states other than the known ones."""
        return self.njobs - (self.num_submitted + self.num_running + self.num_failed + self.num_completed)

    def submit(self):
        """Submit parametric job."""
        # problems here if not running simulation, there will be no macro so
        # everything including context needs reworking.
#        lfn_root = os.path.join('/lz/user/l/lzproduser.grid.hep.ph.ic.ac.uk', '_'.join(('-'.join((self.app, self.app_version)),
#                                                           '-'.join(('DER', self.der_version)))))

        parametric_job = ParametricDiracJobClient()
        dirac_ids = set()
        if self.app_version is not None:

            macro_name = os.path.splitext(os.path.basename(self.macro or ''))[0]
            livetime_sec_per_beamon = 0.1132698957
            livetimeperjob = str((self.nevents or 1) * livetime_sec_per_beamon)
            unixtime = time.time()
            match = UNIXDATE.search(macro_name)
            if match is not None:
                month, day, year = match.groups()
                unixtime = str(int(calendar.timegm(datetime(int(year), int(month), int(day), 0, 0).utctimetuple())))
            with temporary_runscript(root_version='5.34.32',
                                     root_arch='slc6_gcc44_x86_64',
                                     g4_version='4.10.03.p02',
                                     physics_version='1.4.0',
                                     se='UKI-LT2-IC-HEP-disk',
                                     unixtime=unixtime,
                                     livetimeperjob=livetimeperjob, **self) as runscript,\
                 temporary_macro(self.tag, self.macro or '', self.app, self.app_version, self.nevents) as macro:
                logger.info("Submitting ParametricJob %s, macro: %s to DIRAC", self.id, self.macro)
                for sublist in list_splitter(range(self.seed, self.seed + self.njobs), 1000):
                    with parametric_job as j:
                        j.setName(os.path.splitext(os.path.basename(macro))[0] + '-%(args)s')
                        j.setPriority(self.priority)
                        j.setPlatform('ANY')
                        j.setExecutable(os.path.basename(runscript),
                                        os.path.basename(macro) + ' %(args)s' + ' %s' % self.nevents,
                                        'lzproduction_output.log')
                        j.setInputSandbox([runscript, macro])
                        if self.site.endswith('2Processors'):
                            j.setDestination("LCG.UKI-LT2-IC-HEP.uk")
                            j.setTag('2Processors')
                        else:
                            j.setDestination(self.site)
                        j.setBannedSites(['LCG.UKI-LT2-Brunel.uk', 'LCG.UKI-NORTHGRID-LANCS-HEP.uk', 'LCG.UKI-SOUTHGRID-BRIS-HEP.uk'])
                        j.setParameterSequence('args', sublist, addToWorkflow=False)
                    dirac_ids.update(parametric_job.subjob_ids)
        else:
            with temporary_runscript(root_version='5.34.32',
                                     root_arch='slc6_gcc44_x86_64',
                                     g4_version='4.10.03.p02',
                                     physics_version='1.4.0',
                                     se='UKI-LT2-IC-HEP-disk', **self) as runscript:
                logger.info("Submitting ParametricJob %s, inputdir: %s to DIRAC", self.id, self.reduction_lfn_inputdir or self.der_lfn_inputdir or self.lzap_lfn_inputdir)

                input_lfn_dir=self.reduction_lfn_inputdir or\
                               self.der_lfn_inputdir or \
                               self.lzap_lfn_inputdir
                for sublist in list_splitter(list_lfns(input_lfn_dir), 1000):
                    with parametric_job as j:
                        j.setName("%(args)s")
                        j.setPriority(self.priority)
                        j.setPlatform('ANY')
                        j.setExecutable(os.path.basename(runscript),
                                        '%(args)s',
                                        'lzanalysis_output.log')
                        j.setInputSandbox([runscript])
                        if self.site.endswith('2Processors'):
                            j.setDestination("LCG.UKI-LT2-IC-HEP.uk")
                            j.setTag('2Processors')
                        else:
                            j.setDestination(self.site)
                        j.setBannedSites(['LCG.UKI-LT2-Brunel.uk', 'LCG.UKI-NORTHGRID-LANCS-HEP.uk', 'LCG.UKI-SOUTHGRID-BRIS-HEP.uk'])
                        j.setParameterSequence('InputData', sublist, addToWorkflow='ParametricInputData')
                        j.setParameterSequence('args',
                                               [os.path.basename(l) for l in sublist],
                                               addToWorkflow=False)
                    dirac_ids.update(parametric_job.subjob_ids)

        with db_session() as session:
            session.bulk_insert_mappings(DiracJobs, [{'id': i, 'parametricjob_id': self.id}
                                                     for i in dirac_ids])

    def reset(self):
        """Reset parametric job."""
        with db_session(reraise=False) as session:
            dirac_jobs = session.query(DiracJobs).filter_by(parametricjob_id=self.id)
            dirac_job_ids = [j.id for j in dirac_jobs.all()]
            dirac_jobs.delete(synchronize_session=False)
        with dirac_api_client() as dirac:
            logger.info("Removing Dirac jobs %s from ParametricJob %s", dirac_job_ids, self.id)
            dirac.kill(dirac_job_ids)
            dirac.delete(dirac_job_ids)

    def delete_dirac_jobs(self, session):
        """Delete associated DIRAC jobs."""
        logger.info("Deleting DiracJobs for ParametricJob id: %s", self.id)
        session.query(DiracJobs)\
               .filter_by(parametricjob_id=self.id)\
               .delete(synchronize_session=False)

    def update_status(self):
        """Update the status of parametric job."""
        local_statuses = DiracJobs.update_status(self)
        # could just have DiracJobs return this... maybe better
#        local_statuses = Counter(status.local_status for status in dirac_statuses.elements())
        status = max(local_statuses or [self.status])
        with db_session() as session:
            this = session.merge(self)
            this.status = status
            this.num_completed = local_statuses[LOCALSTATUS.Completed]
            this.num_failed = local_statuses[LOCALSTATUS.Failed]
            this.num_submitted = local_statuses[LOCALSTATUS.Submitted]
            this.num_running = local_statuses[LOCALSTATUS.Running]
            this.reschedule = False
        return status

    @staticmethod
    def GET(reqid):  # pylint: disable=invalid-name
        """
        REST Get method.

        Returns all ParametricJobs for a given request id.
        """
        logger.debug("In GET: reqid = %s", reqid)
        requester = cherrypy.request.verified_user
        with db_session() as session:
            user_requests = session.query(ParametricJobs)\
                                   .filter_by(request_id=reqid)
            if not requester.admin:
                user_requests = user_requests.join(ParametricJobs.request)\
                                             .filter_by(requester_id=requester.id)
            return json.dumps({'data': user_requests.all()}, cls=JSONTableEncoder)

    @staticmethod
    def PUT(jobid, reschedule=False):  # pylint: disable=invalid-name
        """REST Put method."""
        logger.debug("In PUT: jobid = %s, reschedule = %s", jobid, reschedule)
        requester = cherrypy.request.verified_user
        with db_session() as session:
            query = session.query(ParametricJobs).filter_by(id=jobid)
            if not requester.admin:
                query = query.join(ParametricJobs.request)\
                             .filter_by(requester_id=requester.id)
            try:
                job = query.one()
            except NoResultFound:
                logger.error("No ParametricJobs found with id: %s", jobid)
            except MultipleResultsFound:
                logger.error("Multiple ParametricJobs found with id: %s", jobid)
            else:
                if reschedule and not job.reschedule:
                    job.reschedule = True
                    job.status = LOCALSTATUS.Submitting

<|endoftext|>


<commit_before>import random

from app.table import Table
from collections import namedtuple

PULMONIC = Table('app/data/pulmonic.csv')
VOWELS = Table('app/data/vowels.csv')

# A Rule is a namedtuple with the following fields:
#     name: a string representing the process' name
#     target: a string representing the process' target
#     replacement: a string representing the process' replacement
#     changes: a dictionary of sound changes
#     environments: a list of environments to apply the rule to
Rule = namedtuple('Rule', ['name', 'target', 'replacement', 'changes', 'environments'])

def combine_lists(list_1, list_2):
    '''Combines two lists into a dictionary, ensuring that any pair that contains a
    '' is removed.
    '''
    pairs = [pair for pair in zip(list_1, list_2) if pair[0] != '' and pair[1] != '']
    return dict(pairs)

##############################################################################
## CONSONANTS
##############################################################################

##############################################################################
## CONSONANTS - LENITION
##############################################################################
def flapping():
    return Rule('flapping', '[t] and [d]', 'flap',
                {'t': 'ɾ', 'd': 'ɾ'},
                ['^.', 'V.V'])

##############################################################################
## CONSONANTS - LENITION - SONORIZATION
##############################################################################
def voicing():
    return Rule('voicing', 'unvoiced plosive', 'voiced plosive',
                {'p': 'b', 't': 'd', 'ʈ': 'ɖ', 'c': 'ɟ', 'k': 'g', 'q': 'ɢ'},
                ['^.', 'V.V', '.$'])

def lateral_vocalization():
    return Rule('vocalization', 'lateral approximant', 'semivowel',
                {'l': 'j', 'ɫ': 'w'},
                ['^.', 'V.V', '.$'])

def palatal_vocalization():
    return Rule('vocalization', 'palatal approximant', 'front vowel',
                {'j': 'i'},
                ['^.', 'V.V', '.$'])

def approximation():
    changes = {}

    for fricative, approximant in zip(PULMONIC['fricative'], PULMONIC['approximant']):
        if fricative != '':
            if approximant == '':
                changes[fricative] = fricative + '\u031E'
            else:
                changes[fricative] = approximant

    return Rule('approximation', 'continuant', 'approximant',
                changes,
                ['^.', 'V.V', '.$'])

##############################################################################
## CONSONANTS - LENITION - OPENING
##############################################################################
def degemination():
    changes = {}
    for phoneme in PULMONIC['plosive']:
        if phoneme != '':
            changes[phoneme + phoneme] = phoneme
            changes[phoneme + phoneme + 'ʰ'] = phoneme + 'ʰ'

    return Rule('degemination', 'geminated plosive', 'plosive',
                changes,
                ['^.', 'V.V'])

def spirantization():
    changes = combine_lists(PULMONIC['plosive'], PULMONIC['fricative'])

    return Rule('spirantization', 'plosive', 'fricative',
                changes,
                ['^.', 'V.V'])

def debuccalization():
    fricatives = PULMONIC['fricative']
    fricatives.remove('h')
    changes = combine_lists(fricatives, ['h'] * len(fricatives))
    return Rule('dubuccalization', 'fricative', 'placeless approximant',
                changes,
                ['^.', 'V.V', '.$'])

def affrication():
    changes = {}

    for plosive, affricate in zip(PULMONIC['plosive'], PULMONIC['nonsibilantaffricate']):
        if plosive != '' and affricate != '':
            changes[plosive] = affricate
            changes[plosive + 'ʰ'] = affricate

    changes['t'] = 'ts'
    changes['tʰ'] = 'ts'

    return Rule('affrication', 'plosive', 'affricate',
                changes,
                ['V.V'])

def deaffrication():
    changes = combine_lists(PULMONIC['nonsibilantaffricate'], PULMONIC['fricative'])
    changes['ts'] = 's'

    return Rule('deaffrication', 'affricate', 'fricative',
                changes,
                ['^.', 'V.V', '.$'])

def approximant_elision():
    changes = {}

    for approximant in PULMONIC['approximant']:
        if approximant != '':
            changes[approximant] = ''

    changes['h'] = ''
    changes['ɦ'] = ''

    return Rule('elision', 'approximant', 'nothing',
                changes,
                ['^.', 'V.V', '.$'])

##############################################################################
## VOWELS
##############################################################################
def vowel_nasalization():
    changes = {}

    for vowel in VOWELS.members():
        changes[vowel] = vowel + '\u0303'

    return Rule('nasalization', 'vowel', 'nasal vowel',
                changes,
                ['{nasal}.'])

rules = [voicing(),
         degemination(),
         spirantization(),
         debuccalization(),
         lateral_vocalization(),
         palatal_vocalization(),
         approximation(),
         flapping(),
         affrication(),
         deaffrication(),
         approximant_elision(),
         vowel_nasalization()]
<commit_msg>Palatalization rule<commit_after>import random

from app.table import Table
from collections import namedtuple

PULMONIC = Table('app/data/pulmonic.csv')
VOWELS = Table('app/data/vowels.csv')

# A Rule is a namedtuple with the following fields:
#     name: a string representing the process' name
#     target: a string representing the process' target
#     replacement: a string representing the process' replacement
#     changes: a dictionary of sound changes
#     environments: a list of environments to apply the rule to
Rule = namedtuple('Rule', ['name', 'target', 'replacement', 'changes', 'environments'])

def combine_lists(list_1, list_2):
    '''Combines two lists into a dictionary, ensuring that any pair that contains a
    '' is removed.
    '''
    pairs = [pair for pair in zip(list_1, list_2) if pair[0] != '' and pair[1] != '']
    return dict(pairs)

##############################################################################
## CONSONANTS
##############################################################################
def palatalization():
    changes = {}

    for plosive in PULMONIC['plosive']:
        if plosive != '':
            changes[plosive] = plosive + 'ʲ'

    return Rule('palatalization', 'plosive', 'palatalized plosive',
                 changes,
                 ['.(?:i|y|e|ø|j)', '(?:i|y|e|ø|j).'])

##############################################################################
## CONSONANTS - LENITION
##############################################################################
def flapping():
    return Rule('flapping', '[t] and [d]', 'flap',
                {'t': 'ɾ', 'd': 'ɾ'},
                ['^.', 'V.V'])

##############################################################################
## CONSONANTS - LENITION - SONORIZATION
##############################################################################
def voicing():
    return Rule('voicing', 'unvoiced plosive', 'voiced plosive',
                {'p': 'b', 't': 'd', 'ʈ': 'ɖ', 'c': 'ɟ', 'k': 'g', 'q': 'ɢ'},
                ['^.', 'V.V', '.$'])

def lateral_vocalization():
    return Rule('vocalization', 'lateral approximant', 'semivowel',
                {'l': 'j', 'ɫ': 'w'},
                ['^.', 'V.V', '.$'])

def palatal_vocalization():
    return Rule('vocalization', 'palatal approximant', 'front vowel',
                {'j': 'i'},
                ['^.', 'V.V', '.$'])

def approximation():
    changes = {}

    for fricative, approximant in zip(PULMONIC['fricative'], PULMONIC['approximant']):
        if fricative != '':
            if approximant == '':
                changes[fricative] = fricative + '\u031E'
            else:
                changes[fricative] = approximant

    return Rule('approximation', 'continuant', 'approximant',
                changes,
                ['^.', 'V.V', '.$'])

##############################################################################
## CONSONANTS - LENITION - OPENING
##############################################################################
def degemination():
    changes = {}
    for phoneme in PULMONIC['plosive']:
        if phoneme != '':
            changes[phoneme + phoneme] = phoneme
            changes[phoneme + phoneme + 'ʰ'] = phoneme + 'ʰ'

    return Rule('degemination', 'geminated plosive', 'plosive',
                changes,
                ['^.', 'V.V'])

def spirantization():
    changes = combine_lists(PULMONIC['plosive'], PULMONIC['fricative'])

    return Rule('spirantization', 'plosive', 'fricative',
                changes,
                ['^.', 'V.V'])

def debuccalization():
    fricatives = PULMONIC['fricative']
    fricatives.remove('h')
    changes = combine_lists(fricatives, ['h'] * len(fricatives))
    return Rule('dubuccalization', 'fricative', 'placeless approximant',
                changes,
                ['^.', 'V.V', '.$'])

def affrication():
    changes = {}

    for plosive, affricate in zip(PULMONIC['plosive'], PULMONIC['nonsibilantaffricate']):
        if plosive != '' and affricate != '':
            changes[plosive] = affricate
            changes[plosive + 'ʰ'] = affricate

    changes['t'] = 'ts'
    changes['tʰ'] = 'ts'

    return Rule('affrication', 'plosive', 'affricate',
                changes,
                ['V.V'])

def deaffrication():
    changes = combine_lists(PULMONIC['nonsibilantaffricate'], PULMONIC['fricative'])
    changes['ts'] = 's'

    return Rule('deaffrication', 'affricate', 'fricative',
                changes,
                ['^.', 'V.V', '.$'])

def approximant_elision():
    changes = {}

    for approximant in PULMONIC['approximant']:
        if approximant != '':
            changes[approximant] = ''

    changes['h'] = ''
    changes['ɦ'] = ''

    return Rule('elision', 'approximant', 'nothing',
                changes,
                ['^.', 'V.V', '.$'])

##############################################################################
## VOWELS
##############################################################################
def vowel_nasalization():
    changes = {}

    for vowel in VOWELS.members():
        changes[vowel] = vowel + '\u0303'

    return Rule('nasalization', 'vowel', 'nasal vowel',
                changes,
                ['{nasal}.'])

rules = [voicing(),
         palatalization(),
         degemination(),
         spirantization(),
         debuccalization(),
         lateral_vocalization(),
         palatal_vocalization(),
         approximation(),
         flapping(),
         affrication(),
         deaffrication(),
         approximant_elision(),
         vowel_nasalization()]
<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Module containing the boiler plate required to construct templates
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

import collections
import re

from google.appengine.ext import db
from google.appengine.ext.db import djangoforms

from django.forms import forms
from django.forms import widgets
from django.template import loader
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext

def choiceWidget(field):
  """Returns a Select widget for the specified field.
  """
  label = field.verbose_name

  choices = []
  choices.append(('', label))
  for choice in field.choices:
    choices.append((str(choice), unicode(choice)))
  return widgets.Select(choices=choices)

def choiceWidgets(model, fields):
  """Returns a dictionary of Select widgets for the specified fields.
  """
  return dict((i, choiceWidget(getattr(model, i))) for i in fields)

class ModelForm(djangoforms.ModelForm):
  """Django ModelForm class which uses our implementation of BoundField.
  """

  def __init__(self, *args, **kwargs):
    """Fixes label and help_text issues after parent initialization.

    Args:
      *args, **kwargs:  passed through to parent __init__() constructor
    """

    super(djangoforms.ModelForm, self).__init__(*args, **kwargs)

    renames = {
        'verbose_name': 'label',
        'help_text': 'help_text',
        'example_text': 'example_text',
        'group': 'group',
        }

    for field_name in self.fields.iterkeys():
      field = self.fields[field_name]

      # Since fields can be added only to the ModelForm subclass, check to
      # see if the Model has a corresponding field first.
      # pylint: disable-msg=E1101
      if not hasattr(self.Meta.model, field_name):
        continue

      model_prop = getattr(self.Meta.model, field_name)

      for old, new in renames.iteritems():
        value = getattr(model_prop, old, None)
        if value and not getattr(field, new, None):
          setattr(field, new, value)

  def __iter__(self):
    grouping = collections.defaultdict(list)

    for name, field in self.fields.items():
      bound = BoundField(self, field, name)
      group = getattr(field, 'group', '0. ')
      grouping[group].append(bound)

    rexp = re.compile(r"\d+. ")

    for group, fields in sorted(grouping.items()):
      yield rexp.sub('', group), fields

  def create(self, commit=True, key_name=None, parent=None):
    """Save this form's cleaned data into a new model instance.

    Args:
      commit: optional bool, default True; if true, the model instance
        is also saved to the datastore.
      key_name: the key_name of the new model instance, default None
      parent: the parent of the new model instance, default None

    Returns:
      The model instance created by this call.
    Raises:
      ValueError if the data couldn't be validated.
    """
    if not self.is_bound:
      raise ValueError('Cannot save an unbound form')
    opts = self._meta
    instance = self.instance
    if self.instance:
      raise ValueError('Cannot create a saved form')
    if self.errors:
      raise ValueError("The %s could not be created because the data didn't "
                       'validate.' % opts.model.kind())
    cleaned_data = self._cleaned_data()
    converted_data = {}
    for name, prop in opts.model.properties().iteritems():
      value = cleaned_data.get(name)
      if value is not None:
        converted_data[name] = prop.make_value_from_form(value)
    try:
      instance = opts.model(key_name=key_name, parent=parent, **converted_data)
      self.instance = instance
    except db.BadValueError, err:
      raise ValueError('The %s could not be created (%s)' %
                       (opts.model.kind(), err))
    if commit:
      instance.put()
    return instance

  def render(self):
    """Renders the template to a string.

    Uses the context method to retrieve the appropriate context, uses the
    self.templatePath() method to retrieve the template that should be used.
    """

    context = {
      'form': self,
    }
    template_path = 'v2/modules/gsoc/_form.html'
    rendered = loader.render_to_string(template_path, dictionary=context)
    return rendered

class BoundField(forms.BoundField):
  """
  """

  NOT_SUPPORTED_MSG_FMT = ugettext('Widget %s is not supported.')

  def is_required(self):
    return self.field.required

  def render(self):
    attrs = {
        'id': self.name
        }

    widget = self.field.widget

    if isinstance(widget, widgets.TextInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.DateInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.Select):
      return self.renderSelect()
    elif isinstance(widget, widgets.CheckboxInput):
      return self.renderCheckboxInput()
    elif isinstance(widget, widgets.Textarea):
      return self.renderTextArea()

    return self.NOT_SUPPORTED_MSG_FMT % (
        widget.__class__.__name__)

  def renderCheckboxInput(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(
        '%s%s%s%s' % (
        self.as_widget(attrs=attrs),
        self.field.label,
        self._render_is_required(),
        self._render_error(),
        ))

  def renderTextArea(self):
    attrs = {
        'id': self.name,
        'class': 'textarea'
        }

    return mark_safe('%s%s%s' % (
        self._render_label(),
        self.as_widget(attrs=attrs),
        self._render_error(),
    ))

  def renderTextInput(self):
    attrs = {
        'id': self.name,
        'class': 'text',
        }

    return mark_safe('%s%s%s' % (
        self._render_label(),
        self.as_widget(attrs=attrs),
        self._render_error(),
    ))

  def renderSelect(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe('%s%s%s%s' % (
        self.as_widget(attrs=attrs),
        self._render_is_required(),
        self._render_error(),
        self._render_note(),
    ))

  def _render_label(self):
    return '%s%s' % (
        self.field.label,
        self._render_is_required(),
    )

  def _render_error(self):
    if not self.errors:
      return ''

    return '
%s
' % (
        self.errors[0])

  def _render_is_required(self):
    if not self.field.required:
      return ''

    return '*'

  def div_class(self):
    name = self.name
    if self.errors:
      name += ' error'
    return name
<commit_msg>Add note rendering<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Module containing the boiler plate required to construct templates
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

import collections
import re

from google.appengine.ext import db
from google.appengine.ext.db import djangoforms

from django.forms import forms
from django.forms import widgets
from django.template import loader
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext

def choiceWidget(field):
  """Returns a Select widget for the specified field.
  """
  label = field.verbose_name

  choices = []
  choices.append(('', label))
  for choice in field.choices:
    choices.append((str(choice), unicode(choice)))
  return widgets.Select(choices=choices)

def choiceWidgets(model, fields):
  """Returns a dictionary of Select widgets for the specified fields.
  """
  return dict((i, choiceWidget(getattr(model, i))) for i in fields)

class ModelForm(djangoforms.ModelForm):
  """Django ModelForm class which uses our implementation of BoundField.
  """

  def __init__(self, *args, **kwargs):
    """Fixes label and help_text issues after parent initialization.

    Args:
      *args, **kwargs:  passed through to parent __init__() constructor
    """

    super(djangoforms.ModelForm, self).__init__(*args, **kwargs)

    renames = {
        'verbose_name': 'label',
        'help_text': 'help_text',
        'example_text': 'example_text',
        'group': 'group',
        }

    for field_name in self.fields.iterkeys():
      field = self.fields[field_name]

      # Since fields can be added only to the ModelForm subclass, check to
      # see if the Model has a corresponding field first.
      # pylint: disable-msg=E1101
      if not hasattr(self.Meta.model, field_name):
        continue

      model_prop = getattr(self.Meta.model, field_name)

      for old, new in renames.iteritems():
        value = getattr(model_prop, old, None)
        if value and not getattr(field, new, None):
          setattr(field, new, value)

  def __iter__(self):
    grouping = collections.defaultdict(list)

    for name, field in self.fields.items():
      bound = BoundField(self, field, name)
      group = getattr(field, 'group', '0. ')
      grouping[group].append(bound)

    rexp = re.compile(r"\d+. ")

    for group, fields in sorted(grouping.items()):
      yield rexp.sub('', group), fields

  def create(self, commit=True, key_name=None, parent=None):
    """Save this form's cleaned data into a new model instance.

    Args:
      commit: optional bool, default True; if true, the model instance
        is also saved to the datastore.
      key_name: the key_name of the new model instance, default None
      parent: the parent of the new model instance, default None

    Returns:
      The model instance created by this call.
    Raises:
      ValueError if the data couldn't be validated.
    """
    if not self.is_bound:
      raise ValueError('Cannot save an unbound form')
    opts = self._meta
    instance = self.instance
    if self.instance:
      raise ValueError('Cannot create a saved form')
    if self.errors:
      raise ValueError("The %s could not be created because the data didn't "
                       'validate.' % opts.model.kind())
    cleaned_data = self._cleaned_data()
    converted_data = {}
    for name, prop in opts.model.properties().iteritems():
      value = cleaned_data.get(name)
      if value is not None:
        converted_data[name] = prop.make_value_from_form(value)
    try:
      instance = opts.model(key_name=key_name, parent=parent, **converted_data)
      self.instance = instance
    except db.BadValueError, err:
      raise ValueError('The %s could not be created (%s)' %
                       (opts.model.kind(), err))
    if commit:
      instance.put()
    return instance

  def render(self):
    """Renders the template to a string.

    Uses the context method to retrieve the appropriate context, uses the
    self.templatePath() method to retrieve the template that should be used.
    """

    context = {
      'form': self,
    }
    template_path = 'v2/modules/gsoc/_form.html'
    rendered = loader.render_to_string(template_path, dictionary=context)
    return rendered

class BoundField(forms.BoundField):
  """
  """

  NOT_SUPPORTED_MSG_FMT = ugettext('Widget %s is not supported.')

  def is_required(self):
    return self.field.required

  def render(self):
    attrs = {
        'id': self.name
        }

    widget = self.field.widget

    if isinstance(widget, widgets.TextInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.DateInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.Select):
      return self.renderSelect()
    elif isinstance(widget, widgets.CheckboxInput):
      return self.renderCheckboxInput()
    elif isinstance(widget, widgets.Textarea):
      return self.renderTextArea()

    return self.NOT_SUPPORTED_MSG_FMT % (
        widget.__class__.__name__)

  def renderCheckboxInput(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(
        '%s%s%s%s%s' % (
        self.as_widget(attrs=attrs),
        self.field.label,
        self._render_is_required(),
        self._render_error(),
        self._render_note(),
        ))

  def renderTextArea(self):
    attrs = {
        'id': self.name,
        'class': 'textarea'
        }

    return mark_safe('%s%s%s%s' % (
        self._render_label(),
        self.as_widget(attrs=attrs),
        self._render_error(),
        self._render_note(),
    ))

  def renderTextInput(self):
    attrs = {
        'id': self.name,
        'class': 'text',
        }

    return mark_safe('%s%s%s%s' % (
        self._render_label(),
        self.as_widget(attrs=attrs),
        self._render_error(),
        self._render_note(),
    ))

  def renderSelect(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe('%s%s%s%s' % (
        self.as_widget(attrs=attrs),
        self._render_is_required(),
        self._render_error(),
        self._render_note(),
    ))

  def _render_label(self):
    return '%s%s' % (
        self.field.label,
        self._render_is_required(),
    )

  def _render_error(self):
    if not self.errors:
      return ''

    return '
%s
' % (
        self.errors[0])

  def _render_is_required(self):
    if not self.field.required:
      return ''

    return '*'

  def _render_note(self):
    return '%s' % (
        self.help_text)

  def div_class(self):
    name = self.name
    if self.errors:
      name += ' error'
    return name
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Adding model 'ServiceTicket'
        db.create_table(u'mama_cas_serviceticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['profile.UserProfile'])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('service', self.gf('django.db.models.fields.CharField')(max_length=255)),
            ('primary', self.gf('django.db.models.fields.BooleanField')(default=False)),
        ))
        db.send_create_signal(u'mama_cas', ['ServiceTicket'])

        # Adding model 'ProxyTicket'
        db.create_table(u'mama_cas_proxyticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['profile.UserProfile'])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('service', self.gf('django.db.models.fields.CharField')(max_length=255)),
            ('granted_by_pgt', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ProxyGrantingTicket'])),
        ))
        db.send_create_signal(u'mama_cas', ['ProxyTicket'])

        # Adding model 'ProxyGrantingTicket'
        db.create_table(u'mama_cas_proxygrantingticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['profile.UserProfile'])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('iou', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('granted_by_st', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ServiceTicket'], null=True, on_delete=models.PROTECT, blank=True)),
            ('granted_by_pt', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ProxyTicket'], null=True, on_delete=models.PROTECT, blank=True)),
        ))
        db.send_create_signal(u'mama_cas', ['ProxyGrantingTicket'])

    def backwards(self, orm):
        # Deleting model 'ServiceTicket'
        db.delete_table(u'mama_cas_serviceticket')

        # Deleting model 'ProxyTicket'
        db.delete_table(u'mama_cas_proxyticket')

        # Deleting model 'ProxyGrantingTicket'
        db.delete_table(u'mama_cas_proxygrantingticket')

    models = {
        u'mama_cas.proxygrantingticket': {
            'Meta': {'object_name': 'ProxyGrantingTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            'granted_by_pt': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ProxyTicket']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
            'granted_by_st': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ServiceTicket']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'iou': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['profile.UserProfile']"})
        },
        u'mama_cas.proxyticket': {
            'Meta': {'object_name': 'ProxyTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            'granted_by_pgt': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ProxyGrantingTicket']"}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'service': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['profile.UserProfile']"})
        },
        u'mama_cas.serviceticket': {
            'Meta': {'object_name': 'ServiceTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'primary': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
            'service': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['profile.UserProfile']"})
        },
        u'profile.userprofile': {
            'Meta': {'object_name': 'UserProfile'},
            'auth_backend': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'id_number': ('django.db.models.fields.CharField', [], {'max_length': '9', 'blank': 'True'}),
            'ip_phone': ('django.db.models.fields.CharField', [], {'max_length': '9', 'blank': 'True'}),
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'manager': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
        }
    }

    complete_apps = ['mama_cas']<commit_msg>Fix user foreign keys in South migrations<commit_after># -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

try:
    from django.contrib.auth import get_user_model
except ImportError:
    from django.contrib.auth.models import User
else:
    User = get_user_model()

user_app_object = '%s.%s' % (User._meta.app_label, User._meta.object_name)
user_app_module = u'%s.%s' % (User._meta.app_label, User._meta.module_name)

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Adding model 'ServiceTicket'
        db.create_table(u'mama_cas_serviceticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_app_object])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('service', self.gf('django.db.models.fields.CharField')(max_length=255)),
            ('primary', self.gf('django.db.models.fields.BooleanField')(default=False)),
        ))
        db.send_create_signal(u'mama_cas', ['ServiceTicket'])

        # Adding model 'ProxyTicket'
        db.create_table(u'mama_cas_proxyticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_app_object])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('service', self.gf('django.db.models.fields.CharField')(max_length=255)),
            ('granted_by_pgt', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ProxyGrantingTicket'])),
        ))
        db.send_create_signal(u'mama_cas', ['ProxyTicket'])

        # Adding model 'ProxyGrantingTicket'
        db.create_table(u'mama_cas_proxygrantingticket', (
            (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('ticket', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_app_object])),
            ('expires', self.gf('django.db.models.fields.DateTimeField')()),
            ('consumed', self.gf('django.db.models.fields.DateTimeField')(null=True)),
            ('iou', self.gf('django.db.models.fields.CharField')(unique=True, max_length=255)),
            ('granted_by_st', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ServiceTicket'], null=True, on_delete=models.PROTECT, blank=True)),
            ('granted_by_pt', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['mama_cas.ProxyTicket'], null=True, on_delete=models.PROTECT, blank=True)),
        ))
        db.send_create_signal(u'mama_cas', ['ProxyGrantingTicket'])

    def backwards(self, orm):
        # Deleting model 'ServiceTicket'
        db.delete_table(u'mama_cas_serviceticket')

        # Deleting model 'ProxyTicket'
        db.delete_table(u'mama_cas_proxyticket')

        # Deleting model 'ProxyGrantingTicket'
        db.delete_table(u'mama_cas_proxygrantingticket')

    models = {
        u'auth.group': {
            'Meta': {'object_name': 'Group'},
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
        },
        u'auth.permission': {
            'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
        },
        user_app_module: {
            'Meta': {'object_name': User.__name__, 'db_table': "'%s'" % User._meta.db_table},
            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
        },
        u'contenttypes.contenttype': {
            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
        },
        u'mama_cas.proxygrantingticket': {
            'Meta': {'object_name': 'ProxyGrantingTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            'granted_by_pt': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ProxyTicket']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
            'granted_by_st': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ServiceTicket']", 'null': 'True', 'on_delete': 'models.PROTECT', 'blank': 'True'}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'iou': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['%s']" % user_app_object})
        },
        u'mama_cas.proxyticket': {
            'Meta': {'object_name': 'ProxyTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            'granted_by_pgt': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['mama_cas.ProxyGrantingTicket']"}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'service': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['%s']" % user_app_object})
        },
        u'mama_cas.serviceticket': {
            'Meta': {'object_name': 'ServiceTicket'},
            'consumed': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
            'expires': ('django.db.models.fields.DateTimeField', [], {}),
            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'primary': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
            'service': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
            'ticket': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['%s']" % user_app_object})
        }
    }

    complete_apps = ['mama_cas']
<|endoftext|>


<commit_before>import random

from app.table import Table

PULMONIC = Table('app/data/pulmonic.csv')
VOWELS = Table('app/data/vowels.csv')

def in_words(search, word_list):
    '''Returns True if search string is in any of the words in word_list, else
    returns False.'''
    return any(search in word for word in word_list)

def rule(f):
    '''A decorator for all rule functions which checks to ensure rules are
    applicable to current inventory.'''
    def wrapper(*args, **kwargs):
        rules, representation = f(*args, **kwargs)

        # If the length of the rules list is 0, there are no applicable rules, so
        # return False.
        if len(rules) == 0:
            return False, None, None
        else:
            return True, rules, representation

    return wrapper

@rule
def sonorization(word_list):
    '''Implements the sonorization, or voicing, sound change, in which plosives are
    converted to their voiced equivalent.'''

    # List unvoiced plosives and their voiced equivalents
    candidates = ['p', 't', 'ʈ', 'c', 'k', 'q']
    targets = ['b', 'd', 'ɖ', 'ɟ', 'g', 'ɢ']

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules. Include only those rules which are relevant to the given
    # inventory.
    rules = [rule for rule in zip(
        candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['Sonorization', 'unvoiced plosive', 'voiced plosive',
                      environments[0]]

    return rules, representation

@rule
def degemination(word_list):
    '''Implements the degemination sound change, in which doubled plosives are
    converted to singular.'''

    candidates = []
    targets = []

    for phoneme in PULMONIC['plosive']:
        if phoneme != '':
            candidates.append(phoneme + phoneme)
            candidates.append(phoneme + phoneme + 'ʰ')
            targets.append(phoneme)
            targets.append(phoneme + 'ʰ')

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(
        candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['Degemination', 'geminated plosive', 'plosive',
                      environments[0]]

    return rules, representation

@rule
def spirantization(word_list):
    '''Implements the spirantization sound change, in which stops are converted
    to fricatives.'''

    candidates = PULMONIC['plosive']
    targets = PULMONIC['fricative']

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    random.shuffle(rules)

    representation = ['spirantization', 'plosive', 'fricative',
                      environments[0]]

    return rules, representation

@rule
def debuccalization(word_list):
    '''Implements the debuccalization sound change, in which fricatives are
    converted to the placeless approximant.'''

    candidates = PULMONIC['fricative']
    targets = ['h'] * len(candidates)

    available_environments = ['^_', '(V)_(V)', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['debuccalization', 'fricative', 'placeless approximant',
                      environments[0]]

    return rules, representation

@rule
def lateral_vocalization(word_list):
    '''Implements the lateral vocalization sound change, in which l is converted
    to a semivowel.'''

    candidates = []
    targets = []
    for phoneme in set(PULMONIC['lateralapproximant'] + ['ɫ']):
        if phoneme != '':
            for target in set(VOWELS['uback'] + VOWELS['rback'] + ['w', 'ɰ', 'j']):
                if target != '':
                    candidates.append(phoneme)
                    targets.append(target)

    available_environments = ['^_', '(V)_(V)', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list)]

    random.shuffle(rules)

    representation = ['vocalization', 'lateral approximant', 'semivowel/back vowel',
                      environments[0]]

    return rules, representation

@rule
def palatal_vocalization(word_list):
    '''Implements the palatal vocalization sound change, in which j is converted
    to front vowel i.'''

    available_environments = ['^_', '(V)_(V)', '_$']
    environment = random.choice(available_environments)

    representation = ['vocalization', 'palatal approximant', 'front vowel',
                      environment]

    rule = ('j', 'i', environment)
    return [rule], representation

@rule
def approximation(word_list):
    '''Implements the approximation sound change, in which continuants are
    converted to approximants.'''

    candidates = PULMONIC['fricative']
    targets = PULMONIC['approximant']

    available_environments = ['^_', '(V)_(V)', '_$']

    environment = random.choice(available_environments)

    rules = []
    for candidate, target in zip(candidates, targets):
        if candidate != '' and in_words(candidate, word_list):
            if target == '':
                rules.append((candidate, candidate + '\u031E', environment))
            else:
                rules.append((candidate, target, environment))

    representation = ['approximation', 'continuant', 'approximant',
                      environment]

    return rules, representation

@rule
def flapping(word_list):
    '''Implements the flapping sound change, in which t and d are
    converted to a tap.'''
    available_environments = ['^_', '(V)_(V)']

    environment = random.choice(available_environments)

    representation = ['flapping', '[t] and [d]', 'flap',
                      environment]

    rules = [('t', 'ɾ', environment), ('d', 'ɾ', environment)]

    return rules, representation

@rule
def affrication(word_list):
    '''Implements the affrication sound change, in which plosives are converted
    to affricates.'''

    candidates = PULMONIC['plosive'] + [p + 'ʰ' for p in PULMONIC['plosive']]
    targets = PULMONIC['nonsibilantaffricate'] + PULMONIC['nonsibilantaffricate']

    available_environments = ['(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    if in_words('t', word_list):
        rules.append(('t', 'ts', environments[0]))
    if in_words('tʰ', word_list):
        rules.append(('tʰ', 'ts', environments[0]))

    random.shuffle(rules)

    representation = ['affrication', 'plosive', 'affricate',
                      environments[0]]

    return rules, representation

@rule
def deaffrication(word_list):
    '''Implements the affrication sound change, in which plosives are converted
    to affricates.'''

    candidates = PULMONIC['nonsibilantaffricate']
    targets = PULMONIC['fricative']

    available_environments = ['(V)_(V)', '^_', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    if in_words('ts', word_list):
        rules.append(('ts', 's', environments[0]))

    random.shuffle(rules)

    representation = ['deaffrication', 'affricate', 'fricative',
                      environments[0]]

    return rules, representation

@rule
def approximant_elision(word_list):
    '''Implements elision of approximants, in which approximants are deleted.'''

    candidates = PULMONIC['approximant']
    targets = ['∅'] * len(candidates)

    available_environments = ['(V)_(V)', '^_', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '']

    if in_words('h', word_list):
        rules.append(('h', '∅', environments[0]))
    if in_words('ɦ', word_list):
        rules.append(('ɦ', '∅', environments[0]))

    representation = ['elision', 'approximant', 'nothing',
                      environments[0]]

    return rules, representation<commit_msg>Make elision actually work<commit_after>import random

from app.table import Table

PULMONIC = Table('app/data/pulmonic.csv')
VOWELS = Table('app/data/vowels.csv')

def in_words(search, word_list):
    '''Returns True if search string is in any of the words in word_list, else
    returns False.'''
    return any(search in word for word in word_list)

def rule(f):
    '''A decorator for all rule functions which checks to ensure rules are
    applicable to current inventory.'''
    def wrapper(*args, **kwargs):
        rules, representation = f(*args, **kwargs)

        # If the length of the rules list is 0, there are no applicable rules, so
        # return False.
        if len(rules) == 0:
            return False, None, None
        else:
            return True, rules, representation

    return wrapper

@rule
def sonorization(word_list):
    '''Implements the sonorization, or voicing, sound change, in which plosives are
    converted to their voiced equivalent.'''

    # List unvoiced plosives and their voiced equivalents
    candidates = ['p', 't', 'ʈ', 'c', 'k', 'q']
    targets = ['b', 'd', 'ɖ', 'ɟ', 'g', 'ɢ']

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules. Include only those rules which are relevant to the given
    # inventory.
    rules = [rule for rule in zip(
        candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['Sonorization', 'unvoiced plosive', 'voiced plosive',
                      environments[0]]

    return rules, representation

@rule
def degemination(word_list):
    '''Implements the degemination sound change, in which doubled plosives are
    converted to singular.'''

    candidates = []
    targets = []

    for phoneme in PULMONIC['plosive']:
        if phoneme != '':
            candidates.append(phoneme + phoneme)
            candidates.append(phoneme + phoneme + 'ʰ')
            targets.append(phoneme)
            targets.append(phoneme + 'ʰ')

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(
        candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['Degemination', 'geminated plosive', 'plosive',
                      environments[0]]

    return rules, representation

@rule
def spirantization(word_list):
    '''Implements the spirantization sound change, in which stops are converted
    to fricatives.'''

    candidates = PULMONIC['plosive']
    targets = PULMONIC['fricative']

    available_environments = ['^_', '(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    random.shuffle(rules)

    representation = ['spirantization', 'plosive', 'fricative',
                      environments[0]]

    return rules, representation

@rule
def debuccalization(word_list):
    '''Implements the debuccalization sound change, in which fricatives are
    converted to the placeless approximant.'''

    candidates = PULMONIC['fricative']
    targets = ['h'] * len(candidates)

    available_environments = ['^_', '(V)_(V)', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list)]

    representation = ['debuccalization', 'fricative', 'placeless approximant',
                      environments[0]]

    return rules, representation

@rule
def lateral_vocalization(word_list):
    '''Implements the lateral vocalization sound change, in which l is converted
    to a semivowel.'''

    candidates = []
    targets = []
    for phoneme in set(PULMONIC['lateralapproximant'] + ['ɫ']):
        if phoneme != '':
            for target in set(VOWELS['uback'] + VOWELS['rback'] + ['w', 'ɰ', 'j']):
                if target != '':
                    candidates.append(phoneme)
                    targets.append(target)

    available_environments = ['^_', '(V)_(V)', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list)]

    random.shuffle(rules)

    representation = ['vocalization', 'lateral approximant', 'semivowel/back vowel',
                      environments[0]]

    return rules, representation

@rule
def palatal_vocalization(word_list):
    '''Implements the palatal vocalization sound change, in which j is converted
    to front vowel i.'''

    available_environments = ['^_', '(V)_(V)', '_$']
    environment = random.choice(available_environments)

    representation = ['vocalization', 'palatal approximant', 'front vowel',
                      environment]

    rule = ('j', 'i', environment)
    return [rule], representation

@rule
def approximation(word_list):
    '''Implements the approximation sound change, in which continuants are
    converted to approximants.'''

    candidates = PULMONIC['fricative']
    targets = PULMONIC['approximant']

    available_environments = ['^_', '(V)_(V)', '_$']

    environment = random.choice(available_environments)

    rules = []
    for candidate, target in zip(candidates, targets):
        if candidate != '' and in_words(candidate, word_list):
            if target == '':
                rules.append((candidate, candidate + '\u031E', environment))
            else:
                rules.append((candidate, target, environment))

    representation = ['approximation', 'continuant', 'approximant',
                      environment]

    return rules, representation

@rule
def flapping(word_list):
    '''Implements the flapping sound change, in which t and d are
    converted to a tap.'''
    available_environments = ['^_', '(V)_(V)']

    environment = random.choice(available_environments)

    representation = ['flapping', '[t] and [d]', 'flap',
                      environment]

    rules = [('t', 'ɾ', environment), ('d', 'ɾ', environment)]

    return rules, representation

@rule
def affrication(word_list):
    '''Implements the affrication sound change, in which plosives are converted
    to affricates.'''

    candidates = PULMONIC['plosive'] + [p + 'ʰ' for p in PULMONIC['plosive']]
    targets = PULMONIC['nonsibilantaffricate'] + PULMONIC['nonsibilantaffricate']

    available_environments = ['(V)_(V)']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    if in_words('t', word_list):
        rules.append(('t', 'ts', environments[0]))
    if in_words('tʰ', word_list):
        rules.append(('tʰ', 'ts', environments[0]))

    random.shuffle(rules)

    representation = ['affrication', 'plosive', 'affricate',
                      environments[0]]

    return rules, representation

@rule
def deaffrication(word_list):
    '''Implements the affrication sound change, in which plosives are converted
    to affricates.'''

    candidates = PULMONIC['nonsibilantaffricate']
    targets = PULMONIC['fricative']

    available_environments = ['(V)_(V)', '^_', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '' and rule[1] != '']

    if in_words('ts', word_list):
        rules.append(('ts', 's', environments[0]))

    random.shuffle(rules)

    representation = ['deaffrication', 'affricate', 'fricative',
                      environments[0]]

    return rules, representation

@rule
def approximant_elision(word_list):
    '''Implements elision of approximants, in which approximants are deleted.'''

    candidates = PULMONIC['approximant']
    targets = [''] * len(candidates)

    available_environments = ['(V)_(V)', '^_', '_$']

    environments = [random.choice(available_environments)] * len(candidates)

    # Zip together the candidates, targets, and environments into a list of
    # rules.
    rules = [rule for rule in zip(candidates, targets, environments) if in_words(rule[0], word_list) and rule[0] != '']

    if in_words('h', word_list):
        rules.append(('h', '∅', environments[0]))
    if in_words('ɦ', word_list):
        rules.append(('ɦ', '∅', environments[0]))

    representation = ['elision', 'approximant', 'nothing',
                      environments[0]]

    return rules, representation<|endoftext|>


<commit_before>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Module containing the boiler plate required to construct templates
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

from google.appengine.ext.db import djangoforms

from django.forms import forms
from django.forms import widgets
from django.template import loader
from django.utils.safestring import mark_safe

class Form(object):
  """Form class that facilitates the rendering of forms.
  """

  def render(self):
    """Renders the template to a string.

    Uses the context method to retrieve the appropriate context, uses the
    self.templatePath() method to retrieve the template that should be used.
    """

    context = self.context()
    template_path = 'v2/modules/gsoc/_form.html'
    rendered = loader.render_to_string(template_path, dictionary=context)
    return rendered

  def context(self):
    """Returns the context for the current template.
    """

    return {}

class BoundField(forms.BoundField):
  """
  """

  def is_required(self):
    return self.field.required

  def render(self):
    attrs = {
        'id': self.name
        }

    widget = self.field.widget

    if isinstance(widget, widgets.TextInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.DateInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.Select):
      return self.renderSelect()
    elif isinstance(widget, widgets.CheckboxInput):
      return self.renderCheckboxInput()

    return self.as_widget(attrs=attrs)

  def renderCheckboxInput(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(
        '%s%s%s' % (
        self.as_widget(attrs=attrs),
        self.field.label,
        self._render_is_required()
        ))

  def renderTextInput(self):
    attrs = {
        'id': self.name,
        'class': 'text',
        }

    return mark_safe('%s%s' % (
        self._render_label(), self.as_widget(attrs=attrs)))

  def renderSelect(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(('%s%s%s') % (
        self.field.label,
        self._render_is_required(),
        self.as_widget(attrs=attrs)))

  def _render_label(self):
    return '%s%s' % (
        self.field.label,
        self._render_is_required())

  def _render_is_required(self):
    if self.field.required:
      return '*'
    else:
      return ''

class ModelForm(djangoforms.ModelForm):
  """
  """

  def __iter__(self):
    for name, field in self.fields.items():
      yield BoundField(self, field, name)
<commit_msg>getForm function added to view.forms.<commit_after>#!/usr/bin/env python2.5
#
# Copyright 2011 the Melange authors.
#
# 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.

"""Module containing the boiler plate required to construct templates
"""

__authors__ = [
  '"Daniel Hans" <daniel.m.hans@gmail.com>',
  '"Sverre Rabbelier" <sverre@rabbelier.nl>',
  ]

from google.appengine.ext.db import djangoforms

from django.forms import forms
from django.forms import widgets
from django.template import loader
from django.utils.safestring import mark_safe

class ModelForm(djangoforms.ModelForm):
  """
  """

  def __iter__(self):
    for name, field in self.fields.items():
      yield BoundField(self, field, name)

class Form(object):
  """Form class that facilitates the rendering of forms.
  """

  class Form(ModelForm):
    """Django Form associated with the class.
    """

    pass

  def render(self):
    """Renders the template to a string.

    Uses the context method to retrieve the appropriate context, uses the
    self.templatePath() method to retrieve the template that should be used.
    """

    context = self.context()
    template_path = 'v2/modules/gsoc/_form.html'
    rendered = loader.render_to_string(template_path, dictionary=context)
    return rendered

  def context(self):
    """Returns the context for the current template.
    """

    return {}

  def getForm(self):
    """Returns the Django form object associated with the class.
    The specialized forms should be defined in subclasses.
    """

    return self.Form()

class BoundField(forms.BoundField):
  """
  """

  def is_required(self):
    return self.field.required

  def render(self):
    attrs = {
        'id': self.name
        }

    widget = self.field.widget

    if isinstance(widget, widgets.TextInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.DateInput):
      return self.renderTextInput()
    elif isinstance(widget, widgets.Select):
      return self.renderSelect()
    elif isinstance(widget, widgets.CheckboxInput):
      return self.renderCheckboxInput()

    return self.as_widget(attrs=attrs)

  def renderCheckboxInput(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(
        '%s%s%s' % (
        self.as_widget(attrs=attrs),
        self.field.label,
        self._render_is_required()
        ))

  def renderTextInput(self):
    attrs = {
        'id': self.name,
        'class': 'text',
        }

    return mark_safe('%s%s' % (
        self._render_label(), self.as_widget(attrs=attrs)))

  def renderSelect(self):
    attrs = {
        'id': self.name,
        'style': 'opacity: 100;',
        }

    return mark_safe(('%s%s%s') % (
        self.field.label,
        self._render_is_required(),
        self.as_widget(attrs=attrs)))

  def _render_label(self):
    return '%s%s' % (
        self.field.label,
        self._render_is_required())

  def _render_is_required(self):
    if self.field.required:
      return '*'
    else:
      return ''
<|endoftext|>