Repository: scrapy/scrapy

Issue:
BaseSettings.__repr__ is too verbose for scrapy shell
Settings object got `__repr__` in https://github.com/scrapy/scrapy/pull/1149, but it looks weird in `scrapy shell`:

> [s] Available Scrapy objects:
> [s]   crawler    &lt;scrapy.crawler.Crawler object at 0x10c042fd0>
> [s]   item       {}
> [s]   request    &lt;GET http://yellowpages.co.th>
> [s]   response   &lt;302 http://yellowpages.co.th>
> [s]   settings   {'CLOSESPIDER_ITEMCOUNT': &lt;SettingsAttribute value=0 priority=0>, 'RETRY_HTTP_CODES': &lt;SettingsAttribute value=[500, 502, 503, 504, 408] priority=0>, 'HTTPCACHE_DIR': &lt;SettingsAttribute value='httpcache-2' priority=20>, 'MEMUSAGE_REPORT': &lt;SettingsAttribute value=False priority=0>, 'DOWNLOAD_HANDLERS_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'s3': &lt;SettingsAttribute value='scrapy.core.downloader.handlers.s3.S3DownloadHandler' priority=0>, 'ftp': &lt;SettingsAttribute value='scrapy.core.downloader.handlers.ftp.FTPDownloadHandler' priority=0>, 'http': &lt;SettingsAttribute value='scrapy.core.downloader.handlers.http.HTTPDownloadHandler' priority=0>, 'https': &lt;SettingsAttribute value='scrapy.core.downloader.handlers.http.HTTPDownloadHandler' priority=0>, 'file': &lt;SettingsAttribute value='scrapy.core.downloader.handlers.file.FileDownloadHandler' priority=0>}> priority=0>, 'RETRY_PRIORITY_ADJUST': &lt;SettingsAttribute value=-1 priority=0>, 'MAIL_FROM': &lt;SettingsAttribute value='scrapy@localhost' priority=0>, 'HTTPCACHE_EXPIRATION_SECS': &lt;SettingsAttribute value=86400 priority=20>, 'SPIDER_LOADER_CLASS': &lt;SettingsAttribute value='scrapy.spiderloader.SpiderLoader' priority=0>, 'COMPRESSION_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'DOWNLOAD_TIMEOUT': &lt;SettingsAttribute value=180 priority=0>, 'MAIL_PASS': &lt;SettingsAttribute value=None priority=0>, 'MEMUSAGE_LIMIT_MB': &lt;SettingsAttribute value=0 priority=0>, 'EXTENSIONS': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'DEPTH_PRIORITY': &lt;SettingsAttribute value=0 priority=0>, 'TELNETCONSOLE_HOST': &lt;SettingsAttribute value='127.0.0.1' priority=0>, 'MEMDEBUG_NOTIFY': &lt;SettingsAttribute value=[] priority=0>, 'HTTPPROXY_AUTH_ENCODING': &lt;SettingsAttribute value='latin-1' priority=0>, 'DOWNLOAD_WARNSIZE': &lt;SettingsAttribute value=33554432 priority=0>, 'SPIDER_MODULES': &lt;SettingsAttribute value=['acrawler.spiders'] priority=20>, 'RETRY_TIMES': &lt;SettingsAttribute value=2 priority=0>, 'TELNETCONSOLE_PORT': &lt;SettingsAttribute value=[6023, 6073] priority=0>, 'TELNETCONSOLE_ENABLED': &lt;SettingsAttribute value=False priority=20>, 'DOWNLOADER_MIDDLEWARES': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'HTTPCACHE_DBM_MODULE': &lt;SettingsAttribute value='anydbm' priority=0>, 'ROBOTSTXT_OBEY': &lt;SettingsAttribute value=True priority=20>, 'DEPTH_LIMIT': &lt;SettingsAttribute value=0 priority=0>, 'REACTOR_THREADPOOL_MAXSIZE': &lt;SettingsAttribute value=10 priority=0>, 'FEED_EXPORT_FIELDS': &lt;SettingsAttribute value=None priority=0>, 'CLOSESPIDER_PAGECOUNT': &lt;SettingsAttribute value=0 priority=0>, 'LOG_SHORT_NAMES': &lt;SettingsAttribute value=False priority=0>, 'AUTOTHROTTLE_MAX_DELAY': &lt;SettingsAttribute value=60 priority=20>, 'URLLENGTH_LIMIT': &lt;SettingsAttribute value=2083 priority=0>, 'FEED_EXPORTERS': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'LOG_ENCODING': &lt;SettingsAttribute value='utf-8' priority=0>, 'FEED_EXPORTERS_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'xml': &lt;SettingsAttribute value='scrapy.exporters.XmlItemExporter' priority=0>, 'jsonlines': &lt;SettingsAttribute value='scrapy.exporters.JsonLinesItemExporter' priority=0>, 'jl': &lt;SettingsAttribute value='scrapy.exporters.JsonLinesItemExporter' priority=0>, 'json': &lt;SettingsAttribute value='scrapy.exporters.JsonItemExporter' priority=0>, 'csv': &lt;SettingsAttribute value='scrapy.exporters.CsvItemExporter' priority=0>, 'pickle': &lt;SettingsAttribute value='scrapy.exporters.PickleItemExporter' priority=0>, 'marshal': &lt;SettingsAttribute value='scrapy.exporters.MarshalItemExporter' priority=0>}> priority=0>, 'FEED_FORMAT': &lt;SettingsAttribute value='jsonlines' priority=0>, 'DOWNLOAD_DELAY': &lt;SettingsAttribute value=0 priority=0>, 'HTTPCACHE_GZIP': &lt;SettingsAttribute value=False priority=0>, 'DOWNLOADER_MIDDLEWARES_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': &lt;SettingsAttribute value=400 priority=0>, 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': &lt;SettingsAttribute value=550 priority=0>, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': &lt;SettingsAttribute value=590 priority=0>, 'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware': &lt;SettingsAttribute value=830 priority=0>, 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': &lt;SettingsAttribute value=100 priority=0>, 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': &lt;SettingsAttribute value=350 priority=0>, 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': &lt;SettingsAttribute value=600 priority=0>, 'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': &lt;SettingsAttribute value=560 priority=0>, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': &lt;SettingsAttribute value=750 priority=0>, 'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': &lt;SettingsAttribute value=900 priority=0>, 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': &lt;SettingsAttribute value=300 priority=0>, 'scrapy.downloadermiddlewares.retry.RetryMiddleware': &lt;SettingsAttribute value=500 priority=0>, 'scrapy.downloadermiddlewares.stats.DownloaderStats': &lt;SettingsAttribute value=850 priority=0>, 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': &lt;SettingsAttribute value=700 priority=0>, 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': &lt;SettingsAttribute value=580 priority=0>}> priority=0>, 'DNSCACHE_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'CONCURRENT_REQUESTS_PER_IP': &lt;SettingsAttribute value=0 priority=0>, 'EDITOR': &lt;SettingsAttribute value='nano' priority=0>, 'MAIL_HOST': &lt;SettingsAttribute value='localhost' priority=0>, 'CONCURRENT_REQUESTS': &lt;SettingsAttribute value=100 priority=20>, 'AUTOTHROTTLE_START_DELAY': &lt;SettingsAttribute value=1 priority=20>, 'CLOSESPIDER_ERRORCOUNT': &lt;SettingsAttribute value=0 priority=0>, 'STATS_CLASS': &lt;SettingsAttribute value='scrapy.statscollectors.MemoryStatsCollector' priority=0>, 'FEED_STORAGES_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'': &lt;SettingsAttribute value='scrapy.extensions.feedexport.FileFeedStorage' priority=0>, 's3': &lt;SettingsAttribute value='scrapy.extensions.feedexport.S3FeedStorage' priority=0>, 'ftp': &lt;SettingsAttribute value='scrapy.extensions.feedexport.FTPFeedStorage' priority=0>, 'file': &lt;SettingsAttribute value='scrapy.extensions.feedexport.FileFeedStorage' priority=0>, 'stdout': &lt;SettingsAttribute value='scrapy.extensions.feedexport.StdoutFeedStorage' priority=0>}> priority=0>, 'REDIRECT_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'AUTOTHROTTLE_ENABLED': &lt;SettingsAttribute value=True priority=20>, 'COMMANDS_MODULE': &lt;SettingsAttribute value='' priority=0>, 'AUTOTHROTTLE_DEBUG': &lt;SettingsAttribute value=False priority=0>, 'NEWSPIDER_MODULE': &lt;SettingsAttribute value='acrawler.spiders' priority=20>, 'LOG_UNSERIALIZABLE_REQUESTS': &lt;SettingsAttribute value=False priority=0>, 'DOWNLOAD_MAXSIZE': &lt;SettingsAttribute value=1073741824 priority=0>, 'MAIL_PORT': &lt;SettingsAttribute value=25 priority=0>, 'REFERER_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'HTTPCACHE_POLICY': &lt;SettingsAttribute value='scrapy.extensions.httpcache.DummyPolicy' priority=0>, 'STATS_DUMP': &lt;SettingsAttribute value=True priority=0>, 'MEMUSAGE_NOTIFY_MAIL': &lt;SettingsAttribute value=[] priority=0>, 'DOWNLOAD_HANDLERS': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'LOG_DATEFORMAT': &lt;SettingsAttribute value='%Y-%m-%d %H:%M:%S' priority=0>, 'LOG_LEVEL': &lt;SettingsAttribute value='DEBUG' priority=0>, 'DOWNLOADER_HTTPCLIENTFACTORY': &lt;SettingsAttribute value='scrapy.core.downloader.webclient.ScrapyHTTPClientFactory' priority=0>, 'REDIRECT_MAX_TIMES': &lt;SettingsAttribute value=20 priority=0>, 'REDIRECT_PRIORITY_ADJUST': &lt;SettingsAttribute value=2 priority=0>, 'DUPEFILTER_CLASS': &lt;SettingsAttribute value='scrapy.dupefilters.BaseDupeFilter' priority=10>, 'RETRY_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'SPIDER_CONTRACTS': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'HTTPCACHE_ENABLED': &lt;SettingsAttribute value=True priority=20>, 'LOG_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'MAIL_USER': &lt;SettingsAttribute value=None priority=0>, 'HTTPCACHE_ALWAYS_STORE': &lt;SettingsAttribute value=False priority=0>, 'LOGSTATS_INTERVAL': &lt;SettingsAttribute value=0 priority=10>, 'DEFAULT_ITEM_CLASS': &lt;SettingsAttribute value='scrapy.item.Item' priority=0>, 'DNS_TIMEOUT': &lt;SettingsAttribute value=60 priority=0>, 'DEPTH_STATS': &lt;SettingsAttribute value=True priority=0>, 'DOWNLOADER_CLIENTCONTEXTFACTORY': &lt;SettingsAttribute value='scrapy.core.downloader.contextfactory.ScrapyClientContextFactory' priority=0>, 'MEMUSAGE_CHECK_INTERVAL_SECONDS': &lt;SettingsAttribute value=60.0 priority=0>, 'EXTENSIONS_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'scrapy.extensions.corestats.CoreStats': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.feedexport.FeedExporter': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.memdebug.MemoryDebugger': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.memusage.MemoryUsage': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.logstats.LogStats': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.telnet.TelnetConsole': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.closespider.CloseSpider': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.spiderstate.SpiderState': &lt;SettingsAttribute value=0 priority=0>, 'scrapy.extensions.throttle.AutoThrottle': &lt;SettingsAttribute value=0 priority=0>}> priority=0>, 'FEED_STORAGES': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'BOT_NAME': &lt;SettingsAttribute value='acrawler' priority=20>, 'SPIDER_CONTRACTS_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'scrapy.contracts.default.ScrapesContract': &lt;SettingsAttribute value=3 priority=0>, 'scrapy.contracts.default.UrlContract': &lt;SettingsAttribute value=1 priority=0>, 'scrapy.contracts.default.ReturnsContract': &lt;SettingsAttribute value=2 priority=0>}> priority=0>, 'METAREFRESH_MAXDELAY': &lt;SettingsAttribute value=100 priority=0>, 'CONCURRENT_REQUESTS_PER_DOMAIN': &lt;SettingsAttribute value=8 priority=0>, 'HTTPCACHE_IGNORE_HTTP_CODES': &lt;SettingsAttribute value=[] priority=0>, 'KEEP_ALIVE': &lt;SettingsAttribute value=True priority=10>, 'ITEM_PROCESSOR': &lt;SettingsAttribute value='scrapy.pipelines.ItemPipelineManager' priority=0>, 'MEMUSAGE_WARNING_MB': &lt;SettingsAttribute value=0 priority=0>, 'FEED_STORE_EMPTY': &lt;SettingsAttribute value=False priority=0>, 'COOKIES_DEBUG': &lt;SettingsAttribute value=False priority=0>, 'FEED_URI': &lt;SettingsAttribute value=None priority=0>, 'SPIDER_MIDDLEWARES': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'DOWNLOADER': &lt;SettingsAttribute value='scrapy.core.downloader.Downloader' priority=0>, 'AUTOTHROTTLE_TARGET_CONCURRENCY': &lt;SettingsAttribute value=1.0 priority=20>, 'USER_AGENT': &lt;SettingsAttribute value='acrawler' priority=20>, 'AJAXCRAWL_ENABLED': &lt;SettingsAttribute value=False priority=0>, 'COOKIES_ENABLED': &lt;SettingsAttribute value=False priority=20>, 'DNSCACHE_SIZE': &lt;SettingsAttribute value=10000 priority=0>, 'LOG_FORMAT': &lt;SettingsAttribute value='%(asctime)s [%(name)s] %(levelname)s: %(message)s' priority=0>, 'ITEM_PIPELINES': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'LOG_FORMATTER': &lt;SettingsAttribute value='scrapy.logformatter.LogFormatter' priority=0>, 'HTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS': &lt;SettingsAttribute value=[] priority=0>, 'METAREFRESH_ENABLED': &lt;SettingsAttribute value=True priority=0>, 'HTTPCACHE_IGNORE_MISSING': &lt;SettingsAttribute value=False priority=0>, 'HTTPCACHE_IGNORE_SCHEMES': &lt;SettingsAttribute value=['file'] priority=0>, 'SCHEDULER_MEMORY_QUEUE': &lt;SettingsAttribute value='scrapy.squeues.LifoMemoryQueue' priority=0>, 'SCHEDULER_DISK_QUEUE': &lt;SettingsAttribute value='scrapy.squeues.PickleLifoDiskQueue' priority=0>, 'RANDOMIZE_DOWNLOAD_DELAY': &lt;SettingsAttribute value=True priority=0>, 'SETTINGS_MODULE': &lt;SettingsAttribute value='acrawler.settings' priority=20>, 'TEMPLATES_DIR': &lt;SettingsAttribute value='/Users/kmike/svn/scrapy/scrapy/templates' priority=0>, 'LOG_STDOUT': &lt;SettingsAttribute value=False priority=0>, 'CONCURRENT_ITEMS': &lt;SettingsAttribute value=100 priority=0>, 'DOWNLOADER_STATS': &lt;SettingsAttribute value=True priority=0>, 'LOG_FILE': &lt;SettingsAttribute value=None priority=0>, 'HTTPCACHE_STORAGE': &lt;SettingsAttribute value='scrapy.extensions.httpcache.FilesystemCacheStorage' priority=20>, 'MEMDEBUG_ENABLED': &lt;SettingsAttribute value=False priority=0>, 'FEED_URI_PARAMS': &lt;SettingsAttribute value=None priority=0>, 'DEFAULT_REQUEST_HEADERS': &lt;SettingsAttribute value=&lt;BaseSettings {'Accept-Language': &lt;SettingsAttribute value='en' priority=0>, 'Accept': &lt;SettingsAttribute value='text/html,application/xhtml+xml,application/xml;q=0.9,_/_;q=0.8' priority=0>}> priority=0>, 'CLOSESPIDER_TIMEOUT': &lt;SettingsAttribute value=0 priority=0>, 'SCHEDULER': &lt;SettingsAttribute value='scrapy.core.scheduler.Scheduler' priority=0>, 'SPIDER_MIDDLEWARES_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {'scrapy.spidermiddlewares.referer.RefererMiddleware': &lt;SettingsAttribute value=700 priority=0>, 'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': &lt;SettingsAttribute value=50 priority=0>, 'scrapy.spidermiddlewares.depth.DepthMiddleware': &lt;SettingsAttribute value=900 priority=0>, 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': &lt;SettingsAttribute value=800 priority=0>, 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': &lt;SettingsAttribute value=500 priority=0>}> priority=0>, 'ITEM_PIPELINES_BASE': &lt;SettingsAttribute value=&lt;BaseSettings {}> priority=0>, 'STATSMAILER_RCPTS': &lt;SettingsAttribute value=[] priority=0>, 'MEMUSAGE_ENABLED': &lt;SettingsAttribute value=False priority=0>}
> [s]   spider     &lt;DefaultSpider 'default' at 0x10ebdcf90>
> [s] Useful shortcuts:
> [s]   shelp()           Shell help (print this help)
> [s]   fetch(req_or_url) Fetch request (or URL) and update local objects
> [s]   view(response)    View response in a browser



