DebugClients/Python3/coverage/data.py

changeset 5051
3586ebd9fac8
parent 4489
d0d6e4ad31bd
equal deleted inserted replaced
5047:04e5dfbd3f3d 5051:3586ebd9fac8
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt 2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3 3
4 """Coverage data for coverage.py.""" 4 """Coverage data for coverage.py."""
5 5
6 import glob 6 import glob
7 import itertools
7 import json 8 import json
8 import optparse 9 import optparse
9 import os 10 import os
10 import os.path 11 import os.path
11 import random 12 import random
14 15
15 from coverage import env 16 from coverage import env
16 from coverage.backward import iitems, string_class 17 from coverage.backward import iitems, string_class
17 from coverage.debug import _TEST_NAME_FILE 18 from coverage.debug import _TEST_NAME_FILE
18 from coverage.files import PathAliases 19 from coverage.files import PathAliases
19 from coverage.misc import CoverageException, file_be_gone 20 from coverage.misc import CoverageException, file_be_gone, isolate_module
21
22 os = isolate_module(os)
20 23
21 24
22 class CoverageData(object): 25 class CoverageData(object):
23 """Manages collected coverage data, including file storage. 26 """Manages collected coverage data, including file storage.
24 27
174 If the file was executed, returns a list of integers, the line numbers 177 If the file was executed, returns a list of integers, the line numbers
175 executed in the file. The list is in no particular order. 178 executed in the file. The list is in no particular order.
176 179
177 """ 180 """
178 if self._arcs is not None: 181 if self._arcs is not None:
179 if filename in self._arcs: 182 arcs = self._arcs.get(filename)
180 return [s for s, __ in self._arcs[filename] if s > 0] 183 if arcs is not None:
184 all_lines = itertools.chain.from_iterable(arcs)
185 return list(set(l for l in all_lines if l > 0))
181 elif self._lines is not None: 186 elif self._lines is not None:
182 if filename in self._lines: 187 return self._lines.get(filename)
183 return self._lines[filename]
184 return None 188 return None
185 189
186 def arcs(self, filename): 190 def arcs(self, filename):
187 """Get the list of arcs executed for a file. 191 """Get the list of arcs executed for a file.
188 192
572 assert isinstance(key, string_class), "Key in _runs shouldn't be %r" % (key,) 576 assert isinstance(key, string_class), "Key in _runs shouldn't be %r" % (key,)
573 577
574 def add_to_hash(self, filename, hasher): 578 def add_to_hash(self, filename, hasher):
575 """Contribute `filename`'s data to the `hasher`. 579 """Contribute `filename`'s data to the `hasher`.
576 580
577 `hasher` is a :class:`coverage.misc.Hasher` instance to be updated with 581 `hasher` is a `coverage.misc.Hasher` instance to be updated with
578 the file's data. It should only get the results data, not the run 582 the file's data. It should only get the results data, not the run
579 data. 583 data.
580 584
581 """ 585 """
582 if self._has_arcs(): 586 if self._has_arcs():
599 603
600 604
601 class CoverageDataFiles(object): 605 class CoverageDataFiles(object):
602 """Manage the use of coverage data files.""" 606 """Manage the use of coverage data files."""
603 607
604 def __init__(self, basename=None): 608 def __init__(self, basename=None, warn=None):
605 """Create a CoverageDataFiles to manage data files. 609 """Create a CoverageDataFiles to manage data files.
606 610
611 `warn` is the warning function to use.
612
607 `basename` is the name of the file to use for storing data. 613 `basename` is the name of the file to use for storing data.
608 614
609 """ 615 """
616 self.warn = warn
610 # Construct the file name that will be used for data storage. 617 # Construct the file name that will be used for data storage.
611 self.filename = os.path.abspath(basename or ".coverage") 618 self.filename = os.path.abspath(basename or ".coverage")
612 619
613 def erase(self, parallel=False): 620 def erase(self, parallel=False):
614 """Erase the data from the file storage. 621 """Erase the data from the file storage.
673 `self.filename` plus dot as a prefix, and those files are combined. 680 `self.filename` plus dot as a prefix, and those files are combined.
674 681
675 If `data_paths` is not provided, then the directory portion of 682 If `data_paths` is not provided, then the directory portion of
676 `self.filename` is used as the directory to search for data files. 683 `self.filename` is used as the directory to search for data files.
677 684
678 Every data file found and combined is then deleted from disk. 685 Every data file found and combined is then deleted from disk. If a file
686 cannot be read, a warning will be issued, and the file will not be
687 deleted.
679 688
680 """ 689 """
681 # Because of the os.path.abspath in the constructor, data_dir will 690 # Because of the os.path.abspath in the constructor, data_dir will
682 # never be an empty string. 691 # never be an empty string.
683 data_dir, local = os.path.split(self.filename) 692 data_dir, local = os.path.split(self.filename)
694 else: 703 else:
695 raise CoverageException("Couldn't combine from non-existent path '%s'" % (p,)) 704 raise CoverageException("Couldn't combine from non-existent path '%s'" % (p,))
696 705
697 for f in files_to_combine: 706 for f in files_to_combine:
698 new_data = CoverageData() 707 new_data = CoverageData()
699 new_data.read_file(f) 708 try:
700 data.update(new_data, aliases=aliases) 709 new_data.read_file(f)
701 file_be_gone(f) 710 except CoverageException as exc:
711 if self.warn:
712 # The CoverageException has the file name in it, so just
713 # use the message as the warning.
714 self.warn(str(exc))
715 else:
716 data.update(new_data, aliases=aliases)
717 file_be_gone(f)
702 718
703 719
704 def canonicalize_json_data(data): 720 def canonicalize_json_data(data):
705 """Canonicalize our JSON data so it can be compared.""" 721 """Canonicalize our JSON data so it can be compared."""
706 for fname, lines in iitems(data.get('lines', {})): 722 for fname, lines in iitems(data.get('lines', {})):

eric ide

mercurial