elex-clarity 0.0.9
A CLI for pulling in election results from Clarity
License: MIT

elex-clarity
============

.. image:: https://img.shields.io/pypi/v/elex-clarity.svg
    :target: https://pypi.org/project/elex-clarity/

.. image:: https://img.shields.io/pypi/pyversions/elex-clarity.svg
    :target: https://pypi.org/project/elex-clarity/

.. image:: https://circleci.com/gh/washingtonpost/elex-clarity.svg?style=shield
    :target: https://circleci.com/gh/washingtonpost/elex-clarity

.. image:: https://img.shields.io/pypi/l/elex-clarity.svg
    :target: https://pypi.python.org/pypi/elex-clarity/

A CLI tool for pulling in election results from sites using Clarity (the "election night reporting" product described `here <https://www.scytl.com/en/election-night-reporting/>`_). This package is hosted on pypi.

Please use the `Github issue tracker <https://github.com/washingtonpost/elex-clarity/issues>`_ to submit bugs or request features.

.. contents:: **Table of Contents**
    :depth: 1


Overview
------------

This library

* Provides a simple CLI tool for pulling in and formatting election results from a Clarity-backed website or local file
* Separates data retrieval from data formatting
* By default, returns results formatted like so

    .. code-block:: python

        {
            "2020-11-03_GA_G_P": {
                "id": "2020-11-03_GA_G_P",
                "source": "clarity",
                "precinctsReportingPct": 100.0,
                "counts": {
                    "donald_j_trump_i_rep": 2461837,
                    "joseph_r_biden_dem": 2474507,
                    "jo_jorgensen_lib": 62138
                },
                "office": "P",
                "lastUpdated": "2020-11-20T20:37:06Z",
                "subunits": {
                    "appling": {
                        "id": "appling",
                        "counts": {
                            "donald_j_trump_i_rep": 6526,
                            "joseph_r_biden_dem": 1779,
                            "jo_jorgensen_lib": 36
                        }
                    },
                    ...
                }
            }
        }


Installation
------------

* Make sure you have python 3.7+ installed
* Optional: we recommend that you set up a `virtualenv <http://virtualenvwrapper.readthedocs.io/en/latest/>`_ and activate it
* ``pip install elex-clarity``


Usage
---------

All CLI commands require a Clarity election ID and state postal code. For example

``elexclarity 105369 GA``

The election ID can be found by navigating to the election in question in whichever results site you're viewing. For example, for Georgia, the Secretary of State's website links to `election results <https://sos.ga.gov/page/georgia-election-results>`_. Following the `Current Election Results` link you get to a clarity page with many election results pages. Looking at the 2020-current results will lead to ``https://results.enr.clarityelections.com/GA/105369/web.264614/#/summary``, which contains the election ID right after the state postal code.

Other parameters
~~~~~~~~~~~~~~~~

.. list-table:: Title
   :header-rows: 1

   * - Name
     - Description
     - Type
     - Required?
     - Default
   * - style
     - what broad type of formatting should be done?
     - one of [default, raw]
     - N
     - default
   * - outputType
     - what specific type of formatting should be done?
     - one of [results, settings, summary]
     - N 
     - results
   * - level
     - what level of data should be fetched/returned?
     - one of [precinct, county, state]
     - N
     - county
   * - countyName
     - Name of county to get results from if counties have their own pages
     - string
     - N
     - --
   * - officeID
     - what office ID(s) should be returned?
     - a comma separated list of office IDs
     - N
     - --
   * - countyMapping
     - an object with race names (as provided via Clarity) mapped to some other identifier that should be used in results formatting. Sample formats can be found in the ``tests/fixtures`` `folder <https://github.com/washingtonpost/elex-clarity/tree/develop/tests/fixtures/mappings>`_
     - object
     - N
     - -- 
   * - voteCompletionMode
     - the method that should be used to determine whether a precinct is fully reporting 
     - string
     - N
     - percentReporting
   * - precinctsReportingPct
     - a county-level override for the precincts reprting percent that applies to all subunits, given as a mapping between county IDs and percents (does not change the value of the reportingStatus field)
     - object
     - N
     - --
   * - filename
     - the path to read results from (if you don't want to ping a Clarity site)
     - string
     - N
     - -- 


Example invocations
~~~~~~~~~~~~~~~~~~~

Retrieving raw data:

* ``elexclarity 105369 GA --outputType=summary --style=raw``
* ``elexclarity 105369 GA --outputType=settings --style=raw``
* ``elexclarity 105369 GA --level=precinct --style=raw``
* ``elexclarity 106043 CA --countyName Santa_Clara --level=precinct``

Retrieving + formatting settings (for presidential races):

* ``elexclarity 105369 GA --outputType=settings --officeID=P``

Retrieving + formatting results:

* ``elexclarity 105369 GA --level=precinct --countyMapping='{"Worth": "13321"}'``
* ``elexclarity 105369 GA --level=precinct``
* ``elexclarity 105369 GA --level=precinct --voteCompletionMode=voteTypes``
* ``elexclarity 105369 GA --level=county``
* ``elexclarity 106210 WV --level=county --countyMapping='<mapping json>'``
* ``elexclarity 105369 WV --level=state``

Formatting data from a local file:

* ``elexclarity 105369 GA --level=precinct --filename="tests/fixtures/results/ga_atkinson_precincts_11-3.xml" --countyMapping='<mapping json>'``
* ``elexclarity 105369 GA --level=county --filename="tests/fixtures/ga_counties_11-3.xml" --countyMapping='<mapping json>'``

Development
------------

* Clone this repository
* ``pip install -r requirements.txt``
* ``tox``
* You should see some code coverage info and test results
* If the above was successful, you are ready for development

Releasing a New Version
------------------------

In preparation for a new release:

* Decide what the next version will be per semantic versioning
* Make a new branch named ``release/<version number>``
* Update the changelog with all changes that will be included in the release
* Commit your changes and make a PR against ``main``
* Once the changes are merged, tag ``main`` (or ``develop`` for a beta release) with the release's version number and push that tag (``git push --tags``)
* Merge ``main`` into ``develop``