From 61d568b82c71936917fa2562c0a41ab23aaffeeb Mon Sep 17 00:00:00 2001 From: Jim Pivarski Date: Fri, 30 Oct 2020 15:55:56 -0500 Subject: [PATCH] Tweaks to investigate #131, but it looks like it was just a bad file. (#166) * Working on issue #131. * Add Model.is_instance and make TBranch.count_branch safer. * Pass flake8. --- uproot4/behaviors/TBranch.py | 43 ++++++++++++++++++------------------ uproot4/model.py | 27 +++++++++++++++++++--- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/uproot4/behaviors/TBranch.py b/uproot4/behaviors/TBranch.py index 98fbd6a3a..fdd0b483b 100644 --- a/uproot4/behaviors/TBranch.py +++ b/uproot4/behaviors/TBranch.py @@ -721,17 +721,11 @@ def __init__(self, source, tree_entry_start, tree_entry_stop, global_offset=0): self._global_offset = global_offset def __repr__(self): - if self._global_offset == 0: - return "Report({0}, {1}, {2})".format( - self._source, self._tree_entry_start, self._tree_entry_stop - ) - else: - return "Report({0}, {1}, {2}, global_offset={3})".format( - self._source, - self._tree_entry_start, - self._tree_entry_stop, - self._global_offset, - ) + return "".format( + self.global_entry_start, + self.global_entry_stop, + repr(self._source.file.file_path + ":" + self._source.object_path), + ) @property def source(self): @@ -2363,11 +2357,13 @@ def count_branch(self): The ``TBranch`` object in which this branch's "counts" reside or None if this branch has no "counts". """ - leaf = self.count_leaf - if leaf is None: - return None + out = self.count_leaf + while isinstance(out, uproot4.model.Model) and out.is_instance("TLeaf"): + out = out.parent + if isinstance(out, uproot4.model.Model) and out.is_instance("TBranch"): + return out else: - return leaf.parent + return None @property def count_leaf(self): @@ -2755,7 +2751,7 @@ def _keys_deep(hasbranches): _regularize_files_braces = re.compile(r"{([^}]*,)*([^}]*)}") -def _regularize_files_inner(files, parse_colon): +def _regularize_files_inner(files, parse_colon, counter): files2 = uproot4._util.regularize_path(files) if uproot4._util.isstr(files2) and not uproot4._util.isstr(files): @@ -2800,12 +2796,15 @@ def _regularize_files_inner(files, parse_colon): elif isinstance(files, dict): for key, object_path in files.items(): - for file_path, _ in _regularize_files_inner(key, False): + for file_path, _ in _regularize_files_inner(key, False, counter): yield file_path, object_path elif isinstance(files, Iterable): for file in files: - for file_path, object_path in _regularize_files_inner(file, parse_colon): + counter[0] += 1 + for file_path, object_path in _regularize_files_inner( + file, parse_colon, counter + ): yield file_path, object_path else: @@ -2820,11 +2819,13 @@ def _regularize_files_inner(files, parse_colon): def _regularize_files(files): out = [] seen = set() - for file_path, object_path in _regularize_files_inner(files, True): + counter = [0] + for file_path, object_path in _regularize_files_inner(files, True, counter): if uproot4._util.isstr(file_path): - if (file_path, object_path) not in seen: + key = (counter[0], file_path, object_path) + if key not in seen: out.append((file_path, object_path)) - seen.add((file_path, object_path)) + seen.add(key) else: out.append((file_path, object_path)) diff --git a/uproot4/model.py b/uproot4/model.py index 4717696d4..29d6b0787 100644 --- a/uproot4/model.py +++ b/uproot4/model.py @@ -558,17 +558,38 @@ def bases(self): def base(self, *cls): """ Extracts instances from :py:attr:`~uproot4.model.Model.bases` by Python class - type. The ``cls`` may be a single class or a (varargs) list of classes - to match. + type. + + The ``cls`` arguments may be Python classes or C++ classname strings to match. """ + cpp_names = [classname_regularize(x) for x in cls if uproot4._util.isstr(x)] + py_types = tuple(x for x in cls if not uproot4._util.isstr(x)) + out = [] for x in getattr(self, "_bases", []): - if isinstance(x, cls): + if ( + isinstance(x, py_types) + or any(getattr(x, "classname", None) == n for n in cpp_names) + ): out.append(x) if isinstance(x, Model): out.extend(x.base(*cls)) return out + def is_instance(self, *cls): + """ + Returns True if this object matches a given type in the C++ class hierarchy. + + The ``cls`` arguments may be Python classes or C++ classname strings to match. + """ + cpp_names = [classname_regularize(x) for x in cls if uproot4._util.isstr(x)] + py_types = tuple(x for x in cls if not uproot4._util.isstr(x)) + + if isinstance(self, py_types) or any(self.classname == n for n in cpp_names): + return True + else: + return len(self.base(*cls)) != 0 + @property def num_bytes(self): """