Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ERROR: Unrecoverable exception thrown when parsing ./help_text_gen.py! This should NEVER happen. If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new #1593

Closed
ThatXliner opened this issue Nov 8, 2020 · 5 comments · Fixed by hypothesis/viahtml#107, wwade/jobrunner#63, kotamya/pandas-estat#79 or hypothesis/checkmate#228
Milestone

Comments

@ThatXliner
Copy link

ERROR: Unrecoverable exception thrown when parsing ./help_text_gen.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
  File "/Users/bryanhu/.pyenv/versions/3.6.0/bin/isort", line 8, in <module>
    sys.exit(main())
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 953, in main
    for sort_attempt in attempt_iterator:
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 947, in <genexpr>
    for file_name in file_names
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 100, in sort_imports
    **kwargs,
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/api.py", line 303, in sort_file
    with io.File.read(filename) as source_file:
AttributeError: type object 'File' has no attribute 'read'

My code:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Initial author: Bryan Hu .

@ThatXliner .

Version: v0.1.0

A discord bot for `chat@vcs (Discord)`

Because we need it.

"""
import asyncio
import json
import random
import sys
import datetime
import aiohttp
import discord
from bs4 import BeautifulSoup

# from rich.traceback import install
# install(theme="monokai")  # For better error messages

# from typing import Iterable

# NOTE: In the future, we'll be using discord.Role instead of IDs

# Intent chooser
intents = discord.Intents.all()
client = discord.Client(intents=intents)


PREFIX = "bb"
TOKEN = "SECRET"

with open("help_text.json", mode="rt") as f:
    HELP_TEXT = json.loads(f.read())


@client.event
async def on_ready() -> None:
    print(
        "We have logged in as {0.user}. All systems go!".format(client), file=sys.stderr
    )


@client.event
async def on_message(message: discord.Message) -> None:

    try:
        # Shortened versions
        CHANNEL: discord.TextChannel = message.channel
        SEND = CHANNEL.send  # NOTE: Is it preferred to do `SEND` or `CHANNEL.send`
        GUILD: discord.Guild = message.guild
        AUTHOR: discord.Member = message.author
        if AUTHOR.bot:  # It is a bot
            return
        STATUS_UPDATE_CHANNEL = GUILD.get_channel(766077636975788072)
        LOG_CHANNEL = GUILD.get_channel(773686991212380161)

        # Useful constants
        MENTIONED: bool = False
        _ = GUILD.get_role
        ROLES = {  # These are in here because of dynamicism
            "Role #1": _(766780249589153873),
            "Role #2": _(766780358908837898),
            "Role #3": _(766780549930156042),
            "Role #4": _(766780732089434162),
            "Role #5": _(766780860157919232),
            "Role #6": _(766781042916196382),
            "Verify | Pending": _(766066811963179029),
            "Verify | In progress": _(766110909755293746),
            "Verified": _(766057652400160818),
            "Administrator": _(766032588829491200),
            "Assistants": _(766063222360375326),
            "Moderators": _(766030895215542303),
        }
        NEED_VERIFY = [
            ROLES["Role #1"],
            ROLES["Role #2"],
            ROLES["Role #3"],
            ROLES["Role #4"],
            ROLES["Role #5"],
            ROLES["Role #6"],
            ROLES["Verify | Pending"],
            ROLES["Verify | In progress"],
        ]

        IS_PREVILEGED: bool = AUTHOR.roles in (
            ROLES["Administrator"],
            ROLES["Assistants"],
            ROLES["Moderators"],
        )

        async def command_delete(messages: int) -> None:
            await CHANNEL.purge(limit=messages)
            await SEND(
                f"I have deleted {int(lexed_message[1])} messages! :partying_face:",
                delete_after=1,
            )

        async def command_verify() -> None:
            if IS_PREVILEGED:
                try:
                    person_to_verify: discord.Member = GUILD.get_member(int(arg2[3:-1]))
                except IndexError:
                    await SEND(
                        "You must enter the @Mention of the person to verify. ;-;"
                    )
                else:
                    if (
                        person_to_verify is not None
                        and person_to_verify in CHANNEL.members
                    ):
                        # Add the "Verified" role
                        await person_to_verify.add_roles(
                            ROLES["VERIFIED"],
                            reason="Automatic role verification.",
                        )

                        # Remove the "need verification" roles
                        await person_to_verify.remove_roles(
                            [
                                role
                                for role in person_to_verify.roles
                                if role in NEED_VERIFY
                            ],
                            reason="Automatic role verification.",
                        )
                        await SEND("Done! Updating status message...")

                        # Update the status message
                        await STATUS_UPDATE_CHANNEL.send(
                            f"STATUS UPDATE:\n{person_to_verify.mention} : Verified"
                        )

                    else:
                        await SEND("That person does not exist in this server.")
            else:
                await SEND(
                    f"Sorry, {AUTHOR.mention},"
                    " you don't have permission to use that."
                )

        async def command_meme() -> None:
            provider = random.choice(("imgflip", "memedroid"))
            async with aiohttp.ClientSession() as session:
                if provider == "imgflip":
                    async with session.get(
                        f"https://imgflip.com/?page={random.randint(0,10)}"
                    ) as response:
                        html = BeautifulSoup(await response.text(), features="lxml")
                        image_url = (
                            "https:"
                            + random.choice(
                                html.find_all("img", attrs={"class": "base-img"})
                            )["src"]
                        )
                elif provider == "memedroid":
                    async with session.get("https://www.memedroid.com/") as response:
                        soup = BeautifulSoup(await response.text(), features="lxml")
                        image_url = random.choice(
                            [
                                str(img.get("src"))
                                for img in soup.find_all(class_="img-responsive")
                                if str(img.get("src")).startswith("https://")
                            ]
                        )
                await SEND(image_url)

        async def command_help() -> None:
            if arg2 is None:
                await SEND(HELP_TEXT["main"])
            else:
                command_to_help = HELP_TEXT.get(arg2)
                await SEND(
                    command_to_help
                    if command_to_help is not None
                    else "Invalid help choice ;-;"
                )

        # Message parsing
        _ = message.content
        if _.lstrip().startswith(PREFIX):
            _ = _[len(PREFIX) :]  # If this fails (i.e. IndexError) we'll catch it
            MENTIONED = True
        elif client.user in message.mentions:
            _ = _.replace(f"<@!{client.user.id}>", "")  # Pinging the bot
            MENTIONED = True

        # Main driver point
        if MENTIONED:
            # NOTE(ThatXliner): Should we put this in "message parsing"?
            lexed_message = _.split()
            try:
                arg2 = lexed_message[1]
            except IndexError:
                arg2 = None

            # We do the following for case insensitivity
            COMMAND: str = lexed_message[0].lower()  # Case insensitive

            # The reason why we make our own message parsing system
            # is because of *control*. I want full control of
            # parsing, etc because I might make this into a
            # framework...

            # COMMAND: Ping
            if COMMAND == "ping":
                await SEND("pong")

            # COMMAND: Delete
            elif COMMAND in {"!", "del", "delete"}:
                if arg2 is None:
                    arg2 = 0
                await command_delete(int(arg2) + 1)

            # COMMAND: Verify
            elif COMMAND in {"v", "verify"}:
                await command_verify()

            # COMMAND: Help
            elif COMMAND in {"help", "h"}:
                await command_help()

            # COMMAND: Meme
            elif COMMAND in {"m", "meme", "memes"}:
                await command_meme()
            else:
                await SEND("Invalid command ;-;")

    except IndexError as e:  # `CLEAN_MESSAGE = CLEAN_MESSAGE[1:]` from 85:13 failed
        print(e)
        await SEND("mhm?")

    except Exception as e:
        await LOG_CHANNEL.send("Oh no, something went wrong. :boom: . Exception:")
        await LOG_CHANNEL.send(e)
        await LOG_CHANNEL.send(f"MESSAGE: {message.content}")
        print(f"MESSAGE: {message.content}")
        raise e


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(client.start(TOKEN))
except KeyboardInterrupt:
    loop.run_until_complete(client.logout())
    # cancel all tasks lingering
    with open("logs.log") as f:
        f.write(f.read() + f"\n---{datetime.date.today()}---")  # Appends date to logs
finally:
    loop.close()
@timothycrosley
Copy link
Member

Hi @ThatXliner,

Thank for for forwarding along this error! At first glance, I can see how this error could possibly occur, however I trust that it is, and you are not the only one who has encountered it:

#1592

Running isort myself I do not get this error against the provided file. Could you provide some additional information:

  • How did you install isort?
  • What OS are you using?
  • Does it happen for just this file or all files?
  • What does pip freeze give you?

@ThatXliner
Copy link
Author

ThatXliner commented Nov 8, 2020

pip freeze:

appdirs==1.4.4
astroid==2.4.2
black==20.8b1
CacheControl==0.12.6
cachy==0.3.0
certifi==2020.6.20
chardet==3.0.4
cleo==0.8.1
click==7.1.2
clikit==0.6.2
colorama==0.4.4
commonmark==0.9.1
crashtest==0.3.1
dataclasses==0.7
distlib==0.3.1
filelock==3.0.12
flake8==3.8.4
html5lib==1.1
idna==2.10
importlib-metadata==1.7.0
importlib-resources==3.3.0
isort==5.6.4
keyring==21.4.0
lazy-object-proxy==1.4.3
lockfile==0.12.2
mccabe==0.6.1
msgpack==1.0.0
mypy==0.790
mypy-extensions==0.4.3
packaging==20.4
pastel==0.2.1
pathspec==0.8.0
pexpect==4.8.0
pipenv==2020.11.4
pkginfo==1.6.1
poetry==1.1.4
poetry-core==1.0.0
ptyprocess==0.6.0
pycodestyle==2.6.0
pyflakes==2.2.0
Pygments==2.7.2
pylev==1.3.0
pylint==2.6.0
pyparsing==2.4.7
regex==2020.10.28
requests==2.24.0
requests-toolbelt==0.9.1
rich==9.1.0
rope==0.18.0
shellingham==1.3.2
six==1.15.0
toml==0.10.2
tomlkit==0.7.0
typed-ast==1.4.1
typing-extensions==3.7.4.3
urllib3==1.25.11
virtualenv==20.1.0
virtualenv-clone==0.5.4
webencodings==0.5.1
wrapt==1.12.1
zipp==3.4.0

pip -V:

pip 20.2.4 from /Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/pip (python 3.6)

misc:

 ~/pr/Discord_bot  on master !1  isort .                                  ✔
ERROR: Unrecoverable exception thrown when parsing ./help_text_gen.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
  File "/Users/bryanhu/.pyenv/versions/3.6.0/bin/isort", line 8, in <module>
    sys.exit(main())
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 953, in main
    for sort_attempt in attempt_iterator:
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 947, in <genexpr>
    for file_name in file_names
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 100, in sort_imports
    **kwargs,
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/api.py", line 303, in sort_file
    with io.File.read(filename) as source_file:
AttributeError: type object 'File' has no attribute 'read'
 ~/projects/Discord_bot  on master !1  isort debug.py                                                                                  1 ✘
ERROR: Unrecoverable exception thrown when parsing debug.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
  File "/Users/bryanhu/.pyenv/versions/3.6.0/bin/isort", line 8, in <module>
    sys.exit(main())
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 953, in main
    for sort_attempt in attempt_iterator:
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 947, in <genexpr>
    for file_name in file_names
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 100, in sort_imports
    **kwargs,
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/api.py", line 303, in sort_file
    with io.File.read(filename) as source_file:
AttributeError: type object 'File' has no attribute 'read'
 ~/projects/Discord_bot  on master !1  isort main.py                                                                                     ✔
ERROR: Unrecoverable exception thrown when parsing main.py! This should NEVER happen.
If encountered, please open an issue: https://github.com/PyCQA/isort/issues/new
Traceback (most recent call last):
  File "/Users/bryanhu/.pyenv/versions/3.6.0/bin/isort", line 8, in <module>
    sys.exit(main())
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 953, in main
    for sort_attempt in attempt_iterator:
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 947, in <genexpr>
    for file_name in file_names
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/main.py", line 100, in sort_imports
    **kwargs,
  File "/Users/bryanhu/.pyenv/versions/3.6.0/lib/python3.6/site-packages/isort/api.py", line 303, in sort_file
    with io.File.read(filename) as source_file:
AttributeError: type object 'File' has no attribute 'read'
 ~/projects/Discord_bot  on master !1 

ls:

Makefile
Pipfile
Pipfile.lock
debug.py
help_text.json
help_text.yml
help_text_gen.py
logs.log
main.py
pickler_helper.py

python -V:

Python 3.6.0

which isort:

/Users/bryanhu/.pyenv/shims/isort

isort -V:


                 _                 _
                (_) ___  ___  _ __| |_
                | |/ _/ / _ \/ '__  _/
                | |\__ \/\_\/| |  | |_
                |_|\___/\___/\_/   \_/

      isort your imports, so you don't have to.

                    VERSION 5.6.4

OS: MacOS 10.15.7

@ThatXliner
Copy link
Author

ThatXliner commented Nov 8, 2020

Funny:

 ~/projects/Discord_bot  on master !1  python3.8 -m isort -rc .                                                                        1 ✘
Fixing /Users/bryanhu/projects/Discord_bot/help_text_gen.py
Fixing /Users/bryanhu/projects/Discord_bot/main.py
Skipped 2 files

Is this a python issue?

which python3.8:

/usr/local/bin/python3.8

@timothycrosley
Copy link
Member

Yep that's it! isort runs against every supported minor release, including 3.6.x, but the latest version of each. It seems to break on 3.6.0 but not 3.6.12 so the automated tests never uncovered it, I imagine it has to do with the decorators on the method in question, but I'll investigate some more.

@timothycrosley
Copy link
Member

Thank you for reporting! After investigation I was able to confirm this issue is a reflection of a bug in early patch release of Python3.6 (the latest 3.6.12 does not have the error) with staticmethods on a NamedTuple class. This is fixed in develop and will be released with the next minor release of isort.

Thanks!

~Timothy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment