Skip to content

Commit 3a697f0

Browse files
authored
Merge pull request #240 from ModellingWebLab/191-commit-cache
Swap call to repo to use enhanced repocache
2 parents 5857063 + 385c6f1 commit 3a697f0

18 files changed

Lines changed: 275 additions & 139 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ before_script:
1515
install:
1616
pip install -r requirements/test.txt
1717
script:
18-
- pytest --cov=weblab --cov-config=weblab/.coveragerc weblab
18+
- pytest --fail-on-template-vars --cov=weblab --cov-config=weblab/.coveragerc weblab
1919
- flake8 weblab
2020
- isort --verbose --check-only --diff --recursive weblab
2121
after_success:

weblab/config/settings/dev.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,14 @@
8080
app.split('.')[0]: copy.deepcopy(local_logger_conf)
8181
for app in LOCAL_APPS
8282
})
83+
84+
85+
class InvalidStringShowWarning(str):
86+
def __mod__(self, other):
87+
import logging
88+
logger = logging.getLogger(__name__)
89+
logger.warning("In template, undefined variable or unknown value for: '%s'" % (other,))
90+
return ""
91+
92+
93+
TEMPLATES[0]['OPTIONS']['string_if_invalid'] = InvalidStringShowWarning("%s")

weblab/entities/models.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from django.core.urlresolvers import reverse
77
from django.core.validators import MinLengthValidator
88
from django.db import models
9+
from django.utils.functional import cached_property
910
from guardian.shortcuts import get_objects_for_user
1011

1112
from core.filetypes import get_file_type
@@ -72,11 +73,12 @@ class Meta:
7273
def __str__(self):
7374
return self.name
7475

75-
@property
76+
@cached_property
7677
def repo(self):
7778
"""This entity's git repository wrapper.
7879
79-
Note that we do not cache this property as this can lead to too many open files.
80+
Caching this property actually reduces the number of open files, but there's still a risk
81+
of running out of file handles eventually.
8082
See also https://gitpython.readthedocs.io/en/stable/intro.html#leakage-of-system-resources
8183
"""
8284
return Repository(self.repo_abs_path)
@@ -92,11 +94,17 @@ def repo_abs_path(self):
9294
self.author.get_storage_dir('repo'), '%ss' % self.entity_type, str(self.id)
9395
)
9496

95-
def nice_version(self, commit):
96-
version = self.repo.get_name_for_commit(commit)
97-
if len(version) > 20:
98-
version = version[:8] + '...'
99-
return version
97+
def nice_version(self, sha_or_tag):
98+
"""
99+
Returns tag/sha with ellipses
100+
101+
:param sha_or_tag: version sha or tag string
102+
:return version_name: string with the sha_or_tag formatted
103+
"""
104+
version_name = self.repocache.get_name_for_version(sha_or_tag)
105+
if len(version_name) > 20:
106+
version_name = version_name[:8] + '...'
107+
return version_name
100108

101109
def get_visibility_from_repo(self, commit):
102110
"""
@@ -296,7 +304,7 @@ def get_version_json(self, commit, ns):
296304
'visibility': self.get_version_visibility(commit.sha, default=self.DEFAULT_VISIBILITY),
297305
'created': commit.timestamp,
298306
'name': self.name,
299-
'version': self.repo.get_name_for_commit(commit.sha), # TODO #191 use repocache instead
307+
'version': self.repocache.get_name_for_version(commit.sha),
300308
'files': files,
301309
'commitMessage': commit.message,
302310
'numFiles': len(files),

weblab/entities/repository.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,6 @@ def tag_dict(self):
138138
tags.setdefault(tag.commit.hexsha, []).append(tag)
139139
return tags
140140

141-
def get_name_for_commit(self, version):
142-
"""Get a human-friendly display name for the given version
143-
144-
:param version: Revision specification (sha, branch name, tag etc.)
145-
or 'latest' to get latest revision
146-
:return: tag for this commit, if any, or version if not
147-
"""
148-
commit = self.get_commit(version)
149-
for tag in self._repo.tags:
150-
if tag.commit == commit._commit:
151-
return tag.name
152-
return version
153-
154141
def hard_reset(self):
155142
"""
156143
Reset the working tree

weblab/entities/templatetags/entities.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,28 +116,32 @@ def url_entity_diff_base(context, entity_type):
116116
@register.filter
117117
def name_of_model(experiment):
118118
model = experiment.model
119-
model_version = model.repo.get_name_for_commit(experiment.model_version)
119+
model_version = model.repocache.get_name_for_version(experiment.model_version)
120120
return '%s @ %s' % (model.name, model_version)
121121

122122

123123
@register.filter
124124
def name_of_protocol(experiment):
125125
protocol = experiment.protocol
126-
protocol_version = protocol.repo.get_name_for_commit(experiment.protocol_version)
126+
protocol_version = protocol.repocache.get_name_for_version(experiment.protocol_version)
127127
return '%s @ %s' % (protocol.name, protocol_version)
128128

129129

130-
def _url_friendly_label(entity, commit):
130+
def _url_friendly_label(entity, version):
131131
"""
132132
Get URL-friendly version label for a commit
133133
134134
:param entity: Entity the commit belongs to
135-
:param commit: `git.Commit` object
135+
:param version: CachedEntityVersion object
136136
"""
137-
last_tag = str(entity.repo.tag_dict.get(commit.sha, ['/'])[-1])
138-
if '/' in last_tag or last_tag in ['new', 'latest']:
139-
last_tag = commit.sha
140-
return last_tag
137+
tags = version.tags.last()
138+
if tags is not None:
139+
tag = tags.tag
140+
if tag is None or tag in ['new', 'latest']:
141+
return version.sha
142+
else:
143+
return tag
144+
return version.sha
141145

