123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- import os
- import sys
- import numbers
- from operator import itemgetter
- import six
- if six.PY2:
- from ConfigParser import SafeConfigParser as ConfigParser
- else:
- from configparser import ConfigParser
- from scrapy.settings import BaseSettings
- from scrapy.utils.deprecate import update_classpath
- from scrapy.utils.python import without_none_values
- def build_component_list(compdict, custom=None, convert=update_classpath):
- """Compose a component list from a { class: order } dictionary."""
- def _check_components(complist):
- if len({convert(c) for c in complist}) != len(complist):
- raise ValueError('Some paths in {!r} convert to the same object, '
- 'please update your settings'.format(complist))
- def _map_keys(compdict):
- if isinstance(compdict, BaseSettings):
- compbs = BaseSettings()
- for k, v in six.iteritems(compdict):
- prio = compdict.getpriority(k)
- if compbs.getpriority(convert(k)) == prio:
- raise ValueError('Some paths in {!r} convert to the same '
- 'object, please update your settings'
- ''.format(list(compdict.keys())))
- else:
- compbs.set(convert(k), v, priority=prio)
- return compbs
- else:
- _check_components(compdict)
- return {convert(k): v for k, v in six.iteritems(compdict)}
- def _validate_values(compdict):
- """Fail if a value in the components dict is not a real number or None."""
- for name, value in six.iteritems(compdict):
- if value is not None and not isinstance(value, numbers.Real):
- raise ValueError('Invalid value {} for component {}, please provide ' \
- 'a real number or None instead'.format(value, name))
- # BEGIN Backward compatibility for old (base, custom) call signature
- if isinstance(custom, (list, tuple)):
- _check_components(custom)
- return type(custom)(convert(c) for c in custom)
- if custom is not None:
- compdict.update(custom)
- # END Backward compatibility
- _validate_values(compdict)
- compdict = without_none_values(_map_keys(compdict))
- return [k for k, v in sorted(six.iteritems(compdict), key=itemgetter(1))]
- def arglist_to_dict(arglist):
- """Convert a list of arguments like ['arg1=val1', 'arg2=val2', ...] to a
- dict
- """
- return dict(x.split('=', 1) for x in arglist)
- def closest_scrapy_cfg(path='.', prevpath=None):
- """Return the path to the closest scrapy.cfg file by traversing the current
- directory and its parents
- """
- if path == prevpath:
- return ''
- path = os.path.abspath(path)
- cfgfile = os.path.join(path, 'scrapy.cfg')
- if os.path.exists(cfgfile):
- return cfgfile
- return closest_scrapy_cfg(os.path.dirname(path), path)
- def init_env(project='default', set_syspath=True):
- """Initialize environment to use command-line tool from inside a project
- dir. This sets the Scrapy settings module and modifies the Python path to
- be able to locate the project module.
- """
- cfg = get_config()
- if cfg.has_option('settings', project):
- os.environ['SCRAPY_SETTINGS_MODULE'] = cfg.get('settings', project)
- closest = closest_scrapy_cfg()
- if closest:
- projdir = os.path.dirname(closest)
- if set_syspath and projdir not in sys.path:
- sys.path.append(projdir)
- def get_config(use_closest=True):
- """Get Scrapy config file as a ConfigParser"""
- sources = get_sources(use_closest)
- cfg = ConfigParser()
- cfg.read(sources)
- return cfg
- def get_sources(use_closest=True):
- xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or \
- os.path.expanduser('~/.config')
- sources = ['/etc/scrapy.cfg', r'c:\scrapy\scrapy.cfg',
- xdg_config_home + '/scrapy.cfg',
- os.path.expanduser('~/.scrapy.cfg')]
- if use_closest:
- sources.append(closest_scrapy_cfg())
- return sources
|