<commit_before>import logging
from enum import Enum

from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.utils import timezone
from django.urls import reverse
from django.template.defaulttags import register

from emstrack.latlon import calculate_orientation, calculate_distance, stationary_radius
from emstrack.models import AddressModel, UpdatedByModel, defaults

logger = logging.getLogger(__name__)

# filters

@register.filter
def get_ambulance_status(key):
    return AmbulanceStatus[key].value

@register.filter
def get_ambulance_capability(key):
    return AmbulanceCapability[key].value

@register.filter
def get_location_type(key):
    return LocationType[key].value

@register.filter
def get_call_status(key):
    return CallStatus[key].value

@register.filter
def get_call_priority(key):
    return CallPriority[key].value

# Ambulance location models

# Ambulance model

class AmbulanceStatus(Enum):
    UK = 'Unknown'
    AV = 'Available'
    OS = 'Out of service'
    PB = 'Patient bound'
    AP = 'At patient'
    HB = 'Hospital bound'
    AH = 'At hospital'

class AmbulanceCapability(Enum):
    B = 'Basic'
    A = 'Advanced'
    R = 'Rescue'

class Ambulance(UpdatedByModel):

    # TODO: Should we consider denormalizing Ambulance to avoid duplication with AmbulanceUpdate?

    # ambulance properties
    identifier = models.CharField(max_length=50, unique=True)

    # TODO: Should we add an active flag?

    AMBULANCE_CAPABILITY_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCapability]
    capability = models.CharField(max_length=1,
                                  choices=AMBULANCE_CAPABILITY_CHOICES)

    # status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default=0.0)
    location = models.PointField(srid=4326, default=defaults['location'])

    # timestamp
    timestamp = models.DateTimeField(default=timezone.now)

    # location client
    location_client = models.ForeignKey('login.Client',
                                        on_delete=models.CASCADE,
                                        blank=True, null=True,
                                        related_name='location_client_set')

    # default value for _loaded_values
    _loaded_values = None

    @classmethod
    def from_db(cls, db, field_names, values):

        # call super
        instance = super(Ambulance, cls).from_db(db, field_names, values)

        # store the original field values on the instance
        instance._loaded_values = dict(zip(field_names, values))

        # return instance
        return instance

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

        # creation?
        created = self.pk is None

        # loaded_values?
        loaded_values = self._loaded_values is not None

        # has location changed?
        has_moved = False
        if (not loaded_values) or \
                calculate_distance(self._loaded_values['location'], self.location) > stationary_radius:
            has_moved = True

        # calculate orientation only if location has changed and orientation has not changed
        if has_moved and loaded_values and self._loaded_values['orientation'] == self.orientation:
            # TODO: should we allow for a small radius before updating direction?
            self.orientation = calculate_orientation(self._loaded_values['location'], self.location)
            logger.debug('< {} - {} = {}'.format(self._loaded_values['location'],
                                                 self.location,
                                                 self.orientation))

        logger.debug('loaded_values: {}'.format(loaded_values))
        logger.debug('_loaded_values: {}'.format(self._loaded_values))
        logger.debug('self.location_client: {}'.format(self.location_client))

        # location_client changed?
        if self.location_client is None:
            location_client_id = None
        else:
            location_client_id = self.location_client.id
        location_client_changed = False
        if loaded_values and location_client_id != self._loaded_values['location_client_id']:
            location_client_changed = True

        logger.debug('location_client_changed: {}'.format(location_client_changed))
        # TODO: Check if client is logged with ambulance if setting location_client

        # if comment, status or location changed
        model_changed = False
        if has_moved or \
                self._loaded_values['status'] != self.status or \
                self._loaded_values['comment'] != self.comment:

            # save to Ambulance
            super().save(*args, **kwargs)

            logger.debug('SAVED')

            # save to AmbulanceUpdate
            data = {k: getattr(self, k)
                    for k in ('status', 'orientation',
                              'location', 'timestamp',
                              'comment', 'updated_by', 'updated_on')}
            data['ambulance'] = self
            obj = AmbulanceUpdate(**data)
            obj.save()

            logger.debug('UPDATE SAVED')

            # model changed
            model_changed = True

        # if identifier or capability changed
        # NOTE: self._loaded_values is NEVER None because has_moved is True
        elif (location_client_changed or
              self._loaded_values['identifier'] != self.identifier or
              self._loaded_values['capability'] != self.capability):

            # save only to Ambulance
            super().save(*args, **kwargs)

            logger.debug('SAVED')

            # model changed
            model_changed = True

        # Did the model change?
        if model_changed:

            # publish to mqtt
            from mqtt.publish import SingletonPublishClient
            SingletonPublishClient().publish_ambulance(self)

            logger.debug('PUBLISHED ON MQTT')

        # just created?
        if created:
            # invalidate permissions cache
            from login.permissions import cache_clear
            cache_clear()

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

        # remove from mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_ambulance(self)

        # invalidate permissions cache
        from login.permissions import cache_clear
        cache_clear()

        # delete from Ambulance
        super().delete(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('ambulance:detail', kwargs={'pk': self.id})

    def __str__(self):
        return ('Ambulance {}(id={}) ({}) [{}]:\n' +
                '    Status: {}\n' +
                '  Location: {} @ {}\n' +
                ' LocClient: {}\n' +
                '   Updated: {} by {}').format(self.identifier,
                                               self.id,
                                               AmbulanceCapability[self.capability].value,
                                               self.comment,
                                               AmbulanceStatus[self.status].value,
                                               self.location,
                                               self.timestamp,
                                               self.location_client,
                                               self.updated_by,
                                               self.updated_on)

# Call related models

class CallPriority(Enum):
    A = 'Resucitation'
    B = 'Emergent'
    C = 'Urgent'
    D = 'Less urgent'
    E = 'Not urgent'
    O = 'Omega'

class CallStatus(Enum):
    P = 'Pending'
    S = 'Started'
    E = 'Ended'

class CallPublishMixin:

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('remove', False)

        # save to Call
        super().save(*args, **kwargs)

        if publish:
            self.publish()

        if remove:
            self.remove()

class Call(CallPublishMixin,
           AddressModel,
           UpdatedByModel):

    # status
    CALL_STATUS_CHOICES = \
        [(m.name, m.value) for m in CallStatus]
    status = models.CharField(max_length=1,
                              choices=CALL_STATUS_CHOICES,
                              default=CallStatus.P.name)

    # details
    details = models.CharField(max_length=500, default="")

    # call priority
    CALL_PRIORITY_CHOICES = \
        [(m.name, m.value) for m in CallPriority]
    priority = models.CharField(max_length=1,
                                choices=CALL_PRIORITY_CHOICES,
                                default=CallPriority.E.name)

    # timestamps
    pending_at = models.DateTimeField(null=True, blank=True)
    started_at = models.DateTimeField(null=True, blank=True)
    ended_at = models.DateTimeField(null=True, blank=True)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('remove', False)

        if self.status == CallStatus.E.name:

            # timestamp
            self.ended_at = timezone.now()

            # remove topic from mqtt server
            remove = True

            # prevent publication
            publish = False

        elif self.status == CallStatus.S.name:

            # timestamp
            self.started_at = timezone.now()

        elif self.status == CallStatus.P.name:

            # timestamp
            self.pending_at = timezone.now()

        # call super
        super().save(*args, **kwargs,
                     publish=publish,
                     remove=remove)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call(self)

    def remove(self):

        # remove topic from mqtt server
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_call(self)

    def abort(self):

        # simply return if already ended
        if self.status == CallStatus.E.name:
            return

        # retrieve all ongoing ambulances
        ongoing_ambulancecalls = self.ambulancecall_set.exclude(status=AmbulanceCallStatus.C.name)

        if ongoing_ambulancecalls:
            # if  ambulancecalls, set ambulancecall to complete until all done

            for ambulancecall in ongoing_ambulancecalls:

                # change call status to finished
                ambulancecall.status = AmbulanceCallStatus.C.name
                ambulancecall.save()

        else:
            # if no ambulancecalls, force abort

            # change call status to finished
            self.status = CallStatus.E.name
            self.save()

    def __str__(self):
        return "{} ({})".format(self.location, self.priority)

class AmbulanceCallStatus(Enum):
    R = 'Requested'
    O = 'Ongoing'
    D = 'Declined'
    S = 'Suspended'
    C = 'Completed'

class AmbulanceCall(CallPublishMixin,
                    models.Model):

    # status
    AMBULANCE_CALL_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCallStatus]
    status = models.CharField(max_length=1,
                              choices=AMBULANCE_CALL_STATUS_CHOICES,
                              default=AmbulanceCallStatus.R.name)

    # call
    call = models.ForeignKey(Call,
                             on_delete=models.CASCADE)

    # ambulance
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('publish', False)

        # changed to ongoing?
        if self.status == AmbulanceCallStatus.O.name:

            # retrieve call
            call = self.call

            if call.status != CallStatus.S.name:

                # change call status to started
                call.status = CallStatus.S.name
                call.save()

        # changed to complete?
        elif self.status == AmbulanceCallStatus.C.name:

            # retrieve call
            call = self.call

            # retrieve all ongoing ambulances
            ongoing_ambulancecalls = call.ambulancecall_set.exclude(status=AmbulanceCallStatus.C.name)

            set_size = len(ongoing_ambulancecalls)
            if (set_size == 0 or
                    (set_size == 1 and ongoing_ambulancecalls[0].ambulance is not self)):

                logger.debug('This is the last ambulance; will end call.')

                # change call status to finished
                call.status = CallStatus.E.name
                call.save()

            else:

                logger.debug('There are still {} ambulances in this call.'.format(set_size))
                logger.debug(ongoing_ambulancecalls)

            # prevent publication
            publish = False

            # remove from mqtt
            # remove = True

        # changed to declined?
        elif self.status == AmbulanceCallStatus.D.name:

            logger.debug('Ambulance call declined.')

        # changed to suspended?
        elif self.status == AmbulanceCallStatus.S.name:

            logger.debug('Ambulance call suspended.')

        # call super
        super().save(*args, **kwargs,
                     publish=publish,
                     remove=remove)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call_status(self)

    def remove(self):

        # remove from mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_call_status(self)

    class Meta:
        unique_together = ('call', 'ambulance')

