We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
jitclass __doc__ passthrough to instance
Jitclass is not exposing the docstring of the class nor the methods.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `numba/jitclass/boxing.py`
Content:
```
1 """
2 Implement logic relating to wrapping (box) and unwrapping (unbox) instances
3 of jitclasses for use inside the python interpreter.
4 """
5 from __future__ import print_function, absolute_import
6 
7 from functools import wraps, partial
8 
9 from llvmlite import ir
10 
11 from numba import types, cgutils
12 from numba.pythonapi import box, unbox, NativeValue
13 from numba import njit
14 from numba.six import exec_
15 from . import _box
16 
17 
18 _getter_code_template = """
19 def accessor(__numba_self_):
20     return __numba_self_.{0}
21 """
22 
23 _setter_code_template = """
24 def mutator(__numba_self_, __numba_val):
25     __numba_self_.{0} = __numba_val
26 """
27 
28 _method_code_template = """
29 def method(__numba_self_, *args):
30     return __numba_self_.{method}(*args)
31 """
32 
33 
34 def _generate_property(field, template, fname):
35     """
36     Generate simple function that get/set a field of the instance
37     """
38     source = template.format(field)
39     glbls = {}
40     exec_(source, glbls)
41     return njit(glbls[fname])
42 
43 
44 _generate_getter = partial(_generate_property, template=_getter_code_template,
45                            fname='accessor')
46 _generate_setter = partial(_generate_property, template=_setter_code_template,
47                            fname='mutator')
48 
49 
50 def _generate_method(name, func):
51     """
52     Generate a wrapper for calling a method.  Note the wrapper will only
53     accept positional arguments.
54     """
55     source = _method_code_template.format(method=name)
56     glbls = {}
57     exec_(source, glbls)
58     method = njit(glbls['method'])
59 
60     @wraps(func)
61     def wrapper(*args, **kwargs):
62         return method(*args, **kwargs)
63 
64     return wrapper
65 
66 
67 _cache_specialized_box = {}
68 
69 
70 def _specialize_box(typ):
71     """
72     Create a subclass of Box that is specialized to the jitclass.
73 
74     This function caches the result to avoid code bloat.
75     """
76     # Check cache
77     if typ in _cache_specialized_box:
78         return _cache_specialized_box[typ]
79     dct = {'__slots__': (),
80            '_numba_type_': typ}
81     # Inject attributes as class properties
82     for field in typ.struct:
83         getter = _generate_getter(field)
84         setter = _generate_setter(field)
85         dct[field] = property(getter, setter)
86     # Inject properties as class properties
87     for field, impdct in typ.jitprops.items():
88         getter = None
89         setter = None
90         if 'get' in impdct:
91             getter = _generate_getter(field)
92         if 'set' in impdct:
93             setter = _generate_setter(field)
94         dct[field] = property(getter, setter)
95     # Inject methods as class members
96     for name, func in typ.methods.items():
97         if not (name.startswith('__') and name.endswith('__')):
98             dct[name] = _generate_method(name, func)
99     # Create subclass
100     subcls = type(typ.classname, (_box.Box,), dct)
101     # Store to cache
102     _cache_specialized_box[typ] = subcls
103 
104     # Pre-compile attribute getter.
105     # Note: This must be done after the "box" class is created because
106     #       compiling the getter requires the "box" class to be defined.
107     for k, v in dct.items():
108         if isinstance(v, property):
109             prop = getattr(subcls, k)
110             if prop.fget is not None:
111                 fget = prop.fget
112                 fast_fget = fget.compile((typ,))
113                 fget.disable_compile()
114                 setattr(subcls, k,
115                         property(fast_fget, prop.fset, prop.fdel))
116 
117     return subcls
118 
119 
120 ###############################################################################
121 # Implement box/unbox for call wrapper
122 
123 @box(types.ClassInstanceType)
124 def _box_class_instance(typ, val, c):
125     meminfo, dataptr = cgutils.unpack_tuple(c.builder, val)
126 
127     # Create Box instance
128     box_subclassed = _specialize_box(typ)
129     # Note: the ``box_subclassed`` is kept alive by the cache
130     int_addr_boxcls = c.context.get_constant(types.uintp, id(box_subclassed))
131 
132     box_cls = c.builder.inttoptr(int_addr_boxcls, c.pyapi.pyobj)
133     box = c.pyapi.call_function_objargs(box_cls, ())
134 
135     # Initialize Box instance
136     llvoidptr = ir.IntType(8).as_pointer()
137     addr_meminfo = c.builder.bitcast(meminfo, llvoidptr)
138     addr_data = c.builder.bitcast(dataptr, llvoidptr)
139 
140     def set_member(member_offset, value):
141         # Access member by byte offset
142         offset = c.context.get_constant(types.uintp, member_offset)
143         ptr = cgutils.pointer_add(c.builder, box, offset)
144         casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())
145         c.builder.store(value, casted)
146 
147     set_member(_box.box_meminfoptr_offset, addr_meminfo)
148     set_member(_box.box_dataptr_offset, addr_data)
149     return box
150 
151 
152 @unbox(types.ClassInstanceType)
153 def _unbox_class_instance(typ, val, c):
154     def access_member(member_offset):
155         # Access member by byte offset
156         offset = c.context.get_constant(types.uintp, member_offset)
157         llvoidptr = ir.IntType(8).as_pointer()
158         ptr = cgutils.pointer_add(c.builder, val, offset)
159         casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())
160         return c.builder.load(casted)
161 
162     struct_cls = cgutils.create_struct_proxy(typ)
163     inst = struct_cls(c.context, c.builder)
164 
165     # load from Python object
166     ptr_meminfo = access_member(_box.box_meminfoptr_offset)
167     ptr_dataptr = access_member(_box.box_dataptr_offset)
168 
169     # store to native structure
170     inst.meminfo = c.builder.bitcast(ptr_meminfo, inst.meminfo.type)
171     inst.data = c.builder.bitcast(ptr_dataptr, inst.data.type)
172 
173     ret = inst._getvalue()
174 
175     c.context.nrt.incref(c.builder, typ, ret)
176 
177     return NativeValue(ret, is_error=c.pyapi.c_api_error())
178
```
--- 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()

