check.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. from __future__ import print_function
  2. import time
  3. import sys
  4. from collections import defaultdict
  5. from unittest import TextTestRunner, TextTestResult as _TextTestResult
  6. from scrapy.commands import ScrapyCommand
  7. from scrapy.contracts import ContractsManager
  8. from scrapy.utils.misc import load_object, set_environ
  9. from scrapy.utils.conf import build_component_list
  10. class TextTestResult(_TextTestResult):
  11. def printSummary(self, start, stop):
  12. write = self.stream.write
  13. writeln = self.stream.writeln
  14. run = self.testsRun
  15. plural = "s" if run != 1 else ""
  16. writeln(self.separator2)
  17. writeln("Ran %d contract%s in %.3fs" % (run, plural, stop - start))
  18. writeln()
  19. infos = []
  20. if not self.wasSuccessful():
  21. write("FAILED")
  22. failed, errored = map(len, (self.failures, self.errors))
  23. if failed:
  24. infos.append("failures=%d" % failed)
  25. if errored:
  26. infos.append("errors=%d" % errored)
  27. else:
  28. write("OK")
  29. if infos:
  30. writeln(" (%s)" % (", ".join(infos),))
  31. else:
  32. write("\n")
  33. class Command(ScrapyCommand):
  34. requires_project = True
  35. default_settings = {'LOG_ENABLED': False}
  36. def syntax(self):
  37. return "[options] <spider>"
  38. def short_desc(self):
  39. return "Check spider contracts"
  40. def add_options(self, parser):
  41. ScrapyCommand.add_options(self, parser)
  42. parser.add_option("-l", "--list", dest="list", action="store_true",
  43. help="only list contracts, without checking them")
  44. parser.add_option("-v", "--verbose", dest="verbose", default=False, action='store_true',
  45. help="print contract tests for all spiders")
  46. def run(self, args, opts):
  47. # load contracts
  48. contracts = build_component_list(self.settings.getwithbase('SPIDER_CONTRACTS'))
  49. conman = ContractsManager(load_object(c) for c in contracts)
  50. runner = TextTestRunner(verbosity=2 if opts.verbose else 1)
  51. result = TextTestResult(runner.stream, runner.descriptions, runner.verbosity)
  52. # contract requests
  53. contract_reqs = defaultdict(list)
  54. spider_loader = self.crawler_process.spider_loader
  55. with set_environ(SCRAPY_CHECK='true'):
  56. for spidername in args or spider_loader.list():
  57. spidercls = spider_loader.load(spidername)
  58. spidercls.start_requests = lambda s: conman.from_spider(s, result)
  59. tested_methods = conman.tested_methods_from_spidercls(spidercls)
  60. if opts.list:
  61. for method in tested_methods:
  62. contract_reqs[spidercls.name].append(method)
  63. elif tested_methods:
  64. self.crawler_process.crawl(spidercls)
  65. # start checks
  66. if opts.list:
  67. for spider, methods in sorted(contract_reqs.items()):
  68. if not methods and not opts.verbose:
  69. continue
  70. print(spider)
  71. for method in sorted(methods):
  72. print(' * %s' % method)
  73. else:
  74. start = time.time()
  75. self.crawler_process.start()
  76. stop = time.time()
  77. result.printErrors()
  78. result.printSummary(start, stop)
  79. self.exitcode = int(not result.wasSuccessful())