Skip to content

Commit 88fcf61

Browse files
authored
Merge pull request #160 from autolab/python3-upgrade
Python 3 Upgrade
2 parents a110853 + 9feb851 commit 88fcf61

19 files changed

+177
-115
lines changed

Diff for: .gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,8 @@ pip-selfcheck.json
2222

2323
# IDEs
2424
.idea
25+
.vscode
26+
27+
# Backup files
28+
*.bak
29+

Diff for: README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@ Please feel free to use Tango at your school/organization. If you run into any p
3535
3. [Read the documentation for the VMMS API](https://github.com/autolab/Tango/wiki/Tango-VMMS-API).
3636
4. [Test whether Tango is set up properly and can process jobs](https://github.com/autolab/Tango/wiki/Testing-Tango).
3737

38-
## Python 3 Upgrade
39-
We are in the process of porting Tango from Python 2 to Python 3. The current working branch for the update is `python3-upgrade`.
38+
## Python 2 Support
39+
Tango now runs on Python 3. However, there is a legacy branch [master-python2](https://github.com/autolab/Tango/tree/master-python2) which is a snapshot of the last Python 2 Tango commit for legacy reasons. You are strongly encouraged to upgrade to the current Python 3 version of Tango if you are still on the Python 2 version, as future enhancements and bug fixes will be focused on the current master.
40+
41+
We will not be backporting new features from `master` to `master-python2`.
4042

4143
## Contributing to Tango
4244

Diff for: clients/tango-cli.py

+46-40
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
# tango-cli.py - Command line client for the RESTful Tango.
55
#
66

7+
from __future__ import print_function
8+
from builtins import range
9+
from future import standard_library
10+
standard_library.install_aliases()
11+
from builtins import map
12+
from builtins import str
713
import os
814
import sys
915

@@ -12,7 +18,7 @@
1218
import argparse
1319
import requests
1420
import json
15-
import urllib
21+
import urllib.request, urllib.parse, urllib.error
1622

1723
#
1824
#
@@ -95,35 +101,35 @@
95101

96102
def checkKey():
97103
if (args.key is None):
98-
print "Key must be specified with -k"
104+
print("Key must be specified with -k")
99105
return -1
100106
return 0
101107

102108

103109
def checkCourselab():
104110
if (args.courselab is None):
105-
print "Courselab must be specified with -l"
111+
print("Courselab must be specified with -l")
106112
return -1
107113
return 0
108114

109115

110116
def checkFilename():
111117
if (args.filename is None):
112-
print "Filename must be specified with --filename"
118+
print("Filename must be specified with --filename")
113119
return -1
114120
return 0
115121

116122

117123
def checkInfiles():
118124
if (args.infiles is None):
119-
print "Input files must be specified with --infiles"
125+
print("Input files must be specified with --infiles")
120126
return -1
121127
return 0
122128

123129

124130
def checkDeadjobs():
125131
if (args.deadJobs is None):
126-
print "Deadjobs must be specified with --deadJobs"
132+
print("Deadjobs must be specified with --deadJobs")
127133
return -1
128134
return 0
129135

@@ -139,11 +145,11 @@ def tango_open():
139145
response = requests.get(
140146
'http://%s:%d/open/%s/%s/' %
141147
(args.server, args.port, args.key, args.courselab))
142-
print "Sent request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab)
143-
print response.content
148+
print("Sent request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab))
149+
print(response.text)
144150

145151
except Exception as err:
146-
print "Failed to send request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab)
152+
print("Failed to send request to %s:%d/open/%s/%s/" % (args.server, args.port, args.key, args.courselab))
147153
print (str(err))
148154
sys.exit(0)
149155

@@ -170,11 +176,11 @@ def tango_upload():
170176
data=f.read(),
171177
headers=header)
172178
f.close()
173-
print "Sent request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename)
174-
print response.content
179+
print("Sent request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename))
180+
print(response.text)
175181

176182
except Exception as err:
177-
print "Failed to send request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename)
183+
print("Failed to send request to %s:%d/upload/%s/%s/ filename=%s" % (args.server, args.port, args.key, args.courselab, args.filename))
178184
print (str(err))
179185
sys.exit(0)
180186

@@ -208,11 +214,11 @@ def tango_addJob():
208214
args.key,
209215
args.courselab),
210216
data=json.dumps(requestObj))
211-
print "Sent request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj))
212-
print response.content
217+
print("Sent request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj)))
218+
print(response.text)
213219

214220
except Exception as err:
215-
print "Failed to send request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj))
221+
print("Failed to send request to %s:%d/addJob/%s/%s/ \t jobObj=%s" % (args.server, args.port, args.key, args.courselab, json.dumps(requestObj)))
216222
print (str(err))
217223
sys.exit(0)
218224

@@ -231,13 +237,13 @@ def tango_poll():
231237
args.port,
232238
args.key,
233239
args.courselab,
234-
urllib.quote(
240+
urllib.parse.quote(
235241
args.outputFile)))
236-
print "Sent request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.quote(args.outputFile))
237-
print response.content
242+
print("Sent request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.parse.quote(args.outputFile)))
243+
print(response.text)
238244

239245
except Exception as err:
240-
print "Failed to send request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.quote(args.outputFile))
246+
print("Failed to send request to %s:%d/poll/%s/%s/%s/" % (args.server, args.port, args.key, args.courselab, urllib.parse.quote(args.outputFile)))
241247
print (str(err))
242248
sys.exit(0)
243249

@@ -252,11 +258,11 @@ def tango_info():
252258

253259
response = requests.get(
254260
'http://%s:%d/info/%s/' % (args.server, args.port, args.key))
255-
print "Sent request to %s:%d/info/%s/" % (args.server, args.port, args.key)
256-
print response.content
261+
print("Sent request to %s:%d/info/%s/" % (args.server, args.port, args.key))
262+
print(response.text)
257263

258264
except Exception as err:
259-
print "Failed to send request to %s:%d/info/%s/" % (args.server, args.port, args.key)
265+
print("Failed to send request to %s:%d/info/%s/" % (args.server, args.port, args.key))
260266
print (str(err))
261267
sys.exit(0)
262268

@@ -272,11 +278,11 @@ def tango_jobs():
272278
response = requests.get(
273279
'http://%s:%d/jobs/%s/%d/' %
274280
(args.server, args.port, args.key, args.deadJobs))
275-
print "Sent request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs)
276-
print response.content
281+
print("Sent request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs))
282+
print(response.text)
277283

278284
except Exception as err:
279-
print "Failed to send request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs)
285+
print("Failed to send request to %s:%d/jobs/%s/%d/" % (args.server, args.port, args.key, args.deadJobs))
280286
print (str(err))
281287
sys.exit(0)
282288

@@ -291,11 +297,11 @@ def tango_pool():
291297

292298
response = requests.get('http://%s:%d/pool/%s/%s/' %
293299
(args.server, args.port, args.key, args.image))
294-
print "Sent request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image)
295-
print response.content
300+
print("Sent request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image))
301+
print(response.text)
296302

297303
except Exception as err:
298-
print "Failed to send request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image)
304+
print("Failed to send request to %s:%d/pool/%s/%s/" % (args.server, args.port, args.key, args.image))
299305
print (str(err))
300306
sys.exit(0)
301307

@@ -321,11 +327,11 @@ def tango_prealloc():
321327
args.image,
322328
args.num),
323329
data=json.dumps(vmObj))
324-
print "Sent request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj))
325-
print response.content
330+
print("Sent request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj)))
331+
print(response.text)
326332

327333
except Exception as err:
328-
print "Failed to send request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj))
334+
print("Failed to send request to %s:%d/prealloc/%s/%s/%s/ \t vmObj=%s" % (args.server, args.port, args.key, args.image, args.num, json.dumps(vmObj)))
329335
print (str(err))
330336
sys.exit(0)
331337

@@ -343,31 +349,31 @@ def file_to_dict(file):
343349

344350
def tango_runJob():
345351
if args.runJob is None:
346-
print "Invalid usage: [runJob]"
352+
print("Invalid usage: [runJob]")
347353
sys.exit(0)
348354

349355
dir = args.runJob
350356
infiles = [file for file in os.listdir(
351357
dir) if os.path.isfile(os.path.join(dir, file))]
352358
files = [os.path.join(dir, file) for file in infiles]
353-
args.infiles = map(file_to_dict, infiles)
359+
args.infiles = list(map(file_to_dict, infiles))
354360

355361
args.jobname += "-0"
356362
args.outputFile += "-0"
357-
for i in xrange(1, args.numJobs + 1):
358-
print "----------------------------------------- STARTING JOB " + str(i) + " -----------------------------------------"
359-
print "----------- OPEN"
363+
for i in range(1, args.numJobs + 1):
364+
print("----------------------------------------- STARTING JOB " + str(i) + " -----------------------------------------")
365+
print("----------- OPEN")
360366
tango_open()
361-
print "----------- UPLOAD"
367+
print("----------- UPLOAD")
362368
for file in files:
363369
args.filename = file
364370
tango_upload()
365-
print "----------- ADDJOB"
371+
print("----------- ADDJOB")
366372
length = len(str(i - 1))
367373
args.jobname = args.jobname[:-length] + str(i)
368374
args.outputFile = args.outputFile[:-length] + str(i)
369375
tango_addJob()
370-
print "--------------------------------------------------------------------------------------------------\n"
376+
print("--------------------------------------------------------------------------------------------------\n")
371377

372378

373379
def router():
@@ -403,7 +409,7 @@ def router():
403409
try:
404410
response = requests.get('http://%s:%d/' % (args.server, args.port))
405411
except:
406-
print 'Tango not reachable on %s:%d!\n' % (args.server, args.port)
412+
print('Tango not reachable on %s:%d!\n' % (args.server, args.port))
407413
sys.exit(0)
408414

409415
router()

Diff for: config.template.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
# config.py - Global configuration constants and runtime info
33
#
44

5+
from builtins import object
56
import logging, time
67

78
# Config - defines
89

910

10-
class Config:
11+
class Config(object):
1112
#####
1213
# Part 1: Tango constants for developers
1314
#

Diff for: jobManager.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from __future__ import print_function
12
#
23
# JobManager - Thread that assigns jobs to worker threads
34
#
@@ -9,6 +10,10 @@
910
# is launched that will handle things from here on. If anything goes
1011
# wrong, the job is made dead with the error.
1112
#
13+
from builtins import object
14+
from future import standard_library
15+
standard_library.install_aliases()
16+
from builtins import str
1217
import threading, logging, time, copy
1318

1419
from datetime import datetime
@@ -20,7 +25,7 @@
2025
from tangoObjects import TangoQueue
2126
from config import Config
2227

23-
class JobManager:
28+
class JobManager(object):
2429

2530
def __init__(self, queue):
2631
self.daemon = True
@@ -62,9 +67,16 @@ def __manage(self):
6267

6368
if id:
6469
job = self.jobQueue.get(id)
70+
71+
# job could no longer exist if it was completed by someone else
72+
if job == None:
73+
continue
74+
6575
if not job.accessKey and Config.REUSE_VMS:
6676
id, vm = self.jobQueue.getNextPendingJobReuse(id)
6777
job = self.jobQueue.get(id)
78+
if job == None:
79+
continue
6880

6981
try:
7082
# Mark the job assigned

Diff for: jobQueue.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
# JobManager: Class that creates a thread object that looks for new
88
# work on the job queue and assigns it to workers.
99
#
10+
from builtins import range
11+
from builtins import object
12+
from builtins import str
1013
import threading, logging, time
1114

1215
from datetime import datetime
@@ -28,7 +31,7 @@
2831
#
2932

3033

31-
class JobQueue:
34+
class JobQueue(object):
3235

3336
def __init__(self, preallocator):
3437
self.liveJobs = TangoDictionary("liveJobs")
@@ -53,7 +56,7 @@ def _getNextID(self):
5356
keys = self.liveJobs.keys()
5457
if (str(id) in keys):
5558
id = -1
56-
for i in xrange(1, Config.MAX_JOBID + 1):
59+
for i in range(1, Config.MAX_JOBID + 1):
5760
if (str(i) not in keys):
5861
id = i
5962
break
@@ -191,7 +194,7 @@ def getNextPendingJob(self):
191194
Called by JobManager when Config.REUSE_VMS==False
192195
"""
193196
self.queueLock.acquire()
194-
for id, job in self.liveJobs.iteritems():
197+
for id, job in self.liveJobs.items():
195198
if job.isNotAssigned():
196199
self.queueLock.release()
197200
return id
@@ -203,7 +206,7 @@ def getNextPendingJobReuse(self, target_id=None):
203206
Called by JobManager when Config.REUSE_VMS==True
204207
"""
205208
self.queueLock.acquire()
206-
for id, job in self.liveJobs.iteritems():
209+
for id, job in self.liveJobs.items():
207210
# if target_id is set, only interested in this id
208211
if target_id and target_id != id:
209212
continue

Diff for: preallocator.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#
22
# preallocator.py - maintains a pool of active virtual machines
33
#
4+
from builtins import object
5+
from builtins import range
46
import threading, logging, time, copy
57

68
from tangoObjects import TangoDictionary, TangoQueue, TangoIntValue
@@ -17,7 +19,7 @@
1719
#
1820

1921

20-
class Preallocator:
22+
class Preallocator(object):
2123

2224
def __init__(self, vmms):
2325
self.machines = TangoDictionary("machines")

Diff for: requirements.txt

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
backports.ssl-match-hostname==3.4.0.2
2-
boto==2.27.0
3-
futures==2.2.0
4-
plumbum==1.4.2
5-
pyflakes==0.8.1
6-
redis==2.10.3
7-
requests==2.2.1
8-
rpyc==3.3.0
9-
wsgiref==0.1.2
10-
tornado==4.1
1+
backports.ssl-match-hostname==3.7.0.1
2+
boto==2.49.0 # used only by ec2SSH.py
3+
plumbum==1.6.9
4+
pyflakes==2.1.1
5+
redis==3.4.1
6+
requests==2.23.0
7+
rpyc==4.1.4
8+
tornado==4.5.3
9+
future==0.18.2

0 commit comments

Comments
 (0)