```

diff --git a/numba/jitclass/boxing.py b/numba/jitclass/boxing.py
--- a/numba/jitclass/boxing.py
+++ b/numba/jitclass/boxing.py
@@ -77,7 +77,9 @@
     if typ in _cache_specialized_box:
         return _cache_specialized_box[typ]
     dct = {'__slots__': (),
-           '_numba_type_': typ}
+           '_numba_type_': typ,
+           '__doc__': typ.class_type.class_def.__doc__,
+           }
     # Inject attributes as class properties
     for field in typ.struct:
         getter = _generate_getter(field)
@@ -91,7 +93,10 @@
             getter = _generate_getter(field)
         if 'set' in impdct:
             setter = _generate_setter(field)
-        dct[field] = property(getter, setter)
+        # get docstring from either the fget or fset
+        imp = impdct.get('get') or impdct.get('set') or None
+        doc = getattr(imp, '__doc__', None)
+        dct[field] = property(getter, setter, doc=doc)
     # Inject methods as class members
     for name, func in typ.methods.items():
         if not (name.startswith('__') and name.endswith('__')):
@@ -112,7 +117,8 @@
                 fast_fget = fget.compile((typ,))
                 fget.disable_compile()
                 setattr(subcls, k,
-                        property(fast_fget, prop.fset, prop.fdel))
+                        property(fast_fget, prop.fset, prop.fdel,
+                                 doc=prop.__doc__))
 
     return subcls

{"golden_diff": "diff --git a/numba/jitclass/boxing.py b/numba/jitclass/boxing.py\n--- a/numba/jitclass/boxing.py\n+++ b/numba/jitclass/boxing.py\n@@ -77,7 +77,9 @@\n     if typ in _cache_specialized_box:\n         return _cache_specialized_box[typ]\n     dct = {'__slots__': (),\n-           '_numba_type_': typ}\n+           '_numba_type_': typ,\n+           '__doc__': typ.class_type.class_def.__doc__,\n+           }\n     # Inject attributes as class properties\n     for field in typ.struct:\n         getter = _generate_getter(field)\n@@ -91,7 +93,10 @@\n             getter = _generate_getter(field)\n         if 'set' in impdct:\n             setter = _generate_setter(field)\n-        dct[field] = property(getter, setter)\n+        # get docstring from either the fget or fset\n+        imp = impdct.get('get') or impdct.get('set') or None\n+        doc = getattr(imp, '__doc__', None)\n+        dct[field] = property(getter, setter, doc=doc)\n     # Inject methods as class members\n     for name, func in typ.methods.items():\n         if not (name.startswith('__') and name.endswith('__')):\n@@ -112,7 +117,8 @@\n                 fast_fget = fget.compile((typ,))\n                 fget.disable_compile()\n                 setattr(subcls, k,\n-                        property(fast_fget, prop.fset, prop.fdel))\n+                        property(fast_fget, prop.fset, prop.fdel,\n+                                 doc=prop.__doc__))\n \n     return subcls\n", "issue": "jitclass __doc__ passthrough to instance\nJitclass is not exposing the docstring of the class nor the methods.\n\n", "before_files": [{"content": "\"\"\"\nImplement logic relating to wrapping (box) and unwrapping (unbox) instances\nof jitclasses for use inside the python interpreter.\n\"\"\"\nfrom __future__ import print_function, absolute_import\n\nfrom functools import wraps, partial\n\nfrom llvmlite import ir\n\nfrom numba import types, cgutils\nfrom numba.pythonapi import box, unbox, NativeValue\nfrom numba import njit\nfrom numba.six import exec_\nfrom . import _box\n\n\n_getter_code_template = \"\"\"\ndef accessor(__numba_self_):\n    return __numba_self_.{0}\n\"\"\"\n\n_setter_code_template = \"\"\"\ndef mutator(__numba_self_, __numba_val):\n    __numba_self_.{0} = __numba_val\n\"\"\"\n\n_method_code_template = \"\"\"\ndef method(__numba_self_, *args):\n    return __numba_self_.{method}(*args)\n\"\"\"\n\n\ndef _generate_property(field, template, fname):\n    \"\"\"\n    Generate simple function that get/set a field of the instance\n    \"\"\"\n    source = template.format(field)\n    glbls = {}\n    exec_(source, glbls)\n    return njit(glbls[fname])\n\n\n_generate_getter = partial(_generate_property, template=_getter_code_template,\n                           fname='accessor')\n_generate_setter = partial(_generate_property, template=_setter_code_template,\n                           fname='mutator')\n\n\ndef _generate_method(name, func):\n    \"\"\"\n    Generate a wrapper for calling a method.  Note the wrapper will only\n    accept positional arguments.\n    \"\"\"\n    source = _method_code_template.format(method=name)\n    glbls = {}\n    exec_(source, glbls)\n    method = njit(glbls['method'])\n\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        return method(*args, **kwargs)\n\n    return wrapper\n\n\n_cache_specialized_box = {}\n\n\ndef _specialize_box(typ):\n    \"\"\"\n    Create a subclass of Box that is specialized to the jitclass.\n\n    This function caches the result to avoid code bloat.\n    \"\"\"\n    # Check cache\n    if typ in _cache_specialized_box:\n        return _cache_specialized_box[typ]\n    dct = {'__slots__': (),\n           '_numba_type_': typ}\n    # Inject attributes as class properties\n    for field in typ.struct:\n        getter = _generate_getter(field)\n        setter = _generate_setter(field)\n        dct[field] = property(getter, setter)\n    # Inject properties as class properties\n    for field, impdct in typ.jitprops.items():\n        getter = None\n        setter = None\n        if 'get' in impdct:\n            getter = _generate_getter(field)\n        if 'set' in impdct:\n            setter = _generate_setter(field)\n        dct[field] = property(getter, setter)\n    # Inject methods as class members\n    for name, func in typ.methods.items():\n        if not (name.startswith('__') and name.endswith('__')):\n            dct[name] = _generate_method(name, func)\n    # Create subclass\n    subcls = type(typ.classname, (_box.Box,), dct)\n    # Store to cache\n    _cache_specialized_box[typ] = subcls\n\n    # Pre-compile attribute getter.\n    # Note: This must be done after the \"box\" class is created because\n    #       compiling the getter requires the \"box\" class to be defined.\n    for k, v in dct.items():\n        if isinstance(v, property):\n            prop = getattr(subcls, k)\n            if prop.fget is not None:\n                fget = prop.fget\n                fast_fget = fget.compile((typ,))\n                fget.disable_compile()\n                setattr(subcls, k,\n                        property(fast_fget, prop.fset, prop.fdel))\n\n    return subcls\n\n\n###############################################################################\n# Implement box/unbox for call wrapper\n\n@box(types.ClassInstanceType)\ndef _box_class_instance(typ, val, c):\n    meminfo, dataptr = cgutils.unpack_tuple(c.builder, val)\n\n    # Create Box instance\n    box_subclassed = _specialize_box(typ)\n    # Note: the ``box_subclassed`` is kept alive by the cache\n    int_addr_boxcls = c.context.get_constant(types.uintp, id(box_subclassed))\n\n    box_cls = c.builder.inttoptr(int_addr_boxcls, c.pyapi.pyobj)\n    box = c.pyapi.call_function_objargs(box_cls, ())\n\n    # Initialize Box instance\n    llvoidptr = ir.IntType(8).as_pointer()\n    addr_meminfo = c.builder.bitcast(meminfo, llvoidptr)\n    addr_data = c.builder.bitcast(dataptr, llvoidptr)\n\n    def set_member(member_offset, value):\n        # Access member by byte offset\n        offset = c.context.get_constant(types.uintp, member_offset)\n        ptr = cgutils.pointer_add(c.builder, box, offset)\n        casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())\n        c.builder.store(value, casted)\n\n    set_member(_box.box_meminfoptr_offset, addr_meminfo)\n    set_member(_box.box_dataptr_offset, addr_data)\n    return box\n\n\n@unbox(types.ClassInstanceType)\ndef _unbox_class_instance(typ, val, c):\n    def access_member(member_offset):\n        # Access member by byte offset\n        offset = c.context.get_constant(types.uintp, member_offset)\n        llvoidptr = ir.IntType(8).as_pointer()\n        ptr = cgutils.pointer_add(c.builder, val, offset)\n        casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())\n        return c.builder.load(casted)\n\n    struct_cls = cgutils.create_struct_proxy(typ)\n    inst = struct_cls(c.context, c.builder)\n\n    # load from Python object\n    ptr_meminfo = access_member(_box.box_meminfoptr_offset)\n    ptr_dataptr = access_member(_box.box_dataptr_offset)\n\n    # store to native structure\n    inst.meminfo = c.builder.bitcast(ptr_meminfo, inst.meminfo.type)\n    inst.data = c.builder.bitcast(ptr_dataptr, inst.data.type)\n\n    ret = inst._getvalue()\n\n    c.context.nrt.incref(c.builder, typ, ret)\n\n    return NativeValue(ret, is_error=c.pyapi.c_api_error())\n", "path": "numba/jitclass/boxing.py"}], "after_files": [{"content": "\"\"\"\nImplement logic relating to wrapping (box) and unwrapping (unbox) instances\nof jitclasses for use inside the python interpreter.\n\"\"\"\nfrom __future__ import print_function, absolute_import\n\nfrom functools import wraps, partial\n\nfrom llvmlite import ir\n\nfrom numba import types, cgutils\nfrom numba.pythonapi import box, unbox, NativeValue\nfrom numba import njit\nfrom numba.six import exec_\nfrom . import _box\n\n\n_getter_code_template = \"\"\"\ndef accessor(__numba_self_):\n    return __numba_self_.{0}\n\"\"\"\n\n_setter_code_template = \"\"\"\ndef mutator(__numba_self_, __numba_val):\n    __numba_self_.{0} = __numba_val\n\"\"\"\n\n_method_code_template = \"\"\"\ndef method(__numba_self_, *args):\n    return __numba_self_.{method}(*args)\n\"\"\"\n\n\ndef _generate_property(field, template, fname):\n    \"\"\"\n    Generate simple function that get/set a field of the instance\n    \"\"\"\n    source = template.format(field)\n    glbls = {}\n    exec_(source, glbls)\n    return njit(glbls[fname])\n\n\n_generate_getter = partial(_generate_property, template=_getter_code_template,\n                           fname='accessor')\n_generate_setter = partial(_generate_property, template=_setter_code_template,\n                           fname='mutator')\n\n\ndef _generate_method(name, func):\n    \"\"\"\n    Generate a wrapper for calling a method.  Note the wrapper will only\n    accept positional arguments.\n    \"\"\"\n    source = _method_code_template.format(method=name)\n    glbls = {}\n    exec_(source, glbls)\n    method = njit(glbls['method'])\n\n    @wraps(func)\n    def wrapper(*args, **kwargs):\n        return method(*args, **kwargs)\n\n    return wrapper\n\n\n_cache_specialized_box = {}\n\n\ndef _specialize_box(typ):\n    \"\"\"\n    Create a subclass of Box that is specialized to the jitclass.\n\n    This function caches the result to avoid code bloat.\n    \"\"\"\n    # Check cache\n    if typ in _cache_specialized_box:\n        return _cache_specialized_box[typ]\n    dct = {'__slots__': (),\n           '_numba_type_': typ,\n           '__doc__': typ.class_type.class_def.__doc__,\n           }\n    # Inject attributes as class properties\n    for field in typ.struct:\n        getter = _generate_getter(field)\n        setter = _generate_setter(field)\n        dct[field] = property(getter, setter)\n    # Inject properties as class properties\n    for field, impdct in typ.jitprops.items():\n        getter = None\n        setter = None\n        if 'get' in impdct:\n            getter = _generate_getter(field)\n        if 'set' in impdct:\n            setter = _generate_setter(field)\n        # get docstring from either the fget or fset\n        imp = impdct.get('get') or impdct.get('set') or None\n        doc = getattr(imp, '__doc__', None)\n        dct[field] = property(getter, setter, doc=doc)\n    # Inject methods as class members\n    for name, func in typ.methods.items():\n        if not (name.startswith('__') and name.endswith('__')):\n            dct[name] = _generate_method(name, func)\n    # Create subclass\n    subcls = type(typ.classname, (_box.Box,), dct)\n    # Store to cache\n    _cache_specialized_box[typ] = subcls\n\n    # Pre-compile attribute getter.\n    # Note: This must be done after the \"box\" class is created because\n    #       compiling the getter requires the \"box\" class to be defined.\n    for k, v in dct.items():\n        if isinstance(v, property):\n            prop = getattr(subcls, k)\n            if prop.fget is not None:\n                fget = prop.fget\n                fast_fget = fget.compile((typ,))\n                fget.disable_compile()\n                setattr(subcls, k,\n                        property(fast_fget, prop.fset, prop.fdel,\n                                 doc=prop.__doc__))\n\n    return subcls\n\n\n###############################################################################\n# Implement box/unbox for call wrapper\n\n@box(types.ClassInstanceType)\ndef _box_class_instance(typ, val, c):\n    meminfo, dataptr = cgutils.unpack_tuple(c.builder, val)\n\n    # Create Box instance\n    box_subclassed = _specialize_box(typ)\n    # Note: the ``box_subclassed`` is kept alive by the cache\n    int_addr_boxcls = c.context.get_constant(types.uintp, id(box_subclassed))\n\n    box_cls = c.builder.inttoptr(int_addr_boxcls, c.pyapi.pyobj)\n    box = c.pyapi.call_function_objargs(box_cls, ())\n\n    # Initialize Box instance\n    llvoidptr = ir.IntType(8).as_pointer()\n    addr_meminfo = c.builder.bitcast(meminfo, llvoidptr)\n    addr_data = c.builder.bitcast(dataptr, llvoidptr)\n\n    def set_member(member_offset, value):\n        # Access member by byte offset\n        offset = c.context.get_constant(types.uintp, member_offset)\n        ptr = cgutils.pointer_add(c.builder, box, offset)\n        casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())\n        c.builder.store(value, casted)\n\n    set_member(_box.box_meminfoptr_offset, addr_meminfo)\n    set_member(_box.box_dataptr_offset, addr_data)\n    return box\n\n\n@unbox(types.ClassInstanceType)\ndef _unbox_class_instance(typ, val, c):\n    def access_member(member_offset):\n        # Access member by byte offset\n        offset = c.context.get_constant(types.uintp, member_offset)\n        llvoidptr = ir.IntType(8).as_pointer()\n        ptr = cgutils.pointer_add(c.builder, val, offset)\n        casted = c.builder.bitcast(ptr, llvoidptr.as_pointer())\n        return c.builder.load(casted)\n\n    struct_cls = cgutils.create_struct_proxy(typ)\n    inst = struct_cls(c.context, c.builder)\n\n    # load from Python object\n    ptr_meminfo = access_member(_box.box_meminfoptr_offset)\n    ptr_dataptr = access_member(_box.box_dataptr_offset)\n\n    # store to native structure\n    inst.meminfo = c.builder.bitcast(ptr_meminfo, inst.meminfo.type)\n    inst.data = c.builder.bitcast(ptr_dataptr, inst.data.type)\n\n    ret = inst._getvalue()\n\n    c.context.nrt.incref(c.builder, typ, ret)\n\n    return NativeValue(ret, is_error=c.pyapi.c_api_error())\n", "path": "numba/jitclass/boxing.py"}]}