Browse Source

Merge pull request #213 from takluyver/check-entry-points

Better error messages for invalid entry points
Thomas Kluyver 4 years ago
parent
commit
1fb17f659d
2 changed files with 29 additions and 3 deletions
  1. 16 3
      nsist/__init__.py
  2. 13 0
      nsist/tests/test_misc.py

+ 16 - 3
nsist/__init__.py

@@ -57,6 +57,18 @@ class InputError(ValueError):
     def __str__(self):
         return "{e.value!r} is not valid for {e.param}, expected {e.expected}".format(e=self)
 
+
+def split_entry_point(ep: str):
+    """Like ep.split(':'), but with extra checks and helpful errors"""
+    module, _, func = ep.partition(':')
+    if all([s.isidentifier() for s in module.split('.')]) and func.isidentifier():
+        return module, func
+
+    raise InputError(
+        'entry point', ep, "'mod:func', so 'from mod import func' works"
+    )
+
+
 class InstallerBuilder(object):
     """Controls building an installer. This includes three main steps:
 
@@ -262,7 +274,7 @@ if __name__ == '__main__':
         py_version and py_bitness are used to write an appropriate shebang line
         for the PEP 397 Windows launcher.
         """
-        module, func = entrypt.split(":")
+        module, func = split_entry_point(entrypt)
         with open(target, 'w') as f:
             f.write(self.SCRIPT_TEMPLATE.format(qualifier=self.py_qualifier,
                     module=module, func=func, extra_preamble=extra_preamble))
@@ -351,6 +363,8 @@ if __name__ == '__main__':
                      py_version=self.py_version, exclude=self.exclude)
 
     def prepare_commands(self):
+        for cmd in self.commands.values():
+            split_entry_point(cmd['entry_point'])  # Check entry point format
         command_dir = Path(self.build_dir) / 'bin'
         command_dir.mkdir()
         prepare_bin_directory(command_dir, self.commands, bitness=self.py_bitness)
@@ -509,13 +523,12 @@ def main(argv=None):
     from . import configreader
     try:
         cfg = configreader.read_and_validate(config_file)
+        args = get_installer_builder_args(cfg)
     except configreader.InvalidConfig as e:
         logger.error('Error parsing configuration file:')
         logger.error(str(e))
         sys.exit(1)
 
-    args = get_installer_builder_args(cfg)
-
     try:
         ec = InstallerBuilder(**args).run(makensis=(not options.no_makensis))
     except InputError as e:

+ 13 - 0
nsist/tests/test_misc.py

@@ -0,0 +1,13 @@
+import pytest
+
+from nsist import InputError, split_entry_point
+
+def test_split_entry_point():
+    assert split_entry_point('mod:func') == ('mod', 'func')
+    assert split_entry_point('mod.submod:func') == ('mod.submod', 'func')
+
+    with pytest.raises(InputError):
+        split_entry_point('.\\src\\main:tf2_discord')  # Github issue 205
+
+    with pytest.raises(InputError):
+        split_entry_point('mod:1func')  # Identifier can't start with number