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
基于百度的语音识别,用python实现,pyaudio+pyqt

Speech-recognition 基于百度的语音识别,python3.8(conda)+pyaudio+pyqt+baidu-aip 百度有面向python

J-L 1 Jan 03, 2022
VampiresVsWerewolves - Our Implementation of a MiniMax algorithm with alpha beta pruning in the context of an in-class competition

VampiresVsWerewolves Our Implementation of a MiniMax algorithm with alpha beta pruning in the context of an in-class competition. Our Algorithm finish

Shawn 1 Jan 21, 2022
This is Assignment1 code for the Web Data Processing System.

This is a Python program to Entity Linking by processing WARC files. We recognize entities from web pages and link them to a Knowledge Base(Wikidata).

3 Dec 04, 2022
HiFi-GAN: Generative Adversarial Networks for Efficient and High Fidelity Speech Synthesis

HiFi-GAN: Generative Adversarial Networks for Efficient and High Fidelity Speech Synthesis Jungil Kong, Jaehyeon Kim, Jaekyoung Bae In our paper, we p

Jungil Kong 1.1k Jan 02, 2023
Deep Learning for Natural Language Processing - Lectures 2021

This repository contains slides for the course "20-00-0947: Deep Learning for Natural Language Processing" (Technical University of Darmstadt, Summer term 2021).

0 Feb 21, 2022
189 Jan 02, 2023
This project uses word frequency and Term Frequency-Inverse Document Frequency to summarize a text.

Text Summarizer This project uses word frequency and Term Frequency-Inverse Document Frequency to summarize a text. Team Members This mini-project was

1 Nov 16, 2021
Reformer, the efficient Transformer, in Pytorch

Reformer, the Efficient Transformer, in Pytorch This is a Pytorch implementation of Reformer https://openreview.net/pdf?id=rkgNKkHtvB It includes LSH

Phil Wang 1.8k Dec 30, 2022
Text-Based zombie apocalyptic decision-making game in Python

Inspiration We shared university first year game coursework.[to gauge previous experience and start brainstorming] Adapted a particular nuclear fallou

Amin Sabbagh 2 Feb 17, 2022
Facilitating the design, comparison and sharing of deep text matching models.

MatchZoo Facilitating the design, comparison and sharing of deep text matching models. MatchZoo 是一个通用的文本匹配工具包,它旨在方便大家快速的实现、比较、以及分享最新的深度文本匹配模型。 🔥 News

Neural Text Matching Community 3.7k Jan 02, 2023
Package for controllable summarization

summarizers summarizers is package for controllable summarization based CTRLsum. currently, we only supports English. It doesn't work in other languag

Hyunwoong Ko 72 Dec 07, 2022
A sample project that exists for PyPUG's "Tutorial on Packaging and Distributing Projects"

A sample Python project A sample project that exists as an aid to the Python Packaging User Guide's Tutorial on Packaging and Distributing Projects. T

Python Packaging Authority 4.5k Dec 30, 2022
2021海华AI挑战赛·中文阅读理解·技术组·第三名

文字是人类用以记录和表达的最基本工具,也是信息传播的重要媒介。透过文字与符号,我们可以追寻人类文明的起源,可以传播知识与经验,读懂文字是认识与了解的第一步。对于人工智能而言,它的核心问题之一就是认知,而认知的核心则是语义理解。

21 Dec 26, 2022
Natural Language Processing

NLP Natural Language Processing apps Multilingual_NLP.py start #This script is demonstartion of Mul

Ritesh Sharma 1 Oct 31, 2021
A Python script that compares files in directories

compare-files A Python script that compares files in different directories, this is similar to the command filecmp.cmp(f1, f2). I made this script in

Colvin 1 Oct 15, 2021
NLP - Machine learning

Flipkart-product-reviews NLP - Machine learning About Product reviews is an essential part of an online store like Flipkart’s branding and marketing.

Harshith VH 1 Oct 29, 2021
OpenAI CLIP text encoders for multiple languages!

Multilingual-CLIP OpenAI CLIP text encoders for any language Colab Notebook · Pre-trained Models · Report Bug Overview OpenAI recently released the pa

Fredrik Carlsson 481 Dec 30, 2022
Code for text augmentation method leveraging large-scale language models

HyperMix Code for our paper GPT3Mix and conducting classification experiments using GPT-3 prompt-based data augmentation. Getting Started Installing P

NAVER AI 47 Dec 20, 2022
Cải thiện Elasticsearch trong bài toán semantic search sử dụng phương pháp Sentence Embeddings

Cải thiện Elasticsearch trong bài toán semantic search sử dụng phương pháp Sentence Embeddings Trong bài viết này mình sẽ sử dụng pretrain model SimCS

Vo Van Phuc 18 Nov 25, 2022
LewusBot - Twitch ChatBot built in python with twitchio library

LewusBot Twitch ChatBot built in python with twitchio library. Uses twitch/leagu

Lewus 25 Dec 04, 2022