class AmbulanceUpdate(models.Model):

    # ambulance
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # ambulance call
    # TODO: Is it possible to enforce that ambulance_call.ambulance == ambulance?
    ambulance_call = models.ForeignKey(AmbulanceCall,
                                       on_delete=models.SET_NULL,
                                       null=True)

    # ambulance status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default=0.0)
    location = models.PointField(srid=4326, default=defaults['location'])

    # timestamp, indexed
    timestamp = models.DateTimeField(db_index=True, default=timezone.now)

    # comment
    comment = models.CharField(max_length=254, null=True, blank=True)

    # updated by
    updated_by = models.ForeignKey(User,
                                   on_delete=models.CASCADE)
    updated_on = models.DateTimeField(default=timezone.now)

    class Meta:
        indexes = [
            models.Index(
                fields=['ambulance', 'timestamp'],
                name='ambulance_timestamp_idx',
            ),
        ]

# Patient might be expanded in the future

class Patient(CallPublishMixin,
              models.Model):
    """
    A model that provides patient fields.
    """

    call = models.ForeignKey(Call,
                             on_delete=models.CASCADE)

    name = models.CharField(max_length=254, default="")
    age = models.IntegerField(null=True)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call(self.call)

# Location related models

# noinspection PyPep8
class LocationType(Enum):
    b = 'Base'
    a = 'AED'
    o = 'Other'

class Location(AddressModel, UpdatedByModel):
    # location name
    name = models.CharField(max_length=254, unique=True)

    # location type
    LOCATION_TYPE_CHOICES = \
        [(m.name, m.value) for m in LocationType]
    type = models.CharField(max_length=1,
                            choices=LOCATION_TYPE_CHOICES,
                            default=LocationType.o.name)

    # location
    location = models.PointField(srid=4326, null=True)

    def get_absolute_url(self):
        return reverse('ambulance:location_detail', kwargs={'pk': self.id})

    def __str__(self):
        return "{} @{} ({})".format(self.name, self.location, self.comment)

# THOSE NEED REVIEWING

class Region(models.Model):
    name = models.CharField(max_length=254, unique=True)
    center = models.PointField(srid=4326, null=True)

    def __str__(self):
        return self.name
<commit_msg>Making sure call and ambulance_call gets to publish end and complete statuses.<commit_after>import logging
from enum import Enum

from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.utils import timezone
from django.urls import reverse
from django.template.defaulttags import register

from emstrack.latlon import calculate_orientation, calculate_distance, stationary_radius
from emstrack.models import AddressModel, UpdatedByModel, defaults

logger = logging.getLogger(__name__)

# filters

@register.filter
def get_ambulance_status(key):
    return AmbulanceStatus[key].value

@register.filter
def get_ambulance_capability(key):
    return AmbulanceCapability[key].value

@register.filter
def get_location_type(key):
    return LocationType[key].value

@register.filter
def get_call_status(key):
    return CallStatus[key].value

@register.filter
def get_call_priority(key):
    return CallPriority[key].value

# Ambulance location models

# Ambulance model

class AmbulanceStatus(Enum):
    UK = 'Unknown'
    AV = 'Available'
    OS = 'Out of service'
    PB = 'Patient bound'
    AP = 'At patient'
    HB = 'Hospital bound'
    AH = 'At hospital'

class AmbulanceCapability(Enum):
    B = 'Basic'
    A = 'Advanced'
    R = 'Rescue'

class Ambulance(UpdatedByModel):

    # TODO: Should we consider denormalizing Ambulance to avoid duplication with AmbulanceUpdate?

    # ambulance properties
    identifier = models.CharField(max_length=50, unique=True)

    # TODO: Should we add an active flag?

    AMBULANCE_CAPABILITY_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCapability]
    capability = models.CharField(max_length=1,
                                  choices=AMBULANCE_CAPABILITY_CHOICES)

    # status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default=0.0)
    location = models.PointField(srid=4326, default=defaults['location'])

    # timestamp
    timestamp = models.DateTimeField(default=timezone.now)

    # location client
    location_client = models.ForeignKey('login.Client',
                                        on_delete=models.CASCADE,
                                        blank=True, null=True,
                                        related_name='location_client_set')

    # default value for _loaded_values
    _loaded_values = None

    @classmethod
    def from_db(cls, db, field_names, values):

        # call super
        instance = super(Ambulance, cls).from_db(db, field_names, values)

        # store the original field values on the instance
        instance._loaded_values = dict(zip(field_names, values))

        # return instance
        return instance

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

        # creation?
        created = self.pk is None

        # loaded_values?
        loaded_values = self._loaded_values is not None

        # has location changed?
        has_moved = False
        if (not loaded_values) or \
                calculate_distance(self._loaded_values['location'], self.location) > stationary_radius:
            has_moved = True

        # calculate orientation only if location has changed and orientation has not changed
        if has_moved and loaded_values and self._loaded_values['orientation'] == self.orientation:
            # TODO: should we allow for a small radius before updating direction?
            self.orientation = calculate_orientation(self._loaded_values['location'], self.location)
            logger.debug('< {} - {} = {}'.format(self._loaded_values['location'],
                                                 self.location,
                                                 self.orientation))

        logger.debug('loaded_values: {}'.format(loaded_values))
        logger.debug('_loaded_values: {}'.format(self._loaded_values))
        logger.debug('self.location_client: {}'.format(self.location_client))

        # location_client changed?
        if self.location_client is None:
            location_client_id = None
        else:
            location_client_id = self.location_client.id
        location_client_changed = False
        if loaded_values and location_client_id != self._loaded_values['location_client_id']:
            location_client_changed = True

        logger.debug('location_client_changed: {}'.format(location_client_changed))
        # TODO: Check if client is logged with ambulance if setting location_client

        # if comment, status or location changed
        model_changed = False
        if has_moved or \
                self._loaded_values['status'] != self.status or \
                self._loaded_values['comment'] != self.comment:

            # save to Ambulance
            super().save(*args, **kwargs)

            logger.debug('SAVED')

            # save to AmbulanceUpdate
            data = {k: getattr(self, k)
                    for k in ('status', 'orientation',
                              'location', 'timestamp',
                              'comment', 'updated_by', 'updated_on')}
            data['ambulance'] = self
            obj = AmbulanceUpdate(**data)
            obj.save()

            logger.debug('UPDATE SAVED')

            # model changed
            model_changed = True

        # if identifier or capability changed
        # NOTE: self._loaded_values is NEVER None because has_moved is True
        elif (location_client_changed or
              self._loaded_values['identifier'] != self.identifier or
              self._loaded_values['capability'] != self.capability):

            # save only to Ambulance
            super().save(*args, **kwargs)

            logger.debug('SAVED')

            # model changed
            model_changed = True

        # Did the model change?
        if model_changed:

            # publish to mqtt
            from mqtt.publish import SingletonPublishClient
            SingletonPublishClient().publish_ambulance(self)

            logger.debug('PUBLISHED ON MQTT')

        # just created?
        if created:
            # invalidate permissions cache
            from login.permissions import cache_clear
            cache_clear()

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

        # remove from mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_ambulance(self)

        # invalidate permissions cache
        from login.permissions import cache_clear
        cache_clear()

        # delete from Ambulance
        super().delete(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('ambulance:detail', kwargs={'pk': self.id})

    def __str__(self):
        return ('Ambulance {}(id={}) ({}) [{}]:\n' +
                '    Status: {}\n' +
                '  Location: {} @ {}\n' +
                ' LocClient: {}\n' +
                '   Updated: {} by {}').format(self.identifier,
                                               self.id,
                                               AmbulanceCapability[self.capability].value,
                                               self.comment,
                                               AmbulanceStatus[self.status].value,
                                               self.location,
                                               self.timestamp,
                                               self.location_client,
                                               self.updated_by,
                                               self.updated_on)

# Call related models

class CallPriority(Enum):
    A = 'Resucitation'
    B = 'Emergent'
    C = 'Urgent'
    D = 'Less urgent'
    E = 'Not urgent'
    O = 'Omega'

class CallStatus(Enum):
    P = 'Pending'
    S = 'Started'
    E = 'Ended'

class CallPublishMixin:

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('remove', False)

        # save to Call
        super().save(*args, **kwargs)

        if publish:
            self.publish()

        if remove:
            self.remove()

class Call(CallPublishMixin,
           AddressModel,
           UpdatedByModel):

    # status
    CALL_STATUS_CHOICES = \
        [(m.name, m.value) for m in CallStatus]
    status = models.CharField(max_length=1,
                              choices=CALL_STATUS_CHOICES,
                              default=CallStatus.P.name)

    # details
    details = models.CharField(max_length=500, default="")

    # call priority
    CALL_PRIORITY_CHOICES = \
        [(m.name, m.value) for m in CallPriority]
    priority = models.CharField(max_length=1,
                                choices=CALL_PRIORITY_CHOICES,
                                default=CallPriority.E.name)

    # timestamps
    pending_at = models.DateTimeField(null=True, blank=True)
    started_at = models.DateTimeField(null=True, blank=True)
    ended_at = models.DateTimeField(null=True, blank=True)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('remove', False)

        if self.status == CallStatus.E.name:

            # timestamp
            self.ended_at = timezone.now()

            # remove topic from mqtt server
            remove = True

            # prevent publication
            # publish = False

        elif self.status == CallStatus.S.name:

            # timestamp
            self.started_at = timezone.now()

        elif self.status == CallStatus.P.name:

            # timestamp
            self.pending_at = timezone.now()

        # call super
        super().save(*args, **kwargs,
                     publish=publish,
                     remove=remove)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call(self)

    def remove(self):

        # remove topic from mqtt server
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_call(self)

    def abort(self):

        # simply return if already ended
        if self.status == CallStatus.E.name:
            return

        # retrieve all ongoing ambulances
        ongoing_ambulancecalls = self.ambulancecall_set.exclude(status=AmbulanceCallStatus.C.name)

        if ongoing_ambulancecalls:
            # if  ambulancecalls, set ambulancecall to complete until all done

            for ambulancecall in ongoing_ambulancecalls:

                # change call status to finished
                ambulancecall.status = AmbulanceCallStatus.C.name
                ambulancecall.save()

        else:
            # if no ambulancecalls, force abort

            # change call status to finished
            self.status = CallStatus.E.name
            self.save()

    def __str__(self):
        return "{} ({})".format(self.location, self.priority)

class AmbulanceCallStatus(Enum):
    R = 'Requested'
    O = 'Ongoing'
    D = 'Declined'
    S = 'Suspended'
    C = 'Completed'

class AmbulanceCall(CallPublishMixin,
                    models.Model):

    # status
    AMBULANCE_CALL_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceCallStatus]
    status = models.CharField(max_length=1,
                              choices=AMBULANCE_CALL_STATUS_CHOICES,
                              default=AmbulanceCallStatus.R.name)

    # call
    call = models.ForeignKey(Call,
                             on_delete=models.CASCADE)

    # ambulance
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # created at
    created_at = models.DateTimeField(auto_now_add=True)

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

        # publish?
        publish = kwargs.pop('publish', True)

        # remove?
        remove = kwargs.pop('publish', False)

        # changed to ongoing?
        if self.status == AmbulanceCallStatus.O.name:

            # retrieve call
            call = self.call

            if call.status != CallStatus.S.name:

                # change call status to started
                call.status = CallStatus.S.name
                call.save()

        # changed to complete?
        elif self.status == AmbulanceCallStatus.C.name:

            # retrieve call
            call = self.call

            # retrieve all ongoing ambulances
            ongoing_ambulancecalls = call.ambulancecall_set.exclude(status=AmbulanceCallStatus.C.name)

            set_size = len(ongoing_ambulancecalls)
            if (set_size == 0 or
                    (set_size == 1 and ongoing_ambulancecalls[0].ambulance is not self)):

                logger.debug('This is the last ambulance; will end call.')

                # change call status to finished
                call.status = CallStatus.E.name
                call.save()

            else:

                logger.debug('There are still {} ambulances in this call.'.format(set_size))
                logger.debug(ongoing_ambulancecalls)

            # prevent publication
            publish = False

            # remove from mqtt
            # remove = True

        # changed to declined?
        elif self.status == AmbulanceCallStatus.D.name:

            logger.debug('Ambulance call declined.')

        # changed to suspended?
        elif self.status == AmbulanceCallStatus.S.name:

            logger.debug('Ambulance call suspended.')

        # call super
        super().save(*args, **kwargs,
                     publish=publish,
                     remove=remove)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call_status(self)

    def remove(self):

        # remove from mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().remove_call_status(self)

    class Meta:
        unique_together = ('call', 'ambulance')

class AmbulanceUpdate(models.Model):

    # ambulance
    ambulance = models.ForeignKey(Ambulance,
                                  on_delete=models.CASCADE)

    # ambulance call
    # TODO: Is it possible to enforce that ambulance_call.ambulance == ambulance?
    ambulance_call = models.ForeignKey(AmbulanceCall,
                                       on_delete=models.SET_NULL,
                                       null=True)

    # ambulance status
    AMBULANCE_STATUS_CHOICES = \
        [(m.name, m.value) for m in AmbulanceStatus]
    status = models.CharField(max_length=2,
                              choices=AMBULANCE_STATUS_CHOICES,
                              default=AmbulanceStatus.UK.name)

    # location
    orientation = models.FloatField(default=0.0)
    location = models.PointField(srid=4326, default=defaults['location'])

    # timestamp, indexed
    timestamp = models.DateTimeField(db_index=True, default=timezone.now)

    # comment
    comment = models.CharField(max_length=254, null=True, blank=True)

    # updated by
    updated_by = models.ForeignKey(User,
                                   on_delete=models.CASCADE)
    updated_on = models.DateTimeField(default=timezone.now)

    class Meta:
        indexes = [
            models.Index(
                fields=['ambulance', 'timestamp'],
                name='ambulance_timestamp_idx',
            ),
        ]

# Patient might be expanded in the future

class Patient(CallPublishMixin,
              models.Model):
    """
    A model that provides patient fields.
    """

    call = models.ForeignKey(Call,
                             on_delete=models.CASCADE)

    name = models.CharField(max_length=254, default="")
    age = models.IntegerField(null=True)

    def publish(self):

        # publish to mqtt
        from mqtt.publish import SingletonPublishClient
        SingletonPublishClient().publish_call(self.call)

# Location related models

# noinspection PyPep8
class LocationType(Enum):
    b = 'Base'
    a = 'AED'
    o = 'Other'

class Location(AddressModel, UpdatedByModel):
    # location name
    name = models.CharField(max_length=254, unique=True)

    # location type
    LOCATION_TYPE_CHOICES = \
        [(m.name, m.value) for m in LocationType]
    type = models.CharField(max_length=1,
                            choices=LOCATION_TYPE_CHOICES,
                            default=LocationType.o.name)

    # location
    location = models.PointField(srid=4326, null=True)

    def get_absolute_url(self):
        return reverse('ambulance:location_detail', kwargs={'pk': self.id})

    def __str__(self):
        return "{} @{} ({})".format(self.name, self.location, self.comment)

# THOSE NEED REVIEWING

class Region(models.Model):
    name = models.CharField(max_length=254, unique=True)
    center = models.PointField(srid=4326, null=True)

    def __str__(self):
        return self.name
<|endoftext|>


<commit_before>import logging
import shutil
import os

from zerver.data_import.import_util import (
    build_attachment,
    create_converted_data_files,
)

from typing import Any, Dict, List, Optional