Discussion:
@kmike , you may want to edit the shell output in Github (e.g. replacing `<` with `&lt;`). it looks really scarier even :)

done :ghost: 

@kmike , how would you prefer it?

1. `__repr__` and `__str__` should be different for SettingsAttribute; repr should return a constructor call, while str should return short representation, maybe even without `SettingsAttribute` name.
2. `BaseSettings.__str__` shouldn't call str(self.attributes) because str(some_dict) calls repr on dict keys and values, this is too verbose. I'm not sure `__str__` won't be too verbose even if we use str for dict keys and values, so maybe something shorter would be better, maybe just `<BaseSettings object at ...>` is fine.
3. scrapy shell should use str(), not repr().

If that's too much, for 1.1 it may be fine to just remove custom str and/or repr for BaseSetting. 

:trollface: Is fine, just pretty print it :trollface:

I'm fine with current behavior, just limit the length of it on shell.

I'm fine with just printing a short `<BaseSettings object at ...>` when scrapy shell starts

```
[s] Available Scrapy objects:
[s]   crawler    <scrapy.crawler.Crawler object at 0x7ffbca4089d0>
[s]   item       {}
[s]   settings   <BaseSettings object at ...>
[s] Useful shortcuts:
[s]   shelp()           Shell help (print this help)
[s]   fetch(req_or_url) Fetch request (or URL) and update local objects
[s]   view(response)    View response in a browser
```

but I'd also like that typing `settings` in the shell outputs something easy to read (which is not the case right now), for those wanting to check some settings quickly.

Although not perfect, `dict(settings)` is already much easier:

```
In [18]: dict(settings)
Out[18]: 
{'AJAXCRAWL_ENABLED': False,
 'AUTOTHROTTLE_DEBUG': False,
 'AUTOTHROTTLE_ENABLED': False,
 'AUTOTHROTTLE_MAX_DELAY': 60.0,
 'AUTOTHROTTLE_START_DELAY': 5.0,
 'AUTOTHROTTLE_TARGET_CONCURRENCY': 1.0,
 'BOT_NAME': 'scrapybot',
 'CLOSESPIDER_ERRORCOUNT': 0,
 'CLOSESPIDER_ITEMCOUNT': 0,
 'CLOSESPIDER_PAGECOUNT': 0,
 'CLOSESPIDER_TIMEOUT': 0,
 'COMMANDS_MODULE': '',
 'COMPRESSION_ENABLED': True,
 'CONCURRENT_ITEMS': 100,
 'CONCURRENT_REQUESTS': 16,
 'CONCURRENT_REQUESTS_PER_DOMAIN': 8,
 'CONCURRENT_REQUESTS_PER_IP': 0,
 'COOKIES_DEBUG': False,
 'COOKIES_ENABLED': True,
 'DEFAULT_ITEM_CLASS': 'scrapy.item.Item',
 'DEFAULT_REQUEST_HEADERS': <BaseSettings {'Accept-Language': <SettingsAttribute value='en' priority=0>, 'Accept': <SettingsAttribute value='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' priority=0>}>,
 'DEPTH_LIMIT': 0,
 'DEPTH_PRIORITY': 0,
 'DEPTH_STATS': True,
 'DNSCACHE_ENABLED': True,
 'DNSCACHE_SIZE': 10000,
 'DNS_TIMEOUT': 60,
 'DOWNLOADER': 'scrapy.core.downloader.Downloader',
 'DOWNLOADER_CLIENTCONTEXTFACTORY': 'scrapy.core.downloader.contextfactory.ScrapyClientContextFactory',
 'DOWNLOADER_HTTPCLIENTFACTORY': 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory',
 'DOWNLOADER_MIDDLEWARES': <BaseSettings {}>,
 'DOWNLOADER_MIDDLEWARES_BASE': <BaseSettings {'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': <SettingsAttribute value=400 priority=0>, 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': <SettingsAttribute value=550 priority=0>, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': <SettingsAttribute value=590 priority=0>, 'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware': <SettingsAttribute value=830 priority=0>, 'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': <SettingsAttribute value=100 priority=0>, 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': <SettingsAttribute value=350 priority=0>, 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': <SettingsAttribute value=600 priority=0>, 'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': <SettingsAttribute value=560 priority=0>, 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': <SettingsAttribute value=750 priority=0>, 'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': <SettingsAttribute value=900 priority=0>, 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': <SettingsAttribute value=300 priority=0>, 'scrapy.downloadermiddlewares.retry.RetryMiddleware': <SettingsAttribute value=500 priority=0>, 'scrapy.downloadermiddlewares.stats.DownloaderStats': <SettingsAttribute value=850 priority=0>, 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': <SettingsAttribute value=700 priority=0>, 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': <SettingsAttribute value=580 priority=0>}>,
 'DOWNLOADER_STATS': True,
 'DOWNLOAD_DELAY': 0,
 'DOWNLOAD_HANDLERS': <BaseSettings {}>,
 'DOWNLOAD_HANDLERS_BASE': <BaseSettings {'s3': <SettingsAttribute value='scrapy.core.downloader.handlers.s3.S3DownloadHandler' priority=0>, 'ftp': <SettingsAttribute value='scrapy.core.downloader.handlers.ftp.FTPDownloadHandler' priority=0>, 'http': <SettingsAttribute value='scrapy.core.downloader.handlers.http.HTTPDownloadHandler' priority=0>, 'https': <SettingsAttribute value='scrapy.core.downloader.handlers.http.HTTPDownloadHandler' priority=0>, 'file': <SettingsAttribute value='scrapy.core.downloader.handlers.file.FileDownloadHandler' priority=0>}>,
 'DOWNLOAD_MAXSIZE': 1073741824,
 'DOWNLOAD_TIMEOUT': 180,
 'DOWNLOAD_WARNSIZE': 33554432,
 'DUPEFILTER_CLASS': 'scrapy.dupefilters.BaseDupeFilter',
 'EDITOR': 'vi',
 'EXTENSIONS': <BaseSettings {}>,
 'EXTENSIONS_BASE': <BaseSettings {'scrapy.extensions.corestats.CoreStats': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.feedexport.FeedExporter': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.memdebug.MemoryDebugger': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.memusage.MemoryUsage': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.logstats.LogStats': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.telnet.TelnetConsole': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.closespider.CloseSpider': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.spiderstate.SpiderState': <SettingsAttribute value=0 priority=0>, 'scrapy.extensions.throttle.AutoThrottle': <SettingsAttribute value=0 priority=0>}>,
 'FEED_EXPORTERS': <BaseSettings {}>,
 'FEED_EXPORTERS_BASE': <BaseSettings {'xml': <SettingsAttribute value='scrapy.exporters.XmlItemExporter' priority=0>, 'jsonlines': <SettingsAttribute value='scrapy.exporters.JsonLinesItemExporter' priority=0>, 'jl': <SettingsAttribute value='scrapy.exporters.JsonLinesItemExporter' priority=0>, 'json': <SettingsAttribute value='scrapy.exporters.JsonItemExporter' priority=0>, 'csv': <SettingsAttribute value='scrapy.exporters.CsvItemExporter' priority=0>, 'pickle': <SettingsAttribute value='scrapy.exporters.PickleItemExporter' priority=0>, 'marshal': <SettingsAttribute value='scrapy.exporters.MarshalItemExporter' priority=0>}>,
 'FEED_EXPORT_FIELDS': None,
 'FEED_FORMAT': 'jsonlines',
 'FEED_STORAGES': <BaseSettings {}>,
 'FEED_STORAGES_BASE': <BaseSettings {'': <SettingsAttribute value='scrapy.extensions.feedexport.FileFeedStorage' priority=0>, 's3': <SettingsAttribute value='scrapy.extensions.feedexport.S3FeedStorage' priority=0>, 'ftp': <SettingsAttribute value='scrapy.extensions.feedexport.FTPFeedStorage' priority=0>, 'file': <SettingsAttribute value='scrapy.extensions.feedexport.FileFeedStorage' priority=0>, 'stdout': <SettingsAttribute value='scrapy.extensions.feedexport.StdoutFeedStorage' priority=0>}>,
 'FEED_STORE_EMPTY': False,
 'FEED_URI': None,
 'FEED_URI_PARAMS': None,
 'HTTPCACHE_ALWAYS_STORE': False,
 'HTTPCACHE_DBM_MODULE': 'anydbm',
 'HTTPCACHE_DIR': 'httpcache',
 'HTTPCACHE_ENABLED': False,
 'HTTPCACHE_EXPIRATION_SECS': 0,
 'HTTPCACHE_GZIP': False,
 'HTTPCACHE_IGNORE_HTTP_CODES': [],
 'HTTPCACHE_IGNORE_MISSING': False,
 'HTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS': [],
 'HTTPCACHE_IGNORE_SCHEMES': ['file'],
 'HTTPCACHE_POLICY': 'scrapy.extensions.httpcache.DummyPolicy',
 'HTTPCACHE_STORAGE': 'scrapy.extensions.httpcache.FilesystemCacheStorage',
 'HTTPPROXY_AUTH_ENCODING': 'latin-1',
 'ITEM_PIPELINES': <BaseSettings {}>,
 'ITEM_PIPELINES_BASE': <BaseSettings {}>,
 'ITEM_PROCESSOR': 'scrapy.pipelines.ItemPipelineManager',
 'KEEP_ALIVE': True,
 'LOGSTATS_INTERVAL': 0,
 'LOG_DATEFORMAT': '%Y-%m-%d %H:%M:%S',
 'LOG_ENABLED': True,
 'LOG_ENCODING': 'utf-8',
 'LOG_FILE': None,
 'LOG_FORMAT': '%(asctime)s [%(name)s] %(levelname)s: %(message)s',
 'LOG_FORMATTER': 'scrapy.logformatter.LogFormatter',
 'LOG_LEVEL': 'DEBUG',
 'LOG_STDOUT': False,
 'LOG_UNSERIALIZABLE_REQUESTS': False,
 'MAIL_FROM': 'scrapy@localhost',
 'MAIL_HOST': 'localhost',
 'MAIL_PASS': None,
 'MAIL_PORT': 25,
 'MAIL_USER': None,
 'MEMDEBUG_ENABLED': False,
 'MEMDEBUG_NOTIFY': [],
 'MEMUSAGE_CHECK_INTERVAL_SECONDS': 60.0,
 'MEMUSAGE_ENABLED': False,
 'MEMUSAGE_LIMIT_MB': 0,
 'MEMUSAGE_NOTIFY_MAIL': [],
 'MEMUSAGE_REPORT': False,
 'MEMUSAGE_WARNING_MB': 0,
 'METAREFRESH_ENABLED': True,
 'METAREFRESH_MAXDELAY': 100,
 'NEWSPIDER_MODULE': '',
 'RANDOMIZE_DOWNLOAD_DELAY': True,
 'REACTOR_THREADPOOL_MAXSIZE': 10,
 'REDIRECT_ENABLED': True,
 'REDIRECT_MAX_TIMES': 20,
 'REDIRECT_PRIORITY_ADJUST': 2,
 'REFERER_ENABLED': True,
 'RETRY_ENABLED': True,
 'RETRY_HTTP_CODES': [500, 502, 503, 504, 408],
 'RETRY_PRIORITY_ADJUST': -1,
 'RETRY_TIMES': 2,
 'ROBOTSTXT_OBEY': False,
 'SCHEDULER': 'scrapy.core.scheduler.Scheduler',
 'SCHEDULER_DISK_QUEUE': 'scrapy.squeues.PickleLifoDiskQueue',
 'SCHEDULER_MEMORY_QUEUE': 'scrapy.squeues.LifoMemoryQueue',
 'SPIDER_CONTRACTS': <BaseSettings {}>,
 'SPIDER_CONTRACTS_BASE': <BaseSettings {'scrapy.contracts.default.ScrapesContract': <SettingsAttribute value=3 priority=0>, 'scrapy.contracts.default.UrlContract': <SettingsAttribute value=1 priority=0>, 'scrapy.contracts.default.ReturnsContract': <SettingsAttribute value=2 priority=0>}>,
 'SPIDER_LOADER_CLASS': 'scrapy.spiderloader.SpiderLoader',
 'SPIDER_MIDDLEWARES': <BaseSettings {}>,
 'SPIDER_MIDDLEWARES_BASE': <BaseSettings {'scrapy.spidermiddlewares.referer.RefererMiddleware': <SettingsAttribute value=700 priority=0>, 'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': <SettingsAttribute value=50 priority=0>, 'scrapy.spidermiddlewares.depth.DepthMiddleware': <SettingsAttribute value=900 priority=0>, 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': <SettingsAttribute value=800 priority=0>, 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': <SettingsAttribute value=500 priority=0>}>,
 'SPIDER_MODULES': [],
 'STATSMAILER_RCPTS': [],
 'STATS_CLASS': 'scrapy.statscollectors.MemoryStatsCollector',
 'STATS_DUMP': True,
 'TELNETCONSOLE_ENABLED': 1,
 'TELNETCONSOLE_HOST': '127.0.0.1',
 'TELNETCONSOLE_PORT': [6023, 6073],
 'TEMPLATES_DIR': '/home/paul/src/scrapy/scrapy/templates',
 'URLLENGTH_LIMIT': 2083,
 'USER_AGENT': u'Scrapy/1.1.0dev1 (+http://scrapy.org)'}
```

