GeezerVison is showing github.com — Implemneted IterableLists for refs, commits and remote objects includ… · gitpython-developers/GitPython@9896717
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: CHANGES +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -38,6 +38,7 @@ Item Iteration | 38 | 38 | hurt performance and memory consumption and reduce response times. | 39 | 39 | iter_items method provide an iterator that will return items on demand as parsed | 40 | 40 | from a stream. This way any amount of objects can be handled. | | 41 | +* list_items method returns IterableList allowing to access list members by name | 41 | 42 |
| 42 | 43 | objects Package | 43 | 44 | ---------------- | |
Collapse file Copy file name to clipboardExpand all lines: TODO -2Lines changed: 0 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -13,8 +13,6 @@ General | 13 | 13 | * Overhaul command caching - currently its possible to create many instances of | 14 | 14 | the std-in command types, as it appears they are not killed when the repo gets | 15 | 15 | deleted. | 16 | | -* ReferenceList being a list that can also be accessed by name, such as rlist.HEAD | 17 | | - or rlist.master, allowing repo.heads.master | 18 | 16 | * References should be parsed 'manually' to get around command invocation, but | 19 | 17 | be sure to be able to read packed refs. | 20 | 18 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/git/objects/commit.py +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -23,6 +23,7 @@ class Commit(base.Object, Iterable, diff.Diffable): | 23 | 23 | type = "commit" | 24 | 24 | __slots__ = ("tree", "author", "authored_date", "committer", "committed_date", | 25 | 25 | "message", "parents") | | 26 | + _id_attribute_ = "id" | 26 | 27 |
| 27 | 28 | def __init__(self, repo, id, tree=None, author=None, authored_date=None, | 28 | 29 | committer=None, committed_date=None, message=None, parents=None): | |
Collapse file Copy file name to clipboardExpand all lines: lib/git/refs.py +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -16,6 +16,7 @@ class Reference(LazyMixin, Iterable): | 16 | 16 | """ | 17 | 17 | __slots__ = ("repo", "path") | 18 | 18 | _common_path_default = "refs" | | 19 | + _id_attribute_ = "name" | 19 | 20 |
| 20 | 21 | def __init__(self, repo, path, object = None): | 21 | 22 | """ | |
Collapse file Copy file name to clipboardExpand all lines: lib/git/remote.py +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -47,6 +47,7 @@ class Remote(LazyMixin, Iterable): | 47 | 47 | """ | 48 | 48 |
| 49 | 49 | __slots__ = ( "repo", "name", "_config_reader" ) | | 50 | + _id_attribute_ = "name" | 50 | 51 |
| 51 | 52 | def __init__(self, repo, name): | 52 | 53 | """ | |
Collapse file Copy file name to clipboardExpand all lines: lib/git/repo.py +6-7Lines changed: 6 additions & 7 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -105,7 +105,7 @@ def heads(self): | 105 | 105 | this repo | 106 | 106 |
| 107 | 107 | Returns | 108 | | - ``git.Head[]`` | | 108 | + ``git.IterableList(Head, ...)`` | 109 | 109 | """ | 110 | 110 | return Head.list_items(self) | 111 | 111 |
| @@ -127,6 +127,9 @@ def head(self,path="HEAD"): | 127 | 127 | def remotes(self): | 128 | 128 | """ | 129 | 129 | A list of Remote objects allowing to access and manipulate remotes | | 130 | + | | 131 | + Returns | | 132 | + ``git.IterableList(Remote, ...)`` | 130 | 133 | """ | 131 | 134 | return Remote.list_items(self) | 132 | 135 |
| @@ -138,19 +141,15 @@ def remote(self, name='origin'): | 138 | 141 | Raise | 139 | 142 | ValueError if no remote with such a name exists | 140 | 143 | """ | 141 | | - for remote in Remote.iter_items(self): | 142 | | - if remote.name == name: | 143 | | - return remote | 144 | | - # END for each existing remote | 145 | | - raise ValueError( "Remote named %s does not exist" % name ) | | 144 | + return Remote(self, name) | 146 | 145 |
| 147 | 146 | @property | 148 | 147 | def tags(self): | 149 | 148 | """ | 150 | 149 | A list of ``Tag`` objects that are available in this repo | 151 | 150 |
| 152 | 151 | Returns | 153 | | - ``git.Tag[]`` | | 152 | + ``git.IterableList(TagReference, ...)`` | 154 | 153 | """ | 155 | 154 | return TagReference.list_items(self) | 156 | 155 |
| |
Collapse file Copy file name to clipboardExpand all lines: lib/git/utils.py +38-1Lines changed: 38 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -56,12 +56,46 @@ def _set_cache_(self, attr): | 56 | 56 | pass | 57 | 57 |
| 58 | 58 |
| | 59 | +class IterableList(list): | | 60 | + """ | | 61 | + List of iterable objects allowing to query an object by id or by named index:: | | 62 | + | | 63 | + heads = repo.heads | | 64 | + heads.master | | 65 | + heads['master'] | | 66 | + heads[0] | | 67 | + """ | | 68 | + __slots__ = '_id_attr' | | 69 | + | | 70 | + def __new__(cls, id_attr): | | 71 | + return super(IterableList,cls).__new__(cls) | | 72 | + | | 73 | + def __init__(self, id_attr): | | 74 | + self._id_attr = id_attr | | 75 | + | | 76 | + def __getattr__(self, attr): | | 77 | + for item in self: | | 78 | + if getattr(item, self._id_attr) == attr: | | 79 | + return item | | 80 | + # END for each item | | 81 | + return list.__getattribute__(self, attr) | | 82 | + | | 83 | + def __getitem__(self, index): | | 84 | + if isinstance(index, int): | | 85 | + return list.__getitem__(self,index) | | 86 | + | | 87 | + try: | | 88 | + return getattr(self, index) | | 89 | + except AttributeError: | | 90 | + raise IndexError( "No item found with id %r" % index ) | | 91 | + | 59 | 92 | class Iterable(object): | 60 | 93 | """ | 61 | 94 | Defines an interface for iterable items which is to assure a uniform | 62 | 95 | way to retrieve and iterate items within the git repository | 63 | 96 | """ | 64 | 97 | __slots__ = tuple() | | 98 | + _id_attribute_ = "attribute that most suitably identifies your instance" | 65 | 99 |
| 66 | 100 | @classmethod | 67 | 101 | def list_items(cls, repo, *args, **kwargs): | @@ -75,7 +109,10 @@ def list_items(cls, repo, *args, **kwargs): | 75 | 109 | Returns: | 76 | 110 | list(Item,...) list of item instances | 77 | 111 | """ | 78 | | - return list(cls.iter_items(repo, *args, **kwargs)) | | 112 | + #return list(cls.iter_items(repo, *args, **kwargs)) | | 113 | + out_list = IterableList( cls._id_attribute_ ) | | 114 | + out_list.extend(cls.iter_items(repo, *args, **kwargs)) | | 115 | + return out_list | 79 | 116 |
| 80 | 117 |
| 81 | 118 | @classmethod | |
Collapse file Copy file name to clipboardExpand all lines: test/git/test_commit.py +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -67,6 +67,9 @@ def test_rev_list_bisect_all(self, git): | 67 | 67 |
| 68 | 68 | def test_count(self): | 69 | 69 | assert self.repo.tag('0.1.5').commit.count( ) == 141 | | 70 | + | | 71 | + def test_list(self): | | 72 | + assert isinstance(Commit.list_items(self.repo, '0.1.5', max_count=5)['5117c9c8a4d3af19a9958677e45cda9269de1541'], Commit) | 70 | 73 |
| 71 | 74 | def test_str(self): | 72 | 75 | commit = Commit(self.repo, id='abc') | |
Collapse file Copy file name to clipboardExpand all lines: test/git/test_remote.py +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -68,6 +68,7 @@ def test_base(self): | 68 | 68 | assert num_remotes == len(remote_set) | 69 | 69 |
| 70 | 70 | origin = self.repo.remote('origin') | | 71 | + assert origin == self.repo.remotes.origin | 71 | 72 |
| 72 | 73 | def test_creation_and_removal(self): | 73 | 74 | new_name = "test_new_one" | |
Collapse file Copy file name to clipboardExpand all lines: test/git/test_repo.py +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -39,6 +39,9 @@ def test_heads_should_populate_head_data(self): | 39 | 39 | assert head.name | 40 | 40 | assert isinstance(head.commit,Commit) | 41 | 41 | # END for each head | | 42 | + | | 43 | + assert isinstance(self.repo.heads.master, Head) | | 44 | + assert isinstance(self.repo.heads['master'], Head) | 42 | 45 |
| 43 | 46 | @patch_object(Git, '_call_process') | 44 | 47 | def test_commits(self, git): | |
|