def graph_query(kind, source, target=None, neighbor_limit=1,
                database_filter=None):
    """Perform a graph query on PathwayCommons.

    For more information on these queries, see
    http://www.pathwaycommons.org/pc2/#graph

    Parameters
    ----------
    kind : str
        The kind of graph query to perform. Currently 3 options are
        implemented, 'neighborhood', 'pathsbetween' and 'pathsfromto'.
    source : list[str]
        A list of gene names which are the source set for the graph query.
    target : Optional[list[str]]
        A list of gene names which are the target set for the graph query.
        Only needed for 'pathsfromto' queries.
    neighbor_limit : Optional[int]
        This limits the length of the longest path considered in
        the graph query. Default: 1

    Returns
    -------
    model : org.biopax.paxtools.model.Model
        A BioPAX model (java object).
    """

    default_databases = ['wp', 'smpdb', 'reconx', 'reactome', 'psp', 'pid',
                         'panther', 'netpath', 'msigdb', 'mirtarbase', 'kegg',
                         'intact', 'inoh', 'humancyc', 'hprd',
                         'drugbank', 'dip', 'corum']
    if not database_filter:
        query_databases = default_databases
    else:
        query_databases = database_filter
    # excluded: ctd

    params = {}
    params['format'] = 'BIOPAX'
    params['organism'] = '9606'
    params['datasource'] = query_databases
    # Get the "kind" string
    kind_str = kind.lower()
    if kind not in ['neighborhood', 'pathsbetween', 'pathsfromto']:
        logger.warn('Invalid query type %s' % kind_str)
        return None
    params['kind'] = kind_str
    # Get the source string
    if isinstance(source, basestring):
        source_str = source
    else:
        source_str = ','.join(source)
    params['source'] = source_str
    try:
        neighbor_limit = int(neighbor_limit)
        params['limit'] = neighbor_limit
    except (TypeError, ValueError):
        logger.warn('Invalid neighborhood limit %s' % neighbor_limit)
        return None
    if target is not None:
        if isinstance(target, basestring):
            target_str = target
        else:
            target_str = ','.join(target)
        params['target'] = target_str
    logger.info('Sending Pathway Commons query with parameters: ')
    for k, v in params.items():
        logger.info(' %s: %s' % (k, v))

    logger.info('Sending Pathway Commons query...')
    res = requests.get(pc2_url + 'graph', params=params)
    if not res.status_code == 200:
        logger.error('Response is HTTP code %d.' % res.status_code)
        if res.status_code == 500:
            logger.error('Note: HTTP code 500 can mean empty '
                         'results for a valid query.')
        return None
    # We don't decode to Unicode here because owl_str_to_model expects
    # a byte stream
    model = owl_str_to_model(res.content)
    if model is not None:
        logger.info('Pathway Commons query returned a model...')
    return model
Perform a graph query on PathwayCommons.

    For more information on these queries, see
    http://www.pathwaycommons.org/pc2/#graph

    Parameters
    ----------
    kind : str
        The kind of graph query to perform. Currently 3 options are
        implemented, 'neighborhood', 'pathsbetween' and 'pathsfromto'.
    source : list[str]
        A list of gene names which are the source set for the graph query.
    target : Optional[list[str]]
        A list of gene names which are the target set for the graph query.
        Only needed for 'pathsfromto' queries.
    neighbor_limit : Optional[int]
        This limits the length of the longest path considered in
        the graph query. Default: 1

    Returns
    -------
    model : org.biopax.paxtools.model.Model
        A BioPAX model (java object).