Here's my proposal:
- get rid of `__str__` and `__repr__` in `BaseSettings`
- add a `to_dict` method to `BaseSettings` class
- users wanting to get a pretty version of settings can use `settings.to_dict()`, or even pprint it if wanted

This is the change I have locally:

```
~/src/scrapy$ git diff
diff --git a/scrapy/settings/__init__.py b/scrapy/settings/__init__.py
index 342d258..6719590 100644
--- a/scrapy/settings/__init__.py
+++ b/scrapy/settings/__init__.py
@@ -368,11 +368,9 @@ class BaseSettings(MutableMapping):
     def __len__(self):
         return len(self.attributes)

-    def __str__(self):
-        return str(self.attributes)
-
-    def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.attributes)
+    def to_dict(self):
+        return {k: (v.to_dict() if isinstance(v, BaseSettings) else v)
+                for k, v in six.iteritems(self)}

     @property
     def overrides(self):
```

and the result in `scrapy shell` is https://gist.github.com/redapple/7f10180981dce6f9c995

@redapple I'm fine the `to_dict` method. I kinda wanted to have it on the past, but never really had a need, now that we have a more complicated `Settings class`  I suppose is useful. Just be sure to document is a copy of the `Settings object` and changes on the `dict` wont affect the `Settings`.


Resolving patch:
diff --git a/scrapy/commands/settings.py b/scrapy/commands/settings.py
--- a/scrapy/commands/settings.py
+++ b/scrapy/commands/settings.py
@@ -1,5 +1,8 @@
 from __future__ import print_function
+import json
+
 from scrapy.commands import ScrapyCommand
+from scrapy.settings import BaseSettings
 
 class Command(ScrapyCommand):
 
@@ -28,7 +31,11 @@ def add_options(self, parser):
     def run(self, args, opts):
         settings = self.crawler_process.settings
         if opts.get:
-            print(settings.get(opts.get))
+            s = settings.get(opts.get)
+            if isinstance(s, BaseSettings):
+                print(json.dumps(s.copy_to_dict()))
+            else:
+                print(s)
         elif opts.getbool:
             print(settings.getbool(opts.getbool))
         elif opts.getint:
diff --git a/scrapy/settings/__init__.py b/scrapy/settings/__init__.py
--- a/scrapy/settings/__init__.py
+++ b/scrapy/settings/__init__.py
@@ -4,6 +4,7 @@
 import warnings
 from collections import MutableMapping
 from importlib import import_module
+from pprint import pformat
 
 from scrapy.utils.deprecate import create_deprecated_class
 from scrapy.exceptions import ScrapyDeprecationWarning
