Sqlacodegen showing Argspec not found

1.7k views Asked by At

can anyone please help me with it. I was trying to use sqlacodegen with postgresql to autogenerate the database models from my database, but it is constantly showing me this import error

>sqlacodegen postgresql://postgres:j1234@localhost:4040/db1
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "C:\Users\user\AppData\Local\Programs\Python\Python311\Scripts\sqlacodegen.exe\__main__.py", line 4, in <module>
  File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\sqlacodegen\main.py", line 11, in <module>
    from sqlacodegen.codegen import CodeGenerator
  File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\sqlacodegen\codegen.py", line 9, in <module>
    from inspect import ArgSpec
ImportError: cannot import name 'ArgSpec' from 'inspect' (C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\inspect.py)

i am working with python 3.11, postgresql, sqlalchemy 2.0.15, and sqlacodegen 2.3.0

I want to autogenerate database models from my database for my fastapi. I am also open to any kind of sqlacodegen alternatives

3

There are 3 answers

1
yusufusta On

I encountered this issue as well. The problem arises because ArgSpec has been removed in Python 3.11.

The solution is to open the /site-packages/sqlacodegen/codegen.py file in your text editor. Then, delete the line that includes from inspect import ArgSpec at line 9. Additionally, remove lines 486 and 488, replacing them with return False, and then run your command again. It should work without any issues.

0
Asqan On

Currently, sqlacodegen is not compatible with 3.11. So as a workaround (Just like @yusufusta suggested)

  • venv/Lib/site-packages/sqlacodegen/codegen.py
  • delete ArgSpec
  • change the following functions by these:

    def _getargspec_init(method):
        try:
            if hasattr(inspect, 'getfullargspec'):
                fullargspec = inspect.getfullargspec(method)
                return {
                    'args': fullargspec.args,
                    'varargs': fullargspec.varargs,
                    'varkw': fullargspec.varkw,
                    'defaults': fullargspec.defaults
                }
            else:
                argspec = inspect.getargspec(method)
                return {
                    'args': argspec.args,
                    'varargs': argspec.varargs,
                    'varkw': argspec.varkw,
                    'defaults': argspec.defaults
                }
        except TypeError:
            if method is object.__init__:
                return {
                    'args': ['self'],
                    'varargs': None,
                    'varkw': None,
                    'defaults': None
                }
            else:
                return {
                    'args': ['self'],
                    'varargs': 'args',
                    'varkw': 'kwargs',
                    'defaults': None
                }

    @classmethod
    def render_column_type(cls, coltype):
        args = []
        kwargs = OrderedDict()
        argspec = cls._getargspec_init(coltype.__class__.__init__)
        defaults = dict(zip(argspec['args'][-len(argspec['defaults'] or ()):],
                            argspec['defaults'] or ()))
        missing = object()
        use_kwargs = False
        for attr in argspec['args'][1:]:
            # Remove annoyances like _warn_on_bytestring
            if attr.startswith('_'):
                continue

            value = getattr(coltype, attr, missing)
            default = defaults.get(attr, missing)
            if value is missing or value == default:
                use_kwargs = True
            elif use_kwargs:
                kwargs[attr] = repr(value)
            else:
                args.append(repr(value))

        if argspec['varargs'] and hasattr(coltype, argspec['varargs']):
            varargs_repr = [repr(arg) for arg in getattr(coltype, argspec['varargs'])]
            args.extend(varargs_repr)

        if isinstance(coltype, Enum) and coltype.name is not None:
            kwargs['name'] = repr(coltype.name)

        for key, value in kwargs.items():
            args.append('{}={}'.format(key, value))

        rendered = coltype.__class__.__name__
        if args:
            rendered += '({0})'.format(', '.join(args))

        return rendered

0
Hawawa On

To add onto what others have mentioned, SQLAcodegen-v2 doesn't have this issue and runs fine on Python 3.11 (with SQLAlchemy 2.0)