Source code for police_api.neighbourhoods

from datetime import datetime

from .exceptions import NeighbourhoodsNeighbourhoodException
from .resource import Resource, SimpleResource


[docs]class Neighbourhood(Resource): """ A Neighbourhood Policing Team. Uses the neighbourhood_ API call. :param PoliceAPI api: The instance of ``PoliceAPI`` to use. :param bool preload: If ``True``, attributes are loaded from the API on instantiation rather than waiting for a property to be accessed. :param attrs: Only the ``force`` and ``id`` are required. Any other attributes supplied will be set on the instance and not fetched from the API. .. doctest:: >>> from police_api import PoliceAPI >>> api = PoliceAPI() >>> force = api.get_force('leicestershire') >>> neighbourhood = force.get_neighbourhood('C04') >>> print(neighbourhood.name) City Centre neighbourhood .. attribute:: id :type: str The neighbourhood's identifier (usually a code, but can contain spaces). .. attribute:: name :type: str The name of the NPT. .. attribute:: description :type: str A description of the NPT's area. .. attribute:: url_force :type: str The URL for this NPT on the force's website .. attribute:: population :type: str An estimate of the number of people living within the NPT boundary. .. attribute:: centre :type: dict The approximate centre point of the neighbourhood. .. doctest:: >>> print(neighbourhood.centre['latitude']) 52.6268 >>> print(neighbourhood.centre['longitude']) -1.12621 .. attribute:: links :type: list A ``list`` of links relevant to this force. .. doctest:: >>> link = neighbourhood.links[0] >>> print(link['title']) Leicester City Council >>> print(link['url']) http://www.leicester.gov.uk/ .. attribute:: locations :type: list A ``list`` of police stations in this NPT. .. doctest:: >>> print(neighbourhood.locations[0]['address']) 74 Belgrave Gate , Leicester .. attribute:: contact_details :type: dict Ways that this NPT can be contacted. .. doctest:: >>> print(neighbourhood.contact_details['email']) centralleicester.npa@leicestershire.pnn.police.uk >>> print(neighbourhood.contact_details['twitter']) http://www.twitter.com/leicesterpolice .. attribute:: officers :type: list A ``list`` of ``Neighbourhood.Officer`` objects. .. attribute:: events :type: list A ``list`` of ``Neighbourhood.Event`` objects. .. attribute:: priorities :type: list A ``list`` of ``Neighbourhood.Priority`` objects. .. attribute:: boundary :type: list A ``list`` of ``(lat, lng)`` coordinates representing the perimeter of this neighbourhood's boundary. .. doctest:: >>> neighbourhood.boundary[0] (52.6235790036, -1.1433951806) .. _neighbourhood: https://data.police.uk/docs/method/neighbourhood/ """ force = None _resource_cache = {} _boundary = None _crimes = None fields = ['contact_details', 'name', 'links', 'description', 'url_force', 'population', 'centre', 'locations']
[docs] class Officer(SimpleResource): """ A police officer. Uses the neighbourhood-team_ API call. :param PoliceAPI api: The instance of ``PoliceAPI`` to use. :param dict data: The attributes that will be copied to this instance. .. doctest:: >>> from police_api import PoliceAPI >>> api = PoliceAPI() >>> force = api.get_force('surrey') >>> neighbourhood = force.get_neighbourhood('ELCO') >>> officer = neighbourhood.officers[0] .. attribute:: neighbourhood :type: :class:`Neighbourhood` The Neighbourhood Policing Team that this officer is part of. .. attribute:: name :type: str The officer's name. .. attribute:: rank :type: str The officer's rank. .. attribute:: bio :type: str The officer's biography. .. attribute:: contact_details :type: list A ``list`` of ``dict``, containing methods of contacting the officer. .. doctest:: >>> print(officer.contact_details['email']) elmbridge@surrey.pnn.police.uk >>> print(officer.contact_details['telephone']) 101 .. _neighbourhood-team: https://data.police.uk/docs/method/neighbourhood-team/ """ fields = ['neighbourhood', 'name', 'rank', 'contact_details', 'bio'] def __str__(self): return '<Neighbourhood.Officer> %s' % self.name
[docs] class Event(SimpleResource): """ A neighbourhood event (e.g. a beat meating or surgery). Uses the neighbourhood-events_ API call. :param PoliceAPI api: The instance of ``PoliceAPI`` to use. :param dict data: The attributes that will be copied to this instance. .. doctest:: >>> from police_api import PoliceAPI >>> api = PoliceAPI() >>> force = api.get_force('leicestershire') >>> neighbourhood = force.get_neighbourhood('C04') >>> event = neighbourhood.events[0] .. attribute:: neighbourhood :type: :class:`Neighbourhood` The Neighbourhood Policing Team that organised this event. .. attribute:: title :type: str The title of the event. .. attribute:: type :type: str The type of the event. .. attribute:: description :type: str A description of the event. .. attribute:: address :type: str The location of the event. .. attribute:: start_date :type: datetime.datetime The date and time that the event starts. .. _neighbourhood-events: https://data.police.uk/docs/method/neighbourhood-events/ """ fields = ['neighbourhood', 'title', 'type', 'description', 'contact_details', 'start_date', 'address'] def __str__(self): return '<Neighbourhood.Event> %s' % self.title def _hydrate_start_date(self, data): return datetime.strptime(data, '%Y-%m-%dT%H:%M:%S')
[docs] class Priority(SimpleResource): """ A neighbourhood priority (i.e. an issue raised by the community and a corresponding policing action to address this). Uses the neighbourhood-priorities_ API call. :param PoliceAPI api: The instance of ``PoliceAPI`` to use. :param dict data: The attributes that will be copied to this instance. .. attribute:: neighbourhood :type: :class:`Neighbourhood` The Neighbourhood Policing Team that owns this priority. .. attribute:: issue :type: str The issue that was raised. .. attribute:: action :type: str The action that was taken to address the issue. .. attribute:: issue_date :type: datetime.datetime The date that the issue was raised. .. attribute:: action_date :type: datetime.datetime The date that the action was implemented. .. _neighbourhood-priorities: https://data.police.uk/docs/method/neighbourhood-priorities/ """ fields = ['neighbourhood', 'issue', 'action', 'issue_date', 'action_date'] def __str__(self): return '<Neighbourhood.Priority> %s' % self.issue def _hydrate(self, data): for field in ['issue-date', 'action-date']: data[field.replace('-', '_')] = data[field] return super(Neighbourhood.Priority, self)._hydrate(data) def __hydrate_date(self, data): return datetime.strptime(data, '%Y-%m-%dT%H:%M:%S') def _hydrate_issue_date(self, data): return self.__hydrate_date(data) if data else None _hydrate_action_date = _hydrate_issue_date
def __init__(self, *args, **kwargs): super(Neighbourhood, self).__init__(*args, **kwargs) self._assert_id_not_neighbourhoods() def __str__(self): return '<Neighbourhood> %s' % self.id def __eq__(self, other): return isinstance(other, Neighbourhood) and self.id == other.id def __hash__(self): return hash(self.id) def _assert_id_not_neighbourhoods(self): # Have a look at the docstring of NeighbourhoodsNeighbourhoodException. if self.id == 'neighbourhoods': raise NeighbourhoodsNeighbourhoodException() def _get_api_method(self): self._assert_id_not_neighbourhoods() return '%s/%s' % (self.force.id, self.id) def _hydrate_population(self, data): return int(data) if data is not None else None def _get_resource(self, cls, method): if method in self._resource_cache: return self._resource_cache[method] objs = [] method = '%s/%s/%s' % (self.force.id, self.id, method) for d in self.api.service.request('GET', method): d.update({ 'neighbourhood': self, }) objs.append(cls(self.api, data=d)) self._resource_cache[method] = objs return objs def _get_boundary(self): method = '%s/%s/boundary' % (self.force.id, self.id) points = self.api.service.request('GET', method) return [(float(p['latitude']), float(p['longitude'])) for p in points] def _get_crimes(self): return self.api.get_crimes_area(self.boundary) @property def officers(self): return self._get_resource(self.Officer, 'people') @property def events(self): return self._get_resource(self.Event, 'events') @property def priorities(self): return sorted(self._get_resource(self.Priority, 'priorities'), key=lambda x: x.issue_date, reverse=True) @property def boundary(self): if self._boundary is None: self._boundary = self._get_boundary() return self._boundary @property def crimes(self): if self._crimes is None: self._crimes = self._get_crimes() return self._crimes