A linter to manage all your python exceptions and try/except blocks (limited only for those who like dinosaurs).

Overview

Manage your exceptions in Python like a PRO

PyPI Code style: black Downloads

Currently in BETA. Inspired by this blog post.

I shared the building process of this tool here.

“For those who like dinosaurs 🦖 and clean try/except blocks.”


Installation and usage

Installation

pip install tryceratops

Usage

tryceratops [filename or dir...]

You can enable experimental analyzers by running:

tryceratops --experimental [filename or dir...]

You can ignore specific violations by using: --ignore TCXXX repeatedly:

tryceratops --ignore TC201 --ignore TC202 [filename or dir...]

You can exclude dirs by using: --exclude dir/path repeatedly:

tryceratops --exclude tests --exclude .venv [filename or dir...]

example

Violations

All violations and its descriptions can be found in docs.

Ignoring violations

If you want to ignore a violation in a specific file, you can either:

  • Add a comment with notc to the top of the file you want to ignore
  • Add a comment with notc to the line you want to ignore
  • Add a comment with notc: CODE to the line you want to ignore a specific violation

Example:

def verbose_reraise_1():
    try:
        a = 1
    except Exception as ex:
        raise ex  # notc: TC202

Pre-commit

If you wish to use pre-commit, add this:

  - repo: https://github.com/guilatrova/tryceratops
    rev: v0.2.3
    hooks:
      - id: tryceratops

Configuration

You can set up a pyproject.toml file to set rules. This is useful to avoid reusing the same CLI flags over and over again and helps to define the structure of your project.

Example:

[tool.tryceratops]
exclude = ["samples"]
ignore = ["TC002", "TC200", "TC300"]
experimental = true

CLI flags always overwrite the config file.

License

MIT

Credits

Thanks to God for the inspiration 🙌 ☁️ ☀️

Logo icon was made by https://www.freepik.com

The black project for insights.