@@ -368,11 +369,31 @@ def __iter__(self):
     def __len__(self):
         return len(self.attributes)
 
-    def __str__(self):
-        return str(self.attributes)
+    def _to_dict(self):
+        return {k: (v._to_dict() if isinstance(v, BaseSettings) else v)
+                for k, v in six.iteritems(self)}
+
+    def copy_to_dict(self):
+        """
+        Make a copy of current settings and convert to a dict.
 
-    def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.attributes)
+        This method returns a new dict populated with the same values
+        and their priorities as the current settings.
+
+        Modifications to the returned dict won't be reflected on the original
+        settings.
+
+        This method can be useful for example for printing settings
+        in Scrapy shell.
+        """
+        settings = self.copy()
+        return settings._to_dict()
+
+    def _repr_pretty_(self, p, cycle):
+        if cycle:
+            p.text(repr(self))
+        else:
+            p.text(pformat(self.copy_to_dict()))
 
     @property
     def overrides(self):


Test patch:
diff --git a/tests/test_cmdline/__init__.py b/tests/test_cmdline/__init__.py
--- a/tests/test_cmdline/__init__.py
+++ b/tests/test_cmdline/__init__.py
@@ -68,4 +68,4 @@ def test_override_dict_settings(self):
             settingsstr = settingsstr.replace(char, '"')
         settingsdict = json.loads(settingsstr)
         six.assertCountEqual(self, settingsdict.keys(), EXTENSIONS.keys())
