Skip to content

Commit 11956cb

Browse files
committed
chore(refactor): use with open, consolidate/un-nest if ...
Various cleanups: use 'with open(...)' rather than 'try: .. finally' to close file. use "return ..." rather than "x = ...; return x" Change if/else to if ternaries Swap ' for " to prevent escaping nested " Add lint silencing comments Fix bare return that needs to be return None.
1 parent 9c7604c commit 11956cb

File tree

1 file changed

+54
-73
lines changed

1 file changed

+54
-73
lines changed

roundup/cgi/client.py

Lines changed: 54 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,11 @@ def __init__(self, instance, request, env, form=None, translator=None):
442442
# will never arrive.
443443
# If not defined, set CONTENT_LENGTH to 0 so it doesn't
444444
# hang reading the data.
445-
if self.env['REQUEST_METHOD'] in ['OPTIONS', 'DELETE', 'PATCH']:
446-
if 'CONTENT_LENGTH' not in self.env:
447-
self.env['CONTENT_LENGTH'] = 0
448-
logger.debug("Setting CONTENT_LENGTH to 0 for method: %s",
449-
self.env['REQUEST_METHOD'])
445+
if self.env['REQUEST_METHOD'] in ['OPTIONS', 'DELETE', 'PATCH'] \
446+
and 'CONTENT_LENGTH' not in self.env:
447+
self.env['CONTENT_LENGTH'] = 0
448+
logger.debug("Setting CONTENT_LENGTH to 0 for method: %s",
449+
self.env['REQUEST_METHOD'])
450450

451451
# cgi.FieldStorage must save all data as
452452
# binary/bytes. Subclass BinaryFieldStorage does this.
@@ -496,8 +496,7 @@ def __init__(self, instance, request, env, form=None, translator=None):
496496

497497
def _gen_nonce(self):
498498
""" generate a unique nonce """
499-
n = b2s(base64.b32encode(random_.token_bytes(40)))
500-
return n
499+
return b2s(base64.b32encode(random_.token_bytes(40)))
501500

