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 simple visual front end to the Maya UE4 RBF plugin delivered with MetaHumans

poseWrangler Overview PoseWrangler is a simple UI to create and edit pose-driven relationships in Maya using the MayaUE4RBF plugin. This plugin is dis

Christopher Evans 105 Dec 18, 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 08, 2023
Automatic privilege escalation for misconfigured capabilities, sudo and suid binaries

GTFONow Automatic privilege escalation for misconfigured capabilities, sudo and suid binaries. Features Automatically escalate privileges using miscon

101 Jan 03, 2023
test

Lidar-data-decode In this project, you can decode your lidar data frame(pcap file) and make your own datasets(test dataset) in Windows without any hug

46 Dec 05, 2022
A telegram bot to translate 100+ Languages

🔥 GOOGLE TRANSLATER 🔥 The owner would not be responsible for any kind of bans due to the bot. • ⚡ INSTALLING ⚡ • • 🔰 Deploy To Railway 🔰 • • ✅ OFF

Aɴᴋɪᴛ Kᴜᴍᴀʀ 5 Dec 20, 2021
PyJPBoatRace: Python-based Japanese boatrace tools 🚤

pyjpboatrace :speedboat: provides you with useful tools for data analysis and auto-betting for boatrace.

5 Oct 29, 2022
The implementation of Parameter Differentiation based Multilingual Neural Machine Translation

The implementation of Parameter Differentiation based Multilingual Neural Machine Translation .

Qian Wang 21 Dec 17, 2022
Subtitle Workshop (subshop): tools to download and synchronize subtitles

SUBSHOP Tools to download, remove ads, and synchronize subtitles. SUBSHOP Purpose Limitations Required Web Credentials Installation, Configuration, an

Joe D 4 Feb 13, 2022
Yet Another Sequence Encoder - Encode sequences to vector of vector in python !

Yase Yet Another Sequence Encoder - encode sequences to vector of vectors in python ! Why Yase ? Yase enable you to encode any sequence which can be r

Pierre PACI 12 Aug 19, 2021
An easier way to build neural search on the cloud

An easier way to build neural search on the cloud Jina is a deep learning-powered search framework for building cross-/multi-modal search systems (e.g

Jina AI 17.1k Jan 09, 2023
Russian GPT3 models.

Russian GPT-3 models (ruGPT3XL, ruGPT3Large, ruGPT3Medium, ruGPT3Small) trained with 2048 sequence length with sparse and dense attention blocks. We also provide Russian GPT-2 large model (ruGPT2Larg

Sberbank AI 1.6k Jan 05, 2023
自然言語で書かれた時間情報表現を抽出/規格化するルールベースの解析器

ja-timex 自然言語で書かれた時間情報表現を抽出/規格化するルールベースの解析器 概要 ja-timex は、現代日本語で書かれた自然文に含まれる時間情報表現を抽出しTIMEX3と呼ばれるアノテーション仕様に変換することで、プログラムが利用できるような形に規格化するルールベースの解析器です。

Yuki Okuda 116 Nov 09, 2022
A Fast Sequence Transducer Implementation with PyTorch Bindings

transducer A Fast Sequence Transducer Implementation with PyTorch Bindings. The corresponding publication is Sequence Transduction with Recurrent Neur

Awni Hannun 184 Dec 18, 2022
A simple Flask site that allows users to create, update, and delete posts in a database, as well as perform basic NLP tasks on the posts.

A simple Flask site that allows users to create, update, and delete posts in a database, as well as perform basic NLP tasks on the posts.

Ian 1 Jan 15, 2022
Code Implementation of "Learning Span-Level Interactions for Aspect Sentiment Triplet Extraction".

Span-ASTE: Learning Span-Level Interactions for Aspect Sentiment Triplet Extraction ***** New March 31th, 2022: Scikit-Style API for Easy Usage *****

Chia Yew Ken 111 Dec 23, 2022
Sentence boundary disambiguation tool for Japanese texts (日本語文境界判定器)

Bunkai Bunkai is a sentence boundary (SB) disambiguation tool for Japanese texts. Quick Start $ pip install bunkai $ echo -e '宿を予約しました♪!まだ2ヶ月も先だけど。早すぎ

Megagon Labs 160 Dec 23, 2022
Official Stanford NLP Python Library for Many Human Languages

Official Stanford NLP Python Library for Many Human Languages

Stanford NLP 6.4k Jan 02, 2023
Yodatranslator is a simple translator English to Yoda-language

yodatranslator Overview yodatranslator is a simple translator English to Yoda-language. Project is created for educational purposes. It is intended to

1 Nov 11, 2021
Use PaddlePaddle to reproduce the paper:mT5: A Massively Multilingual Pre-trained Text-to-Text Transformer

MT5_paddle Use PaddlePaddle to reproduce the paper:mT5: A Massively Multilingual Pre-trained Text-to-Text Transformer English | 简体中文 mT5: A Massively

2 Oct 17, 2021
Code Generation using a large neural network called GPT-J

CodeGenX is a Code Generation system powered by Artificial Intelligence! It is delivered to you in the form of a Visual Studio Code Extension and is Free and Open-source!

DeepGenX 389 Dec 31, 2022