Don't use len() to test emptiness vs not emptiness

Meson has a common pattern of using 'if len(foo) == 0:' or
'if len(foo) != 0:', however, this is a common anti-pattern in python.
Instead tests for emptiness/non-emptiness should be done with a simple
'if foo:' or 'if not foo:'

Consider the following:
>>> import timeit
>>> timeit.timeit('if len([]) == 0: pass')
0.10730923599840025
>>> timeit.timeit('if not []: pass')
0.030033907998586074
>>> timeit.timeit('if len(['a', 'b', 'c', 'd']) == 0: pass')
0.1154778649979562
>>> timeit.timeit("if not ['a', 'b', 'c', 'd']: pass")
0.08259823200205574
>>> timeit.timeit('if len("") == 0: pass')
0.089759664999292
>>> timeit.timeit('if not "": pass')
0.02340641999762738
>>> timeit.timeit('if len("foo") == 0: pass')
0.08848102600313723
>>> timeit.timeit('if not "foo": pass')
0.04032287199879647

And for the one additional case of 'if len(foo.strip()) == 0', which can
be replaced with 'if not foo.isspace()'
>>> timeit.timeit('if len("   ".strip()) == 0: pass')
0.15294511600222904
>>> timeit.timeit('if "   ".isspace(): pass')
0.09413968399894657
>>> timeit.timeit('if len("   abc".strip()) == 0: pass')
0.2023209120015963
>>> timeit.timeit('if "   abc".isspace(): pass')
0.09571301700270851

In other words, it's always a win to not use len(), when you don't
actually want to check the length.
pull/1452/merge
Dylan Baker 8 years ago committed by Jussi Pakkanen
parent ae924b01a0
commit a8173630ea
  1. 2
      ghwt.py
  2. 2
      mesonbuild/backend/backends.py
  3. 6
      mesonbuild/backend/ninjabackend.py
  4. 2
      mesonbuild/backend/vs2010backend.py
  5. 16
      mesonbuild/build.py
  6. 16
      mesonbuild/compilers.py
  7. 6
      mesonbuild/dependencies.py
  8. 6
      mesonbuild/interpreter.py
  9. 14
      mesonbuild/interpreterbase.py
  10. 12
      mesonbuild/mconf.py
  11. 4
      mesonbuild/mesonmain.py
  12. 2
      mesonbuild/modules/gnome.py
  13. 2
      mesonbuild/scripts/depfixer.py
  14. 2
      mesonbuild/scripts/uninstall.py
  15. 4
      mesonbuild/wrap/wraptool.py
  16. 4
      mesontest.py
  17. 4
      run_project_tests.py

@ -85,7 +85,7 @@ def install(sproj):
return unpack(sproj, branch, sproj_dir)
def run(args):
if len(args) == 0 or args[0] == '-h' or args[0] == '--help':
if not args or args[0] == '-h' or args[0] == '--help':
print(sys.argv[0], 'list/install', 'package_name')
return 1
command = args[0]

@ -328,7 +328,7 @@ class Backend:
includeargs = compiler.get_include_args(pchpath, False)
for lang in ['c', 'cpp']:
p = target.get_pch(lang)
if len(p) == 0:
if not p:
continue
if compiler.can_compile(p[-1]):
header = p[0]

@ -1048,7 +1048,7 @@ int dummy;
"""Vala is compiled into C. Set up all necessary build steps here."""
(vala_src, vapi_src, other_src) = self.split_vala_sources(target)
extra_dep_files = []
if len(vala_src) == 0:
if not vala_src:
msg = 'Vala library {!r} has no Vala source files.'
raise InvalidArguments(msg.format(target.name))
@ -2034,7 +2034,7 @@ rule FORTRAN_DEP_HACK
pchlist = target.get_pch(compiler.language)
else:
pchlist = []
if len(pchlist) == 0:
if not pchlist:
pch_dep = []
elif compiler.id == 'intel':
pch_dep = []
@ -2139,7 +2139,7 @@ rule FORTRAN_DEP_HACK
cstr = '_CROSS'
for lang in ['c', 'cpp']:
pch = target.get_pch(lang)
if len(pch) == 0:
if not pch:
continue
if '/' not in pch[0] or '/' not in pch[-1]:
msg = 'Precompiled header of {!r} must not be in the same ' \

@ -865,7 +865,7 @@ class Vs2010Backend(backends.Backend):
pch_sources = {}
for lang in ['c', 'cpp']:
pch = target.get_pch(lang)
if len(pch) == 0:
if not pch:
continue
pch_node.text = 'Use'
pch_sources[lang] = [pch[0], pch[1], lang]

@ -115,7 +115,7 @@ class Build:
self.compilers[lang] = compiler
def add_cross_compiler(self, compiler):
if len(self.cross_compilers) == 0:
if not self.cross_compilers:
self.static_cross_linker = self.environment.detect_static_linker(compiler)
lang = compiler.get_language()
if lang not in self.cross_compilers:
@ -340,9 +340,7 @@ class BuildTarget(Target):
self.process_objectlist(objects)
self.process_kwargs(kwargs, environment)
self.check_unknown_kwargs(kwargs)
if len(self.sources) == 0 \
and len(self.generated) == 0 \
and len(self.objects) == 0:
if not self.sources and not self.generated and not self.objects:
raise InvalidArguments('Build target %s has no sources.' % name)
self.process_compilers()
self.validate_sources()
@ -433,7 +431,7 @@ class BuildTarget(Target):
We also add compilers that were used by extracted objects to simplify
dynamic linker determination.
'''
if len(self.sources) + len(self.generated) + len(self.objects) == 0:
if not self.sources and not self.generated and not self.objects:
return
# Populate list of compilers
if self.is_cross:
@ -488,7 +486,7 @@ class BuildTarget(Target):
self.compilers['c'] = compilers['c']
def validate_sources(self):
if len(self.sources) == 0:
if not self.sources:
return
for lang in ('cs', 'java'):
if lang in self.compilers:
@ -675,7 +673,7 @@ class BuildTarget(Target):
if 'name_prefix' in kwargs:
name_prefix = kwargs['name_prefix']
if isinstance(name_prefix, list):
if len(name_prefix) != 0:
if name_prefix:
raise InvalidArguments('name_prefix array must be empty to signify null.')
elif not isinstance(name_prefix, str):
raise InvalidArguments('name_prefix must be a string.')
@ -684,7 +682,7 @@ class BuildTarget(Target):
if 'name_suffix' in kwargs:
name_suffix = kwargs['name_suffix']
if isinstance(name_suffix, list):
if len(name_suffix) != 0:
if name_suffix:
raise InvalidArguments('name_suffix array must be empty to signify null.')
else:
if not isinstance(name_suffix, str):
@ -825,7 +823,7 @@ You probably should put it in link_with instead.''')
self.link_whole_targets.append(t)
def add_pch(self, language, pchlist):
if len(pchlist) == 0:
if not pchlist:
return
elif len(pchlist) == 1:
if not environment.is_header(pchlist[0]):

@ -317,12 +317,12 @@ def get_base_link_args(options, linker, is_shared_module):
return args
def build_unix_rpath_args(build_dir, rpath_paths, install_rpath):
if len(rpath_paths) == 0 and len(install_rpath) == 0:
if not rpath_paths and not install_rpath:
return []
paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths])
if len(paths) < len(install_rpath):
padding = 'X' * (len(install_rpath) - len(paths))
if len(paths) == 0:
if not paths:
paths = padding
else:
paths = paths + ':' + padding
@ -388,7 +388,7 @@ class CompilerArgs(list):
if len(args) > 2:
raise TypeError("CompilerArgs() only accepts at most 2 arguments: "
"The compiler, and optionally an initial list")
elif len(args) == 0:
elif not args:
return cargs
elif len(args) == 1:
if isinstance(args[0], (Compiler, StaticLinker)):
@ -708,7 +708,7 @@ class Compiler:
return self.get_std_shared_lib_link_args()
def get_link_whole_for(self, args):
if isinstance(args, list) and len(args) == 0:
if isinstance(args, list) and not args:
return []
raise EnvironmentException('Language %s does not support linking whole archives.' % self.language)
@ -1360,7 +1360,7 @@ class CCompiler(Compiler):
extra_dirs = [extra_dirs]
# Gcc + co seem to prefer builtin lib dirs to -L dirs.
# Only try to find std libs if no extra dirs specified.
if len(extra_dirs) == 0:
if not extra_dirs:
args = ['-l' + libname]
if self.links(code, env, extra_args=args):
return args
@ -1700,7 +1700,7 @@ class ValaCompiler(Compiler):
extra_dirs = [extra_dirs]
# Valac always looks in the default vapi dir, so only search there if
# no extra dirs are specified.
if len(extra_dirs) == 0:
if not extra_dirs:
code = 'class MesonFindLibrary : Object { }'
vapi_args = ['--pkg', libname]
args = self.get_cross_extra_flags(env, link=False)
@ -1892,12 +1892,12 @@ class DCompiler(Compiler):
def build_rpath_args(self, build_dir, rpath_paths, install_rpath):
# This method is to be used by LDC and DMD.
# GDC can deal with the verbatim flags.
if len(rpath_paths) == 0 and len(install_rpath) == 0:
if not rpath_paths and not install_rpath:
return []
paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths])
if len(paths) < len(install_rpath):
padding = 'X' * (len(install_rpath) - len(paths))
if len(paths) == 0:
if not paths:
paths = padding
else:
paths = paths + ':' + padding

@ -777,7 +777,7 @@ class BoostDependency(Dependency):
else:
libdir = []
# Can't find libdir, bail
if len(libdir) == 0:
if not libdir:
return
libdir = libdir[0]
self.libdir = libdir
@ -1021,7 +1021,7 @@ class QtBaseDependency(Dependency):
self.is_found = False
if isinstance(mods, str):
mods = [mods]
if len(mods) == 0:
if not mods:
raise DependencyException('No ' + self.qtname + ' modules specified.')
type_text = 'cross' if env.is_cross_build() else 'native'
found_msg = '{} {} {{}} dependency (modules: {}) found:' \
@ -1332,7 +1332,7 @@ class AppleFrameworks(Dependency):
modules = kwargs.get('modules', [])
if isinstance(modules, str):
modules = [modules]
if len(modules) == 0:
if not modules:
raise DependencyException("AppleFrameworks dependency requires at least one module.")
self.frameworks = modules

@ -1581,7 +1581,7 @@ class Interpreter(InterpreterBase):
@noKwargs
def func_configuration_data(self, node, args, kwargs):
if len(args) != 0:
if args:
raise InterpreterException('configuration_data takes no arguments')
return ConfigurationDataHolder()
@ -1818,7 +1818,7 @@ class Interpreter(InterpreterBase):
self.coredata.base_options[optname] = oobj
def func_find_program(self, node, args, kwargs):
if len(args) == 0:
if not args:
raise InterpreterException('No program name specified.')
required = kwargs.get('required', True)
if not isinstance(required, bool):
@ -2533,7 +2533,7 @@ different subdirectory.
self.coredata.target_guids[idname] = str(uuid.uuid4()).upper()
def build_target(self, node, args, kwargs, targetholder):
if len(args) == 0:
if not args:
raise InterpreterException('Target does not have a name.')
name = args[0]
sources = args[1:]

@ -34,7 +34,7 @@ def check_stringlist(a, msg='Arguments must be strings.'):
def noPosargs(f):
@wraps(f)
def wrapped(self, node, args, kwargs):
if len(args) != 0:
if args:
raise InvalidArguments('Function does not take positional arguments.')
return f(self, node, args, kwargs)
return wrapped
@ -42,7 +42,7 @@ def noPosargs(f):
def noKwargs(f):
@wraps(f)
def wrapped(self, node, args, kwargs):
if len(kwargs) != 0:
if kwargs:
raise InvalidArguments('Function does not take keyword arguments.')
return f(self, node, args, kwargs)
return wrapped
@ -94,7 +94,7 @@ class InterpreterBase:
raise InvalidArguments('Missing Meson file in %s' % mesonfile)
with open(mesonfile, encoding='utf8') as mf:
code = mf.read()
if len(code.strip()) == 0:
if code.isspace():
raise InvalidCode('Builder file is empty.')
assert(isinstance(code, str))
try:
@ -113,7 +113,7 @@ class InterpreterBase:
def sanity_check_ast(self):
if not isinstance(self.ast, mparser.CodeBlockNode):
raise InvalidCode('AST is of invalid type. Possibly a bug in the parser.')
if len(self.ast.lines) == 0:
if not self.ast.lines:
raise InvalidCode('No statements in code.')
first = self.ast.lines[0]
if not isinstance(first, mparser.FunctionNode) or first.func_name != 'project':
@ -405,7 +405,7 @@ class InterpreterBase:
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'to_string':
if len(posargs) == 0:
if not posargs:
if obj:
return 'true'
else:
@ -429,12 +429,12 @@ class InterpreterBase:
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'is_even':
if len(posargs) == 0:
if not posargs:
return obj % 2 == 0
else:
raise InterpreterException('int.is_even() must have no arguments.')
elif method_name == 'is_odd':
if len(posargs) == 0:
if not posargs:
return obj % 2 != 0
else:
raise InterpreterException('int.is_odd() must have no arguments.')