502501
def setTranslator(self, translator=None):
503502
"""Replace the translation engine
@@ -694,7 +693,8 @@ def handle_rest(self):
694693
if (self.is_cors_preflight()):
695694
self.handle_preflight()
696695
return
697-
elif not self.db.security.hasPermission('Rest Access', self.userid):
696+
697+
if not self.db.security.hasPermission('Rest Access', self.userid):
698698
output = s2b('{ "error": { "status": 403, "msg": "Forbidden." } }')
699699
self.reject_request(output,
700700
message_type="application/json",
@@ -811,14 +811,11 @@ def inner_main(self):
811811
self.form_wins = True
812812
self._error_message = msg.args
813813

814-
if csrf_ok:
815-
# csrf checks pass. Run actions etc.
816-
# possibly handle a form submit action (may change
817-
# self.classname and self.template, and may also
818-
# append error/ok_messages)
819-
html = self.handle_action()
820-
else:
821-
html = None
814+
# If csrf checks pass. Run actions etc.
815+
# handle_action() may handle a form submit action.
816+
# It can change self.classname and self.template,
817+
# and may also append error/ok_messages.
818+
html = self.handle_action() if csrf_ok else None
822819

823820
if html:
824821
self.write_html(html)
@@ -883,7 +880,7 @@ def inner_main(self):
883880
self.response_code = http_.client.UNAUTHORIZED
884881
realm = self.instance.config.TRACKER_NAME
885882
self.setHeader("WWW-Authenticate",
886-
"Basic realm=\"%s\"" % realm)
883+
'Basic realm="%s"' % realm)
887884
else:
888885
self.response_code = http_.client.FORBIDDEN
889886
self.renderFrontPage(str(message))
@@ -1041,10 +1038,7 @@ def determine_charset(self):
10411038

10421039
def _decode_charref(matchobj):
10431040
num = matchobj.group(1)
1044-
if num[0].lower() == 'x':
1045-
uc = int(num[1:], 16)
1046-
else:
1047-
uc = int(num)
1041+
uc = int(num[1:], 16) if num[0].lower() == 'x' else int(num)
10481042
return uchr(uc)
10491043

10501044
for field_name in self.form:
@@ -1235,7 +1229,7 @@ def determine_user(self, is_api=False):
12351229

12361230
# will be used later to override the get_roles method
12371231
# having it defined as truthy allows it to be used.
1238-
override_get_roles = lambda self: iter_roles( # noqa: E731
1232+
override_get_roles = lambda self: iter_roles( # noqa: ARG005
12391233
','.join(token['roles']))
12401234

12411235
# if user was not set by http authorization, try session lookup
@@ -1291,6 +1285,8 @@ def check_anonymous_access(self):
12911285
raise SeriousError(
12921286
self._('broken form: multiple @action values submitted'))
12931287
elif action != '':
1288+
# '' is value when no action parameter was found so run
1289+
# this to extract action string value when action found.
12941290
action = action.value.lower()
12951291
if action in ('login', 'register'):
12961292
return
@@ -1302,8 +1298,8 @@ def check_anonymous_access(self):
13021298
return
13031299

13041300
# otherwise for everything else
1305-
if self.user == 'anonymous':
1306-
if not self.db.security.hasPermission('Web Access', self.userid):
1301+
if self.user == 'anonymous' and \
1302+
not self.db.security.hasPermission('Web Access', self.userid):
13071303
raise Unauthorised(self._("Anonymous users are not "
13081304
"allowed to use the web interface"))
13091305

@@ -1326,10 +1322,7 @@ def is_origin_header_ok(self, api=False, credentials=False):
13261322
try:
13271323
origin = self.env['HTTP_ORIGIN']
13281324
except KeyError:
1329-
if self.env['REQUEST_METHOD'] == 'GET':
1330-
return True
1331-
else:
1332-
return False
1325+
return self.env['REQUEST_METHOD'] == 'GET'
13331326

13341327
# note base https://host/... ends host with with a /,
13351328
# so add it to origin.
@@ -1478,7 +1471,7 @@ def handle_csrf(self, api=False):
14781471
"ORIGIN",
14791472
"REFERER",
14801473
"X-FORWARDED-HOST",
1481-
"HOST"
1474+
"HOST",
14821475
]
14831476

14841477
header_pass = 0 # count of passing header checks
@@ -1581,21 +1574,20 @@ def handle_csrf(self, api=False):
15811574
raise UsageError(self._("Unable to verify sufficient headers"))
15821575

15831576
enforce = config['WEB_CSRF_ENFORCE_HEADER_X-REQUESTED-WITH']
1584-
if api:
1585-
if enforce in ['required', 'yes']:
1586-
# if we get here we have usually passed at least one
1587-
# header check. We check for presence of this custom
1588-
# header for xmlrpc/rest calls only.
1589-
# E.G. X-Requested-With: XMLHttpRequest
1590-
# Note we do not use CSRF nonces for xmlrpc/rest requests.
1591-
#
1592-
# see: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers
1593-
if 'HTTP_X_REQUESTED_WITH' not in self.env:
1594-
logger.error(self._(
1595-
''"csrf X-REQUESTED-WITH xmlrpc required header "
1596-
''"check failed for user%s."),
1597-
current_user)
1598-
raise UsageError(self._("Required Header Missing"))
1577+
if api and enforce in ['required', 'yes']:
1578+
# if we get here we have usually passed at least one
1579+
# header check. We check for presence of this custom
1580+
# header for xmlrpc/rest calls only.
1581+
# E.G. X-Requested-With: XMLHttpRequest
1582+
# Note we do not use CSRF nonces for xmlrpc/rest requests.
1583+
#
1584+
# see: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers
1585+
if 'HTTP_X_REQUESTED_WITH' not in self.env:
1586+
logger.error(self._(
1587+
''"csrf X-REQUESTED-WITH xmlrpc required header "
1588+
''"check failed for user%s."),
1589+
current_user)
1590+
raise UsageError(self._("Required Header Missing"))
15991591

16001592
# Expire old csrf tokens now so we don't use them. These will
16011593
# be committed after the otks.destroy below. Note that the
@@ -1703,17 +1695,16 @@ def opendb(self, username):
17031695
if not hasattr(self, 'db'):
17041696
self.db = self.instance.open(username)
17051697
self.db.tx_Source = "web"
1706-
else:
1707-
if self.instance.optimize:
1698+
elif self.instance.optimize:
17081699
self.db.setCurrentUser(username)
17091700
self.db.tx_Source = "web"
1710-
else:
1711-
self.db.close()
1712-
self.db = self.instance.open(username)
1713-
self.db.tx_Source = "web"
1714-
# The old session API refers to the closed database;
1715-
# we can no longer use it.
1716-
self.session_api = Session(self)
1701+
else:
1702+
self.db.close()
1703+
self.db = self.instance.open(username)
1704+
self.db.tx_Source = "web"
1705+
# The old session API refers to the closed database;
1706+
# we can no longer use it.
1707+
self.session_api = Session(self)
17171708

17181709
# match designator in URL stripping leading 0's. So:
17191710
# https://issues.roundup-tracker.org/issue002551190 is the same as
@@ -1793,7 +1784,7 @@ def determine_context(self, dre=dre_url):
17931784
else:
17941785
self.template = ''
17951786
return
1796-
elif path[0] in ('_file', '@@file'):
1787+
if path[0] in ('_file', '@@file'):
17971788
raise SendStaticFile(os.path.join(*path[1:]))
17981789
else:
17991790
self.classname = path[0]
@@ -1973,10 +1964,7 @@ def serve_static_file(self, file):
19731964
file = str(file)
19741965
mime_type = mimetypes.guess_type(file)[0]
19751966
if not mime_type:
1976-
if file.endswith('.css'):
1977-
mime_type = 'text/css'
1978-
else:
1979-
mime_type = 'text/plain'
1967+
mime_type = 'text/css' if file.endswith('.css') else 'text/plain'
19801968

19811969
# get filename: given a/b/c.js extract c.js
19821970
fn = file.rpartition("/")[2]
@@ -2079,12 +2067,9 @@ def selectTemplate(self, name, view):
20792067
if (view and view.find('|') != -1):
20802068
# we have alternate templates, parse them apart.
20812069
(oktmpl, errortmpl) = view.split("|", 2)
2082-
if self._error_message:
2083-
# we have an error, use errortmpl
2084-
view = errortmpl
2085-
else:
2086-
# no error message recorded, use oktmpl
2087-
view = oktmpl
2070+
2071+
# Choose the right template
2072+
view = errortmpl if self._error_message else oktmpl
20882073

20892074
loader = self.instance.templates
20902075

@@ -2135,7 +2120,7 @@ def renderContext(self):
21352120
# catch errors so we can handle PT rendering errors more nicely
21362121
args = {
21372122
'ok_message': self._ok_message,
2138-
'error_message': self._error_message
2123+
'error_message': self._error_message,
21392124
}
21402125
pt = self.instance.templates.load(tplname)
21412126
# let the template render figure stuff out
@@ -2189,8 +2174,7 @@ def renderContext(self):
21892174
# than the one we tried to generate above.
21902175
if sys.version_info[0] > 2:
21912176
raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
2192-
else:
2193-
exec('raise exc_info[0], exc_info[1], exc_info[2]') # nosec
2177+
exec('raise exc_info[0], exc_info[1], exc_info[2]') # nosec
21942178

21952179
def renderError(self, error, response_code=400, use_template=True):
21962180
self.response_code = response_code
@@ -2222,7 +2206,7 @@ def renderError(self, error, response_code=400, use_template=True):
22222206

22232207
args = {
22242208
'ok_message': self._ok_message,
2225-
'error_message': self._error_message
2209+
'error_message': self._error_message,
22262210
}
22272211

22282212
try:
@@ -2573,7 +2557,7 @@ def handle_range_header(self, length, etag):
25732557
# If the condition doesn't match the entity tag, then we
25742558
# must send the client the entire file.
25752559
if if_range != etag:
2576-
return
2560+
return None
25772561
# The grammar for the Range header value is:
25782562
#
25792563
# ranges-specifier = byte-ranges-specifier
@@ -2761,13 +2745,10 @@ def write_file(self, filename):
27612745
self._socket_op(self.request.sendfile, filename, offset, length)
27622746
return
27632747
# Fallback to the "write" operation.
2764-
f = open(filename, 'rb')
2765-
try:
2748+
with open(filename, 'rb') as f:
27662749
if offset:
27672750
f.seek(offset)
27682751
content = f.read(length)
2769-
finally:
2770-
f.close()
27712752
self.write(content)
27722753

27732754
def setHeader(self, header, value):

0 commit comments

Comments
 (0)