Skip to content

Commit 09df17d

Browse files
authored
Merge pull request #443 from jkloetzke/py3.10
Python 3.10 compatibility
2 parents 44b9eea + bc8b873 commit 09df17d

File tree

17 files changed

+105
-87
lines changed

17 files changed

+105
-87
lines changed

.github/workflows/workflow.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ on: [push, pull_request]
55
jobs:
66
build:
77
runs-on: ubuntu-latest
8+
timeout-minutes: 15
89
strategy:
910
matrix:
10-
python-version: [3.6, 3.7, 3.8, 3.9]
11+
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
1112
fail-fast: false
1213

1314
steps:

pym/bob/archive.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from .errors import BuildError
2424
from .tty import stepAction, stepMessage, \
2525
SKIPPED, EXECUTED, WARNING, INFO, TRACE, ERROR, IMPORTANT
26-
from .utils import asHexStr, removePath, isWindows
26+
from .utils import asHexStr, removePath, isWindows, sslNoVerifyContext
2727
from shlex import quote
2828
from tempfile import mkstemp, NamedTemporaryFile, TemporaryFile
2929
import argparse
@@ -676,7 +676,7 @@ def _getConnection(self):
676676
if url.scheme == 'http':
677677
connection = http.client.HTTPConnection(url.hostname, url.port)
678678
elif url.scheme == 'https':
679-
ctx = None if self.__sslVerify else ssl.SSLContext(ssl.PROTOCOL_SSLv23)
679+
ctx = None if self.__sslVerify else sslNoVerifyContext()
680680
connection = http.client.HTTPSConnection(url.hostname, url.port,
681681
context=ctx)
682682
else:

pym/bob/cmds/build/build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,12 +261,12 @@ def _downloadLayerArgument(arg):
261261
setTui(args.jobs)
262262
builder.enableBufferedIO()
263263
try:
264-
builder.cook(backlog, True if args.build_mode == 'checkout-only' else False)
264+
builder.cook(backlog, True if args.build_mode == 'checkout-only' else False, loop)
265265
for p in backlog:
266266
resultPath = p.getWorkspacePath()
267267
if resultPath not in results:
268268
results.append(resultPath)
269-
builder.cook(providedBacklog, True if args.build_mode == 'checkout-only' else False, 1)
269+
builder.cook(providedBacklog, True if args.build_mode == 'checkout-only' else False, loop, 1)
270270
for p in providedBacklog:
271271
resultPath = p.getWorkspacePath()
272272
if resultPath not in results:

pym/bob/cmds/build/builder.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -665,9 +665,9 @@ async def _runLocalSCMs(self, step, logger):
665665
def getStatistic(self):
666666
return self.__statistic
667667

668-
def __createGenericTask(self, coro):
668+
def __createGenericTask(self, loop, coro):
669669
"""Create and return task for coroutine."""
670-
return asyncio.get_event_loop().create_task(self.__taskWrapper(coro))
670+
return loop.create_task(self.__taskWrapper(coro))
671671