class AttachmentHandler:
    def __init__(self) -> None:
        self.info_dict = dict()  # type: Dict[str, Dict[str, Any]]

    def handle_message_data(self,
                            realm_id: int,
                            message_id: int,
                            sender_id: int,
                            attachment: Dict[str, Any],
                            files_dir: str) -> Optional[str]:
        if not attachment:
            return None

        size = attachment['size']
        path = attachment['path']
        name = attachment['name']

        local_fn = os.path.join(files_dir, path)

        target_path = os.path.join(
            str(realm_id),
            'HipChatImportAttachment',
            path
        )

        if target_path in self.info_dict:
            logging.info("file used multiple times: " + path)
            info = self.info_dict[target_path]
            info['message_ids'].add(message_id)
            return info['content']

        # HipChat provides size info, but it's not
        # completely trustworthy, so we we just
        # ask the OS for file details.
        size = os.path.getsize(local_fn)
        mtime = os.path.getmtime(local_fn)

        content = '[{name}](/user_uploads/{path})'.format(
            name=name,
            path=target_path,
        )

        info = dict(
            message_ids={message_id},
            sender_id=sender_id,
            local_fn=local_fn,
            target_path=target_path,
            name=name,
            size=size,
            mtime=mtime,
            content=content,
        )
        self.info_dict[target_path] = info

        return content

    def write_info(self, output_dir: str, realm_id: int) -> None:
        attachments = []  # type: List[Dict[str, Any]]
        uploads_records = []  # type: List[Dict[str, Any]]

        def add_attachment(info: Dict[str, Any]) -> None:
            build_attachment(
                realm_id=realm_id,
                message_ids=info['message_ids'],
                user_id=info['sender_id'],
                fileinfo=dict(
                    created=info['mtime'],  # minor lie
                    size=info['size'],
                    name=info['name'],
                ),
                s3_path=info['target_path'],
                zerver_attachment=attachments,
            )

        def add_upload(info: Dict[str, Any]) -> None:
            target_path = info['target_path']
            upload_rec = dict(
                size=info['size'],
                user_profile_id=info['sender_id'],
                realm_id=realm_id,
                s3_path=target_path,
                path=target_path,
                content_type=None,
            )
            uploads_records.append(upload_rec)

        def make_full_target_path(info: Dict[str, Any]) -> str:
            target_path = info['target_path']
            full_target_path = os.path.join(
                output_dir,
                'uploads',
                target_path,
            )
            full_target_path = os.path.abspath(full_target_path)
            os.makedirs(os.path.dirname(full_target_path), exist_ok=True)
            return full_target_path

        def copy_file(info: Dict[str, Any]) -> None:
            source_path = info['local_fn']
            target_path = make_full_target_path(info)
            shutil.copyfile(source_path, target_path)

        logging.info('Start processing attachment files')

        for info in self.info_dict.values():
            add_attachment(info)
            add_upload(info)
            copy_file(info)

        uploads_folder = os.path.join(output_dir, 'uploads')
        os.makedirs(os.path.join(uploads_folder, str(realm_id)), exist_ok=True)

        attachment = dict(
            zerver_attachment=attachments
        )

        create_converted_data_files(uploads_records, output_dir, '/uploads/records.json')
        create_converted_data_files(attachment, output_dir, '/attachment.json')

        logging.info('Done processing attachment files')
<commit_msg>hipchat: Skip attachments without paths.<commit_after>import logging
import shutil
import os

from zerver.data_import.import_util import (
    build_attachment,
    create_converted_data_files,
)

from typing import Any, Dict, List, Optional

class AttachmentHandler:
    def __init__(self) -> None:
        self.info_dict = dict()  # type: Dict[str, Dict[str, Any]]

    def handle_message_data(self,
                            realm_id: int,
                            message_id: int,
                            sender_id: int,
                            attachment: Dict[str, Any],
                            files_dir: str) -> Optional[str]:
        if not attachment:
            return None

        name = attachment['name']

        if 'path' not in attachment:
            logging.info('Skipping HipChat attachment with missing path data: ' + name)
            return None

        size = attachment['size']
        path = attachment['path']

        local_fn = os.path.join(files_dir, path)

        target_path = os.path.join(
            str(realm_id),
            'HipChatImportAttachment',
            path
        )

        if target_path in self.info_dict:
            logging.info("file used multiple times: " + path)
            info = self.info_dict[target_path]
            info['message_ids'].add(message_id)
            return info['content']

        # HipChat provides size info, but it's not
        # completely trustworthy, so we we just
        # ask the OS for file details.
        size = os.path.getsize(local_fn)
        mtime = os.path.getmtime(local_fn)

        content = '[{name}](/user_uploads/{path})'.format(
            name=name,
            path=target_path,
        )

        info = dict(
            message_ids={message_id},
            sender_id=sender_id,
            local_fn=local_fn,
            target_path=target_path,
            name=name,
            size=size,
            mtime=mtime,
            content=content,
        )
        self.info_dict[target_path] = info

        return content

    def write_info(self, output_dir: str, realm_id: int) -> None:
        attachments = []  # type: List[Dict[str, Any]]
        uploads_records = []  # type: List[Dict[str, Any]]

        def add_attachment(info: Dict[str, Any]) -> None:
            build_attachment(
                realm_id=realm_id,
                message_ids=info['message_ids'],
                user_id=info['sender_id'],
                fileinfo=dict(
                    created=info['mtime'],  # minor lie
                    size=info['size'],
                    name=info['name'],
                ),
                s3_path=info['target_path'],
                zerver_attachment=attachments,
            )

        def add_upload(info: Dict[str, Any]) -> None:
            target_path = info['target_path']
            upload_rec = dict(
                size=info['size'],
                user_profile_id=info['sender_id'],
                realm_id=realm_id,
                s3_path=target_path,
                path=target_path,
                content_type=None,
            )
            uploads_records.append(upload_rec)

        def make_full_target_path(info: Dict[str, Any]) -> str:
            target_path = info['target_path']
            full_target_path = os.path.join(
                output_dir,
                'uploads',
                target_path,
            )
            full_target_path = os.path.abspath(full_target_path)
            os.makedirs(os.path.dirname(full_target_path), exist_ok=True)
            return full_target_path

        def copy_file(info: Dict[str, Any]) -> None:
            source_path = info['local_fn']
            target_path = make_full_target_path(info)
            shutil.copyfile(source_path, target_path)

        logging.info('Start processing attachment files')

        for info in self.info_dict.values():
            add_attachment(info)
            add_upload(info)
            copy_file(info)

        uploads_folder = os.path.join(output_dir, 'uploads')
        os.makedirs(os.path.join(uploads_folder, str(realm_id)), exist_ok=True)

        attachment = dict(
            zerver_attachment=attachments
        )

        create_converted_data_files(uploads_records, output_dir, '/uploads/records.json')
        create_converted_data_files(attachment, output_dir, '/attachment.json')

        logging.info('Done processing attachment files')
<|endoftext|>


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

import daemon
import fcntl
import getopt
import logging
import os
import random
import string
import sys
import traceback

from ConfigParser import ConfigParser
from flask import Flask, jsonify, request

# from roush import backends
from roush.db import models
from roush.db.api import api_from_models
from roush.webapp.ast import FilterBuilder, FilterTokenizer

from roush.webapp.adventures import bp as adventures_bp
from roush.webapp.facts import bp as facts_bp
from roush.webapp.facts_please import bp as facts_please
from roush.webapp.attrs import bp as attrs_bp
from roush.webapp.filters import bp as filters_bp
from roush.webapp.index import bp as index_bp
from roush.webapp.nodes import bp as nodes_bp
# from roush.webapp.nodes_please import bp as nodes_please
from roush.webapp.primitives import bp as primitives_bp
from roush.webapp.tasks import bp as tasks_bp
from roush.webapp.plan import bp as plan_bp

# api = api_from_models()

