Skip to content

Commit 5651997

Browse files
Added efficient data structure for maps indexed by file lines (fixes #347) (#348)
* implemented draft FileLineMap * updated CHANGELOG * updated attrs version * added deprecated as a dependency * added deprecation notices * bug fix: missing imports * use comment-style type annotations to support 3.5 * updated imports in core/__init__.py * added pytest to setup.py
1 parent 02569d7 commit 5651997

File tree

4 files changed

+58
-5
lines changed

4 files changed

+58
-5
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
## 2.1.29 (2019-09-05)
1+
## 2.1.29 (????-??-??)
2+
3+
### Features
4+
5+
* Added an efficient data structure for representing maps that are indexed
6+
by FileLine objects: FileLineMap.
7+
28

39
### Changes
410

bugzoo/core/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from .container import Container
33
from .language import Language
44
from .patch import Patch
5-
from .fileline import FileLine, FileLineSet
5+
from .fileline import FileLine, FileLineSet, FileLineMap
66
from .filechar import FileChar, FileCharRange
77
from .test import TestCase, TestOutcome, TestSuite
88
from .coverage import CoverageInstructions, TestCoverage, TestSuiteCoverage

bugzoo/core/fileline.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
# -*- coding: utf-8 -*-
2-
__all__ = ('FileLine', 'FileLineSet')
2+
__all__ = ('FileLine', 'FileLineSet', 'FileLineMap')
33

44
import typing
55
import collections.abc
66
from typing import (Dict, List, Set, Iterator, Iterable, Any, FrozenSet,
7-
Callable, Optional, Tuple)
7+
Callable, Optional, Tuple, TypeVar, MutableMapping,
8+
Mapping)
89

10+
from deprecated import deprecated
911
import attr
1012

13+
T = TypeVar('T')
14+
1115

1216
@attr.s(frozen=True, slots=True)
1317
class FileLine:
@@ -22,6 +26,7 @@ def from_string(s: str) -> 'FileLine':
2226
return FileLine(fn, num)
2327

2428
@staticmethod
29+
@deprecated(version='2.1.29', reason='Replaced by FileLineMap.')
2530
def compactify(d: Dict['FileLine', Any]) -> Dict[str, Dict[int, Any]]:
2631
"""
2732
Converts a dictionary that is indexed by FileLine objects into a
@@ -39,6 +44,7 @@ def compactify(d: Dict['FileLine', Any]) -> Dict[str, Dict[int, Any]]:
3944
return out
4045

4146
@staticmethod
47+
@deprecated(version='2.1.29', reason='Replaced by FileLineMap.')
4248
def decompactify(d: Dict[str, Dict[int, Any]]) -> 'Dict[FileLine, Any]':
4349
lines = {} # type: Dict['FileLine', Any]
4450
for fn in d:
@@ -53,8 +59,46 @@ def __str__(self) -> str:
5359
# see: https://github.com/python/mypy/issues/5446
5460
if typing.TYPE_CHECKING:
5561
BaseSet = Set[FileLine]
62+
BaseMap = MutableMapping[FileLine, T]
5663
else:
5764
BaseSet = collections.abc.Set
65+
BaseMap = collections.abc.MutableMapping
66+
67+
68+
class FileLineMap(BaseMap):
69+
"""
70+
An efficient implementation of maps indexed by file lines.
71+
Note that operations on instances of this class are NOT thread safe.
72+
"""
73+
def __init__(self, contents: Mapping[FileLine, T]) -> None:
74+
self.__contents = {} # type: Dict[str, Dict[int, T]]
75+
self.__length = 0
76+
for line, val in contents.items():
77+
self[line] = val
78+
79+
def __iter__(self) -> Iterator[FileLine]:
80+
for fn in self.__contents:
81+
for lineno in self.__contents[fn]:
82+
yield FileLine(fn, lineno)
83+
84+
def __len__(self) -> int:
85+
return self.__length
86+
87+
def __getitem__(self, line: FileLine) -> T:
88+
return self.__contents[line.filename][line.num]
89+
90+
def __setitem__(self, line: FileLine, val: T) -> None:
91+
if line.filename not in self.__contents:
92+
self.__contents[line.filename] = {}
93+
if line.num not in self.__contents[line.filename]:
94+
self.__length += 1
95+
self.__contents[line.filename][line.num] = val
96+
97+
def __delitem__(self, line: FileLine) -> None:
98+
del self.__contents[line.filename][line.num]
99+
if not self.__contents[line.filename]:
100+
del self.__contents[line.filename]
101+
self.__length -= 1
58102

59103

60104
class FileLineSet(BaseSet):

setup.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,14 @@
2424
'tabulate',
2525
'flask',
2626
'cement>=2.10.12',
27-
'attrs>=17.2.0',
27+
'attrs~=19.1.0',
28+
'deprecated~=1.2.6',
2829
'mypy-extensions>=0.3.0',
2930
'psutil>=5.0.0',
3031
'chardet>=3.0.4'
3132
],
33+
setup_requires=['pytest-runner'],
34+
tests_require=['pytest'],
3235
packages=[
3336
'bugzoo',
3437
'bugzoo.client',

0 commit comments

Comments
 (0)