Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents

Introduction
Anchor
Introduction
Introduction

...

  1. The library avoids CKAN syntax instead using HDX terminology. Hence there is no reference to CKAN related items, only gallery items. The user does not need to learn about CKAN and makes it easier to understand what will be the result in HDX when calling a Python method.

  2. The class structure of the library should be as logical as possible (within the restrictions of the CKAN API it relies on). In HDX, a dataset can contain zero or more resources and a gallery (consisting of gallery items), so the library reflects this even though the CKAN API presents a different interface for gallery items to resources. 

    The UML diagram below shows the relationships between the major classes in the library.  

     

    Drawio
    baseUrlhttps://humanitarian.atlassian.net/wiki
    diagramNameClasses
    width601
    pageId6356996
    height421
    revision3

  3. Datasets, resources and gallery items can use dictionary methods like square brackets to handle metadata which feels natural. (The HDXObject class extends UserDict.) eg.

    dataset['name'] = 'My Dataset'

     

  4. Static metadata can be imported from a YAML file, recommended for being very human readable, or a JSON file eg.

    dataset.update_yaml([path])

    Static metadata can be passed in as a dictionary on initialisation of a dataset, resource or gallery item eg.

    dataset = Dataset(configuration, {
    'name': slugified_name,
    'title': title,
    'dataset_date': dataset_date, # has to be MM/DD/YYYY
    'groups': iso
    })

     

  5. The code is very well documented. Detailed API documentation (generated from Google style docstrings using Sphinx) can be found in the Introduction above. 
    def load_from_hdx(self, id_or_name: str) -> bool:
    """Loads the dataset given by either id or name from HDX
        Args:
    id_or_name (str): Either id or name of dataset
        Returns:
    bool: True if loaded, False if not
    """

    IDEs can take advantage of the documentation eg.

  6. The method arguments and return parameter have type hints. (Although this is a feature of Python 3.5, it has been backported.) Type hints enable sophisticated IDEs like PyCharm to warn of any inconsistencies in using types bringing one of the major benefits of statically typed languages to Python.
    def merge_dictionaries(dicts: List[dict]) -> dict:

    gives:

  7. Default parameters mean that there is a very easy default way to get set up and going eg.
    def update_yaml(self, path: Optional[str] = join('config', 'hdx_dataset_static.yml')) -> None:
  8. Configuration is made as simple as possible with a Configuration class that handles the HDX API key and the merging of configurations from multiple YAML or JSON files or dictionaries:
    class Configuration(UserDict):
    """Configuration for HDX
        Args:
    **kwargs: See below
    hdx_key_file (Optional[str]): Path to HDX key file. Defaults to ~/.hdxkey.
    hdx_config_dict (dict): HDX configuration dictionary OR
    hdx_config_json (str): Path to JSON HDX configuration OR
    hdx_config_yaml (str): Path to YAML HDX configuration. Defaults to library's internal hdx_configuration.yml.
    collector_config_dict (dict): Collector configuration dictionary OR
    collector_config_json (str): Path to JSON Collector configuration OR
    collector_config_yaml (str): Path to YAML Collector configuration. Defaults to config/collector_configuration.yml.
    """

     

  9. Logging is something often neglected so the library aims to make it a breeze to get going with logging and so avoid the spread of print statements. A few loggers are created in the default configuration:
    console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: color
    stream: ext://sys.stdout
    error_file_handler:
    class: logging.FileHandler
    level: ERROR
    formatter: simple
    filename: errors.log
    encoding: utf8
    mode: w
    error_mail_handler:
    class: logging.handlers.SMTPHandler
    level: CRITICAL
    formatter: simple
    mailhost: localhost
    fromaddr: noreply@localhost

     

  10. The library itself uses logging at appropriate levels to ensure that it is clear what operation are being performed eg.

    WARNING - 2016-06-07 11:08:04 - hdx.data.dataset - Dataset exists. Updating acled-conflict-data-for-africa-realtime-2016

     

  11. The library makes errors plain by throwing exceptions rather than returning a False or None (except where that would be more appropriate) eg.

    hdx.configuration.ConfigurationError: More than one collector configuration file given!
     
  12. There are utility functions to handle dictionary merging, loading multiple YAML or JSON files and a few other helpful tasks eg.
     
    def script_dir_plus_file(filename: str, pyobject: Any, follow_symlinks: Optional[bool] = True) -> str:
    """Get current script's directory and then append a filename
        Args:
    filename (str): Filename to append to directory path
    pyobject (Any): Any Python object in the script
    follow_symlinks (Optional[bool]): Follow symlinks or not. Defaults to True.
        Returns:
    str: Current script's directory and with filename appended
    """

  13. There are setup wrappers to which the collector's main function is passed. They neatly cloak the setup of logging and one of them hides the required calls for pushing status into ScraperWiki (used internally in HDX) eg.
    from hdx.collector.scraperwiki import wrapper
    def main(configuration):
        dataset = generate_dataset(configuration, datetime.now())
        ...
    if __name__ == '__main__':
    wrapper(main)

...

  1. Browse to the HDX website
  2. Left click on LOG IN in the top right of the web page if not logged in and log in
  3. Left click on your username in the top right of the web page and select PROFILE from the drop down menu
  4. Scroll down to the bottom of the profile page
  5. Copy the API key which will be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  6. Paste the API key into a text file
  7. Save the text file with filename ".hdxkey" in the current user's home directory

Starting the Data Collector

To include the HDX Python library in your project, add the following to your requirements.txt file:

git+git://github.com/mcarans/hdx-python-api.git#egg=hdx-python-api

The easiest way to get started is to use the wrappers and configuration defaults. You will most likely just need the simple wrapper. If you are in the HDX team, you may need to use the ScraperWiki wrapper which reports status to that platform (in which case replace "simple" with "scraperwiki" in the code below):

...

The default logging configuration reads a configuration file internal to the library that sets up an coloured console handler outputting at DEBUG level, a file handler writing to errors.log at ERROR level and an SMTP handler sending an email in the event of a CRITICAL error. It assumes that you have created a file config/smtp_configuration.yml which contains parameters of the form:

handlers:
error_mail_handler:
toaddrs: EMAIL_ADDRESSES
subject: "COLLECTOR FAILED: MY_COLLECTOR_NAME"

...