prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Importing shellcraft submodules doesn't work
  ```
  $ python
  >>> import pwnlib.shellcraft.arm
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  ImportError: No module named arm
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pwnlib/shellcraft/__init__.py`
  Content:
  ```
  1 from types import ModuleType
  2 import sys, os, re
  3 from . import internal
  4 from ..context import context
  5 
  6 class module(ModuleType):
  7     def __init__(self, name, directory):
  8         super(module, self).__init__(name)
  9 
  10         # Insert nice properties
  11         self.__dict__.update({
  12             '__file__':    __file__,
  13             '__package__': __package__,
  14             '__path__':    __path__,
  15         })
  16 
  17         # Save the shellcode directory
  18         self._dir = directory
  19 
  20         # Find the absolute path of the directory
  21         self._absdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', self._dir)
  22 
  23         # Get the docstring
  24         with open(os.path.join(self._absdir, "__doc__")) as fd:
  25             self.__doc__ = fd.read()
  26 
  27         # Insert into the module list
  28         sys.modules[self.__name__] = self
  29 
  30     def __lazyinit__(self):
  31 
  32         # Create a dictionary of submodules
  33         self._submodules = {}
  34         self._shellcodes = {}
  35         for name in os.listdir(self._absdir):
  36             path = os.path.join(self._absdir, name)
  37             if os.path.isdir(path):
  38                 self._submodules[name] = module(self.__name__ + '.' + name, os.path.join(self._dir, name))
  39             elif os.path.isfile(path) and name != '__doc__' and name[0] != '.':
  40                 funcname, _ext = os.path.splitext(name)
  41                 if not re.match('^[a-zA-Z][a-zA-Z0-9_]*$', funcname):
  42                     raise ValueError("found illegal filename, %r" % name)
  43                 self._shellcodes[funcname] = name
  44 
  45         # Put the submodules into toplevel
  46         self.__dict__.update(self._submodules)
  47 
  48         # These are exported
  49         self.__all__ = sorted(self._shellcodes.keys() + self._submodules.keys())
  50 
  51         # Make sure this is not called again
  52         self.__lazyinit__ = None
  53 
  54     def __getattr__(self, key):
  55         self.__lazyinit__ and self.__lazyinit__()
  56 
  57         # Maybe the lazyinit added it
  58         if key in self.__dict__:
  59             return self.__dict__[key]
  60 
  61         # This function lazy-loads the shellcodes
  62         if key in self._shellcodes:
  63             real = internal.make_function(key, self._shellcodes[key], self._dir)
  64             setattr(self, key, real)
  65             return real
  66 
  67         for m in self._context_modules():
  68             try:
  69                 return getattr(m, key)
  70             except AttributeError:
  71                 pass
  72 
  73         raise AttributeError("'module' object has no attribute '%s'" % key)
  74 
  75     def __dir__(self):
  76         # This function lists the available submodules, available shellcodes
  77         # and potentially shellcodes available in submodules that should be
  78         # avilable because of the context
  79         self.__lazyinit__ and self.__lazyinit__()
  80 
  81         result = list(self._submodules.keys())
  82         result.extend(('__file__', '__package__', '__path__',
  83                        '__all__',  '__name__'))
  84         result.extend(self.__shellcodes__())
  85 
  86         return result
  87 
  88     def _context_modules(self):
  89         self.__lazyinit__ and self.__lazyinit__()
  90         for k, m in self._submodules.items():
  91             if k in [context.arch, context.os]:
  92                 yield m
  93 
  94     def __shellcodes__(self):
  95         self.__lazyinit__ and self.__lazyinit__()
  96         result = self._shellcodes.keys()
  97         for m in self._context_modules():
  98             result.extend(m.__shellcodes__())
  99         return result
  100 
  101 # To prevent garbage collection
  102 tether = sys.modules[__name__]
  103 
  104 # Create the module structure
  105 module(__name__, '')
  106
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/pwnlib/shellcraft/__init__.py b/pwnlib/shellcraft/__init__.py
  --- a/pwnlib/shellcraft/__init__.py
  +++ b/pwnlib/shellcraft/__init__.py
  @@ -102,4 +102,22 @@
   tether = sys.modules[__name__]
   
   # Create the module structure
  -module(__name__, '')
  +shellcraft = module(__name__, '')
  +
  +class LazyImporter:
  +    def find_module(self, fullname, path):
  +        if not fullname.startswith('pwnlib.shellcraft.'):
  +            return None
  +
  +        parts = fullname.split('.')[2:]
  +        cur = shellcraft
  +        for part in parts:
  +            cur = getattr(cur, part, None)
  +            if not isinstance(cur, ModuleType):
  +                return None
  +
  +        return self
  +
  +    def load_module(self, fullname):
  +        return sys.modules[fullname]
  +sys.meta_path.append(LazyImporter())
  
verification_info: {"golden_diff": "diff --git a/pwnlib/shellcraft/__init__.py b/pwnlib/shellcraft/__init__.py\n--- a/pwnlib/shellcraft/__init__.py\n+++ b/pwnlib/shellcraft/__init__.py\n@@ -102,4 +102,22 @@\n tether = sys.modules[__name__]\n \n # Create the module structure\n-module(__name__, '')\n+shellcraft = module(__name__, '')\n+\n+class LazyImporter:\n+    def find_module(self, fullname, path):\n+        if not fullname.startswith('pwnlib.shellcraft.'):\n+            return None\n+\n+        parts = fullname.split('.')[2:]\n+        cur = shellcraft\n+        for part in parts:\n+            cur = getattr(cur, part, None)\n+            if not isinstance(cur, ModuleType):\n+                return None\n+\n+        return self\n+\n+    def load_module(self, fullname):\n+        return sys.modules[fullname]\n+sys.meta_path.append(LazyImporter())\n", "issue": "Importing shellcraft submodules doesn't work\n```\n$ python\n>>> import pwnlib.shellcraft.arm\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nImportError: No module named arm\n```\n\n", "before_files": [{"content": "from types import ModuleType\nimport sys, os, re\nfrom . import internal\nfrom ..context import context\n\nclass module(ModuleType):\n    def __init__(self, name, directory):\n        super(module, self).__init__(name)\n\n        # Insert nice properties\n        self.__dict__.update({\n            '__file__':    __file__,\n            '__package__': __package__,\n            '__path__':    __path__,\n        })\n\n        # Save the shellcode directory\n        self._dir = directory\n\n        # Find the absolute path of the directory\n        self._absdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', self._dir)\n\n        # Get the docstring\n        with open(os.path.join(self._absdir, \"__doc__\")) as fd:\n            self.__doc__ = fd.read()\n\n        # Insert into the module list\n        sys.modules[self.__name__] = self\n\n    def __lazyinit__(self):\n\n        # Create a dictionary of submodules\n        self._submodules = {}\n        self._shellcodes = {}\n        for name in os.listdir(self._absdir):\n            path = os.path.join(self._absdir, name)\n            if os.path.isdir(path):\n                self._submodules[name] = module(self.__name__ + '.' + name, os.path.join(self._dir, name))\n            elif os.path.isfile(path) and name != '__doc__' and name[0] != '.':\n                funcname, _ext = os.path.splitext(name)\n                if not re.match('^[a-zA-Z][a-zA-Z0-9_]*$', funcname):\n                    raise ValueError(\"found illegal filename, %r\" % name)\n                self._shellcodes[funcname] = name\n\n        # Put the submodules into toplevel\n        self.__dict__.update(self._submodules)\n\n        # These are exported\n        self.__all__ = sorted(self._shellcodes.keys() + self._submodules.keys())\n\n        # Make sure this is not called again\n        self.__lazyinit__ = None\n\n    def __getattr__(self, key):\n        self.__lazyinit__ and self.__lazyinit__()\n\n        # Maybe the lazyinit added it\n        if key in self.__dict__:\n            return self.__dict__[key]\n\n        # This function lazy-loads the shellcodes\n        if key in self._shellcodes:\n            real = internal.make_function(key, self._shellcodes[key], self._dir)\n            setattr(self, key, real)\n            return real\n\n        for m in self._context_modules():\n            try:\n                return getattr(m, key)\n            except AttributeError:\n                pass\n\n        raise AttributeError(\"'module' object has no attribute '%s'\" % key)\n\n    def __dir__(self):\n        # This function lists the available submodules, available shellcodes\n        # and potentially shellcodes available in submodules that should be\n        # avilable because of the context\n        self.__lazyinit__ and self.__lazyinit__()\n\n        result = list(self._submodules.keys())\n        result.extend(('__file__', '__package__', '__path__',\n                       '__all__',  '__name__'))\n        result.extend(self.__shellcodes__())\n\n        return result\n\n    def _context_modules(self):\n        self.__lazyinit__ and self.__lazyinit__()\n        for k, m in self._submodules.items():\n            if k in [context.arch, context.os]:\n                yield m\n\n    def __shellcodes__(self):\n        self.__lazyinit__ and self.__lazyinit__()\n        result = self._shellcodes.keys()\n        for m in self._context_modules():\n            result.extend(m.__shellcodes__())\n        return result\n\n# To prevent garbage collection\ntether = sys.modules[__name__]\n\n# Create the module structure\nmodule(__name__, '')\n", "path": "pwnlib/shellcraft/__init__.py"}], "after_files": [{"content": "from types import ModuleType\nimport sys, os, re\nfrom . import internal\nfrom ..context import context\n\nclass module(ModuleType):\n    def __init__(self, name, directory):\n        super(module, self).__init__(name)\n\n        # Insert nice properties\n        self.__dict__.update({\n            '__file__':    __file__,\n            '__package__': __package__,\n            '__path__':    __path__,\n        })\n\n        # Save the shellcode directory\n        self._dir = directory\n\n        # Find the absolute path of the directory\n        self._absdir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates', self._dir)\n\n        # Get the docstring\n        with open(os.path.join(self._absdir, \"__doc__\")) as fd:\n            self.__doc__ = fd.read()\n\n        # Insert into the module list\n        sys.modules[self.__name__] = self\n\n    def __lazyinit__(self):\n\n        # Create a dictionary of submodules\n        self._submodules = {}\n        self._shellcodes = {}\n        for name in os.listdir(self._absdir):\n            path = os.path.join(self._absdir, name)\n            if os.path.isdir(path):\n                self._submodules[name] = module(self.__name__ + '.' + name, os.path.join(self._dir, name))\n            elif os.path.isfile(path) and name != '__doc__' and name[0] != '.':\n                funcname, _ext = os.path.splitext(name)\n                if not re.match('^[a-zA-Z][a-zA-Z0-9_]*$', funcname):\n                    raise ValueError(\"found illegal filename, %r\" % name)\n                self._shellcodes[funcname] = name\n\n        # Put the submodules into toplevel\n        self.__dict__.update(self._submodules)\n\n        # These are exported\n        self.__all__ = sorted(self._shellcodes.keys() + self._submodules.keys())\n\n        # Make sure this is not called again\n        self.__lazyinit__ = None\n\n    def __getattr__(self, key):\n        self.__lazyinit__ and self.__lazyinit__()\n\n        # Maybe the lazyinit added it\n        if key in self.__dict__:\n            return self.__dict__[key]\n\n        # This function lazy-loads the shellcodes\n        if key in self._shellcodes:\n            real = internal.make_function(key, self._shellcodes[key], self._dir)\n            setattr(self, key, real)\n            return real\n\n        for m in self._context_modules():\n            try:\n                return getattr(m, key)\n            except AttributeError:\n                pass\n\n        raise AttributeError(\"'module' object has no attribute '%s'\" % key)\n\n    def __dir__(self):\n        # This function lists the available submodules, available shellcodes\n        # and potentially shellcodes available in submodules that should be\n        # avilable because of the context\n        self.__lazyinit__ and self.__lazyinit__()\n\n        result = list(self._submodules.keys())\n        result.extend(('__file__', '__package__', '__path__',\n                       '__all__',  '__name__'))\n        result.extend(self.__shellcodes__())\n\n        return result\n\n    def _context_modules(self):\n        self.__lazyinit__ and self.__lazyinit__()\n        for k, m in self._submodules.items():\n            if k in [context.arch, context.os]:\n                yield m\n\n    def __shellcodes__(self):\n        self.__lazyinit__ and self.__lazyinit__()\n        result = self._shellcodes.keys()\n        for m in self._context_modules():\n            result.extend(m.__shellcodes__())\n        return result\n\n# To prevent garbage collection\ntether = sys.modules[__name__]\n\n# Create the module structure\nshellcraft = module(__name__, '')\n\nclass LazyImporter:\n    def find_module(self, fullname, path):\n        if not fullname.startswith('pwnlib.shellcraft.'):\n            return None\n\n        parts = fullname.split('.')[2:]\n        cur = shellcraft\n        for part in parts:\n            cur = getattr(cur, part, None)\n            if not isinstance(cur, ModuleType):\n                return None\n\n        return self\n\n    def load_module(self, fullname):\n        return sys.modules[fullname]\nsys.meta_path.append(LazyImporter())\n", "path": "pwnlib/shellcraft/__init__.py"}]}