Changeset 10894:82d8d3c13ee9 in orange


Ignore:
Timestamp:
05/29/12 17:33:11 (23 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
rebase_source:
91f57baed30447ad09841b842ec1be344842a019
Message:

Added search path discovery using setuptools entry points.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/data/io.py

    r10581 r10894  
    8888""" 
    8989import os 
     90import warnings 
    9091 
    9192import Orange 
     
    856857registerFileType = Orange.utils.deprecated_function_name(register_file_type) 
    857858 
    858 #__doc__ +=  \ 
     859__doc__ +=  \ 
    859860"""\ 
    860861Search Paths 
     
    862863 
    863864Associate a prefix with a search path for easier data loading. 
    864 The paths can be stored in a user specific file. 
    865  
    866 Example :: 
     865The paths can be stored in a user specific configuration file. 
     866 
     867.. note: The '' (empty string) prefix can be used to add search paths 
     868         to the default search path. 
     869 
     870.. note: Add-ons can register their search paths using 
     871        'orange.data.io.search_paths' entry point 
     872 
     873Example 
    867874 
    868875    >>> import Orange, os 
    869876    >>> from Orange.data import io 
    870     >>> io.set_search_path("my_datasets", 
    871     ...                     os.path.expanduser("~/Documents/My Datasets")) 
    872     ...                     persistent=True) 
    873     ... 
    874      
    875     >>> data = Orange.data.Table("mydatasets:dataset1.tab") 
     877    >>> directory = os.path.expanduser("~/Documents/My Datasets")) 
     878    >>> io.set_search_path("my_datasets", directory, persistent=True) 
     879    >>> data = Orange.data.Table("my_datasets:dataset1.tab") 
     880    >>> # Add directory to the default search path 
     881    >>> io.set_search_path("", directory) 
     882    >>> data = Orange.data.Table("dataset1.tab") 
    876883 
    877884 
     
    887894 
    888895""" 
     896 
     897 
    889898# Non-persistent registered paths 
    890899_session_paths = [] 
     
    893902from ConfigParser import SafeConfigParser 
    894903 
     904DATA_PATHS_ENTRY_POINT = "orange.data.io.search_paths" 
     905 
     906 
     907def addon_data_search_paths(): 
     908    """Return the search paths registered by setuptools 
     909    'orange.data.io.search_paths' entry point. 
     910 
     911    """ 
     912    import pkg_resources 
     913    search_paths = [] 
     914    for entry_point in pkg_resources.iter_entry_points(DATA_PATHS_ENTRY_POINT): 
     915        try: 
     916            call = entry_point.load() 
     917            paths = call() 
     918        except pkg_resources.DistributionNotFound, ex: 
     919            warnings.warn("Missing dependency for %r: %r" % (entry_point, ex), 
     920                         UserWarning) 
     921            paths = [] 
     922        except Exception, ex: 
     923            warnings.warn("Error calling %r: %r" % (entry_point, ex), 
     924                         UserWarning) 
     925            paths = [] 
     926 
     927        for path in paths: 
     928            if isinstance(path, tuple) and len(path) == 2 and \ 
     929                    all(isinstance(p, basestring) for p in path): 
     930                search_paths.append(path) 
     931            elif isinstance(path, basestring): 
     932                search_paths.append(("", path)) 
     933            else: 
     934                warnings.warn("Invalid search path %r. Expected tuple or " 
     935                              "string, got %r" % (entry_point, type(path))) 
     936    return search_paths 
     937 
     938 
    895939@Orange.utils.lru_cache(maxsize=1) 
    896940def persistent_search_paths(): 
    897     """ Return a list of persistent registered (prefix, path) pairs 
     941    """Return a list of persistent registered (prefix, path) pairs. 
    898942    """ 
    899943 
     
    909953    except ConfigParser.NoSectionError: 
    910954        items = [] 
     955    # Replace "__default__" prefix with "" 
     956    items = [item if item[0] != "__default__" else ("", item[1]) \ 
     957             for item in items] 
    911958    return items 
    912959 
     960 
    913961def save_persistent_search_path(prefix, path): 
    914     """ Save the prefix, path pair. If path is None delete the  
     962    """Save the prefix, path pair. If path is None delete the 
    915963    registered prefix. 
    916      
     964 
    917965    """ 
    918966    if isinstance(path, list): 
    919967        path = os.path.pathsep.join(path) 
     968 
     969    if prefix == "": 
     970        # Store "" prefix as "__default__" 
     971        prefix = "__default__" 
    920972 
    921973    user_settings_dir = Orange.utils.environ.orange_settings_dir 
     
    936988        parser.set("paths", prefix, path) 
    937989    elif parser.has_option("paths", prefix): 
    938         # Remove the registered prefix  
     990        # Remove the registered prefix 
    939991        parser.remove_option("paths", prefix) 
    940992    parser.write(open(filename, "wb")) 
    941993 
     994 
    942995def search_paths(prefix=None): 
    943     """ Return a list of the registered (prefix, path) pairs. 
     996    """Return the search path for `prefix`. The search path is 
     997    the union of registered session paths, user specified persistent 
     998    search paths and any search paths registered by 
     999    'orange.data.io.search_path' `pkg_resources` entry points. 
     1000 
    9441001    """ 
    9451002    persistent_paths = persistent_search_paths() 
    946     paths = _session_paths + persistent_paths 
     1003    addon_paths = addon_data_search_paths() 
     1004    paths = _session_paths + persistent_paths + addon_paths 
    9471005    if prefix is not None: 
     1006        ppaths = [] 
    9481007        for pref, path in paths: 
    9491008            if pref == prefix: 
    950                 return path 
    951         return "" 
     1009                ppaths.extend(path.split(os.path.pathsep)) 
     1010        return os.path.pathsep.join(ppaths) 
    9521011    else: 
    9531012        return paths 
    9541013 
     1014 
    9551015def set_search_path(prefix, path, persistent=False): 
    956     """ Associate a search path with a prefix. 
    957      
     1016    """Associate a search path with a prefix. 
     1017 
    9581018    :param prefix: a prefix 
    9591019    :type prefix: str 
    960      
     1020 
    9611021    :param path: search path (can also be a list of path strings) 
    9621022    :type paths: str 
    963      
    964     :param persistent: if True then the prefix-paths pair will be  
     1023 
     1024    :param persistent: if `True` then the (prefix, path) pair will be 
    9651025        saved between sessions (default False). 
    966     :type persistent: bool  
    967      
     1026    :type persistent: bool 
     1027 
    9681028    """ 
    9691029    global _session_paths 
     
    9811041 
    9821042def expand_filename(prefixed_name): 
    983     """ Expand the prefixed filename with the full path. 
    984     :: 
    985          
     1043    """Expand the prefixed filename with the full path. 
     1044 
    9861045        >>> from Orange.data import io 
    9871046        >>> io.set_search_paths("docs", "/Users/aleserjavec/Documents") 
    9881047        >>> io.expand_filename("docs:my_tab_file.tab") 
    9891048        '/Users/aleserjavec/Documents/my_tab_file.tab' 
    990          
    991          
    992     """ 
    993     prefix, filename = prefixed_name.split(":", 1) #TODO: windows drive letters. 
     1049 
     1050    """ 
     1051    # TODO: handle windows drive letters. 
     1052    if ":" in prefixed_name: 
     1053        prefix, filename = prefixed_name.split(":", 1) 
     1054    else: 
     1055        prefix, filename = "", prefixed_name 
    9941056    paths = search_paths(prefix) 
    9951057    if paths: 
    996         path = paths.split(os.path.pathsep, 1)[0] 
    997         return os.path.join(path, filename) 
     1058        paths = paths.split(os.path.pathsep) 
     1059        for path in paths: 
     1060            if os.path.exists(os.path.join(path, filename)): 
     1061                return os.path.join(path, filename) 
     1062        raise ValueError("%r not found on the search path." % filename) 
    9981063    else: 
    9991064        raise ValueError("Unknown prefix %r." % prefix) 
    10001065 
     1066 
    10011067def find_file(prefixed_name): 
    1002     """ Find the prefixed filename and return its full path. 
    1003     """ 
     1068    """Find the prefixed filename and return its full path. 
     1069    """ 
     1070    # This function is called from C++ if the default search 
     1071    # fails 
    10041072    if not os.path.exists(prefixed_name): 
    1005         if ":" not in prefixed_name: 
    1006             raise ValueError("Not a prefixed name.") 
    1007         prefix, filename = prefixed_name.split(":", 1) 
    1008         paths = search_paths(prefix) 
    1009         if paths: 
    1010             for path in paths.split(os.path.pathsep): 
    1011                 if os.path.exists(os.path.join(path, filename)): 
    1012                     return os.path.join(path, filename) 
    1013             raise ValueError("No file %r on prefixed search path %r." % \ 
    1014                              (filename, paths)) 
    1015         else: 
    1016             raise ValueError("Unknown prefix %r." % prefix) 
     1073        return expand_filename(prefixed_name) 
    10171074    else: 
    10181075        return prefixed_name 
    1019  
Note: See TracChangeset for help on using the changeset viewer.