@ -56,7 +56,7 @@ class Conf:
# Ninja is run.
def print_aligned(self, arr):
if len(arr) == 0:
if not arr:
return
titles = ['Option', 'Description', 'Current Value', '']
longest_name = len(titles[0])
@ -139,7 +139,7 @@ class Conf:
print('')
print('Base options:')
okeys = sorted(self.coredata.base_options.keys())
if len(okeys) == 0:
if not okeys:
print(' No base options\n')
else:
coarr = []
@ -158,7 +158,7 @@ class Conf:
print('')
print('Compiler options:')
okeys = sorted(self.coredata.compiler_options.keys())
if len(okeys) == 0:
if not okeys:
print(' No compiler options\n')
else:
coarr = []
@ -188,7 +188,7 @@ class Conf:
self.print_aligned(parr)
print('')
print('Project options:')
if len(self.coredata.user_options) == 0:
if not self.coredata.user_options:
print(' This project does not have any options')
else:
options = self.coredata.user_options
@ -197,7 +197,7 @@ class Conf:
optarr = []
for key in keys:
opt = options[key]
if (opt.choices is None) or (len(opt.choices) == 0):
if (opt.choices is None) or (not opt.choices):
# Zero length list or string
choices = ''
else:
@ -222,7 +222,7 @@ def run(args):
print('%s <build directory>' % args[0])
print('If you omit the build directory, the current directory is substituted.')
return 1
if len(options.directory) == 0:
if not options.directory:
builddir = os.getcwd()
else:
builddir = options.directory[0]

@ -269,10 +269,10 @@ def run(mainfile, args):
args = mesonlib.expand_arguments(args)
options = parser.parse_args(args)
args = options.directories
if len(args) == 0 or len(args) > 2:
if not args or len(args) > 2:
# if there's a meson.build in the dir above, and not in the current
# directory, assume we're in the build directory
if len(args) == 0 and not os.path.exists('meson.build') and os.path.exists('../meson.build'):
if not args and not os.path.exists('meson.build') and os.path.exists('../meson.build'):
dir1 = '..'
dir2 = '.'
else:

@ -566,7 +566,7 @@ class GnomeModule(ExtensionModule):
return ModuleReturnValue(rv, rv)
def compile_schemas(self, state, args, kwargs):
if len(args) != 0:
if args:
raise MesonException('Compile_schemas does not take positional arguments.')
srcdir = os.path.join(state.build_to_src, state.subdir)
outdir = state.subdir

@ -305,7 +305,7 @@ class Elf(DataSizes):
# the chance of obliterating other strings. It might still happen
# but our behaviour is identical to what chrpath does and it has
# been in use for ages so based on that this should be rare.
if len(new_rpath) == 0:
if not new_rpath:
self.remove_rpath_entry(entrynum)
else:
self.bf.seek(rp_off)

@ -36,7 +36,7 @@ def do_uninstall(log):
print('\nRemember that files created by custom scripts have not been removed.')
def run(args):
if len(args) != 0:
if args:
print('Weird error.')
return 1
if not os.path.exists(logfile):

@ -135,7 +135,7 @@ def update(name):
def info(name):
jd = get_result(API_ROOT + 'projects/' + name)
versions = jd['versions']
if len(versions) == 0:
if not versions:
print('No available versions of', name)
sys.exit(0)
print('Available versions of %s:' % name)
@ -162,7 +162,7 @@ def status():
print('', name, 'not up to date. Have %s %d, but %s %d is available.' % (current_branch, current_revision, latest_branch, latest_revision))
def run(args):
if len(args) == 0 or args[0] == '-h' or args[0] == '--help':
if not args or args[0] == '-h' or args[0] == '--help':
print_help()
return 0
command = args[0]

@ -364,7 +364,7 @@ TIMEOUT: %4d
return False
def test_suitable(self, test):
return (len(self.options.include_suites) == 0 or TestHarness.test_in_suites(test, self.options.include_suites)) \
return (not self.options.include_suites or TestHarness.test_in_suites(test, self.options.include_suites)) \
and not TestHarness.test_in_suites(test, self.options.exclude_suites)
def load_suites(self):
@ -610,7 +610,7 @@ def run(args):
if options.list:
list_tests(th)
return 0
if len(options.args) == 0:
if not options.args:
return th.doit()
return th.run_special()

@ -368,7 +368,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
if returncode != 0:
return TestResult('Running unit tests failed.', BuildStep.test, stdo, stde, mesonlog, gen_time, build_time, test_time)
# Do installation, if the backend supports it
if len(install_commands) != 0:
if install_commands:
env = os.environ.copy()
env['DESTDIR'] = install_dir
# Install with subprocess
@ -384,7 +384,7 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
stde += e
if pi.returncode != 0:
return TestResult('Running clean failed.', BuildStep.clean, stdo, stde, mesonlog, gen_time, build_time, test_time)
if len(install_commands) == 0:
if not install_commands:
return TestResult('', BuildStep.install, '', '', mesonlog, gen_time, build_time, test_time)
return TestResult(validate_install(testdir, install_dir, compiler), BuildStep.validate, stdo, stde, mesonlog, gen_time, build_time, test_time)

Loading…
Cancel
Save