Esempio n. 1
0
def _set_stop_area_locality(connection):
    """ Add locality info based on stops contained within the stop areas. """
    # Find stop areas with associated locality codes
    with connection.begin():
        query_stop_areas = connection.execute(
            db.select([
                models.StopArea.code.label("code"),
                models.StopPoint.locality_ref.label("ref"),
                db.func.count(models.StopPoint.locality_ref).label("count")
            ]).select_from(
                models.StopArea.__table__.join(
                    models.StopPoint, models.StopArea.code ==
                    models.StopPoint.stop_area_ref)).group_by(
                        models.StopArea.code, models.StopPoint.locality_ref))
        stop_areas = query_stop_areas.fetchall()
        # Find locality for each stop area that contain the most stops
        areas, ambiguous = _find_stop_area_mode(stop_areas, "locality_ref")

        # if still ambiguous, measure distance between stop area and each
        # locality and add to above
        if ambiguous:
            add_areas = _find_locality_distance(connection, ambiguous.keys())
            areas.extend(add_areas)

        utils.logger.info("Adding locality codes to stop areas")
        for a in areas:
            connection.execute(
                db.update(models.StopArea).values({
                    "locality_ref":
                    a["locality_ref"]
                }).where(models.StopArea.code == a["code"]))
Esempio n. 2
0
    def call(cls, limit):
        """ Request a call, checking whether it was within the daily limit.
            :param limit: The limit on number of calls each day starting at
            00:00 UTC. Ignored if is None or negative.
        """
        tz = db.bindparam("utc", "UTC")
        one = db.literal_column("1")
        today = db.func.date(db.func.timezone(tz, db.func.now()))
        date_last_called = db.func.date(db.func.timezone(tz, cls.last_called))

        statement = (
            db.update(cls)
            .values(
                last_called=db.func.now(),
                call_count=db.case(
                    (date_last_called < today, one),
                    else_=cls.call_count + one,
                ),
            )
            .returning(cls.call_count)
        )
        count = db.session.execute(statement).scalar()

        if limit is None or limit < 0:
            utils.logger.debug(f"Request limit {limit!r} ignored")
            return True
        elif count <= limit:
            utils.logger.debug(f"Request was allowed: {count} <= {limit}")
            return True
        else:
            utils.logger.warning(f"Request limit exceeded: {count} > {limit}")
            return False
Esempio n. 3
0
def _set_tram_admin_area(connection):
    """ Set admin area ref for tram stops and areas to be the same as their
        localities.
    """
    tram_area = "147"

    with connection.begin():
        # Update stop points
        admin_area_ref = (db.select([models.Locality.admin_area_ref]).where(
            models.Locality.code == models.StopPoint.locality_ref).as_scalar())

        utils.logger.info("Updating tram stops with admin area ref")
        connection.execute(
            db.update(models.StopPoint).values({
                models.StopPoint.admin_area_ref:
                admin_area_ref
            }).where(models.StopPoint.admin_area_ref == tram_area))

        # Find stop areas with associated admin area codes
        stop_areas = connection.execute(
            db.select([
                models.StopArea.code.label("code"),
                models.StopPoint.admin_area_ref.label("ref"),
                db.func.count(models.StopPoint.admin_area_ref).label("count")
            ]).select_from(
                models.StopArea.__table__.join(
                    models.StopPoint,
                    models.StopArea.code == models.StopPoint.stop_area_ref)).
            where(models.StopArea.admin_area_ref == tram_area).group_by(
                models.StopArea.code, models.StopPoint.admin_area_ref))
        areas, ambiguous = _find_stop_area_mode(stop_areas.fetchall(),
                                                "admin_area_ref")

        utils.logger.info("Adding locality codes to stop areas")
        for a in areas:
            connection.execute(
                db.update(models.StopArea).values({
                    "admin_area_ref":
                    a["admin_area_ref"]
                }).where(models.StopArea.code == a["code"]))

        for area, areas in ambiguous.items():
            utils.logger.warning(f"Area {area}: ambiguous admin areas {areas}")
Esempio n. 4
0
def _replace_row(connection, model, element):
    """ Replaces values for rows in tables matching attributes from this
        element.

        :param connection: Connection for population.
        :param model: The database model class.
        :param element: A ``replace`` XML element.
        :returns: Number of rows replaced.
    """
    name = model.__name__
    if not element.keys():
        raise ValueError("Each <replace> element requires at least one XML "
                         "attribute to filter rows.")

    matching = connection.execute(
        db.select([model.__table__]).where(_match_attr(model, element.attrib)))
    matching_entries = matching.fetchall()
    if not matching_entries:
        logger.warning(f"{name}: No rows matching {element.attrib} found.")
        return 0

    updated_values = {}
    for value in element:
        column = value.tag
        old_value = value.get("old")
        new_value = value.text
        existing = set(getattr(r, column) for r in matching_entries)
        # Checks if new values already exist
        if existing == {new_value}:
            logger.warning(f"{name}: {column} {new_value!r} for "
                           f"{element.attrib} already matches.")
            continue
        # Gives a warning if set value does not match the existing
        # value, suggesting it may have been changed in the dataset
        if old_value and not all(e == old_value for e in existing):
            if len(existing) > 1:
                values = f"values {sorted(existing)}"
            else:
                values = f"value {next(iter(existing))!r}"
            logger.warning(f"{name}: {column} {old_value!r} for "
                           f"{element.attrib} does not match existing "
                           f"{values}.")
        updated_values[column] = new_value

    if updated_values:
        # Update matched entries
        update_matching = connection.execute(
            db.update(model).values(updated_values).where(
                _match_attr(model, element.attrib)))
        return update_matching.rowcount
    else:
        return 0
Esempio n. 5
0
def test_request_next_day(create_db):
    # Move the log to the previous day to test the count resetting
    statement = db.update(models.RequestLog).values(
        last_called=(models.RequestLog.last_called -
                     db.cast("1 day", db.Interval)),
        call_count=50,
    )
    db.session.execute(statement)

    log = models.RequestLog.query.one()
    assert log.call_count == 50

    assert models.RequestLog.call(5)
    assert log.call_count == 1