Skip to content

Commit

Permalink
Merge branch 'minimal' into resilient_slug
Browse files Browse the repository at this point in the history
  • Loading branch information
fgregg committed Dec 20, 2023
2 parents 1302790 + ee8eaed commit 4006e51
Show file tree
Hide file tree
Showing 281 changed files with 1,918 additions and 89,820 deletions.
10 changes: 10 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[flake8]
exclude =
venv,
**/migrations/*
tests/test_config*

# So flake8 plays nicely with black
# https://black.readthedocs.io/en/stable/guides/using_black_with_other_tools.html
max-line-length = 120
extend-ignore = E203
75 changes: 35 additions & 40 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@

# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Python package

on: [push]
on:
push:
branches:
- master
- 2.5
- 3.x
pull_request:
workflow_dispatch:

jobs:
build:

test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]

services:
postgres:
image: postgis/postgis:9.6-2.5
image: postgis/postgis:14-3.2
env:
POSTGRES_DB: django_councilmatic
POSTGRES_PASSWORD: postgres
Expand All @@ -25,35 +31,24 @@ jobs:
- 5432:5432

steps:
- name: System dependencies
run: |
sudo apt-get update
sudo apt-get install gdal-bin
- uses: actions/checkout@v2
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
# Semantic version range syntax or exact version of a Python version
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/requirements.txt
pip install -e .
- name: Lint with flake8
run: |
flake8 ./councilmatic_core/*.py
- name: Test with pytest
run: |
pytest -sv
- name: Build and publish
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
pip install twine wheel
pip wheel -w dist --no-deps .
python setup.py sdist
twine upload dist/*
continue-on-error: true
- name: System dependencies
run: |
sudo apt-get update
sudo apt-get install gdal-bin libreoffice unoconv nodejs
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r tests/requirements.txt
pip install -e .
npm install --legacy-peer-deps
- name: Test with pytest
run: |
flake8 councilmatic_core tests --exclude councilmatic_core/migrations
black --check councilmatic_core tests --exclude councilmatic_core/migrations
npx eslint councilmatic_core/static/js/*.js
pytest -sxv
25 changes: 25 additions & 0 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Publish to PyPI

on: push

jobs:
build-and-publish:
name: Publish to PyPI
if: startsWith(github.event.ref, 'refs/tags')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@main
- name: Set up Python 3.11
uses: actions/setup-python@v2
with:
python-version: 3.11
- name: Publish to PyPI
env:
TWINE_USERNAME: "__token__"
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
pip install twine wheel
pip wheel -w dist --no-deps .
python setup.py sdist
twine upload --skip-existing dist/*
continue-on-error: true
16 changes: 16 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
repos:
# Black config (Python formatter)
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
exclude: ^(councilmatic_core/migrations/)

# Flake8 config (Python linter)
# See ./.flake8 for additional configs
- repo: https://github.com/pycqa/flake8
rev: "9f60881"
hooks:
- id: flake8
args: [--config=.flake8]

4 changes: 0 additions & 4 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
include LICENSE
include README.rst
recursive-include councilmatic_core/static *
recursive-include councilmatic_core/templates *
recursive-include councilmatic_core/migrations *
recursive-include councilmatic_core/management *
recursive-include councilmatic_core/templatetags *

141 changes: 33 additions & 108 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,108 +1,33 @@
django-councilmatic
===================

The django-councilmatic app provides the core functionality for the `Councilmatic family <http://www.councilmatic.org/>`_, a set of web apps for keeping tabs on local city council. It is built upon the Open Civic Data standard and ultimately makes Councilmatic easier to re-deploy in new cities.


Features
--------

- Models for bills, people, organizations, events, and more
- Base views for Bill, Person, Organization, and Event listing and detail pages
- Search infrastructure powered by :code:`django-haystack` and Solr

The `Councilmatic family <http://www.councilmatic.org/>`_ includes:

- Philly Councilmatic (the original and first Councilmatic, by Mjumbe Poe, an important predecessor to DataMade's django-councilmatic)
- `Chicago Councilmatic <https://github.com/datamade/chi-councilmatic>`_
- `New York City Councilmatic <https://github.com/datamade/nyc-councilmatic>`_
- `Los Angeles Metro Board <https://github.com/datamade/la-metro-councilmatic>`_


Councilmatic in your city
-------------------------
If you're interested in bringing Councilmatic to your city, `contact us <mailto:[email protected]>`_! We'd love to help.

Want to build your own Councilmatic? Check out our `Starter Template <https://github.com/datamade/councilmatic-starter-template>`_. It contains everything you need to create your own Councilmatic from scratch.


Extending Open Civic Data/Councilmatic models
---------------------------------------------

django-councilmatic leverages, and in some instaances, lightly extends the Open Civic Data Standard, implemented in Django as :code:`python-opencivicdata`. If you'd like to add additional attributes or Python properties to your models, there are two approaches to be aware of: subclassing and proxying.

Subclassing
===========

Leverage `multi-table inheritance <https://docs.djangoproject.com/en/2.2/topics/db/models/#multi-table-inheritance>`_ to add additional fields to OCD models. The primary use case in django-councilmatic is adding slugs to first-class models – Person, Event, Bill, and Organization - and adding metadata outside of the OCD standard, e.g., a headshot to Person and division boundaries to Post.

We recommend using :code:`pupa` to scrape legislative data. Since :code:`pupa` creates OCD objects, `django-councilmatic includes Django signals <https://github.com/datamade/django-councilmatic/pull/240/files#diff-97cdca8c3c4b594b1991875f343b7db5>`_ to each of the subclassed models to create the related Councilmatic model on save. It also includes management commands to import metadata (see above).

If you subclass a model, be sure to include a signal to create instances of your subclass when the parent class is created, and, if applicable, some way to add any metadata, e.g., a management command or admin interface.

Proxying
========

django-councilmatic makes extensive use of proxy models to add custom managers and additional properties and methods to model classes. In order to take advantage of these elsewhere in the code, it is desirable for related objects to be returned as instances of other proxy classes or subclasses, rather than the upstream OCD model classes. In order to force related objects to be returned as Councilmatic models, django-councilmatic makes use of `django-proxy-overrides <https://github.com/datamade/django-proxy-overrides>`_.

If you wish to customize the class of related objects, first proxy an OCD model, then override one or more of its related object attributes with an instance of `ProxyForeignKey`. See `councilmatic_core.models.BillAction <https://github.com/datamade/django-councilmatic/blob/449ff74d3968b0f34016698d4ee89ff50a7b33ef/councilmatic_core/models.py#L612>`_ for an example.


Running tests
-------------

Did you make changes to django-councilmatic? Before you make a pull request, run some tests.

First, install the test requirements:

.. code-block:: bash
pip install -r tests/requirements.txt
We test for style with `flake8 <http://flake8.pycqa.org/en/latest/>`_:

.. code-block:: bash
flake8 ./councilmatic_core/*.py
We test for functionality with `pytest`:

.. code-block:: bash
pytest
If you made material changes to the Councilmatic models, refresh the test fixture from a local instance database. From your instance directory (assuming you've already installed :code:`django-councilmatic` with :code:`pip install -e /path/to/django-councilmatic`), install the test requirements:

.. code-block:: bash
pip install -r /path/to/django-councilmatic/tests/test_requirements.txt
Add :code:`fixture_magic` to your instance's :code:`INSTALLED_APPS` in :code:`settings.py`.

Run the management command to update the test fixture.

.. code-block:: bash
python manage.py make_fixtures
Run the tests and commit your updated fixture with your PR!


Patches and Contributions
-------------------------
We continue to improve django-councilmatic, and we welcome your ideas! You can make suggestions in the form of `github issues <https://github.com/datamade/django-councilmatic/issues>`_ (bug reports, feature requests, general questions), or you can submit a code contribution via a pull request.

How to contribute code:

- Fork the project.
- Make your feature addition or bug fix.
- Bonus points for running tests to check python style (:code:`pip install flake8` and then :code:`flake8 .`).
- Send us a pull request with a description of your work! Don't worry if it isn't perfect - think of a PR as a start of a conversation, rather than a finished product.


Copyright
---------

Copyright (c) 2019 Participatory Politics Foundation and DataMade.
Released under the `MIT
License <https://github.com/datamade/django-councilmatic/blob/master/LICENSE>`__.
django-councilmatic
===================

The django-councilmatic app provides the core models for the `Councilmatic family <http://www.councilmatic.org/>`_, a set of web apps for keeping tabs on local city council.

Extending Open Civic Data/Councilmatic models
---------------------------------------------

django-councilmatic leverages, and in some instaances, lightly extends the Open Civic Data Standard, implemented in Django as :code:`python-opencivicdata`. If you'd like to add additional attributes or Python properties to your models, there are two approaches to be aware of: subclassing and proxying.

Subclassing
===========

Leverage `multi-table inheritance <https://docs.djangoproject.com/en/2.2/topics/db/models/#multi-table-inheritance>`_ to add additional fields to OCD models. The primary use case in django-councilmatic is adding slugs to first-class models – Person, Event, Bill, and Organization - and adding metadata outside of the OCD standard, e.g., a headshot to Person and division boundaries to Post.

We recommend using :code:`pupa` to scrape legislative data. Since :code:`pupa` creates OCD objects, `django-councilmatic includes Django signals <https://github.com/datamade/django-councilmatic/pull/240/files#diff-97cdca8c3c4b594b1991875f343b7db5>`_ to each of the subclassed models to create the related Councilmatic model on save. It also includes management commands to import metadata (see above).

If you subclass a model, be sure to include a signal to create instances of your subclass when the parent class is created, and, if applicable, some way to add any metadata, e.g., a management command or admin interface.

Proxying
========

django-councilmatic makes extensive use of proxy models to add custom managers and additional properties and methods to model classes. In order to take advantage of these elsewhere in the code, it is desirable for related objects to be returned as instances of other proxy classes or subclasses, rather than the upstream OCD model classes. In order to force related objects to be returned as Councilmatic models, django-councilmatic makes use of `django-proxy-overrides <https://github.com/datamade/django-proxy-overrides>`_.

If you wish to customize the class of related objects, first proxy an OCD model, then override one or more of its related object attributes with an instance of `ProxyForeignKey`. See `councilmatic_core.models.BillAction <https://github.com/datamade/django-councilmatic/blob/449ff74d3968b0f34016698d4ee89ff50a7b33ef/councilmatic_core/models.py#L612>`_ for an example.


Copyright
---------

Copyright (c) 2023 Participatory Politics Foundation and DataMade.
Released under the `MIT
License <https://github.com/datamade/django-councilmatic/blob/master/LICENSE>`__.
Loading

0 comments on commit 4006e51

Please sign in to comment.