Full Code of datamade/census for AI

master c64202b56490 cached
14 files
46.0 KB
12.7k tokens
95 symbols
1 requests
Download .txt
Repository: datamade/census
Branch: master
Commit: c64202b56490
Files: 14
Total size: 46.0 KB

Directory structure:
gitextract_87spxlep/

├── .github/
│   └── workflows/
│       └── python-package.yml
├── .gitignore
├── CITATION.cff
├── LICENSE
├── MANIFEST.in
├── README.rst
├── census/
│   ├── __init__.py
│   ├── core.py
│   └── tests/
│       ├── __init__.py
│       └── test_census.py
├── pyproject.toml
├── requirements.txt
├── setup.cfg
└── setup.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/python-package.yml
================================================
# 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:
    branches: [ master ]
    tags:
      - v*
  pull_request:
    branches: [ master ]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install flake8 pytest
    - name: Install package
      run: pip install .
    - name: Lint with flake8
      run: |
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
    - name: Test with pytest
      run: |
        pytest

  publish:
    needs: test
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.12
      uses: actions/setup-python@v4
      with:
        python-version: 3.12
    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
      run: |
        pip install setuptools twine wheel
        pip wheel -w dist --no-deps .
        python setup.py sdist
        twine upload dist/*


================================================
FILE: .gitignore
================================================
*.pyc
.DS_Store
.env
.cache/
.tox/
build/


================================================
FILE: CITATION.cff
================================================
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
authors:
- family-names: "Carbaugh"
  given-names: "Jeremy"
- family-names: "Gregg"
  given-names: "Forest"
- name: "Contributors"
title: "census"
version: 0.8.26
date-released: 2026-02-07
url: "https://github.com/datamade/census"


================================================
FILE: LICENSE
================================================
Copyright (c) 2012, Sunlight Labs; 2017, DataMade

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of Sunlight Labs or DataMade nor the names of its contributors may be
      used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

================================================
FILE: MANIFEST.in
================================================
include LICENSE *.rst *.py

================================================
FILE: README.rst
================================================
======
census
======
.. image:: https://github.com/datamade/census/workflows/Python%20package/badge.svg
 

A simple wrapper for the United States Census Bureau's API.

Provides access to ACS and SF1 data sets.

Install
=======

::

    pip install census

You may also want to install a complementary library, `us <https://pypi.python.org/pypi/us>`_, which help you figure out the
`FIPS <https://en.wikipedia.org/wiki/Federal_Information_Processing_Standard_state_code>`_ codes for many geographies. We use it in the examples below.

::

   pip install us

Usage
=====

First, get yourself a `Census API key <https://api.census.gov/data/key_signup.html>`_.

::

    from census import Census
    from us import states

    c = Census("MY_API_KEY")
    c.acs5.get(('NAME', 'B25034_010E'),
              {'for': 'state:{}'.format(states.MD.fips)})

The call above will return the name of the geographic area and the number of
homes that were built before 1939 for the state of Maryland. Helper methods have
been created to simplify common geometry calls::

    c.acs5.state(('NAME', 'B25034_010E'), states.MD.fips)

Full details on geometries and the states module can be found below.

The get method is the core data access method on both the ACS and SF1 data sets.
The first parameter is either a single string column or a tuple of columns. The
second parameter is a geoemtry dict with a `for` key and on option `in` key. The
`for` argument accepts a `"*"` wildcard character or `Census.ALL`. The wildcard
is not valid for the `in` parameter.

By default, the year for a dataset is the most recent year available. To access earlier data,
pass a year parameter to the API call::

    c.acs5.state(('NAME', 'B25034_010E'), states.MD.fips, year=2010)

The default year may also be set client-wide::

    c = Census("MY_API_KEY", year=2010)


Detailed information about the API can be found at the `Census Data API User Guide <https://www.census.gov/data/developers/guidance/api-user-guide.html>`_.

Datasets
========

For each dataset, the first year listed is the default.

* acs5: `ACS 5 Year Estimates <https://www.census.gov/data/developers/data-sets/acs-5year.html>`_ (2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009)
* acs3: `ACS 3 Year Estimates <https://www.census.gov/data/developers/data-sets/acs-3year.html>`_ (2013, 2012)
* acs1: `ACS 1 Year Estimates <https://www.census.gov/data/developers/data-sets/acs-1year.html>`_ (2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011)
* acs5dp: `ACS 5 Year Estimates, Data Profiles  <https://www.census.gov/data/developers/data-sets/acs-5year.html>`_ (2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009)
* acs3dp: `ACS 3 Year Estimates, Data Profiles <https://www.census.gov/data/developers/data-sets/acs-3year.html>`_ (2013, 2012)
* acs1dp: `ACS 1 Year Estimates, Data Profiles <https://www.census.gov/data/developers/data-sets/acs-1year.html>`_ (2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011)
* acs5st: `ACS 5 Year Estimates, Subject Tables <https://www.census.gov/data/developers/data-sets/acs-5year.html>`_ (2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009)
* sf1: `Census Summary File 1 <https://www.census.gov/data/datasets/2010/dec/summary-file-1.html>`_ (2010)
* pl: `Redistricting Data Summary File <https://www.census.gov/programs-surveys/decennial-census/about/rdo/summary-files.2020.html>`_ (2020, 2010, 2000) 


Geographies
===========

The API supports a wide range of geographic regions. The specification of these
can be quite complicated so a number of convenience methods are provided. Refer to the `Census API documentation <https://www.census.gov/data/developers/guidance/api-user-guide.html>`_
for more geographies beyond the convenience methods.

*Not all geographies are supported in all years. Calling a convenience method
with a year that is not supported will raise census.UnsupportedYearException.*

`Geographic relationship files <https://www.census.gov/geo/maps-data/data/relationship.html>`_ are provided on the Census developer site as a tool to help users compare the geographies from the 1990, 2000 and 2010 Censuses. From these files, data users may determine how geographies from one Census relate to those from the prior Census.

ACS5 Geographies
----------------

* state(fields, state_fips)
* state_county(fields, state_fips, county_fips)
* state_county_blockgroup(fields, state_fips, county_fips, blockgroup)
* state_county_subdivision(fields, state_fips, county_fips, subdiv_fips)
* state_county_tract(fields, state_fips, county_fips, tract)
* state_place(fields, state_fips, place)
* state_congressional_district(fields, state_fips, congressional_district)
* state_legislative_district_upper(fields, state_fips, legislative_district)
* state_legislative_district_lower(fields, state_fips, legislative_district)
* us(fields)
* state_zipcode(fields, state_fips, zip5)

ACS1 Geographies
----------------

* state(fields, state_fips)
* state_congressional_district(fields, state_fips, district)
* us(fields)

SF1 Geographies
---------------

* state(fields, state_fips)
* state_county(fields, state_fips, county_fips)
* state_county_subdivision(fields, state_fips, county_fips, subdiv_fips)
* state_county_tract(fields, state_fips, county_fips, tract)
* state_place(fields, state_fips, place)
* state_congressional_district(fields, state_fips, district)
* state_msa(fields, state_fips, msa)
* state_csa(fields, state_fips, csa)
* state_district_place(fields, state_fips, district, place)
* state_zipcode(fields, state_fips, zip5)

PL Geographies
--------------

* state(fields, state_fips)
* state_county(fields, state_fips, county_fips)
* state_county_subdivision(fields, state_fips, county_fips, subdiv_fips)
* state_county_tract(fields, state_fips, county_fips, tract)
* state_county_blockgroup(fields, state_fips, county_fips, blockgroup)
* state_place(fields, state_fips, place)
* state_congressional_district(fields, state_fips, district)
* state_legislative_district_upper(fields, state_fips, legislative_district)
* state_legislative_district_lower(fields, state_fips, legislative_district)

States
======

This package previously had a `census.states` module, but now uses the
*us* package. ::

    >>> from us import states
    >>> print states.MD.fips
    u'24'

Convert FIPS to state abbreviation using `lookup()`: ::

    >>> print states.lookup('24').abbr
    u'MD'


BYOS - Bring Your Own Session
=============================

If you'd prefer to use a custom configured requests.Session, you can pass it
to the Census constructor::

    s = requests.session()
    s.headers.update({'User-Agent': 'census-demo/0.0'})

    c = Census("MY_API_KEY", session=s)

You can also replace the session used by a specific data set::

    c.sf1.session = s


Examples
========

The geographic name for all census tracts for county 170 in Alaska::

    c.sf1.get('NAME', geo={'for': 'tract:*',
                           'in': 'state:{} county:170'.format(states.AK.fips)})

The same call using the `state_county_tract` convenience method::

    c.sf1.state_county_tract('NAME', states.AK.fips, '170', Census.ALL)

Total number of males age 5 - 9 for all states::

    c.acs5.get('B01001_004E', {'for': 'state:*'})

The same call using the state convenience method::

    c.acs5.state('B01001_004E', Census.ALL)

Don't know the list of tables in a survey, try this:

    c.acs5.tables()


================================================
FILE: census/__init__.py
================================================
from census.core import (Census, ALL, CensusException,
                         UnsupportedYearException)


================================================
FILE: census/core.py
================================================
import warnings
from functools import wraps, lru_cache
from importlib.metadata import version

__version__ = version('census')

ALL = '*'


def new_session(*args, **kwargs):
    import requests
    return requests.session(*args, **kwargs)


class APIKeyError(Exception):
    """ Invalid API key
    """

    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)


def list_or_str(v):
    """ Convert a single value into a list.
    """
    if isinstance(v, (list, tuple)):
        return v
    return [v]


def float_or_str(v):
    try:
        return float(v)
    except ValueError:
        return str(v)


def supported_years(*years):
    def inner(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            year = kwargs.get('year', self.default_year)
            _years = years if years else self.years
            if int(year) not in _years:
                raise UnsupportedYearException(
                    'Geography is not available in {}. Available years include {}'.format(year, _years))
            return func(self, *args, **kwargs)
        return wrapper
    return inner


def retry_on_transient_error(func):

    def wrapper(self, *args, **kwargs):
        for _ in range(max(self.retries - 1, 0)):
            try:
                result = func(self, *args, **kwargs)
            except CensusException as e:
                if "There was an error while running your query.  We've logged the error and we'll correct it ASAP.  Sorry for the inconvenience." in str(e):
                    pass
                else:
                    raise
            else:
                return result
        else:
            return func(self, *args, **kwargs)

    return wrapper


def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]


def merge(dicts):
    return dict(item for d in dicts for item in d.items())


class CensusException(Exception):
    pass


class UnsupportedYearException(CensusException):
    pass


class Client(object):
    endpoint_url = 'https://api.census.gov/data/%s/%s'
    definitions_url = 'https://api.census.gov/data/%s/%s/variables.json'
    definition_url = 'https://api.census.gov/data/%s/%s/variables/%s.json'
    groups_url = 'https://api.census.gov/data/%s/%s/groups.json'

    def __init__(self, key, year=None, session=None, retries=3):
        self._key = key
        self.session = session or new_session()
        if year:
            self.default_year = year
        self.retries = retries

    def tables(self, year=None):
        """
        Returns a list of the data tables available from this source.
        """
        # Set the default year if one hasn't been passed
        if year is None:
            year = self.default_year

        # Query the table metadata as raw JSON
        tables_url = self.groups_url % (year, self.dataset)
        resp = self.session.get(tables_url)

        # Pass it out
        return resp.json()['groups']

    @supported_years()
    def fields(self, year=None, flat=False):
        if year is None:
            year = self.default_year

        data = {}

        fields_url = self.definitions_url % (year, self.dataset)

        resp = self.session.get(fields_url)
        obj = resp.json()

        if flat:

            for key, elem in obj['variables'].items():
                if key in ['for', 'in']:
                    continue
                data[key] = "{}: {}".format(elem['concept'], elem['label'])

        else:

            data = obj['variables']
            if 'for' in data:
                data.pop("for", None)
            if 'in' in data:
                data.pop("in", None)

        return data

    def get(self, fields, geo, year=None, **kwargs):
        """
        The API only accepts up to 50 fields on each query.
        Chunk requests, and use the unique GEO_ID to match up the chunks
        in case the responses are in different orders.
        GEO_ID is not reliably present in pre-2010 requests.
        """
        sort_by_geoid = len(fields) > 49 and (not year or year > 2009)
        all_results = (self.query(forty_nine_fields, geo, year, sort_by_geoid=sort_by_geoid, **kwargs)
                       for forty_nine_fields in chunks(fields, 49))
        merged_results = [merge(result) for result in zip(*all_results)]

        return merged_results

    @retry_on_transient_error
    def query(self, fields, geo, year=None, sort_by_geoid=False, **kwargs):
        if year is None:
            year = self.default_year

        fields = list_or_str(fields)
        if sort_by_geoid:
            if isinstance(fields, list):
                fields += ['GEO_ID']
            elif isinstance(fields, tuple):
                fields += ('GEO_ID',)

        url = self.endpoint_url % (year, self.dataset)

        params = {
            'get': ",".join(fields),
            'for': geo['for'],
            'key': self._key,
        }

        if 'in' in geo:
            params['in'] = geo['in']

        resp = self.session.get(url, params=params)

        if resp.status_code == 200:
            try:
                data = resp.json()
            except ValueError as ex:
                if '<title>Invalid Key</title>' in resp.text:
                    raise APIKeyError(' '.join(resp.text.splitlines()))
                else:
                    raise ex

            headers = data.pop(0)
            types = [self._field_type(header, year) for header in headers]
            results = [{header: (cast(item) if item is not None else None)
                        for header, cast, item
                        in zip(headers, types, d)}
                       for d in data]
            if sort_by_geoid:
                if 'GEO_ID' in fields:
                    results = sorted(results, key=lambda x: x['GEO_ID'])
                else:
                    results = sorted(results, key=lambda x: x.pop('GEO_ID'))
            return results

        elif resp.status_code == 204:
            return []

        else:
            raise CensusException(resp.text)

    @lru_cache(maxsize=1024)
    def _field_type(self, field, year):
        url = self.definition_url % (year, self.dataset, field)
        resp = self.session.get(url)

        types = {"fips-for": str,
                 "fips-in": str,
                 "int": float_or_str,
                 "long": float_or_str,
                 "float": float,
                 "string": str}

        if resp.status_code == 200:
            predicate_type = resp.json().get("predicateType", "string")
            return types[predicate_type]
        else:
            return str

    @supported_years()
    def us(self, fields, **kwargs):
        return self.get(fields, geo={'for': 'us:1'}, **kwargs)

    @supported_years()
    def state(self, fields, state_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years()
    def state_county(self, fields, state_fips, county_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county:{}'.format(county_fips),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years()
    def state_place(self, fields, state_fips, place, **kwargs):
        return self.get(fields, geo={
            'for': 'place:{}'.format(place),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years()
    def state_district(self, fields, state_fips, district, **kwargs):
        warnings.warn(
            "state_district refers to congressional districts; use state_congressional_district instead",
            DeprecationWarning
        )

        # throwaway, but we can't pass it in twice.
        kwargs.pop('congressional_district', None)

        return self.state_congressional_district(fields, state_fips, district, **kwargs)

    @supported_years()
    def state_congressional_district(self, fields, state_fips, congressional_district, **kwargs):
        return self.get(fields, geo={
            'for': 'congressional district:{}'.format(congressional_district),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years()
    def state_legislative_district_upper(self, fields, state_fips, legislative_district, **kwargs):
        return self.get(fields, geo={
            'for': 'state legislative district (upper chamber):{}'.format(str(legislative_district).zfill(3)),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years()
    def state_legislative_district_lower(self, fields, state_fips, legislative_district, **kwargs):
        return self.get(fields, geo={
            'for': 'state legislative district (lower chamber):{}'.format(str(legislative_district).zfill(3)),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)
    @supported_years()
    def combined_statistical_area(self, fields, csa, **kwargs):
        return self.get(fields, geo={
            'for': 'combined statistical area:{}'.format(str(csa)),
        }, **kwargs)
    
    @supported_years()
    def msa(self, fields, msa, **kwargs):
        return self.get(fields, geo={
            'for': ('metropolitan statistical area/' +
                'micropolitan statistical area:{}'.format(msa)), 
        }, **kwargs)

class ACSClient(Client):

    def _switch_endpoints(self, year):

        if year >= 2005:
            self.endpoint_url = 'https://api.census.gov/data/%s/acs/%s'
            self.definitions_url = 'https://api.census.gov/data/%s/acs/%s/variables.json'
            self.definition_url = 'https://api.census.gov/data/%s/acs/%s/variables/%s.json'
            self.groups_url = 'https://api.census.gov/data/%s/acs/%s/groups.json'
        else:
            self.endpoint_url = super(ACSClient, self).endpoint_url
            self.definitions_url = super(ACSClient, self).definitions_url
            self.definition_url = super(ACSClient, self).definition_url
            self.groups_url = super(ACSClient, self).groups_url

    def tables(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))
        return super(ACSClient, self).tables(*args, **kwargs)

    def get(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))

        return super(ACSClient, self).get(*args, **kwargs)


class ACS5Client(ACSClient):

    default_year = 2024
    dataset = 'acs5'

    years = (2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009)

    @supported_years()
    def state_county_subdivision(self, fields, state_fips,
                                 county_fips, subdiv_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county subdivision:{}'.format(subdiv_fips),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_tract(self, fields, state_fips,
                           county_fips, tract, **kwargs):
        return self.get(fields, geo={
            'for': 'tract:{}'.format(tract),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_blockgroup(self, fields, state_fips, county_fips,
                                blockgroup, tract=None, **kwargs):
        geo = {
            'for': 'block group:{}'.format(blockgroup),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }
        if tract:
            geo['in'] += ' tract:{}'.format(tract)
        return self.get(fields, geo=geo, **kwargs)

    @supported_years(2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011)
    def zipcode(self, fields, zcta, **kwargs):
        warnings.warn(
            "zipcode has been deprecated; use state_zipcode instead",
            DeprecationWarning
        )

        state_fips = kwargs.pop('state_fips')

        return self.state_zipcode(fields, state_fips, zcta, **kwargs)

    @supported_years(2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011)
    def state_zipcode(self, fields, state_fips, zcta, **kwargs):
        year = kwargs.get('year', self.default_year)
        geo = {
            'for': 'zip code tabulation area:{}'.format(zcta),
        }
        # for 2020 onward, we need to use "regionin" instead of "in" due to ZCTA's being nested under states 
        if year < 2020:
            geo["in"] = 'state:{}'.format(state_fips)
        else:
            geo["regionin"] = 'state:{}'.format(state_fips)
        return self.get(fields, geo, **kwargs)


class ACS5DpClient(ACS5Client):

    dataset = 'acs5/profile'


class ACS5StClient(ACS5Client):
    def _switch_endpoints(self, year):
        self.endpoint_url = 'https://api.census.gov/data/%s/acs/%s'
        self.definitions_url = 'https://api.census.gov/data/%s/acs/%s/variables.json'
        self.definition_url = 'https://api.census.gov/data/%s/acs/%s/variables/%s.json'
        self.groups_url = 'https://api.census.gov/data/%s/acs/%s/groups.json'

    dataset = 'acs5/subject'


class ACS3Client(ACSClient):

    default_year = 2013
    dataset = 'acs3'

    years = (2013, 2012)

    @supported_years()
    def state_county_subdivision(self, fields, state_fips,
                                 county_fips, subdiv_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county subdivision:{}'.format(subdiv_fips),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)


class ACS3DpClient(ACS3Client):

    dataset = 'acs3/profile'


class ACS1Client(ACSClient):

    default_year = 2024
    dataset = 'acs1'

    years = (2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012, 2011, 2010, 2009, 2008, 2007, 2006, 2005)

    @supported_years()
    def state_county_subdivision(self, fields, state_fips,
                                 county_fips, subdiv_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county subdivision:{}'.format(subdiv_fips),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)


class ACS1DpClient(ACS1Client):

    dataset = 'acs1/profile'

    years = (2024, 2023, 2022, 2021, 2019, 2018, 2017, 2016, 2015, 2014, 2013, 2012)


class SF1Client(Client):

    default_year = 2010
    dataset = 'sf1'

    years = (2010,)

    def _switch_endpoints(self, year):

        self.endpoint_url = 'https://api.census.gov/data/%s/dec/%s'
        self.definitions_url = 'https://api.census.gov/data/%s/dec/%s/variables.json'
        self.definition_url = 'https://api.census.gov/data/%s/dec/%s/variables/%s.json'
        self.groups_url = 'https://api.census.gov/data/%s/dec/%s/groups.json'

    def tables(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))
        return super(SF1Client, self).tables(*args, **kwargs)

    def get(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))

        return super(SF1Client, self).get(*args, **kwargs)

    @supported_years()
    def state_county_subdivision(self, fields, state_fips,
                                 county_fips, subdiv_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county subdivision:{}'.format(subdiv_fips),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_tract(self, fields, state_fips,
                           county_fips, tract, **kwargs):
        return self.get(fields, geo={
            'for': 'tract:{}'.format(tract),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_blockgroup(self, fields, state_fips, county_fips,
                                blockgroup, tract=None, **kwargs):
        geo = {
            'for': 'block group:{}'.format(blockgroup),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }
        if tract:
            geo['in'] += ' tract:{}'.format(tract)
        return self.get(fields, geo=geo, **kwargs)

    @supported_years(2010)
    def state_msa(self, fields, state_fips, msa, **kwargs):
        return self.get(fields, geo={
            'for': ('metropolitan statistical area/' +
                    'micropolitan statistical area (or part):{}'.format(msa)),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years(2010)
    def state_csa(self, fields, state_fips, csa, **kwargs):
        return self.get(fields, geo={
            'for': 'combined statistical area (or part):{}'.format(csa),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)

    @supported_years(2010)
    def state_district_place(self, fields, state_fips,
                             district, place, **kwargs):
        return self.get(fields, geo={
            'for': 'place/remainder (or part):{}'.format(place),
            'in': 'state:{} congressional district:{}'.format(
                state_fips, district),
        }, **kwargs)

    @supported_years(2010)
    def state_zipcode(self, fields, state_fips, zcta, **kwargs):
        return self.get(fields, geo={
            'for': 'zip code tabulation area (or part):{}'.format(zcta),
            'in': 'state:{}'.format(state_fips),
        }, **kwargs)


class PLClient(Client):

    default_year = 2020
    dataset = 'pl'

    years = (2020, 2010, 2000)

    def _switch_endpoints(self, year):

        self.endpoint_url = 'https://api.census.gov/data/%s/dec/%s'
        self.definitions_url = 'https://api.census.gov/data/%s/dec/%s/variables.json'
        self.definition_url = 'https://api.census.gov/data/%s/dec/%s/variables/%s.json'
        self.groups_url = 'https://api.census.gov/data/%s/dec/%s/groups.json'

    def tables(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))
        return super(PLClient, self).tables(*args, **kwargs)

    def get(self, *args, **kwargs):
        self._switch_endpoints(kwargs.get('year', self.default_year))

        return super(PLClient, self).get(*args, **kwargs)

    @supported_years()
    def state_county_subdivision(self, fields, state_fips,
                                 county_fips, subdiv_fips, **kwargs):
        return self.get(fields, geo={
            'for': 'county subdivision:{}'.format(subdiv_fips),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_tract(self, fields, state_fips,
                           county_fips, tract, **kwargs):
        return self.get(fields, geo={
            'for': 'tract:{}'.format(tract),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }, **kwargs)

    @supported_years()
    def state_county_blockgroup(self, fields, state_fips, county_fips,
                                blockgroup, tract=None, **kwargs):
        geo = {
            'for': 'block group:{}'.format(blockgroup),
            'in': 'state:{} county:{}'.format(state_fips, county_fips),
        }
        if tract:
            geo['in'] += ' tract:{}'.format(tract)
        return self.get(fields, geo=geo, **kwargs)


class Census(object):

    ALL = ALL

    def __init__(self, key, year=None, session=None):

        if not session:
            session = new_session()

        self.session = session
        self.session.headers.update({
            'User-Agent': ('python-census/{} '.format(__version__) +
                           'github.com/datamade/census')
        })

        self._acs = ACS5Client(key, year, session)  # deprecated
        self.acs5 = ACS5Client(key, year, session)
        self.acs3 = ACS3Client(key, year, session)
        self.acs1 = ACS1Client(key, year, session)
        self.acs5st = ACS5StClient(key, year, session)
        self.acs5dp = ACS5DpClient(key, year, session)
        self.acs3dp = ACS3DpClient(key, year, session)
        self.acs1dp = ACS1DpClient(key, year, session)
        self.sf1 = SF1Client(key, year, session)
        self.pl = PLClient(key, year, session)

    @property
    def acs(self):
        warnings.warn('Use acs5 instead of acs', DeprecationWarning)
        return self._acs


================================================
FILE: census/tests/__init__.py
================================================


================================================
FILE: census/tests/test_census.py
================================================
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import time
import unittest

from census.core import (
    Census, UnsupportedYearException)

KEY = os.environ.get('CENSUS_KEY', '')

CLIENTS = (
    ('acs5', (
        'us', 'state', 'state_county', 'state_county_subdivision',
        'state_county_tract', 'state_county_blockgroup',
        'state_place', 'state_district',
        'state_congressional_district',
        'state_legislative_district_upper',
        'state_legislative_district_lower', 'zipcode',
    )),
    ('acs1dp', (
        'us', 'state', 'state_congressional_district',
    )),
    ('sf1', (
        'state', 'state_county', 'state_county_subdivision',
        'state_county_tract', 'state_county_blockgroup',
        'state_place', 'state_congressional_district',
        'state_msa', 'state_csa', 'state_district_place',
        'state_zipcode',
    )),
    ('sf3', (
        'state', 'state_county', 'state_county_tract',
        'state_county_blockgroup', 'state_place',
    )),
    ('pl', (
        'us', 'state', 'state_county', 'state_county_subdivision',
        'state_county_tract', 'state_county_blockgroup',
        'state_place', 'state_congressional_district',
        'state_legislative_district_upper',
        'state_legislative_district_lower',
    ))
)

TEST_DATA = {
    'state_fips': '24',
    'county_fips': '031',
    'subdiv_fips': '90796',
    'tract': '700706',
    'blockgroup': '1',
    'place': '31175',
    'district': '06',       # for old `state_district` calling.
    'congressional_district': '06',
    'legislative_district': '06',
    'zcta': '20877',
    'msa': '47900',
    'csa': '548',
}


class CensusTestCase(unittest.TestCase):

    def setUp(self):
        self._client = Census(KEY)

    def client(self, name):
        return getattr(self._client, name)

    def tearDown(self):
        self._client.session.close()


class TestUnsupportedYears(CensusTestCase):

    def setUp(self):
        self._client = Census(KEY, year=2008)

    def test_acs5(self):
        client = self.client('acs5')
        self.assertRaises(UnsupportedYearException,
                          client.state, ('NAME', '06'))

    def test_acs5st(self):
        client = self.client('acs5st')
        self.assertRaises(UnsupportedYearException,
                          client.state, ('NAME', '06'))

    def test_acs1dp(self):
        client = self.client('acs1dp')
        self.assertRaises(UnsupportedYearException,
                          client.state, ('NAME', '06'))

    def test_sf1(self):
        client = self.client('sf1')
        self.assertRaises(UnsupportedYearException,
                          client.state, ('NAME', '06'))

    def test_pl(self):
        client = self.client('sf1')
        self.assertRaises(UnsupportedYearException,
                          client.state, ('NAME', '06'))


class TestEncoding(CensusTestCase):
    """
    Test character encodings of results are properly handled.
    """

    def test_la_canada_2015(self):
        """
        The 'La Cañada Flintridge city, California' place can be a problem.
        """
        geo = {
            'for': 'place:39003',
            'in': u'state:06'
        }
        self.assertEqual(
            self._client.acs5.get('NAME', geo=geo)[0]['NAME'],
            u'La Cañada Flintridge city, California'
        )
        self.assertEqual(
            self._client.acs.get('NAME', geo=geo, year=2016)[0]['NAME'],
            'La Cañada Flintridge city, California'
        )
        # 2015 is returned as:
        # 'La Ca\xf1ada Flintridge city, California'
        self.assertEqual(
            self._client.acs.get('NAME', geo=geo, year=2015)[0]['NAME'],
            'La Cañada Flintridge city, California'
        )


class TestEndpoints(CensusTestCase):

    def check_endpoints(self, client_name, tests, **kwargs):

        client = self.client(client_name)
        fields = ('NAME',)

        for method_name, expected in tests:

            msg = '{}.{}'.format(client_name, method_name)

            method = getattr(client, method_name)
            data = method(fields, **TEST_DATA, **kwargs)
            self.assertTrue(data, msg)
            self.assertEqual(data[0]['NAME'], expected, msg)
            time.sleep(0.2)

    def test_tables(self):
        self.client('acs5').tables()
        self.client('acs5').tables(2010)
        self.client('sf1').tables()
        self.client('pl').tables()

    def test_acs5(self):

        tests = (
            ('us', 'United States'),
            ('state', 'Maryland'),
            ('state_county', 'Montgomery County, Maryland'),
            ('state_county_subdivision',
                'District 9, Montgomery County, Maryland'),
            ('state_county_tract',
                'Census Tract 7007.06; Montgomery County; Maryland'),
            ('state_county_blockgroup',
                ('Block Group 1; Census Tract 7007.06; '
                    'Montgomery County; Maryland')),
            ('state_place', 'Gaithersburg city, Maryland'),
            ('state_district',
                'Congressional District 6 (119th Congress), Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (119th Congress), Maryland'),
            ('state_legislative_district_upper',
                'State Senate District 6 (2024); Maryland'),
            ('state_legislative_district_lower',
                'State Legislative District 6 (2024); Maryland'),
            ('state_zipcode', 'ZCTA5 20877'),
        )

        self.check_endpoints('acs5', tests)

    def test_acs5_previous_years(self):

        tests = (
            ('us', 'United States'),
            ('state', 'Maryland'),
            ('state_county', 'Montgomery County, Maryland'),
            ('state_county_subdivision',
                'District 9, Montgomery County, Maryland'),
            ('state_county_tract',
                'Census Tract 7007.06, Montgomery County, Maryland'),
            ('state_county_blockgroup',
                ('Block Group 1, Census Tract 7007.06, '
                    'Montgomery County, Maryland')),
            ('state_place', 'Gaithersburg city, Maryland'),
            ('state_district',
                'Congressional District 6 (116th Congress), Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (116th Congress), Maryland'),
            ('state_legislative_district_upper',
                'State Senate District 6 (2018), Maryland'),
            ('state_legislative_district_lower',
                'State Legislative District 6 (2018), Maryland'),
            ('state_zipcode', 'ZCTA5 20877'),
        )

        self.check_endpoints('acs5', tests, year=2019)

    def test_acs5st(self):

        tests = (
            ('us', 'United States'),
            ('state', 'Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (119th Congress), Maryland'),
        )

        self.check_endpoints('acs5st', tests)

    def test_acs1dp(self):

        tests = (
            ('us', 'United States'),
            ('state', 'Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (119th Congress), Maryland'),
        )

        self.check_endpoints('acs1dp', tests)

    def test_sf1(self):

        tests = (
            ('state', 'Maryland'),
            ('state_county', 'Montgomery County, Maryland'),
            ('state_county_subdivision',
                ('District 9, Montgomery County, Maryland')),
            ('state_county_tract',
                'Census Tract 7007.06, Montgomery County, Maryland'),
            ('state_county_blockgroup',
                ('Block Group 1, Census Tract 7007.06, '
                 'Montgomery County, Maryland')),
            ('state_place', 'Gaithersburg city, Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (111th Congress), Maryland'),
            ('state_msa',
                ('Washington-Arlington-Alexandria, '
                    'DC-VA-MD-WV Metro Area (part); Maryland')),
            ('state_csa',
                ('Washington-Baltimore-Northern Virginia, '
                    'DC-MD-VA-WV CSA (part); Maryland')),
            # ('state_district_place', 'District 9'),
            ('state_zipcode', 'ZCTA5 20877, Maryland'),
        )

        self.check_endpoints('sf1', tests)

    def test_pl(self):

        tests = (
            ('us', 'United States'),
            ('state', 'Maryland'),
            ('state_county', 'Montgomery County, Maryland'),
            ('state_county_subdivision',
                'District 9, Montgomery County, Maryland'),
            ('state_county_tract',
                'Census Tract 7007.06, Montgomery County, Maryland'),
            ('state_county_blockgroup',
                ('Block Group 1, Census Tract 7007.06, '
                    'Montgomery County, Maryland')),
            ('state_place', 'Gaithersburg city, Maryland'),
            ('state_district',
                'Congressional District 6 (116th Congress), Maryland'),
            ('state_congressional_district',
                'Congressional District 6 (116th Congress), Maryland'),
            ('state_legislative_district_upper',
                'State Senate District 6 (2018), Maryland'),
            ('state_legislative_district_lower',
                'State Legislative District 6 (2018), Maryland'),
        )

        self.check_endpoints('pl', tests)

    def test_more_than_50(self):
        fields = ['B01001_003E', 'B01001_004E', 'B01001_005E',
                  'B01001_006E', 'B01001_007E', 'B01001_008E',
                  'B01001_009E', 'B01001_010E', 'B01001_011E',
                  'B01001_012E', 'B01001_013E', 'B01001_014E',
                  'B01001_015E', 'B01001_016E', 'B01001_017E',
                  'B01001_018E', 'B01001_019E', 'B01001_020E',
                  'B01001_021E', 'B01001_022E', 'B01001_023E',
                  'B01001_024E', 'B01001_025E', 'B01001_027E',
                  'B01001_028E', 'B01001_029E', 'B01001_030E',
                  'B01001_031E', 'B01001_032E', 'B01001_033E',
                  'B01001_034E', 'B01001_035E', 'B01001_036E',
                  'B01001_037E', 'B01001_038E', 'B01001_039E',
                  'B01001_040E', 'B01001_041E', 'B01001_042E',
                  'B01001_043E', 'B01001_044E', 'B01001_045E',
                  'B01001_046E', 'B01001_047E', 'B01001_048E',
                  'B01001_049E', 'B19001_003E', 'B19001_004E',
                  'B19001_005E', 'B19001_006E', 'B19001_007E',
                  'B19001_008E', 'B19001_009E', 'B19001_010E',
                  'B19001_011E', 'B19001_012E', 'B19001_013E',
                  'B19001_014E', 'B19001_015E', 'B19001_016E']

        client = self.client('acs5')
        results = client.us(fields)
        assert set(results[0].keys()).issuperset(fields)
    
    def test_more_than_50_not_out_of_order(self):
        fields = ['GEO_ID', 'B01001_001E', 'B01001_003E',
                  'B01001_006E', 'B01001_007E', 'B01001_008E',
                  'B01001_009E', 'B01001_010E', 'B01001_011E',
                  'B01001_012E', 'B01001_013E', 'B01001_014E',
                  'B01001_015E', 'B01001_016E', 'B01001_017E',
                  'B01001_018E', 'B01001_019E', 'B01001_020E',
                  'B01001_021E', 'B01001_022E', 'B01001_023E',
                  'B01001_024E', 'B01001_025E', 'B01001_027E',
                  'B01001_028E', 'B01001_029E', 'B01001_030E',
                  'B01001_031E', 'B01001_032E', 'B01001_033E',
                  'B01001_034E', 'B01001_035E', 'B01001_036E',
                  'B01001_037E', 'B01001_038E', 'B01001_039E',
                  'B01001_040E', 'B01001_041E', 'B01001_042E',
                  'B01001_043E', 'B01001_044E', 'B01001_045E',
                  'B01001_046E', 'B01001_047E', 'B01001_048E',
                  'B01001_049E', 'B19001_003E', 'B19001_004E',
                  'B19001_005E', 'B19001_006E', 'B19001_007E',
                  'B19001_008E', 'B19001_009E', 'B19001_010E',
                  'B19001_011E', 'B19001_012E', 'B19001_013E',
                  'B19001_014E', 'B19001_015E', 'B19001_016E',
                  'B03002_001E', ]

        client = self.client('acs1')
        results = client.state_county(fields, '*', '*', year=2018)
        # We know that the last 5 digits of the GEO_ID are the FIPS code
        # GEO_ID is grabbed in the first chunk (request), but the state and county are overwritten
        # with each chunk and have the values from the last chunk
        assert results[0]['GEO_ID'][-5:] == results[0]['state'] + \
            results[0]['county']

    def test_new_style_endpoints(self):
        client = Census(KEY, year=2016)

        res_2016_2016 = client.acs1.state('B01001_004E', Census.ALL)
        res_2016_2014 = client.acs1.state('B01001_004E', Census.ALL, year=2014)

        client = Census(KEY, year=2014)

        res_2014_2014 = client.acs1.state('B01001_004E', Census.ALL)
        res_2014_2016 = client.acs1.state('B01001_004E', Census.ALL, year=2016)

        assert sorted(
            res_2016_2016, key=lambda x: x['state']
        ) == sorted(
            res_2014_2016, key=lambda x: x['state']
        )

        assert sorted(
            res_2014_2014, key=lambda x: x['state']
        ) == sorted(
            res_2016_2014, key=lambda x: x['state']
        )

    def test_older_sf1(self):
        client = Census(KEY)
        result_2010 = client.sf1.get(
            ('P008001',  # total
             'P008003',  # white
             'P008004',  # black
             'P008006',  # asian
             'P008010',  # latino
             ),
            geo={'for': 'place:53476', 'in': 'state:06'},
        )
        result_2000 = client.sf1.get(
            ('P008001',  # total
             'P008003',  # white
             'P008004',  # black
             'P008006',  # asian
             'P008010',  # latino
             ),
            geo={'for': 'place:53476', 'in': 'state:06'},
            year=2000,
        )
        assert result_2010 != result_2000


if __name__ == '__main__':
    unittest.main()


================================================
FILE: pyproject.toml
================================================
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"

================================================
FILE: requirements.txt
================================================
requests>=2.31
pytest>=2.9


================================================
FILE: setup.cfg
================================================
[metadata]
name = census
version = 0.8.26
author = Jeremy Carbaugh
author_email = jcarbaugh@sunlightfoundation.com
maintainer = Forest Gregg
maintainer_email = fgregg@gmail.com
license = BSD
description = A wrapper for the US Census Bureau's API
url = http://github.com/datamade/census
long_description = file: README.rst
classifiers =
    Development Status :: 4 - Beta
    Intended Audience :: Developers
    License :: OSI Approved :: BSD License
    Natural Language :: English
    Operating System :: OS Independent
    Programming Language :: Python
platforms = any

[options]
py_modules = census
packages = find:
install_requires =
    requests>=1.1.0


================================================
FILE: setup.py
================================================
from setuptools import setup

setup()
Download .txt
gitextract_87spxlep/

├── .github/
│   └── workflows/
│       └── python-package.yml
├── .gitignore
├── CITATION.cff
├── LICENSE
├── MANIFEST.in
├── README.rst
├── census/
│   ├── __init__.py
│   ├── core.py
│   └── tests/
│       ├── __init__.py
│       └── test_census.py
├── pyproject.toml
├── requirements.txt
├── setup.cfg
└── setup.py
Download .txt
SYMBOL INDEX (95 symbols across 2 files)

FILE: census/core.py
  function new_session (line 10) | def new_session(*args, **kwargs):
  class APIKeyError (line 15) | class APIKeyError(Exception):
    method __init__ (line 19) | def __init__(self, value):
    method __str__ (line 22) | def __str__(self):
  function list_or_str (line 26) | def list_or_str(v):
  function float_or_str (line 34) | def float_or_str(v):
  function supported_years (line 41) | def supported_years(*years):
  function retry_on_transient_error (line 55) | def retry_on_transient_error(func):
  function chunks (line 74) | def chunks(l, n):
  function merge (line 80) | def merge(dicts):
  class CensusException (line 84) | class CensusException(Exception):
  class UnsupportedYearException (line 88) | class UnsupportedYearException(CensusException):
  class Client (line 92) | class Client(object):
    method __init__ (line 98) | def __init__(self, key, year=None, session=None, retries=3):
    method tables (line 105) | def tables(self, year=None):
    method fields (line 121) | def fields(self, year=None, flat=False):
    method get (line 149) | def get(self, fields, geo, year=None, **kwargs):
    method query (line 164) | def query(self, fields, geo, year=None, sort_by_geoid=False, **kwargs):
    method _field_type (line 217) | def _field_type(self, field, year):
    method us (line 235) | def us(self, fields, **kwargs):
    method state (line 239) | def state(self, fields, state_fips, **kwargs):
    method state_county (line 245) | def state_county(self, fields, state_fips, county_fips, **kwargs):
    method state_place (line 252) | def state_place(self, fields, state_fips, place, **kwargs):
    method state_district (line 259) | def state_district(self, fields, state_fips, district, **kwargs):
    method state_congressional_district (line 271) | def state_congressional_district(self, fields, state_fips, congression...
    method state_legislative_district_upper (line 278) | def state_legislative_district_upper(self, fields, state_fips, legisla...
    method state_legislative_district_lower (line 285) | def state_legislative_district_lower(self, fields, state_fips, legisla...
    method combined_statistical_area (line 291) | def combined_statistical_area(self, fields, csa, **kwargs):
    method msa (line 297) | def msa(self, fields, msa, **kwargs):
  class ACSClient (line 303) | class ACSClient(Client):
    method _switch_endpoints (line 305) | def _switch_endpoints(self, year):
    method tables (line 318) | def tables(self, *args, **kwargs):
    method get (line 322) | def get(self, *args, **kwargs):
  class ACS5Client (line 328) | class ACS5Client(ACSClient):
    method state_county_subdivision (line 336) | def state_county_subdivision(self, fields, state_fips,
    method state_county_tract (line 344) | def state_county_tract(self, fields, state_fips,
    method state_county_blockgroup (line 352) | def state_county_blockgroup(self, fields, state_fips, county_fips,
    method zipcode (line 363) | def zipcode(self, fields, zcta, **kwargs):
    method state_zipcode (line 374) | def state_zipcode(self, fields, state_fips, zcta, **kwargs):
  class ACS5DpClient (line 387) | class ACS5DpClient(ACS5Client):
  class ACS5StClient (line 392) | class ACS5StClient(ACS5Client):
    method _switch_endpoints (line 393) | def _switch_endpoints(self, year):
  class ACS3Client (line 402) | class ACS3Client(ACSClient):
    method state_county_subdivision (line 410) | def state_county_subdivision(self, fields, state_fips,
  class ACS3DpClient (line 418) | class ACS3DpClient(ACS3Client):
  class ACS1Client (line 423) | class ACS1Client(ACSClient):
    method state_county_subdivision (line 431) | def state_county_subdivision(self, fields, state_fips,
  class ACS1DpClient (line 439) | class ACS1DpClient(ACS1Client):
  class SF1Client (line 446) | class SF1Client(Client):
    method _switch_endpoints (line 453) | def _switch_endpoints(self, year):
    method tables (line 460) | def tables(self, *args, **kwargs):
    method get (line 464) | def get(self, *args, **kwargs):
    method state_county_subdivision (line 470) | def state_county_subdivision(self, fields, state_fips,
    method state_county_tract (line 478) | def state_county_tract(self, fields, state_fips,
    method state_county_blockgroup (line 486) | def state_county_blockgroup(self, fields, state_fips, county_fips,
    method state_msa (line 497) | def state_msa(self, fields, state_fips, msa, **kwargs):
    method state_csa (line 505) | def state_csa(self, fields, state_fips, csa, **kwargs):
    method state_district_place (line 512) | def state_district_place(self, fields, state_fips,
    method state_zipcode (line 521) | def state_zipcode(self, fields, state_fips, zcta, **kwargs):
  class PLClient (line 528) | class PLClient(Client):
    method _switch_endpoints (line 535) | def _switch_endpoints(self, year):
    method tables (line 542) | def tables(self, *args, **kwargs):
    method get (line 546) | def get(self, *args, **kwargs):
    method state_county_subdivision (line 552) | def state_county_subdivision(self, fields, state_fips,
    method state_county_tract (line 560) | def state_county_tract(self, fields, state_fips,
    method state_county_blockgroup (line 568) | def state_county_blockgroup(self, fields, state_fips, county_fips,
  class Census (line 579) | class Census(object):
    method __init__ (line 583) | def __init__(self, key, year=None, session=None):
    method acs (line 606) | def acs(self):

FILE: census/tests/test_census.py
  class CensusTestCase (line 60) | class CensusTestCase(unittest.TestCase):
    method setUp (line 62) | def setUp(self):
    method client (line 65) | def client(self, name):
    method tearDown (line 68) | def tearDown(self):
  class TestUnsupportedYears (line 72) | class TestUnsupportedYears(CensusTestCase):
    method setUp (line 74) | def setUp(self):
    method test_acs5 (line 77) | def test_acs5(self):
    method test_acs5st (line 82) | def test_acs5st(self):
    method test_acs1dp (line 87) | def test_acs1dp(self):
    method test_sf1 (line 92) | def test_sf1(self):
    method test_pl (line 97) | def test_pl(self):
  class TestEncoding (line 103) | class TestEncoding(CensusTestCase):
    method test_la_canada_2015 (line 108) | def test_la_canada_2015(self):
  class TestEndpoints (line 132) | class TestEndpoints(CensusTestCase):
    method check_endpoints (line 134) | def check_endpoints(self, client_name, tests, **kwargs):
    method test_tables (line 149) | def test_tables(self):
    method test_acs5 (line 155) | def test_acs5(self):
    method test_acs5_previous_years (line 182) | def test_acs5_previous_years(self):
    method test_acs5st (line 209) | def test_acs5st(self):
    method test_acs1dp (line 220) | def test_acs1dp(self):
    method test_sf1 (line 231) | def test_sf1(self):
    method test_pl (line 258) | def test_pl(self):
    method test_more_than_50 (line 284) | def test_more_than_50(self):
    method test_more_than_50_not_out_of_order (line 310) | def test_more_than_50_not_out_of_order(self):
    method test_new_style_endpoints (line 341) | def test_new_style_endpoints(self):
    method test_older_sf1 (line 364) | def test_older_sf1(self):
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (49K chars).
[
  {
    "path": ".github/workflows/python-package.yml",
    "chars": 1863,
    "preview": "# This workflow will install Python dependencies, run tests and lint with a variety of Python versions\n# For more inform"
  },
  {
    "path": ".gitignore",
    "chars": 42,
    "preview": "*.pyc\n.DS_Store\n.env\n.cache/\n.tox/\nbuild/\n"
  },
  {
    "path": "CITATION.cff",
    "chars": 312,
    "preview": "cff-version: 1.2.0\nmessage: \"If you use this software, please cite it as below.\"\nauthors:\n- family-names: \"Carbaugh\"\n  g"
  },
  {
    "path": "LICENSE",
    "chars": 1541,
    "preview": "Copyright (c) 2012, Sunlight Labs; 2017, DataMade\n\nAll rights reserved.\n\nRedistribution and use in source and binary for"
  },
  {
    "path": "MANIFEST.in",
    "chars": 26,
    "preview": "include LICENSE *.rst *.py"
  },
  {
    "path": "README.rst",
    "chars": 7549,
    "preview": "======\ncensus\n======\n.. image:: https://github.com/datamade/census/workflows/Python%20package/badge.svg\n \n\nA simple wrap"
  },
  {
    "path": "census/__init__.py",
    "chars": 106,
    "preview": "from census.core import (Census, ALL, CensusException,\n                         UnsupportedYearException)\n"
  },
  {
    "path": "census/core.py",
    "chars": 20563,
    "preview": "import warnings\nfrom functools import wraps, lru_cache\nfrom importlib.metadata import version\n\n__version__ = version('ce"
  },
  {
    "path": "census/tests/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "census/tests/test_census.py",
    "chars": 14264,
    "preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport os\nimport time\nimport unittest\n\nfrom census.core import (\n    Censu"
  },
  {
    "path": "pyproject.toml",
    "chars": 99,
    "preview": "[build-system]\nrequires = [\"setuptools >= 40.6.0\", \"wheel\"]\nbuild-backend = \"setuptools.build_meta\""
  },
  {
    "path": "requirements.txt",
    "chars": 27,
    "preview": "requests>=2.31\npytest>=2.9\n"
  },
  {
    "path": "setup.cfg",
    "chars": 659,
    "preview": "[metadata]\nname = census\nversion = 0.8.26\nauthor = Jeremy Carbaugh\nauthor_email = jcarbaugh@sunlightfoundation.com\nmaint"
  },
  {
    "path": "setup.py",
    "chars": 38,
    "preview": "from setuptools import setup\n\nsetup()\n"
  }
]

About this extraction

This page contains the full source code of the datamade/census GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (46.0 KB), approximately 12.7k tokens, and a symbol index with 95 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!