Status: | Merged | ||||
---|---|---|---|---|---|
Merge reported by: | Colin Watson | ||||
Merged at revision: | not available | ||||
Proposed branch: | lp:~bellini666/storm/py3 | ||||
Merge into: | lp:storm | ||||
Diff against target: |
3359 lines (+481/-675) 57 files modified
ez_setup.py (+0/-284) setup.py (+20/-36) storm/__init__.py (+3/-1) storm/base.py (+3/-2) storm/cache.py (+3/-2) storm/cextensions.c (+61/-83) storm/database.py (+11/-6) storm/databases/__init__.py (+2/-1) storm/databases/mysql.py (+2/-1) storm/databases/postgres.py (+6/-4) storm/databases/sqlite.py (+7/-4) storm/event.py (+1/-0) storm/exceptions.py (+20/-10) storm/expr.py (+23/-17) storm/info.py (+8/-3) storm/properties.py (+5/-3) storm/references.py (+11/-5) storm/schema/patch.py (+6/-5) storm/schema/schema.py (+4/-2) storm/schema/sharding.py (+2/-1) storm/sqlobject.py (+18/-14) storm/store.py (+8/-6) storm/tracer.py (+3/-1) storm/twisted/testing.py (+1/-0) storm/twisted/transact.py (+2/-1) storm/tz.py (+41/-48) storm/uri.py (+7/-2) storm/variables.py (+27/-21) storm/xid.py (+1/-0) storm/zope/schema.py (+1/-0) storm/zope/testing.py (+1/-1) storm/zope/zstorm.py (+3/-1) tests/cache.py (+6/-3) tests/database.py (+3/-0) tests/databases/base.py (+17/-13) tests/databases/postgres.py (+6/-4) tests/databases/proxy.py (+7/-5) tests/databases/sqlite.py (+3/-2) tests/event.py (+1/-0) tests/expr.py (+10/-7) tests/helper.py (+5/-1) tests/info.py (+4/-2) tests/mocker.py (+28/-20) tests/properties.py (+4/-2) tests/schema/patch.py (+6/-4) tests/schema/schema.py (+2/-3) tests/schema/sharding.py (+3/-1) tests/sqlobject.py (+3/-2) tests/store/base.py (+26/-21) tests/store/postgres.py (+1/-0) tests/tracer.py (+4/-2) tests/uri.py (+1/-0) tests/variables.py (+18/-14) tests/wsgi.py (+5/-2) tests/zope/adapters.py (+1/-0) tests/zope/testing.py (+2/-1) tests/zope/zstorm.py (+4/-1) |
||||
To merge this branch: | bzr merge lp:~bellini666/storm/py3 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stuart Bishop (community) | Needs Fixing | ||
Review via email: mp+325182@code.launchpad.net |
Commit message
Make storm work with python2 and python3 using futurize and six.
Description of the change
Make storm work with python2 and python3 using futurize and six.
This branch has been tested with stoq <https:/
- 494. By Thiago Bellini
-
Workaround virtual subclass checking in python3
The exception handling ignores virtual subclasses in python3
- 495. By Thiago Bellini
-
Update setup.py using the one from the debian package
Ronaldo Maia (romaia) wrote : | # |
I will assume this patch and will send a new version addressing this issues (and some other issues I found with cextensions).
Markus Kemmerling (markus-kemmerling) wrote : | # |
Any news on this? I would really like to see a Python 3 compatible release of storm.
The branch worked for me after two additional fixes. The first one is related to Zope security proxies. For some reason I do not really understand I had to define a '__len__' method for result and reference sets to be able to pass security proxied sets to the 'list' or 'tuple' constructor (although iterating over the sets worked).
The second fix affects the C extensions which raised a 'TypeError' for compile methods that pass the 'join' parameter, e.g. 'storm.
--- cextensions.c.ORIG 2018-07-06 08:46:29.000000000 +0200
+++ cextensions.c 2018-07-05 14:37:02.000000000 +0200
@@ -1682,7 +1682,7 @@
join = default_
- if (!PyArg_
+ if (!PyArg_
return NULL;
}
Colin Watson (cjwatson) wrote : | # |
Thanks for doing this work.
Status report: I've been breaking this down into more reviewable pieces and sending small MPs for each (in some cases doing the work independently, and in some cases borrowing from this MP and giving credit where appropriate). I also switched to tox for running tests, which makes it much easier to run a suitable test matrix. There's still quite a bit to go, but I've got a fair amount merged already and I plan to continue.
Thiago Bellini (bellini666) wrote : | # |
> Thanks for doing this work.
>
> Status report: I've been breaking this down into more reviewable pieces and
> sending small MPs for each (in some cases doing the work independently, and in
> some cases borrowing from this MP and giving credit where appropriate). I
> also switched to tox for running tests, which makes it much easier to run a
> suitable test matrix. There's still quite a bit to go, but I've got a fair
> amount merged already and I plan to continue.
I don't like the fact that the work I've done is being authored by someone else, and I'm loosing the right to say that I contributed to the project. Sends a very sad message to future contributors...
At least this project is finally seeing an update to python3.
Colin Watson (cjwatson) wrote : | # |
Huh, wait, I'm not claiming credit for your work; where I've committed things with my authorship they have been actually different in substantive ways (e.g. for int/long handling I took more care to ensure that the tests were still meaningful on Python 2 while not being syntax errors on Python 3, and for print function conversion I added a bunch of __future__ imports to make it more robust. By contrast, the string exception fix I landed just now (admittedly a small change) I cherry-picked directly from your branch and the commit has your authorship on it. I expect there to be more of the latter. You will absolutely not lose the right to say that you contributed to the project, and I'm sorry for giving that impression.
If I could have fixed up this branch and landed it then I absolutely would have done, but it was just too much to digest, particularly given the poor testing situation described by Stuart. Since most of the comments made on this branch were over a year and a half ago, it seemed likely that you weren't going to have time to engage with them, and attempts by other people to do so also seemed to have stalled. There are also aspects of this branch that I'm not sure I agree with and may want to do differently. On the other hand there are certainly parts of your changes where you seem to know better than I and I expect to be trying to land your changes rather directly, such as the virtual subclass handling or the fleshing out of special object methods.
The approach I'm taking of breaking the branch down into small pieces, separating the large but essentially-
Thiago Bellini (bellini666) wrote : | # |
Regarding the main issue, ok, I understood your motivations.
I would just disagree with the many small merge proposals in this situation specifically. Here are my thoughts about that:
1) The code is actually broken in small pieces. Each change is in its own commit, there's not a single large commit doing the whole "python2 -> python3" migration.
2) Having said that, knowing that there's a dependency between each of those changes in a lot of the times, dividing them into small merge proposals would produce a lot of divergences, specially after code reviews.
3) Testing those would be a nightmare since to test with python3, I cannot just test the unicode migration without doing other one if that needs to be done in the same piece of code.
4) Because storm uses bzr instead of git, there would be no way to open a lot of merge proposals, each one for each subsequent commit, and as long as they were merged in sequence, it would be possible to mimic what you are trying to acomplish.
5) Lastly, the purpose of a merge proposal is to merge a "feature" which was developed in a branch containing a sequence of commits. There are features which can be broken into parts, but "migrate python2 to python3" IMO is something atomic.
But again, that is my opinion and maybe your and the other maintainers of the project will disagree with me. Either way I just wanted to point it out.
Colin Watson (cjwatson) wrote : | # |
OK, I indeed do disagree with you on this and it seems worth explaining why. Point-by-point:
1) I understand that, indeed, but merge proposals are the unit of code review and 3000+-line merge proposals are typically viewed as rather indigestible. It is true that it's possible to go and look at the individual commits, but it's then difficult to comment on those individually. (Some of this is admittedly due to shortcomings in the Launchpad code review system, but you work with what you've got.) It also puts maintainers in a difficult position when they disagree with something near the start of your sequence of commits: what are they to do when they give you feedback and you don't respond for over 18 months, which is something that does happen from time to time (and indeed happened in this case)? They can't easily merge the rest of it and finish off the last bits in some other way, because you've linearised it all.
2) Lots of the changes aren't interdependent and can be proposed in parallel without causing this kind of problem. This is exactly what I've been doing. If you propose the non-interdependent changes in a form that can be tested separately, then you make reviewers' lives easier because they know they can merge the uncontroversial ones separately and reduce the overall size of what's left; that's much harder with a single linearised branch because later commits might well rely on earlier ones and not be cherry-pickable.
3) It's true that it's less easy to test the whole assembly until you're quite far along. On the other hand this merge proposal wasn't fully tested with Python 3 anyway since it fails tests in the way that Stuart pointed out in August 2017 (I proposed https:/
4) You can use prerequisite branches on merge proposals if you like. See my comment at the end of 1) for the practical problems caused by this, though.
5) This is a reasonable philosophical disagreement, but I do find my approach works better in practice. I've done quite a lot of other Python 3 porting work this way.
In any case, I'm certainly grateful for the work you've done on this and will explicitly credit you in the NEWS file regardless of the exact balance of specific commits that end up with your name on them, as well as others who've contributed here.
Colin Watson (cjwatson) wrote : | # |
This is now effectively landed (with some commits from this branch, and some commits prepared separately) in Storm 0.21. Thanks!
Preview Diff
1 | === removed file 'ez_setup.py' |
2 | --- ez_setup.py 2011-10-18 13:59:56 +0000 |
3 | +++ ez_setup.py 1970-01-01 00:00:00 +0000 |
4 | @@ -1,284 +0,0 @@ |
5 | -#!python |
6 | -"""Bootstrap setuptools installation |
7 | - |
8 | -If you want to use setuptools in your package's setup.py, just include this |
9 | -file in the same directory with it, and add this to the top of your setup.py:: |
10 | - |
11 | - from ez_setup import use_setuptools |
12 | - use_setuptools() |
13 | - |
14 | -If you want to require a specific version of setuptools, set a download |
15 | -mirror, or use an alternate download directory, you can do so by supplying |
16 | -the appropriate options to ``use_setuptools()``. |
17 | - |
18 | -This file can also be run as a script to install or upgrade setuptools. |
19 | -""" |
20 | -import sys |
21 | -DEFAULT_VERSION = "0.6c11" |
22 | -DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] |
23 | - |
24 | -md5_data = { |
25 | - 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', |
26 | - 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', |
27 | - 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', |
28 | - 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', |
29 | - 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', |
30 | - 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', |
31 | - 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', |
32 | - 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', |
33 | - 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', |
34 | - 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', |
35 | - 'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090', |
36 | - 'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4', |
37 | - 'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7', |
38 | - 'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5', |
39 | - 'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de', |
40 | - 'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b', |
41 | - 'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2', |
42 | - 'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086', |
43 | - 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', |
44 | - 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', |
45 | - 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', |
46 | - 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', |
47 | - 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', |
48 | - 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', |
49 | - 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', |
50 | - 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', |
51 | - 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', |
52 | - 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', |
53 | - 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', |
54 | - 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', |
55 | - 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', |
56 | - 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', |
57 | - 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', |
58 | - 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', |
59 | - 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', |
60 | - 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', |
61 | - 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', |
62 | - 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', |
63 | - 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', |
64 | - 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', |
65 | - 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', |
66 | - 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', |
67 | -} |
68 | - |
69 | -import sys, os |
70 | -try: from hashlib import md5 |
71 | -except ImportError: from md5 import md5 |
72 | - |
73 | -def _validate_md5(egg_name, data): |
74 | - if egg_name in md5_data: |
75 | - digest = md5(data).hexdigest() |
76 | - if digest != md5_data[egg_name]: |
77 | - print >>sys.stderr, ( |
78 | - "md5 validation of %s failed! (Possible download problem?)" |
79 | - % egg_name |
80 | - ) |
81 | - sys.exit(2) |
82 | - return data |
83 | - |
84 | -def use_setuptools( |
85 | - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, |
86 | - download_delay=15 |
87 | -): |
88 | - """Automatically find/download setuptools and make it available on sys.path |
89 | - |
90 | - `version` should be a valid setuptools version number that is available |
91 | - as an egg for download under the `download_base` URL (which should end with |
92 | - a '/'). `to_dir` is the directory where setuptools will be downloaded, if |
93 | - it is not already available. If `download_delay` is specified, it should |
94 | - be the number of seconds that will be paused before initiating a download, |
95 | - should one be required. If an older version of setuptools is installed, |
96 | - this routine will print a message to ``sys.stderr`` and raise SystemExit in |
97 | - an attempt to abort the calling script. |
98 | - """ |
99 | - was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules |
100 | - def do_download(): |
101 | - egg = download_setuptools(version, download_base, to_dir, download_delay) |
102 | - sys.path.insert(0, egg) |
103 | - import setuptools; setuptools.bootstrap_install_from = egg |
104 | - try: |
105 | - import pkg_resources |
106 | - except ImportError: |
107 | - return do_download() |
108 | - try: |
109 | - pkg_resources.require("setuptools>="+version); return |
110 | - except pkg_resources.VersionConflict, e: |
111 | - if was_imported: |
112 | - print >>sys.stderr, ( |
113 | - "The required version of setuptools (>=%s) is not available, and\n" |
114 | - "can't be installed while this script is running. Please install\n" |
115 | - " a more recent version first, using 'easy_install -U setuptools'." |
116 | - "\n\n(Currently using %r)" |
117 | - ) % (version, e.args[0]) |
118 | - sys.exit(2) |
119 | - except pkg_resources.DistributionNotFound: |
120 | - pass |
121 | - |
122 | - del pkg_resources, sys.modules['pkg_resources'] # reload ok |
123 | - return do_download() |
124 | - |
125 | -def download_setuptools( |
126 | - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, |
127 | - delay = 15 |
128 | -): |
129 | - """Download setuptools from a specified location and return its filename |
130 | - |
131 | - `version` should be a valid setuptools version number that is available |
132 | - as an egg for download under the `download_base` URL (which should end |
133 | - with a '/'). `to_dir` is the directory where the egg will be downloaded. |
134 | - `delay` is the number of seconds to pause before an actual download attempt. |
135 | - """ |
136 | - import urllib2, shutil |
137 | - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) |
138 | - url = download_base + egg_name |
139 | - saveto = os.path.join(to_dir, egg_name) |
140 | - src = dst = None |
141 | - if not os.path.exists(saveto): # Avoid repeated downloads |
142 | - try: |
143 | - from distutils import log |
144 | - if delay: |
145 | - log.warn(""" |
146 | ---------------------------------------------------------------------------- |
147 | -This script requires setuptools version %s to run (even to display |
148 | -help). I will attempt to download it for you (from |
149 | -%s), but |
150 | -you may need to enable firewall access for this script first. |
151 | -I will start the download in %d seconds. |
152 | - |
153 | -(Note: if this machine does not have network access, please obtain the file |
154 | - |
155 | - %s |
156 | - |
157 | -and place it in this directory before rerunning this script.) |
158 | ----------------------------------------------------------------------------""", |
159 | - version, download_base, delay, url |
160 | - ); from time import sleep; sleep(delay) |
161 | - log.warn("Downloading %s", url) |
162 | - src = urllib2.urlopen(url) |
163 | - # Read/write all in one block, so we don't create a corrupt file |
164 | - # if the download is interrupted. |
165 | - data = _validate_md5(egg_name, src.read()) |
166 | - dst = open(saveto,"wb"); dst.write(data) |
167 | - finally: |
168 | - if src: src.close() |
169 | - if dst: dst.close() |
170 | - return os.path.realpath(saveto) |
171 | - |
172 | - |
173 | - |
174 | - |
175 | - |
176 | - |
177 | - |
178 | - |
179 | - |
180 | - |
181 | - |
182 | - |
183 | - |
184 | - |
185 | - |
186 | - |
187 | - |
188 | - |
189 | - |
190 | - |
191 | - |
192 | - |
193 | - |
194 | - |
195 | - |
196 | - |
197 | - |
198 | - |
199 | - |
200 | - |
201 | - |
202 | - |
203 | - |
204 | - |
205 | - |
206 | - |
207 | -def main(argv, version=DEFAULT_VERSION): |
208 | - """Install or upgrade setuptools and EasyInstall""" |
209 | - try: |
210 | - import setuptools |
211 | - except ImportError: |
212 | - egg = None |
213 | - try: |
214 | - egg = download_setuptools(version, delay=0) |
215 | - sys.path.insert(0,egg) |
216 | - from setuptools.command.easy_install import main |
217 | - return main(list(argv)+[egg]) # we're done here |
218 | - finally: |
219 | - if egg and os.path.exists(egg): |
220 | - os.unlink(egg) |
221 | - else: |
222 | - if setuptools.__version__ == '0.0.1': |
223 | - print >>sys.stderr, ( |
224 | - "You have an obsolete version of setuptools installed. Please\n" |
225 | - "remove it from your system entirely before rerunning this script." |
226 | - ) |
227 | - sys.exit(2) |
228 | - |
229 | - req = "setuptools>="+version |
230 | - import pkg_resources |
231 | - try: |
232 | - pkg_resources.require(req) |
233 | - except pkg_resources.VersionConflict: |
234 | - try: |
235 | - from setuptools.command.easy_install import main |
236 | - except ImportError: |
237 | - from easy_install import main |
238 | - main(list(argv)+[download_setuptools(delay=0)]) |
239 | - sys.exit(0) # try to force an exit |
240 | - else: |
241 | - if argv: |
242 | - from setuptools.command.easy_install import main |
243 | - main(argv) |
244 | - else: |
245 | - print "Setuptools version",version,"or greater has been installed." |
246 | - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' |
247 | - |
248 | -def update_md5(filenames): |
249 | - """Update our built-in md5 registry""" |
250 | - |
251 | - import re |
252 | - |
253 | - for name in filenames: |
254 | - base = os.path.basename(name) |
255 | - f = open(name,'rb') |
256 | - md5_data[base] = md5(f.read()).hexdigest() |
257 | - f.close() |
258 | - |
259 | - data = [" %r: %r,\n" % it for it in md5_data.items()] |
260 | - data.sort() |
261 | - repl = "".join(data) |
262 | - |
263 | - import inspect |
264 | - srcfile = inspect.getsourcefile(sys.modules[__name__]) |
265 | - f = open(srcfile, 'rb'); src = f.read(); f.close() |
266 | - |
267 | - match = re.search("\nmd5_data = {\n([^}]+)}", src) |
268 | - if not match: |
269 | - print >>sys.stderr, "Internal error!" |
270 | - sys.exit(2) |
271 | - |
272 | - src = src[:match.start(1)] + repl + src[match.end(1):] |
273 | - f = open(srcfile,'w') |
274 | - f.write(src) |
275 | - f.close() |
276 | - |
277 | - |
278 | -if __name__=='__main__': |
279 | - if len(sys.argv)>2 and sys.argv[1]=='--md5update': |
280 | - update_md5(sys.argv[2:]) |
281 | - else: |
282 | - main(sys.argv[1:]) |
283 | - |
284 | - |
285 | - |
286 | - |
287 | - |
288 | - |
289 | |
290 | === modified file 'setup.py' |
291 | --- setup.py 2016-03-01 13:09:28 +0000 |
292 | +++ setup.py 2017-06-09 20:57:05 +0000 |
293 | @@ -2,10 +2,10 @@ |
294 | import os |
295 | import re |
296 | |
297 | -import ez_setup |
298 | -ez_setup.use_setuptools() |
299 | - |
300 | -from setuptools import setup, Extension, find_packages |
301 | +try: |
302 | + from setuptools import setup, Extension |
303 | +except ImportError: |
304 | + from distutils.core import setup, Extension |
305 | |
306 | |
307 | if os.path.isfile("MANIFEST"): |
308 | @@ -19,12 +19,20 @@ |
309 | open("storm/__init__.py").read()).group(1) |
310 | |
311 | |
312 | +def find_packages(): |
313 | + # implement a simple find_packages so we don't have to depend on |
314 | + # setuptools |
315 | + packages = [] |
316 | + for directory, subdirectories, files in os.walk("storm"): |
317 | + if '__init__.py' in files: |
318 | + packages.append(directory.replace(os.sep, '.')) |
319 | + return packages |
320 | + |
321 | + |
322 | setup( |
323 | name="storm", |
324 | version=VERSION, |
325 | - description=( |
326 | - "Storm is an object-relational mapper (ORM) for Python " |
327 | - "developed at Canonical."), |
328 | + description="Storm is an object-relational mapper (ORM) for Python developed at Canonical.", |
329 | author="Gustavo Niemeyer", |
330 | author_email="gustavo@niemeyer.net", |
331 | maintainer="Storm Developers", |
332 | @@ -33,42 +41,18 @@ |
333 | url="https://storm.canonical.com", |
334 | download_url="https://launchpad.net/storm/+download", |
335 | packages=find_packages(), |
336 | + zip_safe=False, |
337 | + include_package_data=True, |
338 | package_data={"": ["*.zcml"]}, |
339 | classifiers=[ |
340 | "Development Status :: 5 - Production/Stable", |
341 | "Intended Audience :: Developers", |
342 | - ("License :: OSI Approved :: GNU Library or " |
343 | - "Lesser General Public License (LGPL)"), |
344 | + "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", |
345 | "Programming Language :: Python", |
346 | "Topic :: Database", |
347 | "Topic :: Database :: Front-Ends", |
348 | "Topic :: Software Development :: Libraries :: Python Modules", |
349 | ], |
350 | ext_modules=(BUILD_CEXTENSIONS and |
351 | - [Extension("storm.cextensions", ["storm/cextensions.c"])]), |
352 | - # The following options are specific to setuptools but ignored (with a |
353 | - # warning) by distutils. |
354 | - include_package_data=True, |
355 | - zip_safe=False, |
356 | - test_suite = "tests.find_tests", |
357 | - tests_require=[ |
358 | - # Versions based on Lucid, where packaged. |
359 | - "fixtures >= 0.3.5", |
360 | - # pgbouncer (the Python module) is not yet packaged in Ubuntu. |
361 | - "pgbouncer >= 0.0.7", |
362 | - "psycopg2 >= 2.0.13", |
363 | - "testresources >= 0.2.4", |
364 | - "testtools >= 0.9.8", |
365 | - # timeline is not yet packaged in Ubuntu. |
366 | - "timeline >= 0.0.2", |
367 | - "transaction >= 1.0.0", |
368 | - "twisted >= 10.0.0", |
369 | - "zope.component >= 3.8.0", |
370 | - # zope.component 3.11.0 requires a version of zope.interface that no |
371 | - # version of Ubuntu yet packages. The following rule exists for the |
372 | - # sake of convenience rather than necessity, for the situation where |
373 | - # zope.interface is installed via a package but zope.component is not. |
374 | - "zope.component < 3.11.0", |
375 | - "zope.security >= 3.7.2", |
376 | - ], |
377 | - ) |
378 | + [Extension("storm.cextensions", ["storm/cextensions.c"])]) |
379 | +) |
380 | |
381 | === modified file 'storm/__init__.py' |
382 | --- storm/__init__.py 2013-06-28 09:56:58 +0000 |
383 | +++ storm/__init__.py 2017-06-09 20:57:05 +0000 |
384 | @@ -19,6 +19,8 @@ |
385 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
386 | # |
387 | |
388 | +from builtins import str |
389 | +from builtins import object |
390 | import os |
391 | |
392 | |
393 | @@ -53,6 +55,6 @@ |
394 | try: |
395 | from storm import cextensions |
396 | has_cextensions = True |
397 | - except ImportError, e: |
398 | + except ImportError as e: |
399 | if "cextensions" not in str(e): |
400 | raise |
401 | |
402 | === modified file 'storm/base.py' |
403 | --- storm/base.py 2007-07-05 20:29:25 +0000 |
404 | +++ storm/base.py 2017-06-09 20:57:05 +0000 |
405 | @@ -18,18 +18,19 @@ |
406 | # You should have received a copy of the GNU Lesser General Public License |
407 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
408 | # |
409 | +from builtins import object |
410 | from storm.properties import PropertyPublisherMeta |
411 | +from future.utils import with_metaclass |
412 | |
413 | |
414 | __all__ = ["Storm"] |
415 | |
416 | |
417 | -class Storm(object): |
418 | +class Storm(with_metaclass(PropertyPublisherMeta, object)): |
419 | """An optional base class for objects stored in a Storm Store. |
420 | |
421 | It causes your subclasses to be associated with a Storm |
422 | PropertyRegistry. It is necessary to use this if you want to |
423 | specify References with strings. |
424 | """ |
425 | - __metaclass__ = PropertyPublisherMeta |
426 | |
427 | |
428 | === modified file 'storm/cache.py' |
429 | --- storm/cache.py 2009-02-16 10:44:31 +0000 |
430 | +++ storm/cache.py 2017-06-09 20:57:05 +0000 |
431 | @@ -1,3 +1,4 @@ |
432 | +from builtins import object |
433 | import itertools |
434 | |
435 | |
436 | @@ -140,8 +141,8 @@ |
437 | objects, but no more than twice that number. |
438 | """ |
439 | self._size = size |
440 | - cache = itertools.islice(itertools.chain(self._new_cache.iteritems(), |
441 | - self._old_cache.iteritems()), |
442 | + cache = itertools.islice(itertools.chain(iter(self._new_cache.items()), |
443 | + iter(self._old_cache.items())), |
444 | 0, size) |
445 | self._new_cache = dict(cache) |
446 | self._old_cache.clear() |
447 | |
448 | === modified file 'storm/cextensions.c' |
449 | --- storm/cextensions.c 2012-05-31 04:14:32 +0000 |
450 | +++ storm/cextensions.c 2017-06-09 20:57:05 +0000 |
451 | @@ -23,14 +23,15 @@ |
452 | #include <Python.h> |
453 | #include <structmember.h> |
454 | |
455 | - |
456 | -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) |
457 | -typedef int Py_ssize_t; |
458 | -#define PY_SSIZE_T_MAX INT_MAX |
459 | -#define PY_SSIZE_T_MIN INT_MIN |
460 | +#if PY_VERSION_HEX >= 0x03000000 |
461 | +#define PyInt_FromLong PyLong_FromLong |
462 | +#define PyText_AsString _PyUnicode_AsString |
463 | +#define PyString_CheckExact(o) 0 |
464 | +#else |
465 | +/* 2.x */ |
466 | +#define PyText_AsString PyString_AsString |
467 | #endif |
468 | |
469 | - |
470 | #define CATCH(error_value, expression) \ |
471 | do { \ |
472 | if ((expression) == error_value) {\ |
473 | @@ -46,57 +47,6 @@ |
474 | Py_DECREF(tmp); \ |
475 | } while(0) |
476 | |
477 | - |
478 | -/* Python 2.4 does not include the PySet_* API, so provide a minimal |
479 | - implementation for the calls we care about. */ |
480 | -#if PY_VERSION_HEX < 0x02050000 && !defined(PySet_GET_SIZE) |
481 | -# define PySet_GET_SIZE(so) \ |
482 | - ((PyDictObject *)((PySetObject *)so)->data)->ma_used |
483 | -static PyObject * |
484 | -PySet_New(PyObject *p) |
485 | -{ |
486 | - return PyObject_CallObject((PyObject *)&PySet_Type, NULL); |
487 | -} |
488 | - |
489 | -static int |
490 | -PySet_Add(PyObject *set, PyObject *key) |
491 | -{ |
492 | - PyObject *dict; |
493 | - |
494 | - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { |
495 | - PyErr_BadInternalCall(); |
496 | - return -1; |
497 | - } |
498 | - dict = ((PySetObject *)set)->data; |
499 | - return PyDict_SetItem(dict, key, Py_True); |
500 | -} |
501 | - |
502 | -static int |
503 | -PySet_Discard(PyObject *set, PyObject *key) |
504 | -{ |
505 | - PyObject *dict; |
506 | - int result; |
507 | - |
508 | - if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { |
509 | - PyErr_BadInternalCall(); |
510 | - return -1; |
511 | - } |
512 | - dict = ((PySetObject *)set)->data; |
513 | - result = PyDict_DelItem(dict, key); |
514 | - if (result == 0) { |
515 | - /* key found and removed */ |
516 | - result = 1; |
517 | - } else { |
518 | - if (PyErr_ExceptionMatches(PyExc_KeyError)) { |
519 | - /* key not found */ |
520 | - PyErr_Clear(); |
521 | - result = 0; |
522 | - } |
523 | - } |
524 | - return result; |
525 | -} |
526 | -#endif |
527 | - |
528 | static PyObject *Undef = NULL; |
529 | static PyObject *LazyValue = NULL; |
530 | static PyObject *raise_none_error = NULL; |
531 | @@ -300,7 +250,7 @@ |
532 | EventSystem_dealloc(EventSystemObject *self) |
533 | { |
534 | EventSystem_clear(self); |
535 | - self->ob_type->tp_free((PyObject *)self); |
536 | + Py_TYPE(self)->tp_free((PyObject *)self); |
537 | } |
538 | |
539 | static PyObject * |
540 | @@ -521,9 +471,8 @@ |
541 | }; |
542 | #undef OFFSETOF |
543 | |
544 | -statichere PyTypeObject EventSystem_Type = { |
545 | - PyObject_HEAD_INIT(NULL) |
546 | - 0, /*ob_size*/ |
547 | +static PyTypeObject EventSystem_Type = { |
548 | + PyVarObject_HEAD_INIT(NULL, 0) |
549 | "storm.variables.EventSystem", /*tp_name*/ |
550 | sizeof(EventSystemObject), /*tp_basicsize*/ |
551 | 0, /*tp_itemsize*/ |
552 | @@ -707,7 +656,7 @@ |
553 | Variable_dealloc(VariableObject *self) |
554 | { |
555 | Variable_clear(self); |
556 | - self->ob_type->tp_free((PyObject *)self); |
557 | + Py_TYPE(self)->tp_free((PyObject *)self); |
558 | } |
559 | |
560 | static PyObject * |
561 | @@ -1065,7 +1014,7 @@ |
562 | |
563 | /* variable = self.__class__.__new__(self.__class__) */ |
564 | noargs = PyTuple_New(0); |
565 | - CATCH(NULL, variable = self->ob_type->tp_new(self->ob_type, noargs, NULL)); |
566 | + CATCH(NULL, variable = Py_TYPE(self)->tp_new(Py_TYPE(self), noargs, NULL)); |
567 | |
568 | /* variable.set_state(self.get_state()) */ |
569 | CATCH(NULL, |
570 | @@ -1116,9 +1065,8 @@ |
571 | }; |
572 | #undef OFFSETOF |
573 | |
574 | -statichere PyTypeObject Variable_Type = { |
575 | - PyObject_HEAD_INIT(NULL) |
576 | - 0, /*ob_size*/ |
577 | +static PyTypeObject Variable_Type = { |
578 | + PyVarObject_HEAD_INIT(NULL, 0) |
579 | "storm.variables.Variable", /*tp_name*/ |
580 | sizeof(VariableObject), /*tp_basicsize*/ |
581 | 0, /*tp_itemsize*/ |
582 | @@ -1267,7 +1215,7 @@ |
583 | Compile_dealloc(CompileObject *self) |
584 | { |
585 | Compile_clear(self); |
586 | - self->ob_type->tp_free((PyObject *)self); |
587 | + Py_TYPE(self)->tp_free((PyObject *)self); |
588 | } |
589 | |
590 | static PyObject * |
591 | @@ -1434,13 +1382,13 @@ |
592 | return NULL; |
593 | } |
594 | |
595 | -staticforward PyTypeObject Compile_Type; |
596 | +static PyTypeObject Compile_Type; |
597 | |
598 | static PyObject * |
599 | Compile_create_child(CompileObject *self, PyObject *args) |
600 | { |
601 | /* return self.__class__(self) */ |
602 | - return PyObject_CallFunctionObjArgs((PyObject *)self->ob_type, self, NULL); |
603 | + return PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(self), self, NULL); |
604 | } |
605 | |
606 | static PyObject * |
607 | @@ -1538,7 +1486,7 @@ |
608 | if (repr) { |
609 | PyErr_Format(CompileError, |
610 | "Don't know how to compile type %s of %s", |
611 | - expr->ob_type->tp_name, PyString_AS_STRING(repr)); |
612 | + expr->ob_type->tp_name, PyText_AsString(repr)); |
613 | Py_DECREF(repr); |
614 | } |
615 | goto error; |
616 | @@ -1557,7 +1505,7 @@ |
617 | state, NULL)); |
618 | |
619 | /* if inner_precedence < outer_precedence: */ |
620 | - if (PyObject_Compare(inner_precedence, outer_precedence) == -1) { |
621 | + if (PyObject_RichCompareBool(inner_precedence, outer_precedence, Py_LT)) { |
622 | PyObject *args, *tmp; |
623 | |
624 | if (PyErr_Occurred()) |
625 | @@ -1780,9 +1728,8 @@ |
626 | }; |
627 | #undef OFFSETOF |
628 | |
629 | -statichere PyTypeObject Compile_Type = { |
630 | - PyObject_HEAD_INIT(NULL) |
631 | - 0, /*ob_size*/ |
632 | +static PyTypeObject Compile_Type = { |
633 | + PyVarObject_HEAD_INIT(NULL, 0) |
634 | "storm.variables.Compile", /*tp_name*/ |
635 | sizeof(CompileObject), /*tp_basicsize*/ |
636 | 0, /*tp_itemsize*/ |
637 | @@ -2071,9 +2018,8 @@ |
638 | {NULL} |
639 | }; |
640 | |
641 | -statichere PyTypeObject ObjectInfo_Type = { |
642 | - PyObject_HEAD_INIT(NULL) |
643 | - 0, /*ob_size*/ |
644 | +static PyTypeObject ObjectInfo_Type = { |
645 | + PyVarObject_HEAD_INIT(NULL, 0) |
646 | "storm.info.ObjectInfo", /*tp_name*/ |
647 | sizeof(ObjectInfoObject), /*tp_basicsize*/ |
648 | 0, /*tp_itemsize*/ |
649 | @@ -2176,11 +2122,9 @@ |
650 | return PyType_Ready(type); |
651 | } |
652 | |
653 | -DL_EXPORT(void) |
654 | -initcextensions(void) |
655 | +static int |
656 | +do_init(PyObject *module) |
657 | { |
658 | - PyObject *module; |
659 | - |
660 | prepare_type(&EventSystem_Type); |
661 | prepare_type(&Compile_Type); |
662 | ObjectInfo_Type.tp_base = &PyDict_Type; |
663 | @@ -2188,7 +2132,6 @@ |
664 | prepare_type(&ObjectInfo_Type); |
665 | prepare_type(&Variable_Type); |
666 | |
667 | - module = Py_InitModule3("cextensions", cextensions_methods, ""); |
668 | Py_INCREF(&Variable_Type); |
669 | |
670 | #define REGISTER_TYPE(name) \ |
671 | @@ -2201,7 +2144,42 @@ |
672 | REGISTER_TYPE(ObjectInfo); |
673 | REGISTER_TYPE(Compile); |
674 | REGISTER_TYPE(EventSystem); |
675 | -} |
676 | + return 0; |
677 | +} |
678 | + |
679 | +#if PY_VERSION_HEX < 0x03000000 |
680 | +DL_EXPORT(void) |
681 | +initcextensions(void) |
682 | +{ |
683 | + PyObject *module; |
684 | + |
685 | + module = Py_InitModule3("cextensions", cextensions_methods, ""); |
686 | + do_init(module); |
687 | +} |
688 | +#else |
689 | +static struct PyModuleDef cextensionsmodule = { |
690 | + PyModuleDef_HEAD_INIT, |
691 | + "cextensions", |
692 | + NULL, |
693 | + -1, |
694 | + cextensions_methods, |
695 | + NULL, |
696 | + NULL, |
697 | + NULL, |
698 | + NULL |
699 | +}; |
700 | + |
701 | +PyMODINIT_FUNC |
702 | +PyInit_cextensions(void) |
703 | +{ |
704 | + PyObject *module = PyModule_Create(&cextensionsmodule); |
705 | + if (module == NULL) |
706 | + return NULL; |
707 | + do_init(module); |
708 | + return module; |
709 | +} |
710 | +#endif |
711 | + |
712 | |
713 | /* vim:ts=4:sw=4:et |
714 | */ |
715 | |
716 | === modified file 'storm/database.py' |
717 | --- storm/database.py 2015-06-15 13:42:07 +0000 |
718 | +++ storm/database.py 2017-06-09 20:57:05 +0000 |
719 | @@ -25,6 +25,11 @@ |
720 | supported in modules in L{storm.databases}. |
721 | """ |
722 | |
723 | +from builtins import str |
724 | +from builtins import range |
725 | +from builtins import object |
726 | +import six |
727 | + |
728 | from storm.expr import Expr, State, compile |
729 | # Circular import: imported at the end of the module. |
730 | # from storm.tracer import trace |
731 | @@ -318,7 +323,7 @@ |
732 | self._raw_connection.tpc_rollback() |
733 | else: |
734 | self._raw_connection.rollback() |
735 | - except Error, exc: |
736 | + except Error as exc: |
737 | if self.is_disconnection_error(exc): |
738 | self._raw_connection = None |
739 | self._state = STATE_RECONNECT |
740 | @@ -386,7 +391,7 @@ |
741 | """Complete the statement execution, along with result reports.""" |
742 | try: |
743 | self._check_disconnect(raw_cursor.execute, *args) |
744 | - except Exception, error: |
745 | + except Exception as error: |
746 | self._check_disconnect( |
747 | trace, "connection_raw_execute_error", self, raw_cursor, |
748 | statement, params or (), error) |
749 | @@ -402,7 +407,7 @@ |
750 | self._check_disconnect( |
751 | trace, "connection_raw_execute", self, raw_cursor, |
752 | statement, params or ()) |
753 | - except Exception, error: |
754 | + except Exception as error: |
755 | self._check_disconnect( |
756 | trace, "connection_raw_execute_error", self, raw_cursor, |
757 | statement, params or (), error) |
758 | @@ -423,7 +428,7 @@ |
759 | elif self._state == STATE_RECONNECT: |
760 | try: |
761 | self._raw_connection = self._database.raw_connect() |
762 | - except DatabaseError, exc: |
763 | + except DatabaseError as exc: |
764 | self._state = STATE_DISCONNECTED |
765 | self._raw_connection = None |
766 | raise DisconnectionError(str(exc)) |
767 | @@ -452,7 +457,7 @@ |
768 | 'extra_disconnection_errors', ()) |
769 | try: |
770 | return function(*args, **kwargs) |
771 | - except Exception, exc: |
772 | + except Exception as exc: |
773 | if self.is_disconnection_error(exc, extra_disconnection_errors): |
774 | self._state = STATE_DISCONNECTED |
775 | self._raw_connection = None |
776 | @@ -544,7 +549,7 @@ |
777 | - "anything:..." Where 'anything' has previously been registered |
778 | with L{register_scheme}. |
779 | """ |
780 | - if isinstance(uri, basestring): |
781 | + if isinstance(uri, six.string_types): |
782 | uri = URI(uri) |
783 | if uri.scheme in _database_schemes: |
784 | factory = _database_schemes[uri.scheme] |
785 | |
786 | === modified file 'storm/databases/__init__.py' |
787 | --- storm/databases/__init__.py 2007-08-07 18:36:04 +0000 |
788 | +++ storm/databases/__init__.py 2017-06-09 20:57:05 +0000 |
789 | @@ -20,6 +20,7 @@ |
790 | # |
791 | |
792 | |
793 | +from builtins import object |
794 | class Dummy(object): |
795 | """Magic "infectious" class. |
796 | |
797 | @@ -36,7 +37,7 @@ |
798 | def __add__(self, other): |
799 | return self |
800 | |
801 | - def __nonzero__(self): |
802 | + def __bool__(self): |
803 | return False |
804 | |
805 | dummy = Dummy() |
806 | |
807 | === modified file 'storm/databases/mysql.py' |
808 | --- storm/databases/mysql.py 2015-06-15 12:02:12 +0000 |
809 | +++ storm/databases/mysql.py 2017-06-09 20:57:05 +0000 |
810 | @@ -18,6 +18,7 @@ |
811 | # You should have received a copy of the GNU Lesser General Public License |
812 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
813 | # |
814 | +from builtins import str |
815 | from datetime import time, timedelta |
816 | from array import array |
817 | import sys |
818 | @@ -48,7 +49,7 @@ |
819 | @compile.when(Select) |
820 | def compile_select_mysql(compile, select, state): |
821 | if select.offset is not Undef and select.limit is Undef: |
822 | - select.limit = sys.maxint |
823 | + select.limit = sys.maxsize |
824 | return compile_select(compile, select, state) |
825 | |
826 | @compile.when(SQLToken) |
827 | |
828 | === modified file 'storm/databases/postgres.py' |
829 | --- storm/databases/postgres.py 2016-04-28 11:57:12 +0000 |
830 | +++ storm/databases/postgres.py 2017-06-09 20:57:05 +0000 |
831 | @@ -19,6 +19,8 @@ |
832 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
833 | # |
834 | |
835 | +from builtins import zip, str |
836 | +import six |
837 | from datetime import datetime, date, time, timedelta |
838 | import json |
839 | |
840 | @@ -310,7 +312,7 @@ |
841 | Like L{Connection.raw_execute}, but encode the statement to |
842 | UTF-8 if it is unicode. |
843 | """ |
844 | - if type(statement) is unicode: |
845 | + if type(statement) is six.text_type and six.PY2: |
846 | # psycopg breaks with unicode statements. |
847 | statement = statement.encode("UTF-8") |
848 | return Connection.raw_execute(self, statement, params) |
849 | @@ -326,9 +328,9 @@ |
850 | param = param.get(to_db=True) |
851 | if isinstance(param, (datetime, date, time, timedelta)): |
852 | yield str(param) |
853 | - elif isinstance(param, unicode): |
854 | + elif isinstance(param, six.text_type) and six.PY2: |
855 | yield param.encode("UTF-8") |
856 | - elif isinstance(param, str): |
857 | + elif isinstance(param, six.binary_type): |
858 | yield psycopg2.Binary(param) |
859 | else: |
860 | yield param |
861 | @@ -484,7 +486,7 @@ |
862 | __slots__ = () |
863 | |
864 | def _loads(self, value): |
865 | - if isinstance(value, str): |
866 | + if isinstance(value, six.binary_type): |
867 | # psycopg versions < 2.5 don't automatically convert JSON columns |
868 | # to python objects, they return a string. |
869 | # |
870 | |
871 | === modified file 'storm/databases/sqlite.py' |
872 | --- storm/databases/sqlite.py 2015-06-15 12:02:12 +0000 |
873 | +++ storm/databases/sqlite.py 2017-06-09 20:57:05 +0000 |
874 | @@ -18,6 +18,8 @@ |
875 | # You should have received a copy of the GNU Lesser General Public License |
876 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
877 | # |
878 | +from builtins import str |
879 | +import six |
880 | from datetime import datetime, date, time, timedelta |
881 | from time import sleep, time as now |
882 | import sys |
883 | @@ -41,6 +43,7 @@ |
884 | |
885 | |
886 | install_exceptions(sqlite) |
887 | +buffer = buffer if six.PY2 else memoryview |
888 | |
889 | |
890 | compile = compile.create_child() |
891 | @@ -51,9 +54,9 @@ |
892 | if sys.maxsize > 2**32: |
893 | # On 64-bit platforms sqlite doesn't like maxint as LIMIT. See also |
894 | # https://lists.ubuntu.com/archives/storm/2013-June/001492.html |
895 | - select.limit = sys.maxint - 1 |
896 | + select.limit = sys.maxsize - 1 |
897 | else: |
898 | - select.limit = sys.maxint |
899 | + select.limit = sys.maxsize |
900 | statement = compile_select(compile, select, state) |
901 | if state.context is SELECT: |
902 | # SQLite breaks with (SELECT ...) UNION (SELECT ...), so we |
903 | @@ -119,7 +122,7 @@ |
904 | param = param.get(to_db=True) |
905 | if isinstance(param, (datetime, date, time, timedelta)): |
906 | yield str(param) |
907 | - elif isinstance(param, str): |
908 | + elif isinstance(param, six.binary_type): |
909 | yield buffer(param) |
910 | else: |
911 | yield param |
912 | @@ -157,7 +160,7 @@ |
913 | while True: |
914 | try: |
915 | return Connection.raw_execute(self, statement, params) |
916 | - except sqlite.OperationalError, e: |
917 | + except sqlite.OperationalError as e: |
918 | if str(e) != "database is locked": |
919 | raise |
920 | elif now() - started < self._database._timeout: |
921 | |
922 | === modified file 'storm/event.py' |
923 | --- storm/event.py 2008-06-18 21:51:12 +0000 |
924 | +++ storm/event.py 2017-06-09 20:57:05 +0000 |
925 | @@ -18,6 +18,7 @@ |
926 | # You should have received a copy of the GNU Lesser General Public License |
927 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
928 | # |
929 | +from builtins import object |
930 | import weakref |
931 | |
932 | from storm import has_cextensions |
933 | |
934 | === modified file 'storm/exceptions.py' |
935 | --- storm/exceptions.py 2015-11-23 15:03:53 +0000 |
936 | +++ storm/exceptions.py 2017-06-09 20:57:05 +0000 |
937 | @@ -19,11 +19,13 @@ |
938 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
939 | # |
940 | from abc import ABCMeta |
941 | +import six |
942 | import types |
943 | - |
944 | - |
945 | -class StormError(Exception): |
946 | - __metaclass__ = ABCMeta |
947 | +from future.utils import with_metaclass |
948 | + |
949 | + |
950 | +class StormError(with_metaclass(ABCMeta, Exception)): |
951 | + pass |
952 | |
953 | |
954 | class CompileError(StormError): |
955 | @@ -128,7 +130,7 @@ |
956 | self.message = message |
957 | |
958 | def __str__(self): |
959 | - return ', '.join( |
960 | + return ', '.join( |
961 | [repr(element) for element in |
962 | (self.message, self.statement, self.params) |
963 | if element is not None]) |
964 | @@ -144,8 +146,16 @@ |
965 | DataError, NotSupportedError, InterfaceError): |
966 | module_exception = getattr(module, exception.__name__, None) |
967 | if (module_exception is not None and |
968 | - isinstance(module_exception, (type, types.ClassType))): |
969 | - # XXX This may need to be revisited when porting to Python 3 if |
970 | - # virtual subclasses are still ignored for exception handling |
971 | - # (https://bugs.python.org/issue12029). |
972 | - exception.register(module_exception) |
973 | + isinstance(module_exception, type)): |
974 | + if six.PY2: |
975 | + exception.register(module_exception) |
976 | + else: |
977 | + # XXX virtual subclasses are still ignored for exception handling |
978 | + # (https://bugs.python.org/issue12029). |
979 | + try: |
980 | + module_exception.__bases__ += (exception, ) |
981 | + except TypeError: |
982 | + tmp_exc = type(module_exception.__name__, (module_exception, ), {}) |
983 | + setattr(module, module_exception.__name__, tmp_exc) |
984 | + module_exception = getattr(module, exception.__name__) |
985 | + module_exception.__bases__ += (exception, ) |
986 | |
987 | === modified file 'storm/expr.py' |
988 | --- storm/expr.py 2016-05-13 18:55:24 +0000 |
989 | +++ storm/expr.py 2017-06-09 20:57:05 +0000 |
990 | @@ -18,6 +18,8 @@ |
991 | # You should have received a copy of the GNU Lesser General Public License |
992 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
993 | # |
994 | +from builtins import zip, range, object |
995 | +import six |
996 | from decimal import Decimal |
997 | from datetime import datetime, date, time, timedelta |
998 | from weakref import WeakKeyDictionary |
999 | @@ -164,10 +166,10 @@ |
1000 | expr_type = type(expr) |
1001 | |
1002 | if (expr_type is SQLRaw or |
1003 | - raw and (expr_type is str or expr_type is unicode)): |
1004 | + raw and (expr_type is six.binary_type or expr_type is six.text_type)): |
1005 | return expr |
1006 | |
1007 | - if token and (expr_type is str or expr_type is unicode): |
1008 | + if token and (expr_type is six.binary_type or expr_type is six.text_type): |
1009 | expr = SQLToken(expr) |
1010 | |
1011 | if state is None: |
1012 | @@ -178,15 +180,15 @@ |
1013 | compiled = [] |
1014 | for subexpr in expr: |
1015 | subexpr_type = type(subexpr) |
1016 | - if subexpr_type is SQLRaw or raw and (subexpr_type is str or |
1017 | - subexpr_type is unicode): |
1018 | + if subexpr_type is SQLRaw or raw and (subexpr_type is six.binary_type or |
1019 | + subexpr_type is six.text_type): |
1020 | statement = subexpr |
1021 | elif subexpr_type is tuple or subexpr_type is list: |
1022 | state.precedence = outer_precedence |
1023 | statement = self(subexpr, state, join, raw, token) |
1024 | else: |
1025 | - if token and (subexpr_type is unicode or |
1026 | - subexpr_type is str): |
1027 | + if token and (subexpr_type is six.text_type or |
1028 | + subexpr_type is six.binary_type): |
1029 | subexpr = SQLToken(subexpr) |
1030 | statement = self._compile_single(subexpr, state, |
1031 | outer_precedence) |
1032 | @@ -216,7 +218,7 @@ |
1033 | " return match" % |
1034 | (",".join("_%d" % i for i in range(len(state.parameters))), |
1035 | source)) |
1036 | - exec code in namespace |
1037 | + exec(code, namespace) |
1038 | return namespace['closure'](state.parameters, bool) |
1039 | |
1040 | |
1041 | @@ -303,17 +305,17 @@ |
1042 | # -------------------------------------------------------------------- |
1043 | # Builtin type support |
1044 | |
1045 | -@compile.when(str) |
1046 | +@compile.when(six.binary_type) |
1047 | def compile_str(compile, expr, state): |
1048 | state.parameters.append(RawStrVariable(expr)) |
1049 | return "?" |
1050 | |
1051 | -@compile.when(unicode) |
1052 | +@compile.when(six.text_type) |
1053 | def compile_unicode(compile, expr, state): |
1054 | state.parameters.append(UnicodeVariable(expr)) |
1055 | return "?" |
1056 | |
1057 | -@compile.when(int, long) |
1058 | +@compile.when(*six.integer_types) |
1059 | def compile_int(compile, expr, state): |
1060 | state.parameters.append(IntVariable(expr)) |
1061 | return "?" |
1062 | @@ -358,7 +360,7 @@ |
1063 | return "NULL" |
1064 | |
1065 | |
1066 | -@compile_python.when(str, unicode, int, long, float, type(None)) |
1067 | +@compile_python.when(float, type(None), *(six.string_types + six.integer_types)) |
1068 | def compile_python_builtin(compile, expr, state): |
1069 | return repr(expr) |
1070 | |
1071 | @@ -406,6 +408,7 @@ |
1072 | |
1073 | class Comparable(object): |
1074 | __slots__ = () |
1075 | + __hash__ = object.__hash__ |
1076 | |
1077 | def __eq__(self, other): |
1078 | if other is not None and not isinstance(other, (Expr, Variable)): |
1079 | @@ -477,6 +480,9 @@ |
1080 | other = getattr(self, "variable_factory", Variable)(value=other) |
1081 | return Div(self, other) |
1082 | |
1083 | + __floordiv__ = __div__ |
1084 | + __truediv__ = __div__ |
1085 | + |
1086 | def __mod__(self, other): |
1087 | if not isinstance(other, (Expr, Variable)): |
1088 | other = getattr(self, "variable_factory", Variable)(value=other) |
1089 | @@ -508,19 +514,19 @@ |
1090 | return Upper(self) |
1091 | |
1092 | def startswith(self, prefix): |
1093 | - if not isinstance(prefix, unicode): |
1094 | + if not isinstance(prefix, six.text_type): |
1095 | raise ExprError("Expected unicode argument, got %r" % type(prefix)) |
1096 | pattern = prefix.translate(like_escape) + u"%" |
1097 | return Like(self, pattern, u"!") |
1098 | |
1099 | def endswith(self, suffix): |
1100 | - if not isinstance(suffix, unicode): |
1101 | + if not isinstance(suffix, six.text_type): |
1102 | raise ExprError("Expected unicode argument, got %r" % type(suffix)) |
1103 | pattern = u"%" + suffix.translate(like_escape) |
1104 | return Like(self, pattern, u"!") |
1105 | |
1106 | def contains_string(self, substring): |
1107 | - if not isinstance(substring, unicode): |
1108 | + if not isinstance(substring, six.text_type): |
1109 | raise ExprError("Expected unicode argument, got %r" % type(substring)) |
1110 | pattern = u"%" + substring.translate(like_escape) + u"%" |
1111 | return Like(self, pattern, u"!") |
1112 | @@ -736,7 +742,7 @@ |
1113 | state.context = EXPR |
1114 | values = insert.values |
1115 | if values is Undef: |
1116 | - values = [tuple(insert.map.itervalues())] |
1117 | + values = [tuple(insert.map.values())] |
1118 | if isinstance(values, Expr): |
1119 | compiled_values = compile(values, state) |
1120 | else: |
1121 | @@ -1414,7 +1420,7 @@ |
1122 | # -------------------------------------------------------------------- |
1123 | # Plain SQL expressions. |
1124 | |
1125 | -class SQLRaw(str): |
1126 | +class SQLRaw(six.text_type): |
1127 | """Subtype to mark a string as something that shouldn't be compiled. |
1128 | |
1129 | This is handled internally by the compiler. |
1130 | @@ -1422,7 +1428,7 @@ |
1131 | __slots__ = () |
1132 | |
1133 | |
1134 | -class SQLToken(str): |
1135 | +class SQLToken(six.text_type): |
1136 | """Marker for strings that should be considered as a single SQL token. |
1137 | |
1138 | These strings will be quoted, when needed. |
1139 | |
1140 | === modified file 'storm/info.py' |
1141 | --- storm/info.py 2011-08-14 08:55:15 +0000 |
1142 | +++ storm/info.py 2017-06-09 20:57:05 +0000 |
1143 | @@ -18,8 +18,11 @@ |
1144 | # You should have received a copy of the GNU Lesser General Public License |
1145 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1146 | # |
1147 | +from builtins import object |
1148 | from weakref import ref |
1149 | |
1150 | +import six |
1151 | + |
1152 | from storm.exceptions import ClassInfoError |
1153 | from storm.expr import Column, Desc, TABLE |
1154 | from storm.expr import compile, Table |
1155 | @@ -73,7 +76,7 @@ |
1156 | |
1157 | self.cls = cls |
1158 | |
1159 | - if isinstance(self.table, basestring): |
1160 | + if isinstance(self.table, six.string_types): |
1161 | self.table = Table(self.table) |
1162 | |
1163 | pairs = [] |
1164 | @@ -131,7 +134,7 @@ |
1165 | __order__ = (__order__,) |
1166 | self.default_order = [] |
1167 | for item in __order__: |
1168 | - if isinstance(item, basestring): |
1169 | + if isinstance(item, six.string_types): |
1170 | if item.startswith("-"): |
1171 | prop = Desc(getattr(cls, item[1:])) |
1172 | else: |
1173 | @@ -146,6 +149,8 @@ |
1174 | def __ne__(self, other): |
1175 | return self is not other |
1176 | |
1177 | + __hash__ = object.__hash__ |
1178 | + |
1179 | |
1180 | class ObjectInfo(dict): |
1181 | |
1182 | @@ -192,7 +197,7 @@ |
1183 | self.event.emit("object-deleted") |
1184 | |
1185 | def checkpoint(self): |
1186 | - for variable in self.variables.itervalues(): |
1187 | + for variable in self.variables.values(): |
1188 | variable.checkpoint() |
1189 | |
1190 | |
1191 | |
1192 | === modified file 'storm/properties.py' |
1193 | --- storm/properties.py 2011-02-28 21:16:29 +0000 |
1194 | +++ storm/properties.py 2017-06-09 20:57:05 +0000 |
1195 | @@ -18,6 +18,8 @@ |
1196 | # You should have received a copy of the GNU Lesser General Public License |
1197 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1198 | # |
1199 | +from builtins import zip |
1200 | +from builtins import object |
1201 | from bisect import insort_left, bisect_left |
1202 | import weakref |
1203 | import sys |
1204 | @@ -76,7 +78,7 @@ |
1205 | def _detect_attr_name(self, used_cls): |
1206 | self_id = id(self) |
1207 | for cls in used_cls.__mro__: |
1208 | - for attr, prop in cls.__dict__.items(): |
1209 | + for attr, prop in list(cls.__dict__.items()): |
1210 | if id(prop) == self_id: |
1211 | return attr |
1212 | raise RuntimeError("Property used in an unknown class") |
1213 | @@ -218,7 +220,7 @@ |
1214 | |
1215 | def __init__(self, name=None, primary=False, **kwargs): |
1216 | set_map = dict(kwargs.pop("map")) |
1217 | - get_map = dict((value, key) for key, value in set_map.items()) |
1218 | + get_map = dict((value, key) for key, value in list(set_map.items())) |
1219 | if "set_map" in kwargs: |
1220 | set_map = dict(kwargs.pop("set_map")) |
1221 | |
1222 | @@ -260,7 +262,7 @@ |
1223 | i += 1 |
1224 | else: |
1225 | namespace_parts = ("." + namespace).split(".") |
1226 | - best_path_info = (0, sys.maxint) |
1227 | + best_path_info = (0, sys.maxsize) |
1228 | while i < l and self._properties[i][0].startswith(key): |
1229 | path, prop_ref = self._properties[i] |
1230 | prop = prop_ref() |
1231 | |
1232 | === modified file 'storm/references.py' |
1233 | --- storm/references.py 2013-06-28 08:13:08 +0000 |
1234 | +++ storm/references.py 2017-06-09 20:57:05 +0000 |
1235 | @@ -18,8 +18,12 @@ |
1236 | # You should have received a copy of the GNU Lesser General Public License |
1237 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1238 | # |
1239 | +from builtins import zip |
1240 | +from builtins import object |
1241 | import weakref |
1242 | |
1243 | +import six |
1244 | + |
1245 | from storm.exceptions import ( |
1246 | ClassInfoError, FeatureError, NoStoreError, WrongStoreError) |
1247 | from storm.store import Store, get_where_for_args, LostObjectError |
1248 | @@ -206,6 +210,8 @@ |
1249 | def __ne__(self, other): |
1250 | return Not(self == other) |
1251 | |
1252 | + __hash__ = object.__hash__ |
1253 | + |
1254 | |
1255 | class ReferenceSet(object): |
1256 | |
1257 | @@ -621,8 +627,8 @@ |
1258 | if setting: |
1259 | local_vars = local_info.variables |
1260 | remote_vars = remote_info.variables |
1261 | - pairs = zip(self._get_local_columns(local.__class__), |
1262 | - self.remote_key) |
1263 | + pairs = list(zip(self._get_local_columns(local.__class__), |
1264 | + self.remote_key)) |
1265 | if self.on_remote: |
1266 | local_has_changed = False |
1267 | for local_column, remote_column in pairs: |
1268 | @@ -910,7 +916,7 @@ |
1269 | def resolve_one(self, property): |
1270 | if type(property) is tuple: |
1271 | return self.resolve(property) |
1272 | - elif isinstance(property, basestring): |
1273 | + elif isinstance(property, six.string_types): |
1274 | return self._resolve_string(property) |
1275 | elif isinstance(property, SuffixExpr): |
1276 | # XXX This covers cases like order_by=Desc("Bar.id"), see #620369. |
1277 | @@ -938,14 +944,14 @@ |
1278 | |
1279 | def _find_descriptor_class(used_cls, descr): |
1280 | for cls in used_cls.__mro__: |
1281 | - for attr, _descr in cls.__dict__.iteritems(): |
1282 | + for attr, _descr in cls.__dict__.items(): |
1283 | if _descr is descr: |
1284 | return cls |
1285 | raise RuntimeError("Reference used in an unknown class") |
1286 | |
1287 | def _find_descriptor_obj(used_cls, descr): |
1288 | for cls in used_cls.__mro__: |
1289 | - for attr, _descr in cls.__dict__.iteritems(): |
1290 | + for attr, _descr in cls.__dict__.items(): |
1291 | if _descr is descr: |
1292 | return getattr(cls, attr) |
1293 | raise RuntimeError("Reference used in an unknown class") |
1294 | |
1295 | === modified file 'storm/schema/patch.py' |
1296 | --- storm/schema/patch.py 2014-12-12 11:14:47 +0000 |
1297 | +++ storm/schema/patch.py 2017-06-09 20:57:05 +0000 |
1298 | @@ -34,6 +34,9 @@ |
1299 | 'patch' table in the given L{Store}, and it won't be applied again. |
1300 | """ |
1301 | |
1302 | +from future.utils import raise_ |
1303 | +from builtins import str |
1304 | +from builtins import object |
1305 | import sys |
1306 | import os |
1307 | import re |
1308 | @@ -118,10 +121,8 @@ |
1309 | except: |
1310 | type, value, traceback = sys.exc_info() |
1311 | patch_repr = getattr(module, "__file__", version) |
1312 | - raise BadPatchError, \ |
1313 | - "Patch %s failed: %s: %s" % \ |
1314 | - (patch_repr, type.__name__, str(value)), \ |
1315 | - traceback |
1316 | + msg = "Patch %s failed: %s: %s" % (patch_repr, type.__name__, str(value)) |
1317 | + raise_(BadPatchError, msg, traceback) |
1318 | self._committer.commit() |
1319 | |
1320 | def apply_all(self): |
1321 | @@ -244,7 +245,7 @@ |
1322 | patch_directory = self._get_patch_directory() |
1323 | filenames = os.listdir(patch_directory) |
1324 | matches = [(format.match(fn), fn) for fn in filenames] |
1325 | - matches = sorted(filter(lambda x: x[0], matches), |
1326 | + matches = sorted([x for x in matches if x[0]], |
1327 | key=lambda x: int(x[0].group(1))) |
1328 | return [int(match.group(1)) for match, filename in matches] |
1329 | |
1330 | |
1331 | === modified file 'storm/schema/schema.py' |
1332 | --- storm/schema/schema.py 2015-01-26 09:57:25 +0000 |
1333 | +++ storm/schema/schema.py 2017-06-09 20:57:05 +0000 |
1334 | @@ -42,7 +42,9 @@ |
1335 | where patch_module is a Python module containing database patches used to |
1336 | upgrade the schema over time. |
1337 | """ |
1338 | +from __future__ import print_function |
1339 | |
1340 | +from builtins import object |
1341 | import types |
1342 | |
1343 | from storm.locals import StormError |
1344 | @@ -96,7 +98,7 @@ |
1345 | try: |
1346 | store.execute(statement) |
1347 | except Exception: |
1348 | - print "Error running %s" % statement |
1349 | + print("Error running %s" % statement) |
1350 | raise |
1351 | if self._autocommit: |
1352 | store.commit() |
1353 | @@ -172,7 +174,7 @@ |
1354 | except SchemaMissingError: |
1355 | # No schema at all. Create it from the ground. |
1356 | self.create(store) |
1357 | - except UnappliedPatchesError, error: |
1358 | + except UnappliedPatchesError as error: |
1359 | patch_applier.check_unknown() |
1360 | for version in error.unapplied_versions: |
1361 | self.advance(store, version) |
1362 | |
1363 | === modified file 'storm/schema/sharding.py' |
1364 | --- storm/schema/sharding.py 2014-12-28 11:51:53 +0000 |
1365 | +++ storm/schema/sharding.py 2017-06-09 20:57:05 +0000 |
1366 | @@ -41,6 +41,7 @@ |
1367 | be at the same patch level. See L{storm.schema.patch.PatchSet}. |
1368 | """ |
1369 | |
1370 | +from builtins import object |
1371 | from storm.schema.schema import SchemaMissingError, UnappliedPatchesError |
1372 | |
1373 | |
1374 | @@ -101,7 +102,7 @@ |
1375 | schema.check(store) |
1376 | except SchemaMissingError: |
1377 | schema.create(store) |
1378 | - except UnappliedPatchesError, error: |
1379 | + except UnappliedPatchesError as error: |
1380 | if not unapplied_versions: |
1381 | unapplied_versions = error.unapplied_versions |
1382 | elif unapplied_versions != error.unapplied_versions: |
1383 | |
1384 | === modified file 'storm/sqlobject.py' |
1385 | --- storm/sqlobject.py 2011-10-17 15:59:25 +0000 |
1386 | +++ storm/sqlobject.py 2017-06-09 20:57:05 +0000 |
1387 | @@ -23,6 +23,8 @@ |
1388 | L{SQLObjectBase} is the central point of compatibility. |
1389 | """ |
1390 | |
1391 | +from builtins import object |
1392 | +import six |
1393 | import re |
1394 | import warnings |
1395 | |
1396 | @@ -40,6 +42,7 @@ |
1397 | compare_columns) |
1398 | from storm.tz import tzutc |
1399 | from storm import Undef |
1400 | +from future.utils import with_metaclass |
1401 | |
1402 | |
1403 | __all__ = [ |
1404 | @@ -162,7 +165,7 @@ |
1405 | dict["__storm_table__"] = table_name |
1406 | |
1407 | attr_to_prop = {} |
1408 | - for attr, prop in dict.items(): |
1409 | + for attr, prop in list(dict.items()): |
1410 | attr_to_prop[attr] = attr |
1411 | if isinstance(prop, ForeignKey): |
1412 | db_name = prop.kwargs.get("dbName", attr) |
1413 | @@ -185,7 +188,7 @@ |
1414 | if obj is None: |
1415 | raise SQLObjectNotFound |
1416 | return obj |
1417 | - func.func_name = method_name |
1418 | + func.__name__ = method_name |
1419 | dict[method_name] = classmethod(func) |
1420 | elif isinstance(prop, SQLMultipleJoin): |
1421 | # Generate addFoo/removeFoo names. |
1422 | @@ -205,7 +208,9 @@ |
1423 | |
1424 | |
1425 | id_type = dict.setdefault("_idType", int) |
1426 | - id_cls = {int: Int, str: RawStr, unicode: AutoUnicode}[id_type] |
1427 | + id_cls = {int: Int, |
1428 | + six.binary_type: RawStr, |
1429 | + six.text_type: AutoUnicode}[id_type] |
1430 | dict["id"] = id_cls(id_name, primary=True, default=AutoReload) |
1431 | attr_to_prop[id_name] = "id" |
1432 | |
1433 | @@ -222,7 +227,7 @@ |
1434 | property_registry.add_property(obj, getattr(obj, "id"), |
1435 | "<table %s>" % table_name) |
1436 | |
1437 | - for fake_name, real_name in attr_to_prop.items(): |
1438 | + for fake_name, real_name in list(attr_to_prop.items()): |
1439 | prop = getattr(obj, real_name) |
1440 | if fake_name != real_name: |
1441 | property_registry.add_property(obj, prop, fake_name) |
1442 | @@ -259,7 +264,7 @@ |
1443 | return getattr(self._cls, attr) |
1444 | |
1445 | |
1446 | -class SQLObjectBase(Storm): |
1447 | +class SQLObjectBase(with_metaclass(SQLObjectMeta, Storm)): |
1448 | """The root class of all SQLObject-emulating classes in your application. |
1449 | |
1450 | The general strategy for using Storm's SQLObject emulation layer |
1451 | @@ -269,7 +274,6 @@ |
1452 | even be implemented as returning a global L{Store} instance. Then |
1453 | all database classes should subclass that class. |
1454 | """ |
1455 | - __metaclass__ = SQLObjectMeta |
1456 | |
1457 | q = DotQ() |
1458 | _SO_creating = False |
1459 | @@ -296,7 +300,7 @@ |
1460 | self._init(None) |
1461 | |
1462 | def set(self, **kwargs): |
1463 | - for attr, value in kwargs.iteritems(): |
1464 | + for attr, value in kwargs.items(): |
1465 | setattr(self, attr, value) |
1466 | |
1467 | def destroySelf(self): |
1468 | @@ -329,7 +333,7 @@ |
1469 | if not isinstance(orderBy, (tuple, list)): |
1470 | orderBy = (orderBy,) |
1471 | for item in orderBy: |
1472 | - if isinstance(item, basestring): |
1473 | + if isinstance(item, six.string_types): |
1474 | desc = item.startswith("-") |
1475 | if desc: |
1476 | item = item[1:] |
1477 | @@ -404,7 +408,7 @@ |
1478 | |
1479 | def _copy(self, **kwargs): |
1480 | copy = self.__class__(self._cls, **kwargs) |
1481 | - for name, value in self.__dict__.iteritems(): |
1482 | + for name, value in self.__dict__.items(): |
1483 | if name[1:] not in kwargs and name != "_finished_result_set": |
1484 | setattr(copy, name, value) |
1485 | return copy |
1486 | @@ -416,7 +420,7 @@ |
1487 | if self._clause: |
1488 | args.append(self._clause) |
1489 | |
1490 | - for key, value in self._by.items(): |
1491 | + for key, value in list(self._by.items()): |
1492 | args.append(getattr(self._cls, key) == value) |
1493 | |
1494 | tables = [] |
1495 | @@ -548,7 +552,7 @@ |
1496 | result_set = self._without_prejoins()._result_set |
1497 | return item in result_set |
1498 | |
1499 | - def __nonzero__(self): |
1500 | + def __bool__(self): |
1501 | """Return C{True} if this result set contains any results. |
1502 | |
1503 | @note: This method is provided for compatibility with SQL Object. For |
1504 | @@ -603,7 +607,7 @@ |
1505 | return self._copy(prejoinClauseTables=prejoinClauseTables) |
1506 | |
1507 | def sum(self, attribute): |
1508 | - if isinstance(attribute, basestring): |
1509 | + if isinstance(attribute, six.string_types): |
1510 | attribute = SQL(attribute) |
1511 | result_set = self._without_prejoins()._result_set |
1512 | return result_set.sum(attribute) |
1513 | @@ -679,9 +683,9 @@ |
1514 | __slots__ = () |
1515 | |
1516 | def parse_set(self, value, from_db): |
1517 | - if not isinstance(value, basestring): |
1518 | + if not isinstance(value, six.string_types): |
1519 | raise TypeError("Expected basestring, found %s" % repr(type(value))) |
1520 | - return unicode(value) |
1521 | + return six.text_type(value) |
1522 | |
1523 | class AutoUnicode(SimpleProperty): |
1524 | variable_class = AutoUnicodeVariable |
1525 | |
1526 | === modified file 'storm/store.py' |
1527 | --- storm/store.py 2015-04-20 08:46:56 +0000 |
1528 | +++ storm/store.py 2017-06-09 20:57:05 +0000 |
1529 | @@ -24,6 +24,8 @@ |
1530 | This module contains the highest-level ORM interface in Storm. |
1531 | """ |
1532 | |
1533 | +from builtins import zip, object |
1534 | +import six |
1535 | from copy import copy |
1536 | from weakref import WeakValueDictionary |
1537 | from operator import itemgetter |
1538 | @@ -470,7 +472,7 @@ |
1539 | self._dirty = flushing |
1540 | |
1541 | predecessors = {} |
1542 | - for (before_info, after_info), n in self._order.iteritems(): |
1543 | + for (before_info, after_info), n in self._order.items(): |
1544 | if n > 0: |
1545 | before_set = predecessors.get(after_info) |
1546 | if before_set is None: |
1547 | @@ -849,7 +851,7 @@ |
1548 | del obj_info["primary_vars"] |
1549 | |
1550 | def _iter_alive(self): |
1551 | - return self._alive.values() |
1552 | + return list(self._alive.values()) |
1553 | |
1554 | def _enable_change_notification(self, obj_info): |
1555 | obj_info.event.emit("start-tracking-changes", self._event) |
1556 | @@ -1003,7 +1005,7 @@ |
1557 | L{ResultSet} will be returned appropriately modified with |
1558 | C{OFFSET} and C{LIMIT} clauses. |
1559 | """ |
1560 | - if isinstance(index, (int, long)): |
1561 | + if isinstance(index, six.integer_types): |
1562 | if index == 0: |
1563 | result_set = self |
1564 | else: |
1565 | @@ -1377,7 +1379,7 @@ |
1566 | "expression: %r" % repr(expr.expr2)) |
1567 | changes[expr.expr1] = expr.expr2 |
1568 | |
1569 | - for key, value in kwargs.items(): |
1570 | + for key, value in list(kwargs.items()): |
1571 | column = getattr(cls, key) |
1572 | if value is None: |
1573 | changes[column] = None |
1574 | @@ -1402,7 +1404,7 @@ |
1575 | for column in changes: |
1576 | obj_info.variables[column].set(AutoReload) |
1577 | else: |
1578 | - changes = changes.items() |
1579 | + changes = list(changes.items()) |
1580 | for obj in cached: |
1581 | for column, value in changes: |
1582 | variables = get_obj_info(obj).variables |
1583 | @@ -1791,7 +1793,7 @@ |
1584 | if cls is None: |
1585 | raise FeatureError("Can't determine class that keyword " |
1586 | "arguments are associated with") |
1587 | - for key, value in kwargs.items(): |
1588 | + for key, value in list(kwargs.items()): |
1589 | equals.append(getattr(cls, key) == value) |
1590 | if equals: |
1591 | return And(*equals) |
1592 | |
1593 | === modified file 'storm/tracer.py' |
1594 | --- storm/tracer.py 2012-06-28 13:08:48 +0000 |
1595 | +++ storm/tracer.py 2017-06-09 20:57:05 +0000 |
1596 | @@ -1,3 +1,5 @@ |
1597 | +from builtins import range, object |
1598 | +import six |
1599 | from datetime import datetime |
1600 | import re |
1601 | import sys |
1602 | @@ -169,7 +171,7 @@ |
1603 | # string parameters which represent encoded binary data. |
1604 | render_params = [] |
1605 | for param in query_params: |
1606 | - if isinstance(param, unicode): |
1607 | + if isinstance(param, six.text_type): |
1608 | render_params.append(repr(param.encode('utf8'))) |
1609 | else: |
1610 | render_params.append(repr(param)) |
1611 | |
1612 | === modified file 'storm/twisted/testing.py' |
1613 | --- storm/twisted/testing.py 2011-11-30 14:16:50 +0000 |
1614 | +++ storm/twisted/testing.py 2017-06-09 20:57:05 +0000 |
1615 | @@ -1,3 +1,4 @@ |
1616 | +from builtins import object |
1617 | import transaction |
1618 | |
1619 | from twisted.python.failure import Failure |
1620 | |
1621 | === modified file 'storm/twisted/transact.py' |
1622 | --- storm/twisted/transact.py 2011-12-07 10:39:57 +0000 |
1623 | +++ storm/twisted/transact.py 2017-06-09 20:57:05 +0000 |
1624 | @@ -1,3 +1,4 @@ |
1625 | +from builtins import object |
1626 | import time |
1627 | import random |
1628 | import transaction |
1629 | @@ -75,7 +76,7 @@ |
1630 | try: |
1631 | result = function(*args, **kwargs) |
1632 | self._transaction.commit() |
1633 | - except RETRIABLE_ERRORS, error: |
1634 | + except RETRIABLE_ERRORS as error: |
1635 | if isinstance(error, DisconnectionError): |
1636 | # If we got a disconnection, calling rollback may not be |
1637 | # enough because psycopg2 doesn't necessarily use the |
1638 | |
1639 | === modified file 'storm/tz.py' |
1640 | --- storm/tz.py 2007-08-07 18:36:04 +0000 |
1641 | +++ storm/tz.py 2017-06-09 20:57:05 +0000 |
1642 | @@ -7,6 +7,10 @@ |
1643 | __author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>" |
1644 | __license__ = "PSF License" |
1645 | |
1646 | +from builtins import range |
1647 | +from builtins import object |
1648 | +import six |
1649 | + |
1650 | import datetime |
1651 | import struct |
1652 | import time |
1653 | @@ -75,7 +79,7 @@ |
1654 | |
1655 | def __repr__(self): |
1656 | return "%s(%s, %s)" % (self.__class__.__name__, |
1657 | - `self._name`, |
1658 | + repr(self._name), |
1659 | self._offset.days*86400+self._offset.seconds) |
1660 | |
1661 | __reduce__ = object.__reduce__ |
1662 | @@ -161,7 +165,7 @@ |
1663 | for attr in self.__slots__: |
1664 | value = getattr(self, attr) |
1665 | if value is not None: |
1666 | - l.append("%s=%s" % (attr, `value`)) |
1667 | + l.append("%s=%s" % (attr, repr(value))) |
1668 | return "%s(%s)" % (self.__class__.__name__, ", ".join(l)) |
1669 | |
1670 | def __eq__(self, other): |
1671 | @@ -194,13 +198,13 @@ |
1672 | # ftp://elsie.nci.nih.gov/pub/tz*.tar.gz |
1673 | |
1674 | def __init__(self, fileobj): |
1675 | - if isinstance(fileobj, basestring): |
1676 | + if isinstance(fileobj, six.string_types): |
1677 | self._filename = fileobj |
1678 | fileobj = open(fileobj) |
1679 | elif hasattr(fileobj, "name"): |
1680 | self._filename = fileobj.name |
1681 | else: |
1682 | - self._filename = `fileobj` |
1683 | + self._filename = repr(fileobj) |
1684 | |
1685 | # From tzfile(5): |
1686 | # |
1687 | @@ -213,7 +217,7 @@ |
1688 | # of the value is written first). |
1689 | |
1690 | if fileobj.read(4) != "TZif": |
1691 | - raise ValueError, "magic not found" |
1692 | + raise ValueError("magic not found") |
1693 | |
1694 | fileobj.read(16) |
1695 | |
1696 | @@ -465,11 +469,11 @@ |
1697 | |
1698 | |
1699 | def __repr__(self): |
1700 | - return "%s(%s)" % (self.__class__.__name__, `self._filename`) |
1701 | + return "%s(%s)" % (self.__class__.__name__, repr(self._filename)) |
1702 | |
1703 | def __reduce__(self): |
1704 | if not os.path.isfile(self._filename): |
1705 | - raise ValueError, "Unpickable %s class" % self.__class__.__name__ |
1706 | + raise ValueError("Unpickable %s class" % self.__class__.__name__) |
1707 | return (self.__class__, (self._filename,)) |
1708 | |
1709 | class tzrange(datetime.tzinfo): |
1710 | @@ -561,7 +565,7 @@ |
1711 | |
1712 | res = parser._parsetz(s) |
1713 | if res is None: |
1714 | - raise ValueError, "unknown string format" |
1715 | + raise ValueError("unknown string format") |
1716 | |
1717 | # We must initialize it first, since _delta() needs |
1718 | # _std_offset and _dst_offset set. Use False in start/end |
1719 | @@ -615,9 +619,9 @@ |
1720 | return relativedelta.relativedelta(**kwargs) |
1721 | |
1722 | def __repr__(self): |
1723 | - return "%s(%s)" % (self.__class__.__name__, `self._s`) |
1724 | + return "%s(%s)" % (self.__class__.__name__, repr(self._s)) |
1725 | |
1726 | -class _tzicalvtzcomp: |
1727 | +class _tzicalvtzcomp(object): |
1728 | def __init__(self, tzoffsetfrom, tzoffsetto, isdst, |
1729 | tzname=None, rrule=None): |
1730 | self.tzoffsetfrom = datetime.timedelta(seconds=tzoffsetfrom) |
1731 | @@ -685,45 +689,45 @@ |
1732 | return self._find_comp(dt).tzname |
1733 | |
1734 | def __repr__(self): |
1735 | - return "<tzicalvtz %s>" % `self._tzid` |
1736 | + return "<tzicalvtz %s>" % repr(self._tzid) |
1737 | |
1738 | __reduce__ = object.__reduce__ |
1739 | |
1740 | -class tzical: |
1741 | +class tzical(object): |
1742 | def __init__(self, fileobj): |
1743 | global rrule |
1744 | if not rrule: |
1745 | from dateutil import rrule |
1746 | |
1747 | - if isinstance(fileobj, basestring): |
1748 | + if isinstance(fileobj, six.string_types): |
1749 | self._s = fileobj |
1750 | fileobj = open(fileobj) |
1751 | elif hasattr(fileobj, "name"): |
1752 | self._s = fileobj.name |
1753 | else: |
1754 | - self._s = `fileobj` |
1755 | + self._s = repr(fileobj) |
1756 | |
1757 | self._vtz = {} |
1758 | |
1759 | self._parse_rfc(fileobj.read()) |
1760 | |
1761 | def keys(self): |
1762 | - return self._vtz.keys() |
1763 | + return list(self._vtz.keys()) |
1764 | |
1765 | def get(self, tzid=None): |
1766 | if tzid is None: |
1767 | - keys = self._vtz.keys() |
1768 | + keys = list(self._vtz.keys()) |
1769 | if len(keys) == 0: |
1770 | - raise "no timezones defined" |
1771 | + raise Exception("no timezones defined") |
1772 | elif len(keys) > 1: |
1773 | - raise "more than one timezone available" |
1774 | + raise Exception("more than one timezone available") |
1775 | tzid = keys[0] |
1776 | return self._vtz.get(tzid) |
1777 | |
1778 | def _parse_offset(self, s): |
1779 | s = s.strip() |
1780 | if not s: |
1781 | - raise ValueError, "empty offset" |
1782 | + raise ValueError("empty offset") |
1783 | if s[0] in ('+', '-'): |
1784 | signal = (-1,+1)[s[0]=='+'] |
1785 | s = s[1:] |
1786 | @@ -734,12 +738,12 @@ |
1787 | elif len(s) == 6: |
1788 | return (int(s[:2])*3600+int(s[2:4])*60+int(s[4:]))*signal |
1789 | else: |
1790 | - raise ValueError, "invalid offset: "+s |
1791 | + raise ValueError("invalid offset: "+s) |
1792 | |
1793 | def _parse_rfc(self, s): |
1794 | lines = s.splitlines() |
1795 | if not lines: |
1796 | - raise ValueError, "empty string" |
1797 | + raise ValueError("empty string") |
1798 | |
1799 | # Unfold |
1800 | i = 0 |
1801 | @@ -763,7 +767,7 @@ |
1802 | name, value = line.split(':', 1) |
1803 | parms = name.split(';') |
1804 | if not parms: |
1805 | - raise ValueError, "empty property name" |
1806 | + raise ValueError("empty property name") |
1807 | name = parms[0].upper() |
1808 | parms = parms[1:] |
1809 | if invtz: |
1810 | @@ -772,7 +776,7 @@ |
1811 | # Process component |
1812 | pass |
1813 | else: |
1814 | - raise ValueError, "unknown component: "+value |
1815 | + raise ValueError("unknown component: "+value) |
1816 | comptype = value |
1817 | founddtstart = False |
1818 | tzoffsetfrom = None |
1819 | @@ -782,27 +786,21 @@ |
1820 | elif name == "END": |
1821 | if value == "VTIMEZONE": |
1822 | if comptype: |
1823 | - raise ValueError, \ |
1824 | - "component not closed: "+comptype |
1825 | + raise ValueError("component not closed: "+comptype) |
1826 | if not tzid: |
1827 | - raise ValueError, \ |
1828 | - "mandatory TZID not found" |
1829 | + raise ValueError("mandatory TZID not found") |
1830 | if not comps: |
1831 | - raise ValueError, \ |
1832 | - "at least one component is needed" |
1833 | + raise ValueError("at least one component is needed") |
1834 | # Process vtimezone |
1835 | self._vtz[tzid] = _tzicalvtz(tzid, comps) |
1836 | invtz = False |
1837 | elif value == comptype: |
1838 | if not founddtstart: |
1839 | - raise ValueError, \ |
1840 | - "mandatory DTSTART not found" |
1841 | + raise ValueError("mandatory DTSTART not found") |
1842 | if tzoffsetfrom is None: |
1843 | - raise ValueError, \ |
1844 | - "mandatory TZOFFSETFROM not found" |
1845 | + raise ValueError("mandatory TZOFFSETFROM not found") |
1846 | if tzoffsetto is None: |
1847 | - raise ValueError, \ |
1848 | - "mandatory TZOFFSETFROM not found" |
1849 | + raise ValueError("mandatory TZOFFSETFROM not found") |
1850 | # Process component |
1851 | rr = None |
1852 | if rrulelines: |
1853 | @@ -816,8 +814,7 @@ |
1854 | comps.append(comp) |
1855 | comptype = None |
1856 | else: |
1857 | - raise ValueError, \ |
1858 | - "invalid component end: "+value |
1859 | + raise ValueError("invalid component end: "+value) |
1860 | elif comptype: |
1861 | if name == "DTSTART": |
1862 | rrulelines.append(line) |
1863 | @@ -826,40 +823,36 @@ |
1864 | rrulelines.append(line) |
1865 | elif name == "TZOFFSETFROM": |
1866 | if parms: |
1867 | - raise ValueError, \ |
1868 | - "unsupported %s parm: %s "%(name, parms[0]) |
1869 | + raise ValueError("unsupported %s parm: %s "%(name, parms[0])) |
1870 | tzoffsetfrom = self._parse_offset(value) |
1871 | elif name == "TZOFFSETTO": |
1872 | if parms: |
1873 | - raise ValueError, \ |
1874 | - "unsupported TZOFFSETTO parm: "+parms[0] |
1875 | + raise ValueError("unsupported TZOFFSETTO parm: "+parms[0]) |
1876 | tzoffsetto = self._parse_offset(value) |
1877 | elif name == "TZNAME": |
1878 | if parms: |
1879 | - raise ValueError, \ |
1880 | - "unsupported TZNAME parm: "+parms[0] |
1881 | + raise ValueError("unsupported TZNAME parm: "+parms[0]) |
1882 | tzname = value |
1883 | elif name == "COMMENT": |
1884 | pass |
1885 | else: |
1886 | - raise ValueError, "unsupported property: "+name |
1887 | + raise ValueError("unsupported property: "+name) |
1888 | else: |
1889 | if name == "TZID": |
1890 | if parms: |
1891 | - raise ValueError, \ |
1892 | - "unsupported TZID parm: "+parms[0] |
1893 | + raise ValueError("unsupported TZID parm: "+parms[0]) |
1894 | tzid = value |
1895 | elif name in ("TZURL", "LAST-MODIFIED", "COMMENT"): |
1896 | pass |
1897 | else: |
1898 | - raise ValueError, "unsupported property: "+name |
1899 | + raise ValueError("unsupported property: "+name) |
1900 | elif name == "BEGIN" and value == "VTIMEZONE": |
1901 | tzid = None |
1902 | comps = [] |
1903 | invtz = True |
1904 | |
1905 | def __repr__(self): |
1906 | - return "%s(%s)" % (self.__class__.__name__, `self._s`) |
1907 | + return "%s(%s)" % (self.__class__.__name__, repr(self._s)) |
1908 | |
1909 | if sys.platform != "win32": |
1910 | TZFILES = ["/etc/localtime", "localtime"] |
1911 | |
1912 | === modified file 'storm/uri.py' |
1913 | --- storm/uri.py 2008-01-30 13:03:27 +0000 |
1914 | +++ storm/uri.py 2017-06-09 20:57:05 +0000 |
1915 | @@ -18,7 +18,12 @@ |
1916 | # You should have received a copy of the GNU Lesser General Public License |
1917 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1918 | # |
1919 | -from urllib import quote |
1920 | +from future import standard_library |
1921 | +standard_library.install_aliases() |
1922 | +from builtins import chr |
1923 | +from builtins import str |
1924 | +from builtins import object |
1925 | +from urllib.parse import quote |
1926 | |
1927 | from storm.exceptions import URIError |
1928 | |
1929 | @@ -102,7 +107,7 @@ |
1930 | append(escape(self.database, "/")) |
1931 | if self.options: |
1932 | options = ["%s=%s" % (escape(key), escape(value)) |
1933 | - for key, value in sorted(self.options.iteritems())] |
1934 | + for key, value in sorted(self.options.items())] |
1935 | append("?") |
1936 | append("&".join(options)) |
1937 | return "".join(tokens) |
1938 | |
1939 | === modified file 'storm/variables.py' |
1940 | --- storm/variables.py 2011-09-13 10:13:46 +0000 |
1941 | +++ storm/variables.py 2017-06-09 20:57:05 +0000 |
1942 | @@ -1,3 +1,4 @@ |
1943 | +from __future__ import unicode_literals |
1944 | # |
1945 | # Copyright (c) 2006, 2007 Canonical |
1946 | # |
1947 | @@ -18,9 +19,13 @@ |
1948 | # You should have received a copy of the GNU Lesser General Public License |
1949 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1950 | # |
1951 | +from future import standard_library |
1952 | +standard_library.install_aliases() |
1953 | +from builtins import object |
1954 | +import six |
1955 | from datetime import datetime, date, time, timedelta |
1956 | from decimal import Decimal |
1957 | -import cPickle as pickle |
1958 | +import pickle as pickle |
1959 | import re |
1960 | try: |
1961 | import uuid |
1962 | @@ -31,6 +36,7 @@ |
1963 | from storm.exceptions import NoneError |
1964 | from storm import Undef, has_cextensions |
1965 | |
1966 | +buffer = buffer if six.PY2 else memoryview |
1967 | |
1968 | __all__ = [ |
1969 | "VariableFactory", |
1970 | @@ -329,7 +335,7 @@ |
1971 | __slots__ = () |
1972 | |
1973 | def parse_set(self, value, from_db): |
1974 | - if not isinstance(value, (int, long, float, Decimal)): |
1975 | + if not isinstance(value, six.integer_types + (float, Decimal)): |
1976 | raise TypeError("Expected bool, found %r: %r" |
1977 | % (type(value), value)) |
1978 | return bool(value) |
1979 | @@ -339,7 +345,7 @@ |
1980 | __slots__ = () |
1981 | |
1982 | def parse_set(self, value, from_db): |
1983 | - if not isinstance(value, (int, long, float, Decimal)): |
1984 | + if not isinstance(value, six.integer_types + (float, Decimal)): |
1985 | raise TypeError("Expected int, found %r: %r" |
1986 | % (type(value), value)) |
1987 | return int(value) |
1988 | @@ -349,7 +355,7 @@ |
1989 | __slots__ = () |
1990 | |
1991 | def parse_set(self, value, from_db): |
1992 | - if not isinstance(value, (int, long, float, Decimal)): |
1993 | + if not isinstance(value, six.integer_types + (float, Decimal)): |
1994 | raise TypeError("Expected float, found %r: %r" |
1995 | % (type(value), value)) |
1996 | return float(value) |
1997 | @@ -360,8 +366,8 @@ |
1998 | |
1999 | @staticmethod |
2000 | def parse_set(value, from_db): |
2001 | - if (from_db and isinstance(value, basestring) or |
2002 | - isinstance(value, (int, long))): |
2003 | + if (from_db and isinstance(value, six.string_types) or |
2004 | + isinstance(value, six.integer_types)): |
2005 | value = Decimal(value) |
2006 | elif not isinstance(value, Decimal): |
2007 | raise TypeError("Expected Decimal, found %r: %r" |
2008 | @@ -371,7 +377,7 @@ |
2009 | @staticmethod |
2010 | def parse_get(value, to_db): |
2011 | if to_db: |
2012 | - return unicode(value) |
2013 | + return six.text_type(value) |
2014 | return value |
2015 | |
2016 | |
2017 | @@ -380,9 +386,9 @@ |
2018 | |
2019 | def parse_set(self, value, from_db): |
2020 | if isinstance(value, buffer): |
2021 | - value = str(value) |
2022 | - elif not isinstance(value, str): |
2023 | - raise TypeError("Expected str, found %r: %r" |
2024 | + value = six.binary_type(value) |
2025 | + elif not isinstance(value, six.binary_type): |
2026 | + raise TypeError("Expected bytes, found %r: %r" |
2027 | % (type(value), value)) |
2028 | return value |
2029 | |
2030 | @@ -391,7 +397,7 @@ |
2031 | __slots__ = () |
2032 | |
2033 | def parse_set(self, value, from_db): |
2034 | - if not isinstance(value, unicode): |
2035 | + if not isinstance(value, six.text_type): |
2036 | raise TypeError("Expected unicode, found %r: %r" |
2037 | % (type(value), value)) |
2038 | return value |
2039 | @@ -408,7 +414,7 @@ |
2040 | if from_db: |
2041 | if isinstance(value, datetime): |
2042 | pass |
2043 | - elif isinstance(value, (str, unicode)): |
2044 | + elif isinstance(value, six.string_types): |
2045 | if " " not in value: |
2046 | raise ValueError("Unknown date/time format: %r" % value) |
2047 | date_str, time_str = value.split(" ") |
2048 | @@ -422,7 +428,7 @@ |
2049 | else: |
2050 | value = value.astimezone(self._tzinfo) |
2051 | else: |
2052 | - if type(value) in (int, long, float): |
2053 | + if type(value) in six.integer_types + (float, ): |
2054 | value = datetime.utcfromtimestamp(value) |
2055 | elif not isinstance(value, datetime): |
2056 | raise TypeError("Expected datetime, found %s" % repr(value)) |
2057 | @@ -442,7 +448,7 @@ |
2058 | return value.date() |
2059 | if isinstance(value, date): |
2060 | return value |
2061 | - if not isinstance(value, (str, unicode)): |
2062 | + if not isinstance(value, six.string_types): |
2063 | raise TypeError("Expected date, found %s" % repr(value)) |
2064 | if " " in value: |
2065 | value, time_str = value.split(" ") |
2066 | @@ -465,7 +471,7 @@ |
2067 | return None |
2068 | if isinstance(value, time): |
2069 | return value |
2070 | - if not isinstance(value, (str, unicode)): |
2071 | + if not isinstance(value, six.string_types): |
2072 | raise TypeError("Expected time, found %s" % repr(value)) |
2073 | if " " in value: |
2074 | date_str, value = value.split(" ") |
2075 | @@ -488,7 +494,7 @@ |
2076 | return None |
2077 | if isinstance(value, timedelta): |
2078 | return value |
2079 | - if not isinstance(value, (str, unicode)): |
2080 | + if not isinstance(value, six.string_types): |
2081 | raise TypeError("Expected timedelta, found %s" % repr(value)) |
2082 | return _parse_interval(value) |
2083 | else: |
2084 | @@ -502,7 +508,7 @@ |
2085 | |
2086 | def parse_set(self, value, from_db): |
2087 | assert uuid is not None, "The uuid module was not found." |
2088 | - if from_db and isinstance(value, basestring): |
2089 | + if from_db and isinstance(value, six.string_types): |
2090 | value = uuid.UUID(value) |
2091 | elif not isinstance(value, uuid.UUID): |
2092 | raise TypeError("Expected UUID, found %r: %r" |
2093 | @@ -511,7 +517,7 @@ |
2094 | |
2095 | def parse_get(self, value, to_db): |
2096 | if to_db: |
2097 | - return unicode(value) |
2098 | + return six.text_type(value) |
2099 | return value |
2100 | |
2101 | |
2102 | @@ -595,7 +601,7 @@ |
2103 | def parse_set(self, value, from_db): |
2104 | if from_db: |
2105 | if isinstance(value, buffer): |
2106 | - value = str(value) |
2107 | + value = six.binary_type(value) |
2108 | return self._loads(value) |
2109 | else: |
2110 | return value |
2111 | @@ -633,7 +639,7 @@ |
2112 | super(JSONVariable, self).__init__(*args, **kwargs) |
2113 | |
2114 | def _loads(self, value): |
2115 | - if not isinstance(value, unicode): |
2116 | + if not isinstance(value, six.text_type): |
2117 | raise TypeError( |
2118 | "Cannot safely assume encoding of byte string %r." % value) |
2119 | return json.loads(value) |
2120 | @@ -643,7 +649,7 @@ |
2121 | # and so we treat it as such here. In other words, this method returns |
2122 | # unicode and never str. |
2123 | dump = json.dumps(value, ensure_ascii=False) |
2124 | - if not isinstance(dump, unicode): |
2125 | + if not isinstance(dump, six.text_type): |
2126 | # json.dumps() does not always return unicode. See |
2127 | # http://code.google.com/p/simplejson/issues/detail?id=40 for one |
2128 | # of many discussions of str/unicode handling in simplejson. |
2129 | |
2130 | === modified file 'storm/xid.py' |
2131 | --- storm/xid.py 2012-03-01 13:28:26 +0000 |
2132 | +++ storm/xid.py 2017-06-09 20:57:05 +0000 |
2133 | @@ -20,6 +20,7 @@ |
2134 | # |
2135 | |
2136 | |
2137 | +from builtins import object |
2138 | class Xid(object): |
2139 | """ |
2140 | Represent a transaction identifier compliant with the XA specification. |
2141 | |
2142 | === modified file 'storm/zope/schema.py' |
2143 | --- storm/zope/schema.py 2010-08-17 14:00:59 +0000 |
2144 | +++ storm/zope/schema.py 2017-06-09 20:57:05 +0000 |
2145 | @@ -19,6 +19,7 @@ |
2146 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2147 | # |
2148 | """ZStorm-aware schema manager.""" |
2149 | +from builtins import object |
2150 | import transaction |
2151 | |
2152 | from storm.schema import Schema |
2153 | |
2154 | === modified file 'storm/zope/testing.py' |
2155 | --- storm/zope/testing.py 2014-12-18 11:37:22 +0000 |
2156 | +++ storm/zope/testing.py 2017-06-09 20:57:05 +0000 |
2157 | @@ -98,7 +98,7 @@ |
2158 | # compatibility. This should be eventually dropped. |
2159 | if isinstance(databases, dict): |
2160 | databases = [{"name": name, "uri": uri, "schema": schema} |
2161 | - for name, (uri, schema) in databases.iteritems()] |
2162 | + for name, (uri, schema) in databases.items()] |
2163 | |
2164 | # Provide the global IZStorm utility before applying patches, so |
2165 | # patch code can get the ztorm object if needed (e.g. looking up |
2166 | |
2167 | === modified file 'storm/zope/zstorm.py' |
2168 | --- storm/zope/zstorm.py 2012-03-28 10:57:43 +0000 |
2169 | +++ storm/zope/zstorm.py 2017-06-09 20:57:05 +0000 |
2170 | @@ -24,6 +24,8 @@ |
2171 | # You should have received a copy of the GNU Lesser General Public License |
2172 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2173 | # |
2174 | +from builtins import str |
2175 | +from builtins import object |
2176 | import threading |
2177 | import weakref |
2178 | |
2179 | @@ -209,7 +211,7 @@ |
2180 | # avoid the problem where a store is deallocated during |
2181 | # iteration causing RuntimeError: dictionary changed size |
2182 | # during iteration. |
2183 | - for store, name in self._name_index.items(): |
2184 | + for store, name in list(self._name_index.items()): |
2185 | yield name, store |
2186 | |
2187 | def get_name(self, store): |
2188 | |
2189 | === modified file 'tests/cache.py' |
2190 | --- tests/cache.py 2011-07-14 11:15:30 +0000 |
2191 | +++ tests/cache.py 2017-06-09 20:57:05 +0000 |
2192 | @@ -1,3 +1,6 @@ |
2193 | +from builtins import str |
2194 | +from builtins import range |
2195 | +from builtins import object |
2196 | from unittest import defaultTestLoader |
2197 | |
2198 | from storm.properties import Int |
2199 | @@ -134,7 +137,7 @@ |
2200 | """ |
2201 | size = 10 |
2202 | cache = self.Cache(size) |
2203 | - for value in xrange(size): |
2204 | + for value in range(size): |
2205 | cache.add(StubObjectInfo(value)) |
2206 | self.assertEqual(len(cache.get_cached()), size) |
2207 | |
2208 | @@ -255,7 +258,7 @@ |
2209 | """ |
2210 | size = 10 |
2211 | cache = GenerationalCache(size) |
2212 | - for value in xrange(5 * size): |
2213 | + for value in range(5 * size): |
2214 | cache.add(StubObjectInfo(value)) |
2215 | self.assertEquals(len(cache.get_cached()), size * 2) |
2216 | |
2217 | @@ -298,7 +301,7 @@ |
2218 | size = 10 |
2219 | cache = GenerationalCache(size * 100) |
2220 | cache.set_size(size) |
2221 | - for value in xrange(size * 10): |
2222 | + for value in range(size * 10): |
2223 | cache.add(StubObjectInfo(value)) |
2224 | self.assertEquals(len(cache.get_cached()), size * 2) |
2225 | |
2226 | |
2227 | === modified file 'tests/database.py' |
2228 | --- tests/database.py 2013-02-15 17:00:18 +0000 |
2229 | +++ tests/database.py 2017-06-09 20:57:05 +0000 |
2230 | @@ -18,6 +18,9 @@ |
2231 | # You should have received a copy of the GNU Lesser General Public License |
2232 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2233 | # |
2234 | +from builtins import str |
2235 | +from builtins import range |
2236 | +from builtins import object |
2237 | import sys |
2238 | import new |
2239 | import gc |
2240 | |
2241 | === modified file 'tests/databases/base.py' |
2242 | --- tests/databases/base.py 2015-06-15 12:06:44 +0000 |
2243 | +++ tests/databases/base.py 2017-06-09 20:57:05 +0000 |
2244 | @@ -20,8 +20,12 @@ |
2245 | # You should have received a copy of the GNU Lesser General Public License |
2246 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2247 | # |
2248 | +from future import standard_library |
2249 | +standard_library.install_aliases() |
2250 | +from builtins import next, str, object |
2251 | +import six |
2252 | from datetime import datetime, date, time, timedelta |
2253 | -import cPickle as pickle |
2254 | +import pickle as pickle |
2255 | import shutil |
2256 | import sys |
2257 | import os |
2258 | @@ -149,7 +153,7 @@ |
2259 | self.assertTrue(isinstance(result, Result)) |
2260 | row = result.get_one() |
2261 | self.assertEquals(row, ("Title 10",)) |
2262 | - self.assertTrue(isinstance(row[0], unicode)) |
2263 | + self.assertTrue(isinstance(row[0], six.text_type)) |
2264 | |
2265 | def test_execute_params(self): |
2266 | result = self.connection.execute("SELECT one FROM number " |
2267 | @@ -192,12 +196,12 @@ |
2268 | "ORDER BY id DESC") |
2269 | iter1 = iter(result1) |
2270 | iter2 = iter(result2) |
2271 | - self.assertEquals(iter1.next(), (10, "Title 10")) |
2272 | - self.assertEquals(iter2.next(), (20, "Title 20")) |
2273 | - self.assertEquals(iter1.next(), (20, "Title 20")) |
2274 | - self.assertEquals(iter2.next(), (10, "Title 10")) |
2275 | - self.assertRaises(StopIteration, iter1.next) |
2276 | - self.assertRaises(StopIteration, iter2.next) |
2277 | + self.assertEquals(next(iter1), (10, "Title 10")) |
2278 | + self.assertEquals(next(iter2), (20, "Title 20")) |
2279 | + self.assertEquals(next(iter1), (20, "Title 20")) |
2280 | + self.assertEquals(next(iter2), (10, "Title 10")) |
2281 | + self.assertRaises(StopIteration, next, iter1) |
2282 | + self.assertRaises(StopIteration, next, iter2) |
2283 | |
2284 | def test_get_insert_identity(self): |
2285 | result = self.connection.execute("INSERT INTO test (title) " |
2286 | @@ -346,7 +350,7 @@ |
2287 | connection2.execute("UPDATE test SET title='Title 100' " |
2288 | "WHERE id=10") |
2289 | connection2.commit() |
2290 | - except OperationalError, e: |
2291 | + except OperationalError as e: |
2292 | self.assertEquals(str(e), "database is locked") # SQLite blocks |
2293 | result = connection1.execute("SELECT title FROM test WHERE id=10") |
2294 | self.assertEquals(result.get_one(), ("Title 10",)) |
2295 | @@ -385,7 +389,7 @@ |
2296 | def test_wb_result_iter_goes_through_from_database(self): |
2297 | result = self.connection.execute("SELECT one, two FROM number") |
2298 | result.from_database = self.from_database |
2299 | - self.assertEquals(iter(result).next(), (2, 3)) |
2300 | + self.assertEquals(next(iter(result)), (2, 3)) |
2301 | |
2302 | def test_rowcount_insert(self): |
2303 | # All supported backends support rowcount, so far. |
2304 | @@ -772,7 +776,7 @@ |
2305 | cursor = self.connection._raw_connection.cursor() |
2306 | cursor.execute("SELECT 1") |
2307 | cursor.fetchone() |
2308 | - except Error, exc: |
2309 | + except Error as exc: |
2310 | self.assertTrue(self.connection.is_disconnection_error(exc)) |
2311 | else: |
2312 | self.fail("Disconnection was not caught.") |
2313 | @@ -781,7 +785,7 @@ |
2314 | # error when called. |
2315 | try: |
2316 | self.connection._raw_connection.rollback() |
2317 | - except Error, exc: |
2318 | + except Error as exc: |
2319 | self.assertTrue(self.connection.is_disconnection_error(exc)) |
2320 | else: |
2321 | self.fail("Disconnection was not raised.") |
2322 | @@ -805,7 +809,7 @@ |
2323 | cursor = self.connection._raw_connection.cursor() |
2324 | cursor.execute("SELECT 1") |
2325 | cursor.fetchone() |
2326 | - except DatabaseError, exc: |
2327 | + except DatabaseError as exc: |
2328 | self.assertTrue(self.connection.is_disconnection_error(exc)) |
2329 | else: |
2330 | self.fail("Disconnection was not caught.") |
2331 | |
2332 | === modified file 'tests/databases/postgres.py' |
2333 | --- tests/databases/postgres.py 2016-04-29 08:38:51 +0000 |
2334 | +++ tests/databases/postgres.py 2017-06-09 20:57:05 +0000 |
2335 | @@ -18,6 +18,8 @@ |
2336 | # You should have received a copy of the GNU Lesser General Public License |
2337 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2338 | # |
2339 | +from builtins import object |
2340 | +import six |
2341 | from datetime import date, time, timedelta |
2342 | import os |
2343 | import json |
2344 | @@ -154,7 +156,7 @@ |
2345 | result = connection.execute("SELECT title FROM test WHERE id=1") |
2346 | title = result.get_one()[0] |
2347 | |
2348 | - self.assertTrue(isinstance(title, unicode)) |
2349 | + self.assertTrue(isinstance(title, six.text_type)) |
2350 | self.assertEquals(title, uni_str) |
2351 | |
2352 | def test_unicode_array(self): |
2353 | @@ -735,13 +737,13 @@ |
2354 | InterfaceErrors are a form of a disconnection error, so rollback() |
2355 | must swallow them and reconnect. |
2356 | """ |
2357 | - class FakeConnection: |
2358 | + class FakeConnection(object): |
2359 | def rollback(self): |
2360 | raise InterfaceError('connection already closed') |
2361 | self.connection._raw_connection = FakeConnection() |
2362 | try: |
2363 | self.connection.rollback() |
2364 | - except Exception, exc: |
2365 | + except Exception as exc: |
2366 | self.fail('Exception should have been swallowed: %s' % repr(exc)) |
2367 | |
2368 | |
2369 | @@ -875,7 +877,7 @@ |
2370 | self.remaining_time = 0.001 |
2371 | try: |
2372 | self.connection.execute(statement) |
2373 | - except TimeoutError, e: |
2374 | + except TimeoutError as e: |
2375 | self.assertEqual("SQL server cancelled statement", e.message) |
2376 | self.assertEqual(statement, e.statement) |
2377 | self.assertEqual((), e.params) |
2378 | |
2379 | === modified file 'tests/databases/proxy.py' |
2380 | --- tests/databases/proxy.py 2007-10-24 06:27:06 +0000 |
2381 | +++ tests/databases/proxy.py 2017-06-09 20:57:05 +0000 |
2382 | @@ -20,22 +20,24 @@ |
2383 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2384 | # |
2385 | |
2386 | +from future import standard_library |
2387 | +standard_library.install_aliases() |
2388 | import os |
2389 | import select |
2390 | import socket |
2391 | -import SocketServer |
2392 | +import socketserver |
2393 | import threading |
2394 | |
2395 | |
2396 | TIMEOUT = 0.1 |
2397 | |
2398 | |
2399 | -class ProxyRequestHandler(SocketServer.BaseRequestHandler): |
2400 | +class ProxyRequestHandler(socketserver.BaseRequestHandler): |
2401 | """A request handler that proxies traffic to another TCP port.""" |
2402 | |
2403 | def __init__(self, request, client_address, server): |
2404 | self._generation = server._generation |
2405 | - SocketServer.BaseRequestHandler.__init__( |
2406 | + socketserver.BaseRequestHandler.__init__( |
2407 | self, request, client_address, server) |
2408 | |
2409 | def handle(self): |
2410 | @@ -66,12 +68,12 @@ |
2411 | self.request.shutdown(socket.SHUT_WR) |
2412 | |
2413 | |
2414 | -class ProxyTCPServer(SocketServer.ThreadingTCPServer): |
2415 | +class ProxyTCPServer(socketserver.ThreadingTCPServer): |
2416 | |
2417 | allow_reuse_address = True |
2418 | |
2419 | def __init__(self, proxy_dest): |
2420 | - SocketServer.ThreadingTCPServer.__init__( |
2421 | + socketserver.ThreadingTCPServer.__init__( |
2422 | self, ("127.0.0.1", 0), ProxyRequestHandler) |
2423 | # Python 2.4 doesn't retrieve the socket details, so record |
2424 | # them here. We need to do this so we can recreate the socket |
2425 | |
2426 | === modified file 'tests/databases/sqlite.py' |
2427 | --- tests/databases/sqlite.py 2013-05-05 10:36:13 +0000 |
2428 | +++ tests/databases/sqlite.py 2017-06-09 20:57:05 +0000 |
2429 | @@ -18,6 +18,7 @@ |
2430 | # You should have received a copy of the GNU Lesser General Public License |
2431 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2432 | # |
2433 | +from builtins import str |
2434 | from datetime import timedelta |
2435 | import time |
2436 | import os |
2437 | @@ -114,7 +115,7 @@ |
2438 | started = time.time() |
2439 | try: |
2440 | connection2.execute("INSERT INTO test VALUES (2)") |
2441 | - except OperationalError, exception: |
2442 | + except OperationalError as exception: |
2443 | self.assertEquals(str(exception), "database is locked") |
2444 | self.assertTrue(time.time()-started >= 0.3) |
2445 | else: |
2446 | @@ -141,7 +142,7 @@ |
2447 | started = time.time() |
2448 | try: |
2449 | connection1.commit() |
2450 | - except OperationalError, exception: |
2451 | + except OperationalError as exception: |
2452 | self.assertEquals(str(exception), "database is locked") |
2453 | # In 0.10, the next assertion failed because the timeout wasn't |
2454 | # enforced for the "COMMIT" statement. |
2455 | |
2456 | === modified file 'tests/event.py' |
2457 | --- tests/event.py 2008-06-18 15:27:03 +0000 |
2458 | +++ tests/event.py 2017-06-09 20:57:05 +0000 |
2459 | @@ -18,6 +18,7 @@ |
2460 | # You should have received a copy of the GNU Lesser General Public License |
2461 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2462 | # |
2463 | +from builtins import object |
2464 | from storm.event import EventSystem |
2465 | |
2466 | from tests.helper import TestHelper |
2467 | |
2468 | === modified file 'tests/expr.py' |
2469 | --- tests/expr.py 2012-03-26 14:27:29 +0000 |
2470 | +++ tests/expr.py 2017-06-09 20:57:05 +0000 |
2471 | @@ -1,3 +1,4 @@ |
2472 | +from __future__ import division |
2473 | # |
2474 | # Copyright (c) 2006, 2007 Canonical |
2475 | # |
2476 | @@ -18,6 +19,8 @@ |
2477 | # You should have received a copy of the GNU Lesser General Public License |
2478 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2479 | # |
2480 | +from builtins import range |
2481 | +from builtins import object |
2482 | from decimal import Decimal |
2483 | |
2484 | from tests.helper import TestHelper |
2485 | @@ -35,9 +38,9 @@ |
2486 | # Create columnN, tableN, and elemN variables. |
2487 | for i in range(10): |
2488 | for name in ["column", "elem"]: |
2489 | - exec "%s%d = SQLToken('%s%d')" % (name, i, name, i) |
2490 | + exec("%s%d = SQLToken('%s%d')" % (name, i, name, i)) |
2491 | for name in ["table"]: |
2492 | - exec "%s%d = '%s %d'" % (name, i, name, i) |
2493 | + exec("%s%d = '%s %d'" % (name, i, name, i)) |
2494 | |
2495 | |
2496 | class TrackContext(FromExpr): |
2497 | @@ -495,7 +498,7 @@ |
2498 | |
2499 | def test_precedence(self): |
2500 | for i in range(10): |
2501 | - exec "e%d = SQLRaw('%d')" % (i, i) |
2502 | + exec("e%d = SQLRaw('%d')" % (i, i)) |
2503 | expr = And(e1, Or(e2, e3), |
2504 | Add(e4, Mul(e5, Sub(e6, Div(e7, Div(e8, e9)))))) |
2505 | statement = compile(expr) |
2506 | @@ -586,7 +589,7 @@ |
2507 | |
2508 | def test_long(self): |
2509 | state = State() |
2510 | - statement = compile(1L, state) |
2511 | + statement = compile(1, state) |
2512 | self.assertEquals(statement, "?") |
2513 | self.assertVariablesEqual(state.parameters, [IntVariable(1)]) |
2514 | |
2515 | @@ -1360,7 +1363,7 @@ |
2516 | self.assertEquals(statement, "elem1/elem2/elem3") |
2517 | self.assertEquals(state.parameters, []) |
2518 | |
2519 | - expr = Func1() / "value" |
2520 | + expr = Func1() // "value" |
2521 | state = State() |
2522 | statement = compile(expr, state) |
2523 | self.assertEquals(statement, "func1()/?") |
2524 | @@ -2130,7 +2133,7 @@ |
2525 | |
2526 | def test_precedence(self): |
2527 | for i in range(10): |
2528 | - exec "e%d = SQLRaw('%d')" % (i, i) |
2529 | + exec("e%d = SQLRaw('%d')" % (i, i)) |
2530 | expr = And(e1, Or(e2, e3), |
2531 | Add(e4, Mul(e5, Sub(e6, Div(e7, Div(e8, e9)))))) |
2532 | py_expr = compile_python(expr) |
2533 | @@ -2172,7 +2175,7 @@ |
2534 | self.assertEquals(py_expr, "1") |
2535 | |
2536 | def test_long(self): |
2537 | - py_expr = compile_python(1L) |
2538 | + py_expr = compile_python(1) |
2539 | self.assertEquals(py_expr, "1L") |
2540 | |
2541 | def test_bool(self): |
2542 | |
2543 | === modified file 'tests/helper.py' |
2544 | --- tests/helper.py 2012-04-04 23:42:51 +0000 |
2545 | +++ tests/helper.py 2017-06-09 20:57:05 +0000 |
2546 | @@ -18,7 +18,11 @@ |
2547 | # You should have received a copy of the GNU Lesser General Public License |
2548 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2549 | # |
2550 | -from cStringIO import StringIO |
2551 | +from future import standard_library |
2552 | +standard_library.install_aliases() |
2553 | +from builtins import zip |
2554 | +from builtins import object |
2555 | +from io import StringIO |
2556 | import tempfile |
2557 | import logging |
2558 | import shutil |
2559 | |
2560 | === modified file 'tests/info.py' |
2561 | --- tests/info.py 2011-12-07 11:57:07 +0000 |
2562 | +++ tests/info.py 2017-06-09 20:57:05 +0000 |
2563 | @@ -18,6 +18,8 @@ |
2564 | # You should have received a copy of the GNU Lesser General Public License |
2565 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2566 | # |
2567 | +from builtins import zip |
2568 | +from builtins import object |
2569 | from weakref import ref |
2570 | import gc |
2571 | |
2572 | @@ -28,6 +30,7 @@ |
2573 | from storm.info import * |
2574 | |
2575 | from tests.helper import TestHelper |
2576 | +from future.utils import with_metaclass |
2577 | |
2578 | |
2579 | class Wrapper(object): |
2580 | @@ -569,8 +572,7 @@ |
2581 | cls = type.__new__(meta_cls, name, bases, dict) |
2582 | cls.__storm_table__ = "HAH! GOTCH YA!" |
2583 | return cls |
2584 | - class Class(object): |
2585 | - __metaclass__ = MetaClass |
2586 | + class Class(with_metaclass(MetaClass, object)): |
2587 | __storm_table__ = "table" |
2588 | prop1 = Property("column1", primary=True) |
2589 | Alias = ClassAlias(Class, "USE_THIS") |
2590 | |
2591 | === modified file 'tests/mocker.py' |
2592 | --- tests/mocker.py 2008-05-18 10:22:29 +0000 |
2593 | +++ tests/mocker.py 2017-06-09 20:57:05 +0000 |
2594 | @@ -3,7 +3,13 @@ |
2595 | |
2596 | Graceful platform for test doubles in Python (mocks, stubs, fakes, and dummies). |
2597 | """ |
2598 | -import __builtin__ |
2599 | +from future import standard_library |
2600 | +standard_library.install_aliases() |
2601 | +from builtins import zip |
2602 | +from builtins import str |
2603 | +from builtins import range |
2604 | +from builtins import object |
2605 | +import builtins |
2606 | import tempfile |
2607 | import unittest |
2608 | import inspect |
2609 | @@ -13,6 +19,8 @@ |
2610 | import os |
2611 | import gc |
2612 | |
2613 | +import six |
2614 | + |
2615 | |
2616 | if sys.version_info < (2, 4): |
2617 | from sets import Set as set # pragma: nocover |
2618 | @@ -274,7 +282,7 @@ |
2619 | """ |
2620 | first_methods = dict(inspect.getmembers(first, inspect.ismethod)) |
2621 | second_methods = dict(inspect.getmembers(second, inspect.ismethod)) |
2622 | - for name, first_method in first_methods.items(): |
2623 | + for name, first_method in list(first_methods.items()): |
2624 | first_argspec = inspect.getargspec(first_method) |
2625 | first_formatted = inspect.formatargspec(*first_argspec) |
2626 | |
2627 | @@ -487,7 +495,7 @@ |
2628 | for event in self._events: |
2629 | try: |
2630 | event.verify() |
2631 | - except AssertionError, e: |
2632 | + except AssertionError as e: |
2633 | error = str(e) |
2634 | if not error: |
2635 | raise RuntimeError("Empty error message from %r" |
2636 | @@ -562,7 +570,7 @@ |
2637 | explicitly requested via the L{passthrough()} |
2638 | method. |
2639 | """ |
2640 | - if isinstance(object, basestring): |
2641 | + if isinstance(object, six.string_types): |
2642 | if name is None: |
2643 | name = object |
2644 | import_stack = object.split(".") |
2645 | @@ -583,7 +591,7 @@ |
2646 | if spec is True: |
2647 | spec = object |
2648 | if type is True: |
2649 | - type = __builtin__.type(object) |
2650 | + type = builtins.type(object) |
2651 | return Mock(self, spec=spec, type=type, object=object, |
2652 | name=name, count=count, passthrough=passthrough) |
2653 | |
2654 | @@ -1029,7 +1037,7 @@ |
2655 | path.root_object = object |
2656 | try: |
2657 | return self.__mocker__.act(path) |
2658 | - except MatchError, exception: |
2659 | + except MatchError as exception: |
2660 | root_mock = path.root_mock |
2661 | if (path.root_object is not None and |
2662 | root_mock.__mocker_passthrough__): |
2663 | @@ -1037,7 +1045,7 @@ |
2664 | # Reinstantiate to show raise statement on traceback, and |
2665 | # also to make the traceback shown shorter. |
2666 | raise MatchError(str(exception)) |
2667 | - except AssertionError, e: |
2668 | + except AssertionError as e: |
2669 | lines = str(e).splitlines() |
2670 | message = [ERROR_PREFIX + "Unmet expectation:", ""] |
2671 | message.append("=> " + lines.pop(0)) |
2672 | @@ -1083,16 +1091,16 @@ |
2673 | # something that doesn't offer them. |
2674 | try: |
2675 | result = self.__mocker_act__("len") |
2676 | - except MatchError, e: |
2677 | + except MatchError as e: |
2678 | raise AttributeError(str(e)) |
2679 | if type(result) is Mock: |
2680 | return 0 |
2681 | return result |
2682 | |
2683 | - def __nonzero__(self): |
2684 | + def __bool__(self): |
2685 | try: |
2686 | return self.__mocker_act__("nonzero") |
2687 | - except MatchError, e: |
2688 | + except MatchError as e: |
2689 | return True |
2690 | |
2691 | def __iter__(self): |
2692 | @@ -1115,13 +1123,13 @@ |
2693 | frame = sys._getframe(depth+1) |
2694 | except: |
2695 | return None |
2696 | - for name, frame_obj in frame.f_locals.iteritems(): |
2697 | + for name, frame_obj in frame.f_locals.items(): |
2698 | if frame_obj is obj: |
2699 | return name |
2700 | self = frame.f_locals.get("self") |
2701 | if self is not None: |
2702 | try: |
2703 | - items = list(self.__dict__.iteritems()) |
2704 | + items = list(self.__dict__.items()) |
2705 | except: |
2706 | pass |
2707 | else: |
2708 | @@ -1270,7 +1278,7 @@ |
2709 | result = "del %s.%s" % (result, action.args[0]) |
2710 | elif action.kind == "call": |
2711 | args = [repr(x) for x in action.args] |
2712 | - items = list(action.kwargs.iteritems()) |
2713 | + items = list(action.kwargs.items()) |
2714 | items.sort() |
2715 | for pair in items: |
2716 | args.append("%s=%r" % pair) |
2717 | @@ -1390,7 +1398,7 @@ |
2718 | |
2719 | # Either we have the same number of kwargs, or unknown keywords are |
2720 | # accepted (KWARGS was used), so check just the ones in kwargs1. |
2721 | - for key, arg1 in kwargs1.iteritems(): |
2722 | + for key, arg1 in kwargs1.items(): |
2723 | if key not in kwargs2: |
2724 | return False |
2725 | arg2 = kwargs2[key] |
2726 | @@ -1519,7 +1527,7 @@ |
2727 | for task in self._tasks: |
2728 | try: |
2729 | task_result = task.run(path) |
2730 | - except AssertionError, e: |
2731 | + except AssertionError as e: |
2732 | error = str(e) |
2733 | if not error: |
2734 | raise RuntimeError("Empty error message from %r" % task) |
2735 | @@ -1562,7 +1570,7 @@ |
2736 | for task in self._tasks: |
2737 | try: |
2738 | task.verify() |
2739 | - except AssertionError, e: |
2740 | + except AssertionError as e: |
2741 | error = str(e) |
2742 | if not error: |
2743 | raise RuntimeError("Empty error message from %r" % task) |
2744 | @@ -1672,7 +1680,7 @@ |
2745 | def __init__(self, min, max=False): |
2746 | self.min = min |
2747 | if max is None: |
2748 | - self.max = sys.maxint |
2749 | + self.max = sys.maxsize |
2750 | elif max is False: |
2751 | self.max = min |
2752 | else: |
2753 | @@ -1920,7 +1928,7 @@ |
2754 | for referrer in gc.get_referrers(remove): |
2755 | if (type(referrer) is dict and |
2756 | referrer.get("__mocker_replace__", True)): |
2757 | - for key, value in referrer.items(): |
2758 | + for key, value in list(referrer.items()): |
2759 | if value is remove: |
2760 | referrer[key] = install |
2761 | |
2762 | @@ -1992,7 +2000,7 @@ |
2763 | for kind in self._monitored: |
2764 | attr = self._get_kind_attr(kind) |
2765 | seen = set() |
2766 | - for obj in self._monitored[kind].itervalues(): |
2767 | + for obj in self._monitored[kind].values(): |
2768 | cls = type(obj) |
2769 | if issubclass(cls, type): |
2770 | cls = obj |
2771 | @@ -2006,7 +2014,7 @@ |
2772 | self.execute) |
2773 | |
2774 | def restore(self): |
2775 | - for obj, attr, original in self._patched.itervalues(): |
2776 | + for obj, attr, original in self._patched.values(): |
2777 | if original is Undefined: |
2778 | delattr(obj, attr) |
2779 | else: |
2780 | |
2781 | === modified file 'tests/properties.py' |
2782 | --- tests/properties.py 2011-09-07 14:04:04 +0000 |
2783 | +++ tests/properties.py 2017-06-09 20:57:05 +0000 |
2784 | @@ -18,9 +18,11 @@ |
2785 | # You should have received a copy of the GNU Lesser General Public License |
2786 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2787 | # |
2788 | +from builtins import object |
2789 | from datetime import datetime, date, time, timedelta |
2790 | from decimal import Decimal as decimal |
2791 | import gc |
2792 | +from future.utils import with_metaclass |
2793 | try: |
2794 | import uuid |
2795 | except ImportError: |
2796 | @@ -991,8 +993,8 @@ |
2797 | def setUp(self): |
2798 | TestHelper.setUp(self) |
2799 | |
2800 | - class Base(object): |
2801 | - __metaclass__ = PropertyPublisherMeta |
2802 | + class Base(with_metaclass(PropertyPublisherMeta, object)): |
2803 | + pass |
2804 | |
2805 | class Class(Base): |
2806 | __storm_table__ = "mytable" |
2807 | |
2808 | === modified file 'tests/schema/patch.py' |
2809 | --- tests/schema/patch.py 2014-12-18 10:57:52 +0000 |
2810 | +++ tests/schema/patch.py 2017-06-09 20:57:05 +0000 |
2811 | @@ -18,6 +18,8 @@ |
2812 | # You should have received a copy of the GNU Lesser General Public License |
2813 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2814 | # |
2815 | +from builtins import str |
2816 | +from builtins import object |
2817 | import traceback |
2818 | import sys |
2819 | import os |
2820 | @@ -345,7 +347,7 @@ |
2821 | self.add_module("patch_999.py", patch_no_args_apply) |
2822 | try: |
2823 | self.patch_applier.apply_all() |
2824 | - except BadPatchError, e: |
2825 | + except BadPatchError as e: |
2826 | self.assertTrue("mypackage/patch_999.py" in str(e)) |
2827 | self.assertTrue("takes no arguments" in str(e)) |
2828 | self.assertTrue("TypeError" in str(e)) |
2829 | @@ -360,7 +362,7 @@ |
2830 | self.add_module("patch_999.py", patch_missing_apply) |
2831 | try: |
2832 | self.patch_applier.apply_all() |
2833 | - except BadPatchError, e: |
2834 | + except BadPatchError as e: |
2835 | self.assertTrue("mypackage/patch_999.py" in str(e)) |
2836 | self.assertTrue("no attribute" in str(e)) |
2837 | self.assertTrue("AttributeError" in str(e)) |
2838 | @@ -375,7 +377,7 @@ |
2839 | self.add_module("patch_999.py", "that's not python") |
2840 | try: |
2841 | self.patch_applier.apply_all() |
2842 | - except BadPatchError, e: |
2843 | + except BadPatchError as e: |
2844 | self.assertTrue(" 999 " in str(e)) |
2845 | self.assertTrue("SyntaxError" in str(e)) |
2846 | else: |
2847 | @@ -389,7 +391,7 @@ |
2848 | self.add_module("patch_999.py", patch_name_error) |
2849 | try: |
2850 | self.patch_applier.apply_all() |
2851 | - except BadPatchError, e: |
2852 | + except BadPatchError as e: |
2853 | self.assertTrue("mypackage/patch_999.py" in str(e)) |
2854 | self.assertTrue("NameError" in str(e)) |
2855 | self.assertTrue("blah" in str(e)) |
2856 | |
2857 | === modified file 'tests/schema/schema.py' |
2858 | --- tests/schema/schema.py 2015-01-26 09:57:25 +0000 |
2859 | +++ tests/schema/schema.py 2017-06-09 20:57:05 +0000 |
2860 | @@ -18,6 +18,7 @@ |
2861 | # You should have received a copy of the GNU Lesser General Public License |
2862 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2863 | # |
2864 | +from builtins import object |
2865 | import os |
2866 | import sys |
2867 | |
2868 | @@ -65,9 +66,7 @@ |
2869 | for name in list(sys.modules): |
2870 | if name in self._package_names: |
2871 | del sys.modules[name] |
2872 | - elif filter( |
2873 | - None, |
2874 | - [name.startswith("%s." % x) for x in self._package_names]): |
2875 | + elif [_f for _f in [name.startswith("%s." % x) for x in self._package_names] if _f]: |
2876 | del sys.modules[name] |
2877 | |
2878 | super(SchemaTest, self).tearDown() |
2879 | |
2880 | === modified file 'tests/schema/sharding.py' |
2881 | --- tests/schema/sharding.py 2014-12-18 11:37:22 +0000 |
2882 | +++ tests/schema/sharding.py 2017-06-09 20:57:05 +0000 |
2883 | @@ -18,6 +18,8 @@ |
2884 | # You should have received a copy of the GNU Lesser General Public License |
2885 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2886 | # |
2887 | +from builtins import range |
2888 | +from builtins import object |
2889 | from tests.mocker import MockerTestCase |
2890 | |
2891 | from storm.schema.schema import SchemaMissingError, UnappliedPatchesError |
2892 | @@ -35,7 +37,7 @@ |
2893 | if store.pristine: |
2894 | raise SchemaMissingError() |
2895 | if store.patch < self.patches: |
2896 | - unapplied_versions = range(store.patch + 1, self.patches + 1) |
2897 | + unapplied_versions = list(range(store.patch + 1, self.patches + 1)) |
2898 | raise UnappliedPatchesError(unapplied_versions) |
2899 | |
2900 | def create(self, store): |
2901 | |
2902 | === modified file 'tests/sqlobject.py' |
2903 | --- tests/sqlobject.py 2016-03-01 11:44:05 +0000 |
2904 | +++ tests/sqlobject.py 2017-06-09 20:57:05 +0000 |
2905 | @@ -18,6 +18,7 @@ |
2906 | # You should have received a copy of the GNU Lesser General Public License |
2907 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2908 | # |
2909 | +import six |
2910 | import datetime |
2911 | import operator |
2912 | |
2913 | @@ -121,7 +122,7 @@ |
2914 | _defaultOrder = "-Person.name" |
2915 | _table = "person" |
2916 | _idName = "name" |
2917 | - _idType = unicode |
2918 | + _idType = six.text_type |
2919 | age = IntCol() |
2920 | ts = UtcDateTimeCol() |
2921 | |
2922 | @@ -1183,7 +1184,7 @@ |
2923 | # properties: |
2924 | class Person(self.SQLObject): |
2925 | _idName = "name" |
2926 | - _idType = unicode |
2927 | + _idType = six.text_type |
2928 | address = ForeignKey(foreignKey="Phone", dbName="address_id", |
2929 | notNull=True) |
2930 | |
2931 | |
2932 | === modified file 'tests/store/base.py' |
2933 | --- tests/store/base.py 2016-05-13 18:55:24 +0000 |
2934 | +++ tests/store/base.py 2017-06-09 20:57:05 +0000 |
2935 | @@ -20,7 +20,11 @@ |
2936 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2937 | # |
2938 | |
2939 | -from cStringIO import StringIO |
2940 | +from future import standard_library |
2941 | +standard_library.install_aliases() |
2942 | +from builtins import range, object |
2943 | +import six |
2944 | +from io import StringIO |
2945 | import decimal |
2946 | import gc |
2947 | import operator |
2948 | @@ -47,6 +51,7 @@ |
2949 | |
2950 | from tests.info import Wrapper |
2951 | from tests.helper import TestHelper |
2952 | +from future.utils import with_metaclass |
2953 | |
2954 | |
2955 | class Foo(object): |
2956 | @@ -1021,7 +1026,7 @@ |
2957 | def test_find_max_unicode(self): |
2958 | title = self.store.find(Foo).max(Foo.title) |
2959 | self.assertEquals(title, "Title 30") |
2960 | - self.assertTrue(isinstance(title, unicode)) |
2961 | + self.assertTrue(isinstance(title, six.text_type)) |
2962 | |
2963 | def test_find_max_with_empty_result_and_disallow_none(self): |
2964 | class Bar(object): |
2965 | @@ -1042,7 +1047,7 @@ |
2966 | def test_find_min_unicode(self): |
2967 | title = self.store.find(Foo).min(Foo.title) |
2968 | self.assertEquals(title, "Title 10") |
2969 | - self.assertTrue(isinstance(title, unicode)) |
2970 | + self.assertTrue(isinstance(title, six.text_type)) |
2971 | |
2972 | def test_find_min_with_empty_result_and_disallow_none(self): |
2973 | class Bar(object): |
2974 | @@ -1126,7 +1131,7 @@ |
2975 | values = list(values) |
2976 | self.assertEquals(values, ["Title 30", "Title 20", "Title 10"]) |
2977 | self.assertEquals([type(value) for value in values], |
2978 | - [unicode, unicode, unicode]) |
2979 | + [six.text_type, six.text_type, six.text_type]) |
2980 | |
2981 | def test_find_multiple_values(self): |
2982 | result = self.store.find(Foo).order_by(Foo.id) |
2983 | @@ -1138,7 +1143,7 @@ |
2984 | |
2985 | def test_find_values_with_no_arguments(self): |
2986 | result = self.store.find(Foo).order_by(Foo.id) |
2987 | - self.assertRaises(FeatureError, result.values().next) |
2988 | + self.assertRaises(FeatureError, next, result.values()) |
2989 | |
2990 | def test_find_slice_values(self): |
2991 | values = self.store.find(Foo).order_by(Foo.id)[1:2].values(Foo.id) |
2992 | @@ -1552,7 +1557,7 @@ |
2993 | result.group_by(FooValue.value2) |
2994 | result.order_by(Count(FooValue.id), Sum(FooValue.value1)) |
2995 | result = list(result) |
2996 | - self.assertEquals(result, [(2L, 2L), (2L, 2L), (2L, 3L), (3L, 6L)]) |
2997 | + self.assertEquals(result, [(2, 2), (2, 2), (2, 3), (3, 6)]) |
2998 | |
2999 | def test_find_group_by_table(self): |
3000 | result = self.store.find( |
3001 | @@ -2534,7 +2539,7 @@ |
3002 | foo = self.store.get(Foo, 20) |
3003 | self.store.execute("UPDATE foo SET title='Title 40' WHERE id=20") |
3004 | self.store.reload(foo) |
3005 | - for variable in get_obj_info(foo).variables.values(): |
3006 | + for variable in list(get_obj_info(foo).variables.values()): |
3007 | self.assertFalse(variable.has_changed()) |
3008 | |
3009 | def test_reload_new(self): |
3010 | @@ -4426,8 +4431,8 @@ |
3011 | self.assertRaises(NoStoreError, foo2.bars.remove, object()) |
3012 | |
3013 | def test_string_reference(self): |
3014 | - class Base(object): |
3015 | - __metaclass__ = PropertyPublisherMeta |
3016 | + class Base(with_metaclass(PropertyPublisherMeta, object)): |
3017 | + pass |
3018 | |
3019 | class MyBar(Base): |
3020 | __storm_table__ = "bar" |
3021 | @@ -4453,8 +4458,8 @@ |
3022 | metaclass. This makes it possible to work around problems with |
3023 | circular dependencies by delaying property resolution. |
3024 | """ |
3025 | - class Base(object): |
3026 | - __metaclass__ = PropertyPublisherMeta |
3027 | + class Base(with_metaclass(PropertyPublisherMeta, object)): |
3028 | + pass |
3029 | |
3030 | class MyFoo(Base): |
3031 | __storm_table__ = "foo" |
3032 | @@ -4493,8 +4498,8 @@ |
3033 | metaclass. This makes it possible to work around problems with |
3034 | circular dependencies by delaying resolution of the order by column. |
3035 | """ |
3036 | - class Base(object): |
3037 | - __metaclass__ = PropertyPublisherMeta |
3038 | + class Base(with_metaclass(PropertyPublisherMeta, object)): |
3039 | + pass |
3040 | |
3041 | class MyFoo(Base): |
3042 | __storm_table__ = "foo" |
3043 | @@ -4918,7 +4923,7 @@ |
3044 | foo = self.store.get(DictFoo, 20) |
3045 | foo["a"] = 1 |
3046 | |
3047 | - self.assertEquals(foo.items(), [("a", 1)]) |
3048 | + self.assertEquals(list(foo.items()), [("a", 1)]) |
3049 | |
3050 | new_obj = DictFoo() |
3051 | new_obj.id = 40 |
3052 | @@ -5252,7 +5257,7 @@ |
3053 | self.store.add(foo) |
3054 | foo.id = AutoReload |
3055 | foo.title = u"New Title" |
3056 | - self.assertTrue(isinstance(foo.id, (int, long))) |
3057 | + self.assertTrue(isinstance(foo.id, six.integer_types)) |
3058 | self.assertEquals(foo.title, "New Title") |
3059 | |
3060 | def test_autoreload_primary_key_doesnt_reload_everything_else(self): |
3061 | @@ -5762,8 +5767,8 @@ |
3062 | self.assertEquals(foo.title, "New Title") |
3063 | |
3064 | def get_bar_proxy_with_string(self): |
3065 | - class Base(object): |
3066 | - __metaclass__ = PropertyPublisherMeta |
3067 | + class Base(with_metaclass(PropertyPublisherMeta, object)): |
3068 | + pass |
3069 | |
3070 | class MyBarProxy(Base): |
3071 | __storm_table__ = "bar" |
3072 | @@ -5930,8 +5935,8 @@ |
3073 | self.store.commit() |
3074 | try: |
3075 | self.assertEquals(myfoo.title, title) |
3076 | - except AssertionError, e: |
3077 | - raise AssertionError(unicode(e, 'replace') + |
3078 | + except AssertionError as e: |
3079 | + raise AssertionError(six.text_type(e, 'replace') + |
3080 | " (ensure your database was created with CREATE DATABASE" |
3081 | " ... CHARACTER SET utf8)") |
3082 | |
3083 | @@ -6224,8 +6229,8 @@ |
3084 | self.assertEquals(list(result), []) |
3085 | |
3086 | def test_values_no_columns(self): |
3087 | - self.assertRaises(FeatureError, list, self.result.values()) |
3088 | - self.assertRaises(FeatureError, list, self.empty.values()) |
3089 | + self.assertRaises(FeatureError, list, list(self.result.values())) |
3090 | + self.assertRaises(FeatureError, list, list(self.empty.values())) |
3091 | |
3092 | def test_values(self): |
3093 | self.assertEquals(list(self.result.values(Foo.title)), []) |
3094 | |
3095 | === modified file 'tests/store/postgres.py' |
3096 | --- tests/store/postgres.py 2012-03-08 13:46:23 +0000 |
3097 | +++ tests/store/postgres.py 2017-06-09 20:57:05 +0000 |
3098 | @@ -18,6 +18,7 @@ |
3099 | # You should have received a copy of the GNU Lesser General Public License |
3100 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3101 | # |
3102 | +from builtins import object |
3103 | import os |
3104 | import gc |
3105 | |
3106 | |
3107 | === modified file 'tests/tracer.py' |
3108 | --- tests/tracer.py 2012-06-28 14:21:49 +0000 |
3109 | +++ tests/tracer.py 2017-06-09 20:57:05 +0000 |
3110 | @@ -1,3 +1,5 @@ |
3111 | +from builtins import str |
3112 | +from builtins import object |
3113 | import datetime |
3114 | import os |
3115 | import sys |
3116 | @@ -290,7 +292,7 @@ |
3117 | |
3118 | try: |
3119 | self.execute() |
3120 | - except TimeoutError, e: |
3121 | + except TimeoutError as e: |
3122 | self.assertEqual("0 seconds remaining in time budget", e.message) |
3123 | self.assertEqual(self.statement, e.statement) |
3124 | self.assertEqual(self.params, e.params) |
3125 | @@ -662,7 +664,7 @@ |
3126 | try: |
3127 | with CaptureTracer(): |
3128 | raise RuntimeError("boom") |
3129 | - except RuntimeError, error: |
3130 | + except RuntimeError as error: |
3131 | errors.append(error) |
3132 | [error] = errors |
3133 | self.assertEqual("boom", str(error)) |
3134 | |
3135 | === modified file 'tests/uri.py' |
3136 | --- tests/uri.py 2008-01-30 13:03:27 +0000 |
3137 | +++ tests/uri.py 2017-06-09 20:57:05 +0000 |
3138 | @@ -18,6 +18,7 @@ |
3139 | # You should have received a copy of the GNU Lesser General Public License |
3140 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3141 | # |
3142 | +from builtins import str |
3143 | from storm.uri import URI, URIError |
3144 | |
3145 | from tests.helper import TestHelper |
3146 | |
3147 | === modified file 'tests/variables.py' |
3148 | --- tests/variables.py 2011-09-13 22:48:50 +0000 |
3149 | +++ tests/variables.py 2017-06-09 20:57:05 +0000 |
3150 | @@ -18,9 +18,13 @@ |
3151 | # You should have received a copy of the GNU Lesser General Public License |
3152 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3153 | # |
3154 | +from future import standard_library |
3155 | +standard_library.install_aliases() |
3156 | +from builtins import str, object |
3157 | +import six |
3158 | from datetime import datetime, date, time, timedelta |
3159 | from decimal import Decimal |
3160 | -import cPickle as pickle |
3161 | +import pickle as pickle |
3162 | import gc |
3163 | import weakref |
3164 | try: |
3165 | @@ -143,7 +147,7 @@ |
3166 | variable = CustomVariable(allow_none=False, column=column) |
3167 | try: |
3168 | variable.set(None) |
3169 | - except NoneError, e: |
3170 | + except NoneError as e: |
3171 | pass |
3172 | self.assertTrue("column_name" in str(e)) |
3173 | |
3174 | @@ -152,7 +156,7 @@ |
3175 | variable = CustomVariable(allow_none=False, column=column) |
3176 | try: |
3177 | variable.set(None) |
3178 | - except NoneError, e: |
3179 | + except NoneError as e: |
3180 | pass |
3181 | self.assertTrue("table_name.column_name" in str(e)) |
3182 | |
3183 | @@ -467,7 +471,7 @@ |
3184 | self.assertEquals(variable.get(), epoch) |
3185 | variable.set(0.0) |
3186 | self.assertEquals(variable.get(), epoch) |
3187 | - variable.set(0L) |
3188 | + variable.set(0) |
3189 | self.assertEquals(variable.get(), epoch) |
3190 | variable.set(epoch) |
3191 | self.assertEquals(variable.get(), epoch) |
3192 | @@ -475,7 +479,7 @@ |
3193 | |
3194 | def test_get_set_from_database(self): |
3195 | datetime_str = "1977-05-04 12:34:56.78" |
3196 | - datetime_uni = unicode(datetime_str) |
3197 | + datetime_uni = six.text_type(datetime_str) |
3198 | datetime_obj = datetime(1977, 5, 4, 12, 34, 56, 780000) |
3199 | |
3200 | variable = DateTimeVariable() |
3201 | @@ -488,7 +492,7 @@ |
3202 | self.assertEquals(variable.get(), datetime_obj) |
3203 | |
3204 | datetime_str = "1977-05-04 12:34:56" |
3205 | - datetime_uni = unicode(datetime_str) |
3206 | + datetime_uni = six.text_type(datetime_str) |
3207 | datetime_obj = datetime(1977, 5, 4, 12, 34, 56) |
3208 | |
3209 | variable.set(datetime_str, from_db=True) |
3210 | @@ -553,7 +557,7 @@ |
3211 | |
3212 | def test_get_set_from_database(self): |
3213 | date_str = "1977-05-04" |
3214 | - date_uni = unicode(date_str) |
3215 | + date_uni = six.text_type(date_str) |
3216 | date_obj = date(1977, 5, 4) |
3217 | datetime_obj = datetime(1977, 5, 4, 0, 0, 0) |
3218 | |
3219 | @@ -597,7 +601,7 @@ |
3220 | |
3221 | def test_get_set_from_database(self): |
3222 | time_str = "12:34:56.78" |
3223 | - time_uni = unicode(time_str) |
3224 | + time_uni = six.text_type(time_str) |
3225 | time_obj = time(12, 34, 56, 780000) |
3226 | |
3227 | variable = TimeVariable() |
3228 | @@ -610,7 +614,7 @@ |
3229 | self.assertEquals(variable.get(), time_obj) |
3230 | |
3231 | time_str = "12:34:56" |
3232 | - time_uni = unicode(time_str) |
3233 | + time_uni = six.text_type(time_str) |
3234 | time_obj = time(12, 34, 56) |
3235 | |
3236 | variable.set(time_str, from_db=True) |
3237 | @@ -667,7 +671,7 @@ |
3238 | |
3239 | def test_get_set_from_database(self): |
3240 | delta_str = "42 days 12:34:56.78" |
3241 | - delta_uni = unicode(delta_str) |
3242 | + delta_uni = six.text_type(delta_str) |
3243 | delta_obj = timedelta(days=42, hours=12, minutes=34, |
3244 | seconds=56, microseconds=780000) |
3245 | |
3246 | @@ -681,7 +685,7 @@ |
3247 | self.assertEquals(variable.get(), delta_obj) |
3248 | |
3249 | delta_str = "1 day, 12:34:56" |
3250 | - delta_uni = unicode(delta_str) |
3251 | + delta_uni = six.text_type(delta_str) |
3252 | delta_obj = timedelta(days=1, hours=12, minutes=34, seconds=56) |
3253 | |
3254 | variable.set(delta_str, from_db=True) |
3255 | @@ -769,7 +773,7 @@ |
3256 | def test_unsupported_unit(self): |
3257 | try: |
3258 | self.check("1 month", None) |
3259 | - except ValueError, e: |
3260 | + except ValueError as e: |
3261 | self.assertEquals(str(e), "Unsupported interval unit 'month' " |
3262 | "in interval '1 month'") |
3263 | else: |
3264 | @@ -778,7 +782,7 @@ |
3265 | def test_missing_value(self): |
3266 | try: |
3267 | self.check("day", None) |
3268 | - except ValueError, e: |
3269 | + except ValueError as e: |
3270 | self.assertEquals(str(e), "Expected an interval value rather than " |
3271 | "'day' in interval 'day'") |
3272 | else: |
3273 | @@ -916,7 +920,7 @@ |
3274 | # simplejson/json. |
3275 | variable = self.variable_type() |
3276 | variable.set({u"a": 1}) |
3277 | - self.assertTrue(isinstance(variable.get(to_db=True), unicode)) |
3278 | + self.assertTrue(isinstance(variable.get(to_db=True), six.text_type)) |
3279 | |
3280 | |
3281 | class ListVariableTest(TestHelper): |
3282 | |
3283 | === modified file 'tests/wsgi.py' |
3284 | --- tests/wsgi.py 2012-06-04 14:14:50 +0000 |
3285 | +++ tests/wsgi.py 2017-06-09 20:57:05 +0000 |
3286 | @@ -1,4 +1,7 @@ |
3287 | -import Queue |
3288 | +from future import standard_library |
3289 | +standard_library.install_aliases() |
3290 | +from builtins import object |
3291 | +import queue |
3292 | from unittest import TestCase |
3293 | import threading |
3294 | import time |
3295 | @@ -65,7 +68,7 @@ |
3296 | # with two threads in a request at once, each only sees their own |
3297 | # timeline. |
3298 | app, find_timeline = make_app(self.stub_app) |
3299 | - errors = Queue.Queue() |
3300 | + errors = queue.Queue() |
3301 | sync = threading.Condition() |
3302 | waiting = [] |
3303 | def check_timeline(): |
3304 | |
3305 | === modified file 'tests/zope/adapters.py' |
3306 | --- tests/zope/adapters.py 2009-03-05 21:53:12 +0000 |
3307 | +++ tests/zope/adapters.py 2017-06-09 20:57:05 +0000 |
3308 | @@ -18,6 +18,7 @@ |
3309 | # You should have received a copy of the GNU Lesser General Public License |
3310 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3311 | # |
3312 | +from builtins import object |
3313 | from tests.helper import TestHelper |
3314 | from tests.zope import has_zope_component |
3315 | |
3316 | |
3317 | === modified file 'tests/zope/testing.py' |
3318 | --- tests/zope/testing.py 2015-05-11 08:47:32 +0000 |
3319 | +++ tests/zope/testing.py 2017-06-09 20:57:05 +0000 |
3320 | @@ -18,6 +18,7 @@ |
3321 | # You should have received a copy of the GNU Lesser General Public License |
3322 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3323 | # |
3324 | +from builtins import object |
3325 | import os |
3326 | import sys |
3327 | |
3328 | @@ -237,7 +238,7 @@ |
3329 | real_invalidate = store.invalidate |
3330 | |
3331 | def invalidate_proxy(): |
3332 | - self.assertEqual(0, len(store._alive.values())) |
3333 | + self.assertEqual(0, len(list(store._alive.values()))) |
3334 | real_invalidate() |
3335 | store.invalidate = invalidate_proxy |
3336 | |
3337 | |
3338 | === modified file 'tests/zope/zstorm.py' |
3339 | --- tests/zope/zstorm.py 2012-03-06 10:28:06 +0000 |
3340 | +++ tests/zope/zstorm.py 2017-06-09 20:57:05 +0000 |
3341 | @@ -18,6 +18,9 @@ |
3342 | # You should have received a copy of the GNU Lesser General Public License |
3343 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
3344 | # |
3345 | +from future import standard_library |
3346 | +standard_library.install_aliases() |
3347 | +from builtins import range |
3348 | import threading |
3349 | import weakref |
3350 | import gc |
3351 | @@ -355,7 +358,7 @@ |
3352 | store.execute("SELECT 1") |
3353 | except ZStormError: |
3354 | failures.append("ZStormError raised") |
3355 | - except Exception, exc: |
3356 | + except Exception as exc: |
3357 | failures.append("Expected ZStormError, got %r" % exc) |
3358 | else: |
3359 | failures.append("Expected ZStormError, nothing raised") |
A critical part of landing this on trunk is a test suite working under both python2.7 and python3. I haven't succeeded here (using a fresh Xenial container).
The mechanical python2->python3 bits seem fine.
I'm in no way qualified to review storm/cextensions.c , so will be relying on the tests here unless I can get some alternative eyeballs to have a look.
I'm unsure about the changes from explicit large ints to plain ints (1L -> 1). I haven't looked closely into what the tests that needed this change were actually testing, and how this change can be valid under both py2 and py3.
I've setup a clean Xenial container, and setup a dev environment to run the test suite (we can only land this if the tests pass under both python2 and python3).
dev/ubuntu-deps needs updating (or an alternative mechanism for getting developer dependencies. Add these packages: python-future python3-future python-dev python3-dev python3-mysqldb python3-fixtures python3-psycopg2 python3- testresources python3-transaction python3-twisted python3- zope.component python3- zope.security python3-setuptools
'make check' uses the default python2, and is running 0 tests. Something has broken with test discovery, and this needs to be fixed.
'make check PYTHON=python3' uses python3, and is failing to build:
$ make check PYTHON=python3 info/dependency _links. txt info/top_ level.txt info/PKG- INFO egg-info/ SOURCES. txt' egg-info/ SOURCES. txt' linux-x86_ 64-3.5/ storm/cextensio ns.cpython- 35m-x86_ 64-linux- gnu.so -> storm "storm. cextensions" , ["storm/ cextensions. c"])]) python3. 5/distutils/ core.py" , line 148, in setup run_commands( ) python3. 5/distutils/ dist.py" , line 955, in run_commands run_command( cmd) python3. 5/distutils/ dist.py" , line 974, in run_command python3/ dist-packages/ setuptools/ command/ test.py" , line 159, in run with_project_ on_sys_ path(self. run_tests) python3/ dist-packages/ setuptools/ command/ test.py" , line 140, in with_project_ on_sys_ path python3/ dist-packages/ setuptools/ command/ test.py" , line 180, in run_tests self._resolve_ as_ep(self. test_runner) , python3. 5/unittest/ main.py" , line 93, in __init__ parseArgs( argv) python3. 5/unittest/ main.py" , line 123, in parseArgs _do_discovery( []) python3. 5/unittest/ main.py" , line 228, in _do_discovery discover( self.start, self.pattern, self.top) python3. 5/unittest/ loader. py", line 341, in discover _find_tests( start_dir, pattern)) python3. 5/unittest/ loader. py", line 398, in _find_tests
STORM_CEXTENSIONS=0 python3 setup.py test
running test
running egg_info
writing dependency_links to storm.egg-
writing top-level names to storm.egg-
writing storm.egg-
reading manifest file 'storm.
reading manifest template 'MANIFEST.in'
warning: no files found matching 'ez_setup.py'
writing manifest file 'storm.
running build_ext
copying build/lib.
Traceback (most recent call last):
File "setup.py", line 57, in <module>
[Extension(
File "/usr/lib/
dist.
File "/usr/lib/
self.
File "/usr/lib/
cmd_obj.run()
File "/usr/lib/
self.
File "/usr/lib/
func()
File "/usr/lib/
testRunner=
File "/usr/lib/
self.
File "/usr/lib/
self.
File "/usr/lib/
self.test = loader.
File "/usr/lib/
tests = list(self.
File "/usr/lib/
full_pa...