# Stolen: http://code.activestate.com/recipes/\
#         577911-context-manager-for-a-daemon-pid-file/
class PidFile(object):
    def __init__(self, path):
        self.path = path
        self.pidfile = None

    def __enter__(self):
        self.pidfile = open(self.path, 'a+')
        try:
            fcntl.flock(self.pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError:
            raise SystemExit('Pid file in use')

        self.pidfile.seek(0)
        self.pidfile.truncate()
        self.pidfile.write(str(os.getpid()))
        self.pidfile.flush()
        self.pidfile.seek(0)
        return self.pidfile

    def __exit__(self, exc_type=None, exc_value=None, exc_tb=None):
        try:
            self.pidfile.close()
        except IOError as err:
            if err.errno != 9:
                raise
        os.remove(self.path)

class Thing(Flask):
    def __init__(self, name, argv=None, configfile=None,
                 confighash=None, debug=False):
        daemonize = False
        self.registered_models = []
        # Define a global transaction_id
        self.trans = {
            'session_key': "".join([random.choice(string.hexdigits)
                                   for n in xrange(30)]),
            'latest': 0,
            'lowest': 0,
            'updates': {'nodes': []}}

        super(Thing, self).__init__(name)

        if argv:
            try:
                opts, args = getopt.getopt(argv, 'c:vd',
                                           ['config=', 'verbose', 'daemonize'])
            except getopt.GetoptError as err:
                print str(err)
                self.usage()
                sys.exit(1)

            for o, a in opts:
                if o in ('-c', '--config'):
                    configfile = a
                elif o in ('-v', '--verbose'):
                    debug = True
                elif o in ('-d', '--daemonize'):
                    daemonize = True
                else:
                    print "Bad option"
                    self.usage()
                    sys.exit(1)

            sys.argv = [sys.argv[0]] + args

        defaults = {
            'logging': {},
            'main': {
                'bind_address': '0.0.0.0',
                'bind_port': 8080,
                'backend': '/dev/null',
                'loglevel': 'WARNING',
                'database_uri': 'sqlite:///',
                'daemonize': False,
                'pidfile': None
            },
            'ChefClientBackend': {
                'role_location': '/etc/roush/roles.d'},
            'ChefServerBackend': {},
            'UnprovisionedBackend': {}
        }

        if configfile:
            config = ConfigParser()
            config.read(configfile)

            configfile_hash = dict(
                [(s, dict(config.items(s))) for s in config.sections()])

            for section in configfile_hash:
                if section in defaults:
                    defaults[section].update(configfile_hash[section])
                else:
                    defaults[section] = configfile_hash[section]

        if confighash:
            defaults.update(confighash)

        logging.basicConfig(level=logging.WARNING)
        LOG = logging.getLogger()

        if debug:
            LOG.setLevel(logging.DEBUG)
        elif 'loglevel' in defaults['main']:
            LOG.setLevel(defaults['main']['loglevel'])
        else:
            LOG.setLevel(logging.WARNING)

        if 'logfile' in defaults['main']:
            for handler in LOG.handlers:
                LOG.removeHandler(handler)

            handler = logging.FileHandler(defaults['main']['logfile'])
            LOG.addHandler(handler)
        self._logger = LOG

        # Allow for logging section to overload specific children LogLevels
        if 'logging' in defaults:
            overrides = defaults['logging'].keys()
            for ns in overrides:
                TMP_LOG = logging.getLogger(ns)
                TMP_LOG.setLevel(defaults['logging'][ns].upper())

        # # load the backends
        # backends.load(defaults['main']['backend'], defaults)

        # set the notification dispatcher
        # self.dispatch = backends.notify

        self.config.update(defaults['main'])

        print("daemonize: %s, debug: %s, configfile: %s, loglevel: %s " %
              (daemonize, debug, configfile,
               logging.getLevelName(LOG.getEffectiveLevel())))

        self.register_blueprint(index_bp)
        self.register_blueprint(nodes_bp, url_prefix='/nodes')
        self.register_blueprint(nodes_bp, url_prefix='/admin/nodes')
        self.register_blueprint(tasks_bp, url_prefix='/tasks')
        self.register_blueprint(tasks_bp, url_prefix='/admin/tasks')
        self.register_blueprint(adventures_bp, url_prefix='/adventures')
        self.register_blueprint(adventures_bp, url_prefix='/admin/adventures')
        self.register_blueprint(filters_bp, url_prefix='/filters')
        self.register_blueprint(filters_bp, url_prefix='/admin/filters')
        self.register_blueprint(facts_please, url_prefix='/facts')
        self.register_blueprint(facts_bp, url_prefix='/admin/facts')
        self.register_blueprint(attrs_bp, url_prefix='/attrs')
        self.register_blueprint(attrs_bp, url_prefix='/admin/attrs')
        self.register_blueprint(primitives_bp, url_prefix='/primitives')
        self.register_blueprint(primitives_bp, url_prefix='/admin/primitives')
        self.register_blueprint(plan_bp, url_prefix='/plan')
        self.register_blueprint(plan_bp, url_prefix='/admin/plan')
        self.testing = debug

        if debug:
            self.config['TESTING'] = True

        if daemonize:
            self.config['daemonize'] = True

    def usage(self):
        """Print a usage message."""

        print """The following command line flags are supported:

[-c|--config] <file>: use this config file
[-v|--verbose]:       include if you want verbose logging
[-d|--deamonize]:     if set then roush will run as a daemon"""

    def register_blueprint(self, blueprint, url_prefix='/', **kwargs):
        super(Thing, self).register_blueprint(blueprint,
                                              url_prefix=url_prefix,
                                              **kwargs)

        # auto-register the schema url
        def schema_details(what):
            def f():
                api = api_from_models()
                return jsonify({"schema": api._model_get_schema(what)})
            return f

        def filter_object(what):
            def f():
                resp = None

                builder = FilterBuilder(
                    FilterTokenizer(),
                    '%s: %s' % (what, request.json['filter']),
                    api=api_from_models())

                # try:
                result = builder.filter()
                resp = jsonify({'status': 200,
                                'message': 'success',
                                what: result})
                # except SyntaxError as e:
                #     resp = jsonify({'status': 400,
                #                     'message': 'Syntax error: %s' % e.msg})
                #     resp.status_code = 400

                return resp
            return f

        def filter_object_by_id(what):
            def f(filter_id):
                api = api_from_models()
                filter_obj = api.filter_get_by_id(filter_id)
                full_expr = filter_obj['full_expr']
                builder = FilterBuilder(FilterTokenizer(),
                                        '%s: %s' % (what, full_expr))

                return jsonify({what: builder.filter()})

            return f

        def root_schema():
            schema = {'schema': {'objects': self.registered_models}}
            return jsonify(schema)

        bpname = blueprint.name
        if bpname.endswith('_please'):
            bpname = bpname.split('_')[0]

        if url_prefix != '/' and hasattr(models, bpname.capitalize()):
            self._logger.debug('registering %s at %s' % (blueprint.name,
                                                         url_prefix))

            self._logger.debug('mangling name to %s' % bpname)

            if not url_prefix.startswith('/admin/'):
                self.registered_models.append(bpname)

            url = '%s/schema' % (url_prefix,)
            self.add_url_rule(url, '%s.schema' % blueprint.name,
                              schema_details(bpname),
                              methods=['GET'])
            filter_url = '%s/filter' % (url_prefix,)
            self.add_url_rule(filter_url, '%s.filter' % blueprint.name,
                              filter_object(bpname),
                              methods=['POST'])
            f_id_url = '%s/filter/<filter_id>' % (url_prefix,)
            self.add_url_rule(f_id_url, '%s.filter_by_id' % blueprint.name,
                              filter_object_by_id(bpname),
                              methods=['GET'])

        elif url_prefix == '/':
            self.add_url_rule('/schema', 'root.schema',
                              root_schema,
                              methods=['GET'])
            self.add_url_rule('/admin/schema', 'admin.schema',
                              root_schema,
                              methods=['GET'])

    def run(self):
        context = None

        LOG = logging.getLogger()

        if self.config['daemonize']:
            pidfile = None
            if self.config['pidfile']:
                pidfile = PidFile(self.config['pidfile'])

            context = daemon.DaemonContext(
                working_directory='/',
                umask=0o022,
                pidfile=pidfile)

        try:
            if context:
                context.open()

            super(Thing, self).run(host=self.config['bind_address'],
                                   port=self.config['bind_port'])
        except KeyboardInterrupt:
            sys.exit(1)
        except SystemExit:
            raise
        except:
            exc_info = sys.exc_info()
            if hasattr(exc_info[0], "__name__"):
                exc_class, exc, tb = exc_info
                tb_path, tb_lineno, tb_func = traceback.extract_tb(tb)[-1][:3]
                logging.error("%s (%s:%s in %s)", exc_info[1], tb_path,
                              tb_lineno, tb_func)
            else:  # string exception
                logging.error(exc_info[0])
            if LOG.isEnabledFor(logging.DEBUG):
                print ''
                traceback.print_exception(*exc_info)
                sys.exit(1)
            else:
                sys.exit(1)
        finally:
            if context:
                context.close()
<commit_msg>minor typo<commit_after>#!/usr/bin/env python
#
# Copyright 2012, Rackspace US, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import daemon
import fcntl
import getopt
import logging
import os
import random
import string
import sys
import traceback

from ConfigParser import ConfigParser
from flask import Flask, jsonify, request

# from roush import backends
from roush.db import models
from roush.db.api import api_from_models
from roush.webapp.ast import FilterBuilder, FilterTokenizer

from roush.webapp.adventures import bp as adventures_bp
from roush.webapp.facts import bp as facts_bp
from roush.webapp.facts_please import bp as facts_please
from roush.webapp.attrs import bp as attrs_bp
from roush.webapp.filters import bp as filters_bp
from roush.webapp.index import bp as index_bp
from roush.webapp.nodes import bp as nodes_bp
# from roush.webapp.nodes_please import bp as nodes_please
from roush.webapp.primitives import bp as primitives_bp
from roush.webapp.tasks import bp as tasks_bp
from roush.webapp.plan import bp as plan_bp

# api = api_from_models()

# Stolen: http://code.activestate.com/recipes/\
#         577911-context-manager-for-a-daemon-pid-file/
class PidFile(object):
    def __init__(self, path):
        self.path = path
        self.pidfile = None

    def __enter__(self):
        self.pidfile = open(self.path, 'a+')
        try:
            fcntl.flock(self.pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError:
            raise SystemExit('Pid file in use')

        self.pidfile.seek(0)
        self.pidfile.truncate()
        self.pidfile.write(str(os.getpid()))
        self.pidfile.flush()
        self.pidfile.seek(0)
        return self.pidfile

    def __exit__(self, exc_type=None, exc_value=None, exc_tb=None):
        try:
            self.pidfile.close()
        except IOError as err:
            if err.errno != 9:
                raise
        os.remove(self.path)

class Thing(Flask):
    def __init__(self, name, argv=None, configfile=None,
                 confighash=None, debug=False):
        daemonize = False
        self.registered_models = []
        # Define a global transaction_id
        self.trans = {
            'session_key': "".join([random.choice(string.hexdigits)
                                   for n in xrange(30)]),
            'latest': 0,
            'lowest': 0,
            'updates': {0: {'nodes': []}}}

        super(Thing, self).__init__(name)

        if argv:
            try:
                opts, args = getopt.getopt(argv, 'c:vd',
                                           ['config=', 'verbose', 'daemonize'])
            except getopt.GetoptError as err:
                print str(err)
                self.usage()
                sys.exit(1)

            for o, a in opts:
                if o in ('-c', '--config'):
                    configfile = a
                elif o in ('-v', '--verbose'):
                    debug = True
                elif o in ('-d', '--daemonize'):
                    daemonize = True
                else:
                    print "Bad option"
                    self.usage()
                    sys.exit(1)

            sys.argv = [sys.argv[0]] + args

        defaults = {
            'logging': {},
            'main': {
                'bind_address': '0.0.0.0',
                'bind_port': 8080,
                'backend': '/dev/null',
                'loglevel': 'WARNING',
                'database_uri': 'sqlite:///',
                'daemonize': False,
                'pidfile': None
            },
            'ChefClientBackend': {
                'role_location': '/etc/roush/roles.d'},
            'ChefServerBackend': {},
            'UnprovisionedBackend': {}
        }

        if configfile:
            config = ConfigParser()
            config.read(configfile)

            configfile_hash = dict(
                [(s, dict(config.items(s))) for s in config.sections()])

            for section in configfile_hash:
                if section in defaults:
                    defaults[section].update(configfile_hash[section])
                else:
                    defaults[section] = configfile_hash[section]

        if confighash:
            defaults.update(confighash)

        logging.basicConfig(level=logging.WARNING)
        LOG = logging.getLogger()

        if debug:
            LOG.setLevel(logging.DEBUG)
        elif 'loglevel' in defaults['main']:
            LOG.setLevel(defaults['main']['loglevel'])
        else:
            LOG.setLevel(logging.WARNING)

        if 'logfile' in defaults['main']:
            for handler in LOG.handlers:
                LOG.removeHandler(handler)

            handler = logging.FileHandler(defaults['main']['logfile'])
            LOG.addHandler(handler)
        self._logger = LOG

        # Allow for logging section to overload specific children LogLevels
        if 'logging' in defaults:
            overrides = defaults['logging'].keys()
            for ns in overrides:
                TMP_LOG = logging.getLogger(ns)
                TMP_LOG.setLevel(defaults['logging'][ns].upper())

        # # load the backends
        # backends.load(defaults['main']['backend'], defaults)

        # set the notification dispatcher
        # self.dispatch = backends.notify

        self.config.update(defaults['main'])

        print("daemonize: %s, debug: %s, configfile: %s, loglevel: %s " %
              (daemonize, debug, configfile,
               logging.getLevelName(LOG.getEffectiveLevel())))

        self.register_blueprint(index_bp)
        self.register_blueprint(nodes_bp, url_prefix='/nodes')
        self.register_blueprint(nodes_bp, url_prefix='/admin/nodes')
        self.register_blueprint(tasks_bp, url_prefix='/tasks')
        self.register_blueprint(tasks_bp, url_prefix='/admin/tasks')
        self.register_blueprint(adventures_bp, url_prefix='/adventures')
        self.register_blueprint(adventures_bp, url_prefix='/admin/adventures')
        self.register_blueprint(filters_bp, url_prefix='/filters')
        self.register_blueprint(filters_bp, url_prefix='/admin/filters')
        self.register_blueprint(facts_please, url_prefix='/facts')
        self.register_blueprint(facts_bp, url_prefix='/admin/facts')
        self.register_blueprint(attrs_bp, url_prefix='/attrs')
        self.register_blueprint(attrs_bp, url_prefix='/admin/attrs')
        self.register_blueprint(primitives_bp, url_prefix='/primitives')
        self.register_blueprint(primitives_bp, url_prefix='/admin/primitives')
        self.register_blueprint(plan_bp, url_prefix='/plan')
        self.register_blueprint(plan_bp, url_prefix='/admin/plan')
        self.testing = debug

        if debug:
            self.config['TESTING'] = True

        if daemonize:
            self.config['daemonize'] = True

    def usage(self):
        """Print a usage message."""

        print """The following command line flags are supported:

[-c|--config] <file>: use this config file
[-v|--verbose]:       include if you want verbose logging
[-d|--deamonize]:     if set then roush will run as a daemon"""

    def register_blueprint(self, blueprint, url_prefix='/', **kwargs):
        super(Thing, self).register_blueprint(blueprint,
                                              url_prefix=url_prefix,
                                              **kwargs)

        # auto-register the schema url
        def schema_details(what):
            def f():
                api = api_from_models()
                return jsonify({"schema": api._model_get_schema(what)})
            return f

        def filter_object(what):
            def f():
                resp = None

                builder = FilterBuilder(
                    FilterTokenizer(),
                    '%s: %s' % (what, request.json['filter']),
                    api=api_from_models())

                # try:
                result = builder.filter()
                resp = jsonify({'status': 200,
                                'message': 'success',
                                what: result})
                # except SyntaxError as e:
                #     resp = jsonify({'status': 400,
                #                     'message': 'Syntax error: %s' % e.msg})
                #     resp.status_code = 400

                return resp
            return f

        def filter_object_by_id(what):
            def f(filter_id):
                api = api_from_models()
                filter_obj = api.filter_get_by_id(filter_id)
                full_expr = filter_obj['full_expr']
                builder = FilterBuilder(FilterTokenizer(),
                                        '%s: %s' % (what, full_expr))

                return jsonify({what: builder.filter()})

            return f

        def root_schema():
            schema = {'schema': {'objects': self.registered_models}}
            return jsonify(schema)

        bpname = blueprint.name
        if bpname.endswith('_please'):
            bpname = bpname.split('_')[0]

        if url_prefix != '/' and hasattr(models, bpname.capitalize()):
            self._logger.debug('registering %s at %s' % (blueprint.name,
                                                         url_prefix))

            self._logger.debug('mangling name to %s' % bpname)

            if not url_prefix.startswith('/admin/'):
                self.registered_models.append(bpname)

            url = '%s/schema' % (url_prefix,)
            self.add_url_rule(url, '%s.schema' % blueprint.name,
                              schema_details(bpname),
                              methods=['GET'])
            filter_url = '%s/filter' % (url_prefix,)
            self.add_url_rule(filter_url, '%s.filter' % blueprint.name,
                              filter_object(bpname),
                              methods=['POST'])
            f_id_url = '%s/filter/<filter_id>' % (url_prefix,)
            self.add_url_rule(f_id_url, '%s.filter_by_id' % blueprint.name,
                              filter_object_by_id(bpname),
                              methods=['GET'])

        elif url_prefix == '/':
            self.add_url_rule('/schema', 'root.schema',
                              root_schema,
                              methods=['GET'])
            self.add_url_rule('/admin/schema', 'admin.schema',
                              root_schema,
                              methods=['GET'])

    def run(self):
        context = None

        LOG = logging.getLogger()

        if self.config['daemonize']:
            pidfile = None
            if self.config['pidfile']:
                pidfile = PidFile(self.config['pidfile'])

            context = daemon.DaemonContext(
                working_directory='/',
                umask=0o022,
                pidfile=pidfile)

        try:
            if context:
                context.open()

            super(Thing, self).run(host=self.config['bind_address'],
                                   port=self.config['bind_port'])
        except KeyboardInterrupt:
            sys.exit(1)
        except SystemExit:
            raise
        except:
            exc_info = sys.exc_info()
            if hasattr(exc_info[0], "__name__"):
                exc_class, exc, tb = exc_info
                tb_path, tb_lineno, tb_func = traceback.extract_tb(tb)[-1][:3]
                logging.error("%s (%s:%s in %s)", exc_info[1], tb_path,
                              tb_lineno, tb_func)
            else:  # string exception
                logging.error(exc_info[0])
            if LOG.isEnabledFor(logging.DEBUG):
                print ''
                traceback.print_exception(*exc_info)
                sys.exit(1)
            else:
                sys.exit(1)
        finally:
            if context:
                context.close()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# © 2016 Comunitea - Javier Colmenero <javier@comunitea.com>
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import api, fields, models
import time
from odoo.addons import decimal_precision as dp
from odoo.tools import float_compare

class SaleOrder(models.Model):
    _inherit = "sale.order"

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('proforma', 'Proforma'),
        ('lqdr', 'Pending LQDR'),
        ('progress_lqdr', 'Progress LQDR'),
        ('pending', 'Revision Pending '),
        ('sale', 'Sales Order'),
        ('done', 'Locked'),
        ('cancel', 'Cancelled'),
    ])

    work_to_do = fields.Text('Trabajo a realizar')
    route_id = fields.Many2one('stock.location.route', string='Force Route', domain=[('sale_selectable', '=', True)])

    @api.multi
    def action_proforma(self):
        for order in self:
            order.state = 'proforma'
        return True

    @api.multi
    def action_lqdr_option(self):
        for order in self:
            if order.order_line.filtered('product_id.lqdr'):
                order.state = 'lqdr'
            else:
               order.state = 'pending'
        return True

    @api.multi
    def action_lqdr_ok(self):
        for order in self:
            order.state = 'pending'
        return True

    @api.multi
    def action_pending_ok(self):
        for order in self:
            order.action_sale()
        return True

    @api.multi
    def action_sale(self):
        for order in self:
            order.action_confirm()
            picking_out = order.picking_ids.filtered(lambda x: x.picking_type_id.code == 'outgoing')
            picking_out.write({'ready': True})
        return True

    @api.onchange('warehouse_id')
    def _onchange_warehouse_id(self):
        """
        Avoid change warehouse_company_id
        """
        return

    def apply_route_to_order_lines(self):

        for order in self:
            if order.state == 'done':
                raise ValueError("No puedes asignar rutas a un pedido confirmado")
            for line in order.template_lines:
                line.route_id = order.route_id
            for line in self.order_line:
                line.route_id = self.route_id

    @api.multi
    def action_view_delivery(self):
        '''
        TODO HARDCODEADO
        Añado para filtrar intercompañia

        '''
        action = super(SaleOrder, self).action_view_delivery()
        if 'domain' in action and action['domain']:
            action['domain'].append(('picking_type_id.name', 'not like', '%Inter%'))

        return action