142146

143147
@register.filter

weblab/entities/tests/test_models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def test_nice_version(self, model_with_version):
9797
assert model_with_version.nice_version(commit) == '%s...' % commit[:8]
9898

9999
model_with_version.repo.tag('v1')
100+
populate_entity_cache(model_with_version)
100101
assert model_with_version.nice_version(commit) == 'v1'
101102

102103
def test_set_and_get_version_visibility(self, model_with_version):

weblab/entities/tests/test_repository.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,19 +77,6 @@ def test_tag(self, repo, repo_file, author):
7777
with pytest.raises(GitCommandError):
7878
repo.tag('v1')
7979

80-
def test_name_for_commit(self, repo, repo_file, author):
81-
repo.add_file(repo_file)
82-
commit = repo.commit('commit_message', author)
83-
84-
assert repo.get_name_for_commit(commit.sha) == commit.sha
85-
assert repo.get_name_for_commit('latest') == 'latest'
86-
87-
repo.tag('v1')
88-
89-
assert repo.get_name_for_commit(commit.sha) == 'v1'
90-
assert repo.get_name_for_commit('v1') == 'v1'
91-
assert repo.get_name_for_commit('latest') == 'v1'
92-
9380
def test_has_changes(self, repo, repo_file, author):
9481
assert not repo.has_changes
9582
repo.add_file(repo_file)

weblab/entities/tests/test_templatetags.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import entities.templatetags.entities as entity_tags
44
from core import recipes
5+
from repocache.populate import populate_entity_cache
56

67

78
def test_human_readable_bytes():
@@ -34,7 +35,7 @@ def test_file_type():
3435
@pytest.mark.django_db
3536
def test_model_urls(model_with_version):
3637
model = model_with_version
37-
model_version = model.repo.latest_commit
38+
model_version = model.repocache.latest_version
3839
context = {'current_namespace': 'entities'}
3940

4041
assert entity_tags.ns_url(context, 'new', 'model') == '/entities/models/new'
@@ -64,7 +65,7 @@ def test_model_urls(model_with_version):
6465
@pytest.mark.django_db
6566
def test_protocol_urls(protocol_with_version):
6667
protocol = protocol_with_version
67-
protocol_version = protocol.repo.latest_commit
68+
protocol_version = protocol.repocache.latest_version
6869
context = {'current_namespace': 'entities'}
6970

7071
assert entity_tags.ns_url(context, 'new', 'protocol') == '/entities/protocols/new'
@@ -98,6 +99,8 @@ def test_protocol_urls(protocol_with_version):
9899
def test_name_of_entity_linked_to_experiment(model_with_version, protocol_with_version):
99100
model_with_version.repo.tag('v1')
100101
protocol_with_version.repo.tag('v2')
102+
populate_entity_cache(model_with_version)
103+
populate_entity_cache(protocol_with_version)
101104

102105
exp = recipes.experiment_version.make(
103106
status='SUCCESS',
@@ -114,29 +117,39 @@ def test_name_of_entity_linked_to_experiment(model_with_version, protocol_with_v
114117
@pytest.mark.django_db
115118
def test_url_friendly_label(model_with_version, helpers):
116119
commit = model_with_version.repo.latest_commit
117-
assert entity_tags._url_friendly_label(model_with_version, commit) == commit.sha
120+
version = model_with_version.repocache.get_version(commit.sha)
121+
122+
assert entity_tags._url_friendly_label(model_with_version, version) == commit.sha
118123

119124
model_with_version.repo.tag('v1')
120-
assert entity_tags._url_friendly_label(model_with_version, commit) == 'v1'
125+
populate_entity_cache(model_with_version)
126+
127+
assert entity_tags._url_friendly_label(model_with_version, version) == 'v1'
121128

122129
commit2 = helpers.add_version(model_with_version)
123130
model_with_version.repo.tag('new')
124-
assert entity_tags._url_friendly_label(model_with_version, commit2) == commit2.sha
131+
populate_entity_cache(model_with_version)
132+
version2 = model_with_version.repocache.get_version(commit2.sha)
133+
134+
assert entity_tags._url_friendly_label(model_with_version, version2) == commit2.sha
125135

126136
commit3 = helpers.add_version(model_with_version)
127137
model_with_version.repo.tag('latest')
128-
assert entity_tags._url_friendly_label(model_with_version, commit3) == commit3.sha
138+
populate_entity_cache(model_with_version)
139+
version3 = model_with_version.repocache.get_version(commit3.sha)
140+
141+
assert entity_tags._url_friendly_label(model_with_version, version3) == commit3.sha
129142

130143

131144
@pytest.mark.django_db
132145
def test_url_runexperiments(model_with_version, protocol_with_version):
133146
model = model_with_version
134-
model_commit = model.repo.latest_commit
147+
model_commit = model.repocache.latest_version
135148
assert (entity_tags.url_run_experiments(model, model_commit) ==
136149
'/entities/models/%d/versions/%s/runexperiments' % (model.pk, model_commit.sha))
137150

138151
protocol = protocol_with_version
139-
protocol_commit = protocol.repo.latest_commit
152+
protocol_commit = protocol.repocache.latest_version
140153
assert (entity_tags.url_run_experiments(protocol, protocol_commit) ==
141154
'/entities/protocols/%d/versions/%s/runexperiments' % (protocol.pk, protocol_commit.sha))
142155

0 commit comments

Comments
 (0)