-        self.assertIn('value=200', settingsdict[EXT_PATH])
+        self.assertEquals(200, settingsdict[EXT_PATH])
diff --git a/tests/test_settings/__init__.py b/tests/test_settings/__init__.py
--- a/tests/test_settings/__init__.py
+++ b/tests/test_settings/__init__.py
@@ -302,6 +302,21 @@ def test_copy(self):
         self.assertListEqual(copy.get('TEST_LIST_OF_LISTS')[0],
                              ['first_one', 'first_two'])
 
+    def test_copy_to_dict(self):
+        s = BaseSettings({'TEST_STRING': 'a string',
+                          'TEST_LIST': [1, 2],
+                          'TEST_BOOLEAN': False,
+                          'TEST_BASE': BaseSettings({1: 1, 2: 2}, 'project'),
+                          'TEST': BaseSettings({1: 10, 3: 30}, 'default'),
+                          'HASNOBASE': BaseSettings({3: 3000}, 'default')})
+        self.assertDictEqual(s.copy_to_dict(),
+                            {'HASNOBASE': {3: 3000},
+                             'TEST': {1: 10, 3: 30},
+                             'TEST_BASE': {1: 1, 2: 2},
+                             'TEST_BOOLEAN': False,
+                             'TEST_LIST': [1, 2],
+                             'TEST_STRING': 'a string'})
+
     def test_freeze(self):
         self.settings.freeze()
         with self.assertRaises(TypeError) as cm:
@@ -343,14 +358,6 @@ def test_deprecated_attribute_defaults(self):
             self.assertEqual(self.settings.defaults.get('BAR'), 'foo')
             self.assertIn('BAR', self.settings.defaults)
 
-    def test_repr(self):
-        settings = BaseSettings()
-        self.assertEqual(repr(settings), "<BaseSettings {}>")
-        attr = SettingsAttribute('testval', 15)
-        settings['testkey'] = attr
-        self.assertEqual(repr(settings),
-                         "<BaseSettings {'testkey': %s}>" % repr(attr))
-
 
 class SettingsTest(unittest.TestCase):