class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('lqdr', 'LQDR'),
        ('pending', 'Pending Approval'),
        ('sale', 'Sales Order'),
        ('done', 'Locked'),
        ('cancel', 'Cancelled'),
    ])

    lqdr = fields.Boolean(related="product_id.lqdr", store=False)

    @api.multi
    @api.onchange('product_id')
    def product_id_change(self):
        res = super(SaleOrderLine, self).product_id_change()
        #if self.product_id.route_ids:
        self.route_id = self.order_id.route_id or self.product_id.route_ids and self.product_id.route_ids[0]

        return res

    @api.multi
    def _get_display_price(self, product):
        res = super(SaleOrderLine, self)._get_display_price(product)
        # Search for specific prices in variants
        qty = product._context.get('quantity', 1.0)
        vals = {}
        partner_id = self.order_id.partner_id.id
        date = self.order_id.date_order
        customer_price = self.env['customer.price'].\
                    get_customer_price(partner_id, product, qty, date=date)
        if customer_price:
            return customer_price
        return res

    @api.multi
    def action_procurement_create(self):
        old_state = self.order_id.state
        self.order_id.state = 'sale'
        new_procs = self._action_procurement_create()
        self.order_id.state = old_state
        return new_procs

    @api.multi
    def _action_procurement_create(self):
        return super(SaleOrderLine, self)._action_procurement_create()

