- a `Path` is a better description for an instance of the model
- the `Location`s en route are renamed into `.waypoints`
- generic `assoc` is renamed into `path` in the test suite
- as of September 2021, PyCharm is used to write some of the code
- PyCharm's built-in code styler, linter, and type checker issued
some warnings that are resolved in this commit
+ spelling mistakes
+ all instance attributes must be specified explicitly
in a class's __init__() method
=> use `functools.cached_property` for caching
+ make `tuple`s explicit with `(...)`
+ one test failed randomly although everything is ok
=> adjust the fixture's return value (stub for Google Directions API)
+ reformulate SQL so that PyCharm can understand the symbols
- `DistanceMatrix.from_addresses()` takes a variable number of
`Address` objects and creates distance matrix entries for them
- as a base measure, the air distance between two `Address`
objects is calculated
- in addition, an integration with the Google Maps Directions API is
implemented that provides a more realistic measure of the distance
and duration a rider on a bicycle would need to travel between two
`Address` objects
- add a `Location.lat_lng` convenience property that provides the
`.latitude` and `.longitude` of an `Address` as a 2-`tuple`
- the class stores the data of a distance matrix between all addresses
+ air distances
+ bicycle distances
- in addition, the "path" returned by the Google Directions API are
also stored as a JSON serialized sequence of latitude-longitude pairs
- we assume a symmetric graph
- ensure a `Restaurant` only has one unique `Order.pickup_address`
- rework `Grid.gridify()` so that only pickup addresses are assigned
into `Pixel`s
- include database migrations to ensure the data adhere to these
tighter constraints
- add `.low80`, `.high80`, `.low95`, and `.high95` columns
- add check contraints for the confidence intervals
- rename the `.method` column into `.model` for consistency
- the main purpose of this class is to manage querying the order totals
from the database and slice various kinds of time series out of the
data
- the class holds the former `aggregate_orders()` function as a method
- modularize the corresponding tests
- add `tests.config` with globals used when testing to provide a
single source of truth for various settings
- the function queries the database and aggregates the ad-hoc orders
by pixel and time steps into a demand time series
- implement "heavy" integration tests for `aggregate_orders()`
- make `pandas` a package dependency
- streamline the `Config`
- reorganize `urban_meal_delivery.console` into a sub-package
- move `tests.db.conftest` fixtures into `tests.conftest`
=> some integration tests regarding CLI scripts need a database
- add `urban_meal_delivery.console.decorators.db_revision` decorator
to ensure the database is at a certain state before a CLI script runs
- refactor the `urban_meal_delivery.db.grids.Grid.gridify()` constructor:
- bug fix: even empty `Pixel`s end up in the database temporarily
=> create `Pixel` objects only if an `Address` is to be assigned
to it
- streamline code and docstring
- add further test cases
- the purpose of this constructor method is to generate all `Pixel`s
for a `Grid` that have at least one `Address` assigned to them
- fix missing `UniqueConstraint` in `Grid` class => it was not possible
to create two `Grid`s with the same `.side_length` in different cities
- change the `City.viewport` property into two separate `City.southwest`
and `City.northeast` properties; also add `City.total_x` and
`City.total_y` properties for convenience
- the old `UTMCoordinate` class becomes the new `Location` class
- its main purpose is to represent locations in both lat-long
coordinates as well as in the UTM system
- remove `Address.__init__()` and `City.__init__()` methods as they
are not executed for entries retrieved from the database
- simplfiy the `Location.__init__()` => remove `relative_to` argument
- remove the factory functions for creating engines and sessions
- define global engine, connection, and session objects to be used
everywhere in the urban_meal_delivery package
- add Grid, Pixel, and AddressPixelAssociation ORM models
- each Grid belongs to a City an is characterized by the side_length
of all the square Pixels contained in it
- Pixels aggregate Addresses => many-to-many relationship (that is
modeled with SQLAlchemy's Association Pattern to implement a couple
of constraints)
- the Address.x and Address.y properties use the UTMCoordinate class
behind the scenes
- x and y are simple coordinates in an x-y plane
- the (0, 0) origin is the southwest corner of Address.city.viewport
- the class is a utility to abstract working with latitude-longitude
coordinates in their UTM representation (~ "cartesian plane")
- the class's .x and .y properties enable working with simple x-y
coordinates where the (0, 0) origin is the lower-left of a city's
viewport
- create `*Factory` classes with fakerboy and faker that generate
randomized instances of the ORM models
- add new pytest marker: "db" are the integration tests involving the
database whereas "e2e" will be all other integration tests
- streamline the docstrings in the ORM models
- use Alembic to migrate the PostgreSQL database
+ create initial migration script to set up the database,
as an alternative to db.Base.metadata.create_all()
+ integrate Alembic into the test suite; the db_engine fixture
now has two modes:
* create the latest version of tables all at once
* invoke `alembic upgrade head`
=> the "e2e" tests are all run twice, once in each mode; this
ensures that the migration scripts re-create the same database
schema as db.Base.metadata.create_all() would
* in both modes, a temporary PostgreSQL schema is used to create the
tables in
=> could now run "e2e" tests against production database and still
have isolation
- make the configuration module public (to be used by Alembic)
- adjust linting rules for Alembic
- use SQLAlchemy (and PostgreSQL) to model the ORM layer
- add the following models:
+ Address => modelling all kinds of addresses
+ City => model the three target cities
+ Courier => model the UDP's couriers
+ Customer => model the UDP's customers
+ Order => model the orders received by the UDP
+ Restaurant => model the restaurants active on the UDP
- so far, the emphasis lies on expression the Foreign Key
and Check Constraints that are used to validate the assumptions
inherent to the cleanded data
- provide database-independent unit tests with 100% coverage
- provide additional integration tests ("e2e") that commit data to
a PostgreSQL instance to validate that the constraints work
- adapt linting rules a bit