672672
def __createCookTask(self, coro, step, checkoutOnly, tracker, count):
673673
"""Create and return task for a cook()-like coroutine.
@@ -756,7 +756,7 @@ async def __taskWrapper(self, coro, trackingKey=None, tracker=None,
756756
self.__buildErrors.append(e)
757757
raise CancelBuildException
758758

759-
def cook(self, steps, checkoutOnly, depth=0):
759+
def cook(self, steps, checkoutOnly, loop, depth=0):
760760
def cancelJobs():
761761
if self.__jobs > 1:
762762
log("Cancel all running jobs...", WARNING)
@@ -767,19 +767,18 @@ def cancelJobs():
767767
async def dispatcher():
768768
if self.__jobs > 1:
769769
packageJobs = [
770-
self.__createGenericTask(lambda s=step: self._cookTask(s, checkoutOnly, depth))
770+
self.__createGenericTask(loop, lambda s=step: self._cookTask(s, checkoutOnly, depth))
771771
for step in steps ]
772772
await gatherTasks(packageJobs)
773773
else:
774774
packageJobs = []
775775
for step in steps:
776-
job = self.__createGenericTask(lambda s=step: self._cookTask(s, checkoutOnly, depth))
776+
job = self.__createGenericTask(loop, lambda s=step: self._cookTask(s, checkoutOnly, depth))
777777
packageJobs.append(job)
778778
await asyncio.wait({job})
779779
# retrieve results as last step to --keep-going
780780
for job in packageJobs: job.result()
781781

782-
loop = asyncio.get_event_loop()
783782
self.__restart = True
784783
while self.__restart:
785784
self.__running = True
@@ -801,7 +800,7 @@ async def dispatcher():
801800
self.__tasksDone = 0
802801
self.__tasksNum = 0
803802

804-
j = self.__createGenericTask(dispatcher)
803+
j = self.__createGenericTask(loop, dispatcher)
805804
try:
806805
loop.add_signal_handler(signal.SIGINT, cancelJobs)
807806
except NotImplementedError:

pym/bob/cmds/graph.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .. import BOB_VERSION
77
from ..input import RecipeSet
88
from ..tty import colorize
9-
from ..utils import processDefines
9+
from ..utils import processDefines, runInEventLoop
1010
import argparse
1111
import asyncio
1212
import json
@@ -15,9 +15,6 @@
1515
import collections
1616
from shutil import copyfile
1717

18-
def run(coro):
19-
return asyncio.get_event_loop().run_until_complete(coro)
20-
2118
def findPackages(package, excludes, highlights, done, maxdepth, donePackages, level = 0):
2219
def isHighLigh(package):
2320
for h in highlights:
@@ -472,7 +469,7 @@ def getHover(package, options):
472469
simulation.force("link").links(links)
473470
</script>
474471
<div class='info' style="width: 100%; text-align: center;">
475-
<div id='innerLeft' style="float: left"> Recipes: """ + run(RecipeSet().getScmStatus()) + """</div>
472+
<div id='innerLeft' style="float: left"> Recipes: """ + runInEventLoop(RecipeSet().getScmStatus()) + """</div>
476473
<div id='innerRight' style="float: right">Bob version: """ + BOB_VERSION +"""</div>
477474
<div id='innerMiddle' style="display: inline-block">Generated using <a href="https://www.d3js.org">D3JS</a></div>
478475
</div>

pym/bob/cmds/jenkins.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from ..state import BobState
1212
from ..stringparser import isTrue
1313
from ..tty import WarnOnce
14-
from ..utils import asHexStr, processDefines
14+
from ..utils import asHexStr, processDefines, runInEventLoop, sslNoVerifyContext
1515
from shlex import quote
1616
import argparse
1717
import ast
@@ -67,9 +67,6 @@
6767

6868
SHARED_GENERATION = '-2'
6969

70-
def run(coro):
71-
return asyncio.get_event_loop().run_until_complete(coro)
72-
7370
class Wiper:
7471
def __init__(self):
7572
self.mode = 0
@@ -236,7 +233,7 @@ def getDescription(self, date, warnLazy):
236233
description.extend([
237234
"<h2>Recipe</h2>",
238235
"<p>Name: " + self.__recipe.getName()
239-
+ "<br/>Source: " + run(self.__recipe.getRecipeSet().getScmStatus())
236+
+ "<br/>Source: " + runInEventLoop(self.__recipe.getRecipeSet().getScmStatus())
240237
+ "<br/>Configured: " + date
241238
+ "<br/>Bob version: " + BOB_VERSION + "</p>",
242239
"<h2>Packages</h2>", "<ul>"
@@ -386,7 +383,7 @@ def dumpStepAuditGen(self, step, auditMeta):
386383
]
387384
for (var, val) in sorted(step.getPackage().getMetaEnv().items()):
388385
cmd.extend(["-E", var, quote(val)])
389-
recipesAudit = run(step.getPackage().getRecipe().getRecipeSet().getScmAudit())
386+
recipesAudit = runInEventLoop(step.getPackage().getRecipe().getRecipeSet().getScmAudit())
390387
if recipesAudit is not None:
391388
cmd.extend(["--recipes",
392389
quote(json.dumps(recipesAudit.dump(), sort_keys=True))])
@@ -1568,7 +1565,7 @@ def __init__(self, config, sslVerify):
15681565
# Optionally disable SSL certificate checks
15691566
if not sslVerify:
15701567
handlers.append(urllib.request.HTTPSHandler(
1571-
context=ssl.SSLContext(ssl.PROTOCOL_SSLv23)))
1568+
context=sslNoVerifyContext()))
15721569

15731570
# handle authorization
15741571
username = url.get("username")

pym/bob/input.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3302,8 +3302,11 @@ def __loadPlugin(self, mangledName, fileName, name):
33023302
pluginStat = binStat(fileName)
33033303
try:
33043304
from importlib.machinery import SourceFileLoader
3305+
from importlib.util import spec_from_loader, module_from_spec
33053306
loader = SourceFileLoader(mangledName, fileName)
3306-
mod = loader.load_module()
3307+
spec = spec_from_loader(mangledName, loader)
3308+
mod = module_from_spec(spec)
3309+
loader.exec_module(mod)
33073310
except SyntaxError as e:
33083311
import traceback
33093312
raise ParseError("Error loading plugin "+fileName+": "+str(e),

pym/bob/scm/url.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from .. import BOB_VERSION
77
from ..errors import BuildError, ParseError
88
from ..stringparser import IfExpression
9-
from ..utils import asHexStr, hashFile, isWindows, removeUserFromUrl
9+
from ..utils import asHexStr, hashFile, isWindows, removeUserFromUrl, sslNoVerifyContext
1010
from .scm import Scm, ScmAudit
1111
import asyncio
1212
import concurrent
@@ -220,7 +220,7 @@ def getProperties(self, isJenkins):
220220
def _download(self, destination):
221221
headers = {}
222222
headers["User-Agent"] = "BobBuildTool/{}".format(BOB_VERSION)
223-
context = None if self.__sslVerify else ssl.SSLContext(ssl.PROTOCOL_SSLv23)
223+
context = None if self.__sslVerify else sslNoVerifyContext()
224224
if os.path.isfile(destination) and self.__url.startswith("http"):
225225
# Try to avoid download if possible
226226
headers["If-Modified-Since"] = time2HTTPDate(os.stat(destination).st_mtime)

pym/bob/utils.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,6 @@ def __init__(self):
640640

641641
if sys.platform == 'win32':
642642
loop = asyncio.ProactorEventLoop()
643-
asyncio.set_event_loop(loop)
644643
multiprocessing.set_start_method('spawn')
645644
executor = concurrent.futures.ProcessPoolExecutor()
646645
else:
@@ -651,7 +650,7 @@ def __init__(self):
651650
# have to ignore BrokenProcessPool errors as we will likely hit them.
652651
# To "prime" the process pool a dummy workload must be executed because
653652
# the processes are spawned lazily.
654-
loop = asyncio.get_event_loop()
653+
loop = asyncio.new_event_loop()
655654
origSigInt = signal.getsignal(signal.SIGINT)
656655
signal.signal(signal.SIGINT, signal.SIG_IGN)
657656

@@ -689,11 +688,15 @@ def run(self):
689688
self.__executor = executor
690689

691690
def __enter__(self):
691+
import asyncio
692+
asyncio.set_event_loop(self.__loop)
692693
return (self.__loop, self.__executor)
693694

694695
def __exit__(self, exc_type, exc_value, traceback):
696+
import asyncio
695697
self.__executor.shutdown()
696698
self.__loop.close()
699+
asyncio.set_event_loop(None)
697700

698701

699702
async def run(args, universal_newlines=False, check=False, shell=False, **kwargs):
@@ -730,3 +733,26 @@ async def check_output(args, **kwargs):
730733
"""The subprocess.check_output() call as coroutine."""
731734
import subprocess
732735
return (await run(args, check=True, stdout=subprocess.PIPE, **kwargs)).stdout
736+
737+
def runInEventLoop(coro):
738+
"""Backwards compatibility stub for asyncio.run()"""
739+
import asyncio
740+
741+
if sys.version_info.minor >= 7:
742+
return asyncio.run(coro)
743+
744+
loop = asyncio.new_event_loop()
745+
try:
746+
asyncio.set_event_loop(loop)
747+
return loop.run_until_complete(coro)
748+
finally:
749+
asyncio.set_event_loop(None)
750+
loop.close()
751+
752+
def sslNoVerifyContext():
753+
"""Generate a SSL context that does not validate certificates."""
754+
import ssl
755+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
756+
context.check_hostname = False
757+
context.verify_mode = ssl.CERT_NONE
758+
return context

test/jenkins/jenkins_mock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ def do_POST(self):
5555
self.end_headers()
5656
return
5757
if 'doDelete' in self.path:
58+
self.server.rxJenkinsData((self.path , ''))
5859
self.send_response(302)
5960
self.end_headers()
60-
self.server.rxJenkinsData((self.path , ''))
6161
return
6262
if 'createItem' in self.path:
6363
length = int(self.headers.get('content-length',0))

0 commit comments

Comments
 (0)