class SaleOrderLineTemplate(models.Model):

    _inherit = 'sale.order.line.template'

    lqdr = fields.Boolean(related="product_template.lqdr", store=False)

    @api.multi
    def create_template_procurements(self):
        for line in self.order_lines:
            line.action_procurement_create()
        return True
<commit_msg>[IMP] Verificacion de provincia al confirmar pedido<commit_after># -*- coding: utf-8 -*-
# © 2016 Comunitea - Javier Colmenero <javier@comunitea.com>
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import api, fields, models
import time
from odoo.addons import decimal_precision as dp
from odoo.tools import float_compare
from odoo.exceptions import ValidationError

class SaleOrder(models.Model):
    _inherit = "sale.order"

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('proforma', 'Proforma'),
        ('lqdr', 'Pending LQDR'),
        ('progress_lqdr', 'Progress LQDR'),
        ('pending', 'Revision Pending '),
        ('sale', 'Sales Order'),
        ('done', 'Locked'),
        ('cancel', 'Cancelled'),
    ])

    work_to_do = fields.Text('Trabajo a realizar')
    route_id = fields.Many2one('stock.location.route', string='Force Route', domain=[('sale_selectable', '=', True)])

    @api.multi
    def action_proforma(self):
        for order in self:
            order.state = 'proforma'
        return True

    @api.multi
    def action_lqdr_option(self):
        for order in self:
            self.confirm_checks()

            if order.order_line.filtered('product_id.lqdr'):
                order.state = 'lqdr'
            else:
               order.state = 'pending'
        return True

    @api.multi
    def action_lqdr_ok(self):
        for order in self:
            order.state = 'pending'
        return True

    @api.multi
    def action_pending_ok(self):
        for order in self:
            order.action_sale()
        return True

    @api.multi
    def action_sale(self):
        for order in self:
            order.action_confirm()
            picking_out = order.picking_ids.filtered(lambda x: x.picking_type_id.code == 'outgoing')
            picking_out.write({'ready': True})
        return True

    @api.onchange('warehouse_id')
    def _onchange_warehouse_id(self):
        """
        Avoid change warehouse_company_id
        """
        return

    def apply_route_to_order_lines(self):

        for order in self:
            if order.state == 'done':
                raise ValueError("No puedes asignar rutas a un pedido confirmado")
            for line in order.template_lines:
                line.route_id = order.route_id
            for line in self.order_line:
                line.route_id = self.route_id

    @api.multi
    def action_view_delivery(self):
        '''
        TODO HARDCODEADO
        Añado para filtrar intercompañia

        '''
        action = super(SaleOrder, self).action_view_delivery()
        if 'domain' in action and action['domain']:
            action['domain'].append(('picking_type_id.name', 'not like', '%Inter%'))

        return action

    def confirm_checks(self):
        if self.partner_shipping_id.country_id and self.partner_shipping_id.country_id.name.encode('UTF-8') == "%s"%"España":
            if not self.partner_shipping_id.state_id:
                raise ValidationError("No puedes confirmar sin provincia de envío")

class SaleOrderLine(models.Model):
    _inherit = "sale.order.line"

    state = fields.Selection([
        ('draft', 'Quotation'),
        ('sent', 'Quotation Sent'),
        ('lqdr', 'LQDR'),
        ('pending', 'Pending Approval'),
        ('sale', 'Sales Order'),
        ('done', 'Locked'),
        ('cancel', 'Cancelled'),
    ])

    lqdr = fields.Boolean(related="product_id.lqdr", store=False)

    @api.multi
    @api.onchange('product_id')
    def product_id_change(self):
        res = super(SaleOrderLine, self).product_id_change()
        #if self.product_id.route_ids:
        self.route_id = self.order_id.route_id or self.product_id.route_ids and self.product_id.route_ids[0]

        return res

    @api.multi
    def _get_display_price(self, product):
        res = super(SaleOrderLine, self)._get_display_price(product)
        # Search for specific prices in variants
        qty = product._context.get('quantity', 1.0)
        vals = {}
        partner_id = self.order_id.partner_id.id
        date = self.order_id.date_order
        customer_price = self.env['customer.price'].\
                    get_customer_price(partner_id, product, qty, date=date)
        if customer_price:
            return customer_price
        return res

    @api.multi
    def action_procurement_create(self):
        old_state = self.order_id.state
        self.order_id.state = 'sale'
        new_procs = self._action_procurement_create()
        self.order_id.state = old_state
        return new_procs

    @api.multi
    def _action_procurement_create(self):
        return super(SaleOrderLine, self)._action_procurement_create()

class SaleOrderLineTemplate(models.Model):

    _inherit = 'sale.order.line.template'

    lqdr = fields.Boolean(related="product_template.lqdr", store=False)

    @api.multi
    def create_template_procurements(self):
        for line in self.order_lines:
            line.action_procurement_create()
        return True
<|endoftext|>


<commit_before>from __future__ import division

from nose.tools import assert_is_instance

from dit import Distribution, ScalarDistribution
from dit.convert import DtoSD, SDtoD

def test_DtoSD():
    outcomes = ['00', '01', '10', '11']
    pmf = [1/4]*4
    d = Distribution(outcomes, pmf)
    sd = DtoSD(d, False)
    assert_is_instance(d, Distribution)
    assert_is_instance(sd, ScalarDistribution)

def test_SDtoD():
    sd = ScalarDistribution([1/4]*4)
    d = SDtoD(sd)
    assert_is_instance(sd, ScalarDistribution)
    assert_is_instance(d, Distribution)<commit_msg>fix tests for py26 again... i wish unittest2 installed in the unittest namespace<commit_after>from __future__ import division

from nose.tools import assert_is_instance

from dit import Distribution, ScalarDistribution
from dit.convert import DtoSD, SDtoD

def test_DtoSD():
    outcomes = ['00', '01', '10', '11']
    pmf = [1/4]*4
    d = Distribution(outcomes, pmf)
    sd = DtoSD(d, False)
    assert(type(d) is Distribution)
    assert(type(sd) is ScalarDistribution)

def test_SDtoD():
    sd = ScalarDistribution([1/4]*4)
    d = SDtoD(sd)
    assert(type(sd) is ScalarDistribution)
    assert(type(d) is Distribution)<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Originally a MATLAB script. Also included ASPEC, CDSGN, CSPEC:

Author: Christophe Couvreur, Faculte Polytechnique de Mons (Belgium)
        couvreur@thor.fpms.ac.be
Last modification: Aug. 20, 1997, 10:00am.

http://www.mathworks.com/matlabcentral/fileexchange/69
http://replaygain.hydrogenaudio.org/mfiles/adsgn.m

