Skip to content

Commit 3f0ac8f

Browse files
committed
Context manager scoping aligned with CPython
1 parent 8af6ada commit 3f0ac8f

File tree

4 files changed

+70
-34
lines changed

4 files changed

+70
-34
lines changed

transcrypt/development/automated_tests/transcrypt/control_structures/__init__.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ def __exit__ (self, *args):
1010
self.counter += 99
1111

1212
def run (autoTester):
13+
14+
# General control structure tests
15+
1316
for index in range (10):
1417
autoTester.check (index)
1518

@@ -80,15 +83,45 @@ def run (autoTester):
8083
autoTester.check ('oceania')
8184
else:
8285
autoTester.check ('anywhere')
86+
87+
# Context manager tests
8388

84-
with ContextManagerExample () as contextManagerExample:
85-
pass
86-
87-
autoTester.check (contextManagerExample.counter)
88-
89+
externalCounter1 = 0
90+
with ContextManagerExample () as contextManagerExample1:
91+
externalCounter1 += 1
92+
autoTester.check ('ctx1', contextManagerExample1.counter, externalCounter1)
93+
94+
externalCounter2 = 0
8995
with ContextManagerExample () as contextManagerExample2:
96+
externalCounter2 += 1
9097
contextManagerExample2.counter += 100
91-
92-
autoTester.check (contextManagerExample2.counter)
93-
94-
98+
externalCounter3 = 0
99+
with ContextManagerExample () as contextManagerExample3:
100+
externalCounter3 += 1
101+
contextManagerExample2.counter += 100
102+
externalCounter3 += 2
103+
contextManagerExample3.counter += 200
104+
autoTester.check ('ctx3', contextManagerExample3.counter, externalCounter3)
105+
externalCounter2 += 2
106+
contextManagerExample2.counter += 200
107+
autoTester.check ('ctx2', contextManagerExample2.counter, externalCounter2)
108+
109+
try:
110+
externalCounter4 = 0
111+
with ContextManagerExample () as contextManagerExample4:
112+
externalCounter4 += 1
113+
contextManagerExample4.counter += 100
114+
externalCounter5 = 0
115+
with ContextManagerExample () as contextManagerExample5:
116+
externalCounter5 += 1
117+
contextManagerExample5.counter += 100
118+
raise Exception ()
119+
externalCounter5 += 2
120+
contextManagerExample5.counter += 200
121+
externalCounter4 += 2
122+
contextManagerExample4.counter += 200
123+
except Exception as exception:
124+
autoTester.check ('ctx6', exception)
125+
finally:
126+
autoTester.check ('ctx5', contextManagerExample5.counter, externalCounter5)
127+
autoTester.check ('ctx4', contextManagerExample4.counter, externalCounter4)

transcrypt/development/shipment/shipment_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def test (relSourcePrepath, run, extraSwitches, messagePrename = '', nodeJs = Fa
5757
buildSwitch = '-b ' if build else ''
5858

5959
# Compile with Transcrypt
60-
os.system (f'{transpileCommand} -m {buildSwitch}-da -sf -n {transitSwitches}{extraSwitches}{sourcePrepath}{redirect}')
60+
os.system (f'{transpileCommand} {buildSwitch}-da -sf -n {transitSwitches}{extraSwitches}{sourcePrepath}{redirect}')
6161

6262
# Run back to back in CPython
6363
if run:

transcrypt/modules/org/transcrypt/__builtin__.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ export function __withblock__ (manager, statements) {
119119
}
120120
}
121121
}
122-
else {
122+
else { // Close an open file object, even if it doesn't support context management
123123
statements ();
124124
manager.close ();
125125
}

transcrypt/modules/org/transcrypt/compiler.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3322,44 +3322,47 @@ def visit_While (self, node):
33223322
def visit_With (self, node):
33233323
self.adaptLineNrString (node)
33243324

3325-
self.emit ('{{\n')
3326-
self.indent ()
3327-
33283325
for item in node.items:
3326+
self.emit ('var ') # Should be in surrounding scope but may be overwritten, so use var rather than let
33293327
if (item.optional_vars):
3330-
self.emit ('var ')
3331-
self.visit (item.optional_vars) # Keep this visit to register with __all__
3328+
self.visit (item.optional_vars)
33323329
withId = item.optional_vars.id
33333330
else:
3334-
self.emit ('let ')
3335-
withId = self.nextTemp ('withid') # Won't be registered, but is guaranteed not to be referenced
3331+
withId = self.nextTemp ('withid')
33363332
self.emit (withId)
33373333

33383334
self.emit (' = ')
33393335
self.visit (item.context_expr)
33403336
self.emit (';\n')
33413337

3342-
self.emit('let ')
3343-
self.emit (self.nextTemp ('withfunc'))
3344-
self.emit (' = function() {{\n')
3345-
self.indent()
3338+
self.emit ('if (hasattr ({}, \'__enter__\')) {{\n', withId)
3339+
self.indent ()
3340+
self.emit ('try {{\n')
3341+
self.indent ()
3342+
self.emit ('{}.__enter__ ();\n', withId)
33463343
self.emitBody (node.body)
3344+
self.emit ('{}.__exit__ ();\n', withId)
33473345
self.dedent ()
3348-
self.emit('}};\n')
3349-
3350-
self.emit ('__withblock__(')
3351-
self.emit (withId)
3352-
self.emit (' , ')
3353-
self.emit (self.getTemp ('withfunc'))
3354-
self.emit (');\n')
3355-
3356-
self.prevTemp ('withfunc')
3346+
self.emit ('}}\n')
3347+
self.emit ('catch ({}) {{\n', self.nextTemp ('except'))
3348+
self.indent ()
3349+
self.emit ('if (! ({0}.__exit__ ({1}.name, {1}, {1}.stack))) {{\n', withId, self.getTemp ('except'))
3350+
self.indent ()
3351+
self.emit ('throw {};\n', self.getTemp ('except'))
3352+
self.dedent ()
3353+
self.emit ('}}\n')
3354+
self.dedent ()
3355+
self.emit ('}}\n')
3356+
self.prevTemp ('except')
3357+
self.dedent ()
3358+
self.emit ('}}\n')
3359+
self.emit ('else {{\n')
3360+
self.indent ()
3361+
self.dedent ()
3362+
self.emit ('}}\n')
33573363

33583364
if withId == self.getTemp ('withid'):
33593365
self.prevTemp ('withid')
3360-
3361-
self.dedent()
3362-
self.emit('}}')
33633366

33643367
def visit_Yield (self, node):
33653368
self.getScope (ast.FunctionDef, ast.AsyncFunctionDef) .containsYield = True

0 commit comments

Comments
 (0)