Skip to content

Commit 960f885

Browse files
committed
python 2.6 support, tests and fixes
1 parent 05735bc commit 960f885

File tree

7 files changed

+87
-51
lines changed

7 files changed

+87
-51
lines changed

.travis.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
language: python
22
python:
3-
- "2.7"
4-
- "3.2"
5-
- "3.3"
3+
- 2.6
4+
- 2.7
5+
- 3.2
6+
- 3.3
67
install:
7-
- "pip install -r tests/requirements.txt --use-mirrors"
8-
- "pip install coveralls"
8+
- pip install -r tests/requirements.txt --use-mirrors
9+
- pip install coveralls
10+
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi
911
script:
10-
- "nosetests --with-coverage --cover-package=redmine"
12+
- nosetests --with-coverage --cover-erase --cover-package=redmine
1113
after_success:
12-
- "coveralls"
14+
- coveralls

docs/changelog.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Changelog
44
0.1.1 (2014-0X-XX)
55
------------------
66

7+
- Added: Python 2.6 support
8+
- Fixed: Resource representation was broken in Python 2.x, i.e. __repr__()
79
- Fixed: dir() call on a resource object didn't work in Python 3.2.x
810
- Changed: WikiPage resource refresh() method now automatically determines it's project_id
911

redmine/managers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def get(self, resource_id, **params):
8484
if self.resource_class.query_one is None or self.resource_class.container_one is None:
8585
raise ResourceBadMethodError()
8686

87-
self.url = '{}{}'.format(self.redmine.url, self.resource_class.query_one.format(resource_id, **params))
87+
self.url = '{0}{1}'.format(self.redmine.url, self.resource_class.query_one.format(resource_id, **params))
8888
self.params = params
8989
self.container = self.resource_class.container_one
9090

@@ -98,7 +98,7 @@ def all(self, **params):
9898
if self.resource_class.query_all is None or self.resource_class.container_all is None:
9999
raise ResourceBadMethodError()
100100

101-
self.url = '{}{}'.format(self.redmine.url, self.resource_class.query_all)
101+
self.url = '{0}{1}'.format(self.redmine.url, self.resource_class.query_all)
102102
self.params = params
103103
self.container = self.resource_class.container_all
104104
return ResourceSet(self)
@@ -112,11 +112,11 @@ def filter(self, **filters):
112112
raise ResourceNoFiltersProvidedError()
113113

114114
try:
115-
self.url = '{}{}'.format(self.redmine.url, self.resource_class.query_filter.format(**filters))
115+
self.url = '{0}{1}'.format(self.redmine.url, self.resource_class.query_filter.format(**filters))
116116
self.container = self.resource_class.container_filter.format(**filters)
117117
except KeyError:
118118
if self.resource_class.query_all is not None and self.resource_class.container_all is not None:
119-
self.url = '{}{}'.format(self.redmine.url, self.resource_class.query_all)
119+
self.url = '{0}{1}'.format(self.redmine.url, self.resource_class.query_all)
120120
self.container = self.resource_class.container_all
121121
else:
122122
raise ResourceFilterError()

redmine/resources.py

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import sys
12
from datetime import datetime
23
from redmine.managers import ResourceManager
34
from redmine.exceptions import ResourceAttrError
@@ -84,7 +85,7 @@ def __getattr__(self, item):
8485

8586
# If item should be requested from Redmine, let's do it
8687
elif item in _RESOURCE_RELATIONS_MAP and self.attributes[item] is None:
87-
filters = {'{}_id'.format(self.__class__.__name__.lower()): self.id}
88+
filters = {'{0}_id'.format(self.__class__.__name__.lower()): self.id}
8889
manager = ResourceManager(self.manager.redmine, _RESOURCE_RELATIONS_MAP[item])
8990
return manager.filter(**filters)
9091

@@ -121,11 +122,11 @@ def __iter__(self):
121122