Comments
  • Provide file names when

    Provide file names when "Failed to process {len(self.discovery.failures)} files" is returned

    When running tryceratops if any of the files aren't able to process, more information should be returned about which files can't be processed.

    Specifically, running tryceratops on a simple project with only 16 files returns the following:

    Done processing! 🦖✨
    Processed 16 files
    Found 0 violations
    Failed to process 1 files
    Skipped 2340 files
    

    Without knowing which file failed to process, I'm not sure what, if anything, I should do for next steps.

    This message comes from interfaces.py line 51

    opened by ryancheley 9
  • Better naming: tryceratops and triceratops

    Better naming: tryceratops and triceratops

    Isn't the naming unfortunate when there is already a Python module called triceratops?

    • https://pypi.org/project/triceratops/
    • https://pypi.org/project/tryceratops/
    opened by kseistrup 9
  • Crash when displaying the output on Windows in Anaconda

    Crash when displaying the output on Windows in Anaconda

    It seems there can be an encoding issue with the text in "Done processing" on Windows with anaconda:

    File "C:\Users\anon\.cache\pre-commit\repoqfqlxkvs\py_env-python3\lib\site-packages\tryceratops\interfaces.py", line 50, in _present_status
        print("Done processing! \U0001f996\u2728")
      File "c:\Users\anon\anaconda3\lib\encodings\cp1252.py", line 19, in encode
        return codecs.charmap_encode(input,self.errors,encoding_table)[0]
    UnicodeEncodeError: 'charmap' codec can't encode characters in position 17-18: character maps to <undefined>
    
    bug 
    opened by Pierre-Sassoulas 6
  • New violation: Prefer TypeError for unexpected types

    New violation: Prefer TypeError for unexpected types

    Hi there,

    A couple of times on existing code bases I've ran into a problem with built-in exceptions. I'm hoping to interest you into accepting it into this project, as it's the closest I've seen so far to the use case.

    A simple GitHub search results in many codebases struggling with this pattern.

    The issue

    Often built-in exceptions are used regardless of their semantics. This results in confusing diagnostic information for the user.

    if isinstance(my_var, int):
        pass
    else:
        raise ValueError("...") #should be typeerror
    

    The above examples has variations with multiple elif statements and other exception types as RuntimeError.

    Similarly, if the if/elif conditions check values, not type, then a TypeError is misleading.

    Proposed solution

    Detect these patterns and report them, ideally fix them automatically (as pyupgrade would do).

    Are you open to including this functionality in the package? If you're to busy, but open, then the community could take a turn (hacktoberfest).

    help wanted good first issue violation hacktoberfest 
    opened by sbrugman 6
  • Generic name when running tryceratops as a module

    Generic name when running tryceratops as a module

    I installed tryceratops and tryceratops.exe got installed into a folder that is not on my PATH variable.

    What I usually do, to run things like black, is python -m black, and the same thing works for tryceratops, naturally.

    However, some of the command-line options give generic info back because __name__ is now "__main__":

     > python -m tryceratops --version
    __main__.py, version 0.2.3
    

    and

     > python -m tryceratops --help
    Usage: __main__.py [OPTIONS] [DIR]...
    # omitted
    

    Notice both appearances of __main__.py where I expected tryceratops or tryceratops.py. In my opinion the __main__.py doesn't look good, in a stylistic sense.

    opened by rodrigogiraoserrao 6
  • Allow Click 8

    Allow Click 8

    Current Click specification actually disallows Click ^8. This is causing dependency issues for me. This PR loosens the requirements to allow ^8 and ^7. This might not actually be desired, and we might want to constrain to ^8.0, but wanted to keep changes to a minimum for now. All tests are passing on Click 8.0.3.


    Thanks for the project!

    opened by paw-lu 5
  • Unpin dependencies (or adopt a bot to help upgrade it like Dependabot)

    Unpin dependencies (or adopt a bot to help upgrade it like Dependabot)

    Hi! Enjoying the project!

    One issue I have come across again is that this project's dependecy pinning causes conflicts with other libraries

    It happened once before to Click, and recently again have had trouble with Rich.

    • https://github.com/guilatrova/tryceratops/pull/39
    • https://github.com/guilatrova/tryceratops/pull/46

    Rich itself updates major versions pretty often, so this is likely to happen again in the future.

    Two solutions:

    1. Unpin the dependencies, this is becoming more popular. It just involves switching from pining to the major version to just enforcing a minmum version.

      - rich = "^10.14.0"
      + rich = ">=10.14.0"
      
    2. Use an automation tool like Dependabot to keep your depenencies up to date, and update often.

    Happy to help with either of these if you are interested.

    Again, thanks for the tool!

    Edit: Wrong article was linked in first point (it supported the second point)

    opened by paw-lu 4
  • Crash when the code analysed is unparseable

    Crash when the code analysed is unparseable

    Hello, thank you for this tool, I appreciate it.

    I encountered a crash on some code with git artifact not removed:

    Traceback (most recent call last):
      File "/home/psassoulas/.cache/pre-commit/repo1clg70g2/py_env-python3/lib/python3.8/site-packages/tryceratops/files/discovery.py", line 54, in _parse_python_files_from_dir
        parsed, filefilter = parse_file(filename)
      File "/home/psassoulas/.cache/pre-commit/repo1clg70g2/py_env-python3/lib/python3.8/site-packages/tryceratops/files/parser.py", line 42, in parse_file
        tree = parse_tree(content)
      File "/home/psassoulas/.cache/pre-commit/repo1clg70g2/py_env-python3/lib/python3.8/site-packages/tryceratops/files/parser.py", line 37, in parse_tree
        return ast.parse(content.read())
      File "/usr/lib/python3.8/ast.py", line 47, in parse
        return compile(source, filename, mode, flags,
      File "<unknown>", line 74
        <<<<<<< Updated upstream
    
    opened by Pierre-Sassoulas 4
  • tryceratops sometimes fails to create `.tryceratops-errors.log`, raising `FileNotFoundError` when checking

    tryceratops sometimes fails to create `.tryceratops-errors.log`, raising `FileNotFoundError` when checking

    Thanks for sharing this work. Interesting idea for a linter!


    When ran from a pre-commit hook as a local hook:

    repos:
      - repo: local
        hooks:
          - id: tryceratops
            name: tryceratops
            entry: tryceratops
            language: system
            types: [python]
    

    and tryceratops-errors.log has not been created yet, this is raised at each check:

    Traceback (most recent call last):
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/bin/tryceratops", line 8, in <module>
        sys.exit(main())
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/tryceratops/__main__.py", line 62, in main
        entrypoint(prog_name="tryceratops")
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/click/core.py", line 829, in __call__
        return self.main(*args, **kwargs)
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/click/core.py", line 782, in main
        rv = self.invoke(ctx)
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/click/core.py", line 1066, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/click/core.py", line 610, in invoke
        return callback(*args, **kwargs)
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/tryceratops/__main__.py", line 57, in entrypoint
        interface.present_and_exit()
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/tryceratops/interfaces.py", line 95, in present_and_exit
        self._delete_empty_logs()
      File "/Users/pawlu/Documents/personal/nbpreview/.nox/pre-commit/lib/python3.9/site-packages/tryceratops/interfaces.py", line 86, in _delete_empty_logs
        is_log_empty = os.path.getsize(log_file_path) == 0
      File "/usr/local/Cellar/[email protected]/3.9.6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/genericpath.py", line 50, in getsize
        return os.stat(filename).st_size
    FileNotFoundError: [Errno 2] No such file or directory: '/Users/pawlu/Documents/personal/nbpreview/.tryceratops-errors.log'
    

    Things work fine if the command is invoked directly through the terminal.

    opened by paw-lu 4
  • Is it bad to capture a bare `Exception`?

    Is it bad to capture a bare `Exception`?

    I learned that catching Exception is a dangerous shortcut. It does not communicate what is expected to fail, it might silence arbitrary unexpected errors (e.g. AttributeError where ValueError is expected) and finally it also catches severe misconditions like MemoryError. Thus usually I try to be as specific as possible.

    What is your position on catching Exception? Is it something thats acceptable in Tryceratops?

    opened by MaxG87 4
  • Fix #8

    Fix #8

    This fixes issue #8 by calling the logging.shutdown function: https://docs.python.org/3/library/logging.html#logging.shutdown

    As per the docs,

    Informs the logging system to perform an orderly shutdown by flushing and closing all handlers. This should be called at application exit and no further use of the logging system should be made after this call.

    When the logging module is imported, it registers this function as an exit handler (see atexit), so normally there’s no need to do that manually.

    There might be a more appropriate place to insert this .shutdown() call, but it must be before the empty logs are deleted.

    opened by rodrigogiraoserrao 4
  • feat: changed flake8 code from TC to TRY

    feat: changed flake8 code from TC to TRY

    Hi! Thanks for great project.

    As was mentioned in https://github.com/guilatrova/tryceratops/issues/41, there is a flake8 code clash between your project and flake8-type-checkin. When used together within single project tryceratops completely disables flake8-type-checkin. Flake8 doesn't give any warning about this, which leads to bad code passing linters silently.

    good first issue 
    opened by exister 1
  • Add `--config` option to specify the location of the configuration file.

    Add `--config` option to specify the location of the configuration file.

    Hi,

    I would like to point tryceratops to a specifc configuration file using a --config option or something similar. Currently, tryceratops tries to find the configuration itself.

    In my specifc use-case, I have a repository containing a cookiecutter template (https://github.com/pytask-dev/cookiecutter-pytask-project). There are two pyproject.toml files: one for the cookiecutter and one in the src folder which is rendered as part of the template. Since the latter pyproject.toml contains Jinja syntax it causes an error when tryceratops tries to read the file.

    What do you think? I assume not many people are having a similar problem because they don't divide configuration files or something like that.

    opened by tobiasraabe 3
  • False positive use 'exception' instead of 'error' when raisign a parser error with ``argparse``

    False positive use 'exception' instead of 'error' when raisign a parser error with ``argparse``

    In the following code the parser is mistaken for a logger and using parser.exception is suggested :

    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "config_folder", help="Path to the project configuration folder"
    )
    args = parser.parse_args()
    try:
        int(args.config_folder) / 0
    except:
        parser.error(
            f"Your configuration folder can't be divided by zero, use something else !"
        )
    
    opened by Pierre-Sassoulas 4
  • False negative for TC003 long message not detected

    False negative for TC003 long message not detected

    Hello again :)

    The following code is not raising a TC003 but I think it should:

    import numpy as np
    
    
    def check_a_b(a: np.ndarray, b: np.ndarray) -> None:
        if len(a) != len(b):
            raise ValueError(
                "cezczeczeczecezczeczecnezklcnzelkczkenclkzecnzeklck"
                f"({len(a)})zedenzcklzelkcnzelcknzeklcnzelkncklzeckl"
                f"({len(b)})dzekckezncknzecklnzeklczkelcklzencknzeck"
            )
    
    
    bug help wanted hacktoberfest 
    opened by Pierre-Sassoulas 2
Releases(v1.1.0)
Owner
Guilherme Latrova
Sportist, Creator, Software writer, Coffee appreciator, Lucky husband and God servant :)
Guilherme Latrova
A relatively simple python program to generate one of those reddit text to speech videos dominating youtube.

Reddit text to speech generator A basic reddit tts video generator Current functionality Generate videos for subs based on comments,(askreddit) so rea

Aadvik 17 Dec 19, 2022
xFormers is a modular and field agnostic library to flexibly generate transformer architectures by interoperable and optimized building blocks.

Description xFormers is a modular and field agnostic library to flexibly generate transformer architectures by interoperable and optimized building bl

Facebook Research 2.3k Jan 8, 2023
Neural building blocks for speaker diarization: speech activity detection, speaker change detection, overlapped speech detection, speaker embedding

⚠️ Checkout develop branch to see what is coming in pyannote.audio 2.0: a much smaller and cleaner codebase Python-first API (the good old pyannote-au

pyannote 2.2k Jan 9, 2023
Coreference resolution for English, German and Polish, optimised for limited training data and easily extensible for further languages

Coreferee Author: Richard Paul Hudson, msg systems ag 1. Introduction 1.1 The basic idea 1.2 Getting started 1.2.1 English 1.2.2 German 1.2.3 Polish 1

msg systems ag 169 Dec 21, 2022
Coreference resolution for English, French, German and Polish, optimised for limited training data and easily extensible for further languages

Coreferee Author: Richard Paul Hudson, Explosion AI 1. Introduction 1.1 The basic idea 1.2 Getting started 1.2.1 English 1.2.2 French 1.2.3 German 1.2

Explosion 70 Dec 12, 2022
This repository contains data used in the NAACL 2021 Paper - Proteno: Text Normalization with Limited Data for Fast Deployment in Text to Speech Systems

Proteno This is the data release associated with the corresponding NAACL 2021 Paper - Proteno: Text Normalization with Limited Data for Fast Deploymen

null 37 Dec 4, 2022
Official code for "Parser-Free Virtual Try-on via Distilling Appearance Flows", CVPR 2021

Parser-Free Virtual Try-on via Distilling Appearance Flows, CVPR 2021 Official code for CVPR 2021 paper 'Parser-Free Virtual Try-on via Distilling App

null 395 Jan 3, 2023
Smart discord chatbot integrated with Dialogflow to manage different classrooms and assist in teaching!

smart-school-chatbot Smart discord chatbot integrated with Dialogflow to interact with students naturally and manage different classes in a school. De

Tom Huynh 5 Oct 24, 2022
NLPretext packages in a unique library all the text preprocessing functions you need to ease your NLP project.

NLPretext packages in a unique library all the text preprocessing functions you need to ease your NLP project.

Artefact 114 Dec 15, 2022
A python script to prefab your scripts/text files, and re create them with ease and not have to open your browser to copy code or write code yourself

Scriptfab - What is it? A python script to prefab your scripts/text files, and re create them with ease and not have to open your browser to copy code

DevNugget 3 Jul 28, 2021
This simple Python program calculates a love score based on your and your crush's full names in English

This simple Python program calculates a love score based on your and your crush's full names in English. There is no logic or reason in the calculation behind the love score. The calculation could have been anything different from what's shown in this code.

p.katekomol 1 Jan 24, 2022
🛸 Use pretrained transformers like BERT, XLNet and GPT-2 in spaCy

spacy-transformers: Use pretrained transformers like BERT, XLNet and GPT-2 in spaCy This package provides spaCy components and architectures to use tr

Explosion 1.2k Jan 8, 2023
🛸 Use pretrained transformers like BERT, XLNet and GPT-2 in spaCy

spacy-transformers: Use pretrained transformers like BERT, XLNet and GPT-2 in spaCy This package provides spaCy components and architectures to use tr

Explosion 903 Feb 17, 2021
A modular Karton Framework service that unpacks common packers like UPX and others using the Qiling Framework.

Unpacker Karton Service A modular Karton Framework service that unpacks common packers like UPX and others using the Qiling Framework. This project is

c3rb3ru5 45 Jan 5, 2023
Extract city and country mentions from Text like GeoText without regex, but FlashText, a Aho-Corasick implementation.

flashgeotext ⚡ ?? Extract and count countries and cities (+their synonyms) from text, like GeoText on steroids using FlashText, a Aho-Corasick impleme

Ben 57 Dec 16, 2022