Translated from adsgn.m to SciPy 2009-07-14 endolith@gmail.com
"""

from __future__ import division
from numpy import pi, polymul
from scipy.signal.filter_design import bilinear
from scipy.signal import lfilter

def A_weighting(fs):
    """
    Design of an A-weighting filter.

    B, A = A_weighting(fs) designs a digital A-weighting filter for
    sampling frequency fs. Usage: y = lfilter(b, a, x).
    Warning: fs should normally be higher than 20 kHz. For example,
    fs = 48000 yields a class 1-compliant filter.

    References:
       [1] IEC/CD 1672: Electroacoustics-Sound Level Meters, Nov. 1996.
    """

    # Definition of analog A-weighting filter according to IEC/CD 1672.
    f1 = 20.598997
    f2 = 107.65265
    f3 = 737.86223
    f4 = 12194.217
    A1000 = 1.9997

    NUMs = [(2*pi * f4)**2 * (10**(A1000/20)), 0, 0, 0, 0]

    DENs = polymul([1, 4*pi * f4, (2*pi * f4)**2],
                   [1, 4*pi * f1, (2*pi * f1)**2])
    DENs = polymul(DENs, [1, 2*pi * f3])
    DENs = polymul(DENs, [1, 2*pi * f2])

    # Analog confirmed to match https://en.wikipedia.org/wiki/A-weighting#A_2

    # Use the bilinear transformation to get the digital filter.
    return bilinear(NUMs, DENs, fs)

def A_weight(signal, fs):
    """
    Return the given signal after passing through an A-weighting filter

    signal : array_like
        Input signal
    fs : float
        Sampling frequency
    """

    b, a = A_weighting(fs)
    return lfilter(b, a, signal)

# When importing a stereo sound file with scikits.audiolab, it needs axis = 0:
# y = lfilter(B, A, x, axis = 0)
<commit_msg>docstrings<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Originally a MATLAB script. Also included ASPEC, CDSGN, CSPEC:

Author: Christophe Couvreur, Faculte Polytechnique de Mons (Belgium)
        couvreur@thor.fpms.ac.be
Last modification: Aug. 20, 1997, 10:00am.

http://www.mathworks.com/matlabcentral/fileexchange/69
http://replaygain.hydrogenaudio.org/mfiles/adsgn.m

Translated from adsgn.m to SciPy 2009-07-14 endolith@gmail.com

When importing a stereo sound file with scikits.audiolab or pysoundfile, it
needs axis = 0:
y = lfilter(b, a, x, axis = 0)
"""

from __future__ import division
from numpy import pi, polymul
from scipy.signal.filter_design import bilinear
from scipy.signal import lfilter

def A_weighting(fs):
    """
    Design of an A-weighting filter.

    Designs a digital A-weighting filter for
    sampling frequency `fs`. Usage: y = lfilter(b, a, x).
    Warning: fs should normally be higher than 20 kHz. For example,
    fs = 48000 yields a class 1-compliant filter.

    Since this uses the bilinear transform, frequency response around fs/2 will
    be inaccurate at lower sampling rates.  A-weighting is undefined above
    20 kHz, though.

    Example:

    from scipy.signal import freqz
    import matplotlib.pyplot as plt
    fs = 200000  # change to 48000 to see truncation
    b, a = A_weighting(fs)
    f = np.logspace(np.log10(10), np.log10(fs/2), 1000)
    w = 2*pi * f / fs
    w, h = freqz(b, a, w)
    plt.semilogx(w*fs/(2*pi), 20*np.log10(abs(h)))
    plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
    plt.axis([10, 100e3, -50, 20])

    References:
       [1] IEC/CD 1672: Electroacoustics-Sound Level Meters, Nov. 1996.
    """

    # Definition of analog A-weighting filter according to IEC/CD 1672.
    f1 = 20.598997
    f2 = 107.65265
    f3 = 737.86223
    f4 = 12194.217
    A1000 = 1.9997

    NUMs = [(2*pi * f4)**2 * (10**(A1000/20)), 0, 0, 0, 0]

    DENs = polymul([1, 4*pi * f4, (2*pi * f4)**2],
                   [1, 4*pi * f1, (2*pi * f1)**2])
    DENs = polymul(DENs, [1, 2*pi * f3])
    DENs = polymul(DENs, [1, 2*pi * f2])

    # Analog confirmed to match https://en.wikipedia.org/wiki/A-weighting#A_2

    # Use the bilinear transformation to get the digital filter.
    return bilinear(NUMs, DENs, fs)

def A_weight(signal, fs):
    """
    Return the given signal after passing through an A-weighting filter

    signal : array_like
        Input signal
    fs : float
        Sampling frequency
    """

    b, a = A_weighting(fs)
    return lfilter(b, a, signal)
<|endoftext|>


<commit_before>import os
import ycm_core

flags = [
'-Wall',
'-Wextra',
'-Werror',
'-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-std=c++11',
'-x', 'c++',
'-I', '.',
'-isystem', '/usr/include',
'-isystem', '/usr/local/include',
'-isystem', '/usr/include/c++/5.1.0',
'-isystem', '/usr/include/c++/5.1.0/x86_64-unknown-linux-gnu',
'-isystem', '/usr/include/c++/5.1.0/backward'
]

compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
  database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
  database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():
  return os.path.dirname( os.path.abspath( __file__ ) )

def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
  if not working_directory:
    return list( flags )
  new_flags = []
  make_next_absolute = False
  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
  for flag in flags:
    new_flag = flag

    if make_next_absolute:
      make_next_absolute = False
      if not flag.startswith( '/' ):
        new_flag = os.path.join( working_directory, flag )

    for path_flag in path_flags:
      if flag == path_flag:
        make_next_absolute = True
        break

      if flag.startswith( path_flag ):
        path = flag[ len( path_flag ): ]
        new_flag = path_flag + os.path.join( working_directory, path )
        break

    if new_flag:
      new_flags.append( new_flag )
  return new_flags

def IsHeaderFile( filename ):
  extension = os.path.splitext( filename )[ 1 ]
  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]

def GetCompilationInfoForFile( filename ):
  if IsHeaderFile( filename ):
    basename = os.path.splitext( filename )[ 0 ]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists( replacement_file ):
        compilation_info = database.GetCompilationInfoForFile(
          replacement_file )
        if compilation_info.compiler_flags_:
          return compilation_info
    return None
  return database.GetCompilationInfoForFile( filename )

def FlagsForFile( filename, **kwargs ):
  if database:
    compilation_info = GetCompilationInfoForFile( filename )
    if not compilation_info:
      return None

    final_flags = MakeRelativePathsInFlagsAbsolute(
      compilation_info.compiler_flags_,
      compilation_info.compiler_working_dir_ )

    try:
      final_flags.remove( '-stdlib=libc++' )
    except ValueError:
      pass
  else:
    relative_to = DirectoryOfThisScript()
    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

  return {
    'flags': final_flags,
    'do_cache': True
  }

<commit_msg>Remove -Wc++98-compat from default .ycm_extra_conf<commit_after>import os
import ycm_core

flags = [
'-Wall',
'-Wextra',
'-Werror',
# '-Wc++98-compat',
'-Wno-long-long',
'-Wno-variadic-macros',
'-fexceptions',
'-std=c++11',
'-x', 'c++',
'-I', '.',
'-isystem', '/usr/include',
'-isystem', '/usr/local/include',
'-isystem', '/usr/include/c++/5.1.0',
'-isystem', '/usr/include/c++/5.1.0/x86_64-unknown-linux-gnu',
'-isystem', '/usr/include/c++/5.1.0/backward'
]

compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
  database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
  database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ]

def DirectoryOfThisScript():
  return os.path.dirname( os.path.abspath( __file__ ) )

def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
  if not working_directory:
    return list( flags )
  new_flags = []
  make_next_absolute = False
  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
  for flag in flags:
    new_flag = flag

    if make_next_absolute:
      make_next_absolute = False
      if not flag.startswith( '/' ):
        new_flag = os.path.join( working_directory, flag )

    for path_flag in path_flags:
      if flag == path_flag:
        make_next_absolute = True
        break

      if flag.startswith( path_flag ):
        path = flag[ len( path_flag ): ]
        new_flag = path_flag + os.path.join( working_directory, path )
        break

    if new_flag:
      new_flags.append( new_flag )
  return new_flags

def IsHeaderFile( filename ):
  extension = os.path.splitext( filename )[ 1 ]
  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]

def GetCompilationInfoForFile( filename ):
  if IsHeaderFile( filename ):
    basename = os.path.splitext( filename )[ 0 ]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists( replacement_file ):
        compilation_info = database.GetCompilationInfoForFile(
          replacement_file )
        if compilation_info.compiler_flags_:
          return compilation_info
    return None
  return database.GetCompilationInfoForFile( filename )

def FlagsForFile( filename, **kwargs ):
  if database:
    compilation_info = GetCompilationInfoForFile( filename )
    if not compilation_info:
      return None

    final_flags = MakeRelativePathsInFlagsAbsolute(
      compilation_info.compiler_flags_,
      compilation_info.compiler_working_dir_ )

    try:
      final_flags.remove( '-stdlib=libc++' )
    except ValueError:
      pass
  else:
    relative_to = DirectoryOfThisScript()
    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

  return {
    'flags': final_flags,
    'do_cache': True
  }

<|endoftext|>