122123
def __repr__(self):
123124
"""Official representation of the Redmine resource"""
124-
return '<{}.{} #{} "{}">'.format(
125+
return '<{0}.{1} #{2} "{3}">'.format(
125126
self.__class__.__module__,
126127
self.__class__.__name__,
127128
self.id,
128-
self.name
129+
self.name.encode('utf-8') if sys.version_info[0] < 3 else self.name
129130
)
130131

131132

@@ -134,7 +135,7 @@ class Project(_Resource):
134135
container_all = 'projects'
135136
container_one = 'project'
136137
query_all = '/projects.json'
137-
query_one = '/projects/{}.json'
138+
query_one = '/projects/{0}.json'
138139

139140
_relations = {
140141
'wiki_pages': None,
@@ -152,7 +153,7 @@ class Issue(_Resource):
152153
container_one = 'issue'
153154
container_filter = 'issues'
154155
query_all = '/issues.json'
155-
query_one = '/issues/{}.json'
156+
query_one = '/issues/{0}.json'
156157
query_filter = '/issues.json'
157158

158159
_relations = {
@@ -162,14 +163,14 @@ class Issue(_Resource):
162163

163164
def __repr__(self):
164165
try:
165-
return '<{}.{} #{} "{}">'.format(
166+
return '<{0}.{1} #{2} "{3}">'.format(
166167
self.__class__.__module__,
167168
self.__class__.__name__,
168169
self.id,
169-
self.subject
170+
self.subject.encode('utf-8') if sys.version_info[0] < 3 else self.subject
170171
)
171172
except ResourceAttrError:
172-
return '<{}.{} #{}>'.format(
173+
return '<{0}.{1} #{2}>'.format(
173174
self.__class__.__module__,
174175
self.__class__.__name__,
175176
self.id
@@ -182,11 +183,11 @@ class TimeEntry(_Resource):
182183
container_one = 'time_entry'
183184
container_filter = 'time_entries'
184185
query_all = '/time_entries.json'
185-
query_one = '/time_entries/{}.json'
186+
query_one = '/time_entries/{0}.json'
186187
query_filter = '/issues/{issue_id}/time_entries.json'
187188

188189
def __repr__(self):
189-
return '<{}.{} #{}>'.format(
190+
return '<{0}.{1} #{2}>'.format(
190191
self.__class__.__module__,
191192
self.__class__.__name__,
192193
self.id
@@ -202,22 +203,22 @@ class Enumeration(_Resource):
202203
class Attachment(_Resource):
203204
version = '1.3'
204205
container_one = 'attachment'
205-
query_one = '/attachments/{}.json'
206+
query_one = '/attachments/{0}.json'
206207

207208
def __repr__(self):
208-
return '<{}.{} #{} "{}">'.format(
209+
return '<{0}.{1} #{2} "{3}">'.format(
209210
self.__class__.__module__,
210211
self.__class__.__name__,
211212
self.id,
212-
self.filename
213+
self.filename.encode('utf-8') if sys.version_info[0] < 3 else self.filename
213214
)
214215

215216

216217
class IssueJournal(_Resource):
217218
version = '1.0'
218219

219220
def __repr__(self):
220-
return '<{}.{} #{}>'.format(
221+
return '<{0}.{1} #{2}>'.format(
221222
self.__class__.__module__,
222223
self.__class__.__name__,
223224
self.id
@@ -229,16 +230,16 @@ class WikiPage(_Resource):
229230
container_filter = 'wiki_pages'
230231
container_one = 'wiki_page'
231232
query_filter = '/projects/{project_id}/wiki/index.json'
232-
query_one = '/projects/{project_id}/wiki/{}.json'
233+
query_one = '/projects/{project_id}/wiki/{0}.json'
233234

234235
def refresh(self):
235236
return self.manager.get(self.title, **{'project_id': self.manager.params['project_id']})
236237

237238
def __repr__(self):
238-
return '<{}.{} "{}">'.format(
239+
return '<{0}.{1} "{2}">'.format(
239240
self.__class__.__module__,
240241
self.__class__.__name__,
241-
self.title
242+
self.title.encode('utf-8') if sys.version_info[0] < 3 else self.title
242243
)
243244

244245

@@ -247,10 +248,10 @@ class ProjectMembership(_Resource):
247248
container_filter = 'memberships'
248249
container_one = 'membership'
249250
query_filter = '/projects/{project_id}/memberships.json'
250-
query_one = '/memberships/{}.json'
251+
query_one = '/memberships/{0}.json'
251252

252253
def __repr__(self):
253-
return '<{}.{} #{}>'.format(
254+
return '<{0}.{1} #{2}>'.format(
254255
self.__class__.__module__,
255256
self.__class__.__name__,
256257
self.id
@@ -262,18 +263,18 @@ class IssueCategory(_Resource):
262263
container_filter = 'issue_categories'
263264
container_one = 'issue_category'
264265
query_filter = '/projects/{project_id}/issue_categories.json'
265-
query_one = '/issue_categories/{}.json'
266+
query_one = '/issue_categories/{0}.json'
266267

267268

268269
class IssueRelation(_Resource):
269270
version = '1.3'
270271
container_filter = 'relations'
271272
container_one = 'relation'
272273
query_filter = '/issues/{issue_id}/relations.json'
273-
query_one = '/relations/{}.json'
274+
query_one = '/relations/{0}.json'
274275

275276
def __repr__(self):
276-
return '<{}.{} #{}>'.format(
277+
return '<{0}.{1} #{2}>'.format(
277278
self.__class__.__module__,
278279
self.__class__.__name__,
279280
self.id
@@ -285,7 +286,7 @@ class Version(_Resource):
285286
container_filter = 'versions'
286287
container_one = 'version'
287288
query_filter = '/projects/{project_id}/versions.json'
288-
query_one = '/versions/{}.json'
289+
query_one = '/versions/{0}.json'
289290

290291

291292
class User(_Resource):
@@ -294,19 +295,19 @@ class User(_Resource):
294295
container_one = 'user'
295296
container_filter = 'users'
296297
query_all = '/users.json'
297-
query_one = '/users/{}.json'
298+
query_one = '/users/{0}.json'
298299
query_filter = '/users.json'
299300

300301
def __repr__(self):
301302
try:
302303
return super(User, self).__repr__()
303304
except ResourceAttrError:
304-
return '<{}.{} #{} "{} {}">'.format(
305+
return '<{0}.{1} #{2} "{3} {4}">'.format(
305306
self.__class__.__module__,
306307
self.__class__.__name__,
307308
self.id,
308-
self.firstname,
309-
self.lastname
309+
self.firstname.encode('utf-8') if sys.version_info[0] < 3 else self.firstname,
310+
self.lastname.encode('utf-8') if sys.version_info[0] < 3 else self.lastname
310311
)
311312

312313

@@ -315,15 +316,15 @@ class Group(_Resource):
315316
container_all = 'groups'
316317
container_one = 'group'
317318
query_all = '/groups.json'
318-
query_one = '/groups/{}.json'
319+
query_one = '/groups/{0}.json'
319320

320321

321322
class Role(_Resource):
322323
version = '1.4'
323324
container_all = 'roles'
324325
container_one = 'role'
325326
query_all = '/roles.json'
326-
query_one = '/roles/{}.json'
327+
query_one = '/roles/{0}.json'
327328

328329

329330
class News(_Resource):

redmine/resultsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def __len__(self):
6161

6262
def __repr__(self):
6363
"""Official representation of ResourceSet object"""
64-
return '<{}.{} object with {} resources>'.format(
64+
return '<{0}.{1} object with {2} resources>'.format(
6565
self.__class__.__module__,
6666
self.__class__.__name__,
6767
self.manager.resource_class.__name__

tests/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import unittest
1+
try:
2+
import unittest2 as unittest
3+
except ImportError:
4+
import unittest
25

36
try:
47
from unittest import mock

0 commit comments

Comments
 (0)