Repository: Gallopsled/pwntools

Issue:
undetected functions
I don't know if it could be a pwntools or PyCharm problem, but some functions like ```p32, p64, u32, u64``` of pwntools are not detected by the IDE, do you know a way to fix this annoying problem?

![Istantanea_2020-08-15_00-59-37](https://user-images.githubusercontent.com/53967416/90298514-de09d800-de92-11ea-8b5d-5146616c6b57.png)


Discussion:
These functions are created dynamically, we would have to manually add them
to __all__ and even then I’m not sure they would be detected.

On Fri, Aug 14, 2020 at 6:02 PM Th3F0x-code <notifications@github.com>
wrote:

>
>
> I don't know if it could be a pwntools or PyCharm problem, but some
> functions like p32, p64, u32, u64 of pwntools are not detected by the
> IDE, do you know a way to fix this annoying problem?
>
>
> [image: Istantanea_2020-08-15_00-59-37]
> <https://user-images.githubusercontent.com/53967416/90298514-de09d800-de92-11ea-8b5d-5146616c6b57.png>
>
>
>
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/Gallopsled/pwntools/issues/1657>, or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAA3IGEXNY6Z63H2IPKXX5LSAW7AJANCNFSM4P75XD7A>
> .
>
>
> --

*Zach Riggle*

I researched the problem a bit, the best solution I can find on Google is to use pylint's option `--generated-members` to tell it that p32, p64 etc. will be generated dynamically.
The option supports regex but still this is very annoying.
Does adding them to `__all__` solve anything?
I wasn't able to solve it that way from my attempts but I could be wrong

Resolving patch:
diff --git a/pwnlib/util/packing.py b/pwnlib/util/packing.py
--- a/pwnlib/util/packing.py
+++ b/pwnlib/util/packing.py
@@ -296,12 +296,7 @@ def unpack_many(data, word_size = None):
 ends  = ['b','l']
 signs = ['s','u']
 
-return_types     = {'p': 'bytes', 'u': 'int'}
 op_verbs         = {'p': 'pack', 'u': 'unpack'}
-arg_doc          = {'p': 'number (int): Number to convert',
-                    'u': 'data (bytes): Byte string to convert'}
-rv_doc           = {'p': 'The packed number as a byte string',
-                    'u': 'The unpacked number'}
 
 
 def make_single(op,size,end,sign):
@@ -334,46 +329,166 @@ def routine(data, stacklevel=None):
 #
 # Make normal user-oriented packers, e.g. p8
 #
-def make_multi(op, size):
+def _do_packing(op, size, number):
 
     name = "%s%s" % (op,size)
+    mod = sys.modules[__name__]
 
     ls = getattr(mod, "_%sls" % (name))
     lu = getattr(mod, "_%slu" % (name))
     bs = getattr(mod, "_%sbs" % (name))
     bu = getattr(mod, "_%sbu" % (name))
 
-    @LocalNoarchContext
-    def routine(number):
-        endian = context.endian
-        signed = context.signed
-        return {("little", True  ): ls,
-                ("little", False):  lu,
-                ("big",    True  ): bs,
-                ("big",    False):  bu}[endian, signed](number, 3)
+    endian = context.endian
+    signed = context.signed
+    return {("little", True ):  ls,
+            ("little", False):  lu,
+            ("big",    True ):  bs,
+            ("big",    False):  bu}[endian, signed](number, 3)
 
-    routine.__name__ = name
-    routine.__doc__  = """%s%s(number, sign, endian, ...) -> %s
+@LocalNoarchContext
+def p8(number, endianness = None, sign = None, **kwargs):
+    """p8(number, endianness, sign, ...) -> bytes
 
-    %ss an %s-bit integer
+    Packs an 8-bit integer
 
     Arguments:
-        %s
+        number (int): Number to convert
         endianness (str): Endianness of the converted integer ("little"/"big")
         sign (str): Signedness of the converted integer ("unsigned"/"signed")
         kwargs (dict): Arguments passed to context.local(), such as
             ``endian`` or ``signed``.
 
     Returns:
-        %s
-    """ % (op, size, return_types[op], op_verbs[op].title(), size, arg_doc[op], rv_doc[op])
+        The packed number as a byte string
+    """
+    return _do_packing('p', 8, number)
 
-    return name, routine
+@LocalNoarchContext
+def p16(number, endianness = None, sign = None, **kwargs):
+    """p16(number, endianness, sign, ...) -> bytes
 
+    Packs an 16-bit integer
 
-for op,size in iters.product(ops, sizes):
-    name, routine = make_multi(op,size)
-    setattr(mod, name, routine)
+    Arguments:
+        number (int): Number to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The packed number as a byte string
+    """
+    return _do_packing('p', 16, number)
+
+@LocalNoarchContext
+def p32(number, endianness = None, sign = None, **kwargs):
+    """p32(number, endianness, sign, ...) -> bytes
+
+    Packs an 32-bit integer
+
+    Arguments:
+        number (int): Number to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The packed number as a byte string
+    """
+    return _do_packing('p', 32, number)
+
+@LocalNoarchContext
+def p64(number, endianness = None, sign = None, **kwargs):
+    """p64(number, endianness, sign, ...) -> bytes
+
+    Packs an 64-bit integer
+
+    Arguments:
+        number (int): Number to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The packed number as a byte string
+    """
+    return _do_packing('p', 64, number)
+
+@LocalNoarchContext
+def u8(data, endianness = None, sign = None, **kwargs):
+    """u8(data, endianness, sign, ...) -> int
+
+    Unpacks an 8-bit integer
+
+    Arguments:
+        data (bytes): Byte string to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The unpacked number
+    """
+    return _do_packing('u', 8, data)
+
+@LocalNoarchContext
+def u16(data, endianness = None, sign = None, **kwargs):
+    """u16(data, endianness, sign, ...) -> int
+
+    Unpacks an 16-bit integer
+
+    Arguments:
+        data (bytes): Byte string to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The unpacked number
+    """
+    return _do_packing('u', 16, data)
+
+@LocalNoarchContext
+def u32(data, endianness = None, sign = None, **kwargs):
+    """u32(data, endianness, sign, ...) -> int
+
+    Unpacks an 32-bit integer
+
+    Arguments:
+        data (bytes): Byte string to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The unpacked number
+    """
+    return _do_packing('u', 32, data)
+
+@LocalNoarchContext
+def u64(data, endianness = None, sign = None, **kwargs):
+    """u64(data, endianness, sign, ...) -> int
+
+    Unpacks an 64-bit integer
+
+    Arguments:
+        data (bytes): Byte string to convert
+        endianness (str): Endianness of the converted integer ("little"/"big")
+        sign (str): Signedness of the converted integer ("unsigned"/"signed")
+        kwargs (dict): Arguments passed to context.local(), such as
+            ``endian`` or ``signed``.
+
+    Returns:
+        The unpacked number
+    """
+    return _do_packing('u', 64, data)
 
 def make_packer(word_size = None, sign = None, **kwargs):
     """make_packer(word_size = None, endianness = None, sign = None) -> number → str


Test patch: