Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull metadata from API Discovery Tool #153

Open
antidipyramid opened this issue Jan 9, 2025 · 2 comments
Open

Pull metadata from API Discovery Tool #153

antidipyramid opened this issue Jan 9, 2025 · 2 comments
Assignees

Comments

@antidipyramid
Copy link

https://www.census.gov/data/developers/updates/new-discovery-tool.html

@antidipyramid antidipyramid self-assigned this Jan 9, 2025
@antidipyramid
Copy link
Author

antidipyramid commented Jan 10, 2025

@fgregg I made some progress using a metaclass to programmatically pull in each client's supported years, default year, and enpoint urls from the discovery tool:

import requests
from functools import lru_cache


@lru_cache
def fetch_metadata():
    # Fetches bulk metadata from the US Census' Discovery Tool API
    r = requests.get("https://api.census.gov/data.json")
    return r.json()


class ClientMeta(type):
    def __init__(cls, name, bases, dct):
        metadata = fetch_metadata()

        if not hasattr(cls, "dataset"):
            return super().__init__(name, bases, dct)

        # Initialize years attribute
        setattr(cls, "years", set())

        # e.g. ACS5Client.dataset is "acs/acs5" which corresponds to a metadata
        # object with a dataset attribute of ["acs", "acs5"]
        dataset = cls.dataset.split("/")

        for m in metadata["dataset"]:
            if "c_vintage" not in m:
                continue

            if m["c_dataset"] == dataset:
                cls.years.add(m["c_vintage"])

                # Set API URL attributes
                setattr(cls, "definitions_url", m["c_variablesLink"])
                setattr(cls, "groups_url", m["c_groupsLink"])

                setattr(cls, "default_year", max(cls.years))

        return super().__init__(name, bases, dct)

Then we can just define Client like:

class Client(metaclass=ClientMeta):
    def __init__(self, key, year=None, session=None, retries=3):
        ...

Seems like this runs once on package import for each client in core.py.

What do you think about this approach, @fgregg?

@fgregg
Copy link
Member

fgregg commented Jan 10, 2025

love it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants