somedecorators


Namesomedecorators JSON
Version 1.2.5 PyPI version JSON
download
home_pagehttps://github.com/somenzz/somedecorators
SummarySome useful decorators in Python.
upload_time2024-08-28 01:43:36
maintainerNone
docs_urlNone
authorsomenzz
requires_pythonNone
licenseMIT
keywords awesome decorators
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # somedecorators

Some very useful Python decorators, functions, classes, continuously updated.


一些非常实用的 Python 装饰器、函数、类,持续更新。

- 新增 robot_on_exception,报错通过企业微信机器人发送至企业微信群聊 :  from somedecorators import robot_on_exception
- 新增 wechat_on_exception,报错发送企业微信 :  from somedecorators import wechat_on_exception
- 新增 setup_logger,快速配置日志  : from somedecorators import setup_logger  
- 新增 ConfigManager,快速搞定配置文件 : from somedecorators import ConfigManager 

使用方法如下:

## 安装

```sh
pip install somedecorators
```

## 装饰器介绍:

#### 发送企业微信机器人

调用代码 
mentioned_list 参数可以不填写。
```python
@robot_on_exception(webhook_url= "你的企业威胁你机器人 webhook",mentioned_list=["@谁就填写谁的企业微信账号","user2"], extra_msg="运行报错")
def myfunc(args):
    if args == 1:
        raise Exception1
    elif args == 2:
        raise Exception2
    else:
        raise Exception3
```



#### timeit

耗时统计装饰器,单位是秒,保留 4 位小数


使用方法:

```python
from somedecorators import timeit
@timeit()
def test_timeit():
    time.sleep(1)

#test_timeit cost 1.0026 seconds

@timeit(logger = your_logger)
def test_timeit():
    time.sleep(1)
```


#### timeout

超时装饰器,单位是秒,函数运行超过指定的时间会抛出 TimeOutError 异常。

使用方法:

```python
import time
from somedecorators import timeout
@timeout(2)
def test_timeit():
    time.sleep(3)

#somedecorators.timeit.TimeoutError: Operation did not finish within 2 seconds
```



#### retry

重试装饰器
- 当被装饰的函数调用抛出指定的异常时,函数会被重新调用。
- 直到达到指定的最大调用次数才重新抛出指定的异常,可以指定时间间隔,默认 5 秒后重试。
- traced_exceptions 为监控的异常,可以为 None(默认)、异常类、或者一个异常类的列表或元组 tuple。
- traced_exceptions 如果为 None,则监控所有的异常;如果指定了异常类,则若函数调用抛出指定的异常时,重新调用函数,直至成功返回结果。
- 未出现监控的异常时,如果指定定了 reraised_exception 则抛出 reraised_exception,否则抛出原来的异常。


```python
from somedecorators import retry 

@retry(
    times=2,
    wait_seconds=1,
    traced_exceptions=myException,
    reraised_exception=CustomException,
)
def test_retry():
    # time.sleep(1)
    raise myException


test_retry()
```



#### email_on_exception

报错发邮件装饰器。当被装饰的函数调用抛出指定的异常时,函数发送邮件给指定的人员,使用独立的 [djangomail](https://github.com/somenzz/djangomail) 发邮件模块,非常好用。

- recipient_list: 一个字符串列表,每项都是一个邮箱地址。recipient_list 中的每个成员都可以在邮件的 "收件人:" 中看到其他的收件人。
- traced_exceptions 为监控的异常,可以为 None(默认)、异常类、或者一个异常类的元组。
traced_exceptions 如果为 None,则监控所有的异常;如果指定了异常类,则若函数调用抛出指定的异常时,发送邮件。

**使用方法**:

首先在项目目录新建 settings.py,配置邮件服务器或企业微信,内容如下:

```python
EMAIL_USE_LOCALTIME = True

#for unitest
#EMAIL_BACKEND = 'djangomail.backends.console.EmailBackend'
#EMAIL_BACKEND = 'djangomail.backends.smtp.EmailBackend'
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.163.com' #可以换其他邮箱
EMAIL_PORT = 465
EMAIL_HOST_USER = 'your-username'
EMAIL_HOST_PASSWORD = '********'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
SERVER_EMAIL = EMAIL_HOST_USER


# 用于发送企业微信
CORPID="**********************"  # 企业 ID
APPID="*******"  # 企业应用 ID
CORPSECRET="************************" # 企业应用 Secret

```

如果你的文件名不是 settings.py,假如是 mysettings.py 则需要修改环境变量:

```python
os.environ.setdefault("SETTINGS_MODULE", "mysettings")
```
然后主程序中这样使用:

##### 监控所有的异常

```python
from somedecorators import email_on_exception 
#import os
#os.environ.setdefault("SETTINGS_MODULE", "settings") #默认配置,可以不写此行代码

@email_on_exception(['somenzz@163.com'])
def myfunc(arg):
    1/arg

myfunc(0)
```

你会收到如下的邮件信息,非常便于排查错误。

```sh
Subject: myfunc(arg=0) raise Exception
From: your-username
To: somenzz@163.com
Date: Fri, 11 Jun 2021 20:55:01 -0500
Message-ID: 
 <162346290112.13869.15957310483971819045@1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa>

myfunc(arg=0) raise Exception: division by zero 
 traceback:
 Traceback (most recent call last):
  File "/Users/aaron/github/somenzz/somedecorators/somedecorators/email.py", line 35, in wrapper
    return func(*args, **kwargs)
  File "/Users/aaron/github/somenzz/somedecorators/tests/tests.py", line 55, in myfunc
    return 1/arg
ZeroDivisionError: division by zero

extra_msg = 严重错误
```

##### 监控指定的异常

```python

from somedecorators import email_on_exception
import os
os.environ.setdefault("SETTINGS_MODULE", "settings")

class Exception1(Exception):
    pass

class Exception2(Exception):
    pass

class Exception3(Exception):
    pass

@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)
def myfunc(args):
    if args == 1:
        raise Exception1
    elif args == 2:
        raise Exception2
    else:
        raise Exception3

myfunc(2)

```
上述代码只有在 raise Exception2 时才会发送邮件:

##### 不同的异常发给不同的人

```python
@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)
@email_on_exception(['others@163.com'],traced_exceptions = (Exception1, Exception3))
def myfunc(args):
    if args == 1:
        raise Exception1
    elif args == 2:
        raise Exception2
    else:
        raise Exception3
```

是不是非常方便?

#### 发送企业微信

发送前需要在 settings.py 文件企业微信相关信息

settings.py 示例:

```python

CORPID="**********************"  # 企业 ID
APPID="*******"  # 企业应用 ID
CORPSECRET="************************" # 企业应用 Secret

```

调用代码 

```python
@wechat_on_exception(['企业微信接收者ID'],traced_exceptions = Exception2)
def myfunc(args):
    if args == 1:
        raise Exception1
    elif args == 2:
        raise Exception2
    else:
        raise Exception3
```


#### 快速配置日志 setup_logger

一个简单的使用日志的方法

```python
from somedecorators import setup_logger
logger = setup_logger("myapp")
logger.info("hello this is myapp log")
logger2 = setup_logger("myapp2", log_path="./log/app.log")
logger3 = setup_logger("myapp3",handlers=['console']) 
logger4 = setup_logger("myapp4",handlers=['console','file']) 
```

#### 快速搞定配置文件

```python
from somedecorators import ConfigManager
config_manager = ConfigManager("config.yml")
config_data = config_manager.get_all()
print(config_data)
```

## 参与项目

欢迎分享你最常用的装饰器、类、函数,加入到这里。

## 联系我 

微信:somenzz-enjoy

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/somenzz/somedecorators",
    "name": "somedecorators",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "awesome decorators",
    "author": "somenzz",
    "author_email": "somenzz@163.com",
    "download_url": "https://files.pythonhosted.org/packages/a5/5c/5fc15a2d43f722cd639d5fffdb868818d79a3de001cddef80b10d72499be/somedecorators-1.2.5.tar.gz",
    "platform": null,
    "description": "# somedecorators\n\nSome very useful Python decorators, functions, classes, continuously updated.\n\n\n\u4e00\u4e9b\u975e\u5e38\u5b9e\u7528\u7684 Python \u88c5\u9970\u5668\u3001\u51fd\u6570\u3001\u7c7b\uff0c\u6301\u7eed\u66f4\u65b0\u3002\n\n- \u65b0\u589e robot_on_exception\uff0c\u62a5\u9519\u901a\u8fc7\u4f01\u4e1a\u5fae\u4fe1\u673a\u5668\u4eba\u53d1\u9001\u81f3\u4f01\u4e1a\u5fae\u4fe1\u7fa4\u804a :  from somedecorators import robot_on_exception\n- \u65b0\u589e wechat_on_exception\uff0c\u62a5\u9519\u53d1\u9001\u4f01\u4e1a\u5fae\u4fe1 :  from somedecorators import wechat_on_exception\n- \u65b0\u589e setup_logger\uff0c\u5feb\u901f\u914d\u7f6e\u65e5\u5fd7  : from somedecorators import setup_logger  \n- \u65b0\u589e ConfigManager\uff0c\u5feb\u901f\u641e\u5b9a\u914d\u7f6e\u6587\u4ef6 : from somedecorators import ConfigManager \n\n\u4f7f\u7528\u65b9\u6cd5\u5982\u4e0b\uff1a\n\n## \u5b89\u88c5\n\n```sh\npip install somedecorators\n```\n\n## \u88c5\u9970\u5668\u4ecb\u7ecd\uff1a\n\n#### \u53d1\u9001\u4f01\u4e1a\u5fae\u4fe1\u673a\u5668\u4eba\n\n\u8c03\u7528\u4ee3\u7801 \nmentioned_list \u53c2\u6570\u53ef\u4ee5\u4e0d\u586b\u5199\u3002\n```python\n@robot_on_exception(webhook_url= \"\u4f60\u7684\u4f01\u4e1a\u5a01\u80c1\u4f60\u673a\u5668\u4eba webhook\",mentioned_list=[\"@\u8c01\u5c31\u586b\u5199\u8c01\u7684\u4f01\u4e1a\u5fae\u4fe1\u8d26\u53f7\",\"user2\"], extra_msg=\"\u8fd0\u884c\u62a5\u9519\")\ndef myfunc(args):\n    if args == 1:\n        raise Exception1\n    elif args == 2:\n        raise Exception2\n    else:\n        raise Exception3\n```\n\n\n\n#### timeit\n\n\u8017\u65f6\u7edf\u8ba1\u88c5\u9970\u5668\uff0c\u5355\u4f4d\u662f\u79d2\uff0c\u4fdd\u7559 4 \u4f4d\u5c0f\u6570\n\n\n\u4f7f\u7528\u65b9\u6cd5\uff1a\n\n```python\nfrom somedecorators import timeit\n@timeit()\ndef test_timeit():\n    time.sleep(1)\n\n#test_timeit cost 1.0026 seconds\n\n@timeit(logger = your_logger)\ndef test_timeit():\n    time.sleep(1)\n```\n\n\n#### timeout\n\n\u8d85\u65f6\u88c5\u9970\u5668\uff0c\u5355\u4f4d\u662f\u79d2\uff0c\u51fd\u6570\u8fd0\u884c\u8d85\u8fc7\u6307\u5b9a\u7684\u65f6\u95f4\u4f1a\u629b\u51fa TimeOutError \u5f02\u5e38\u3002\n\n\u4f7f\u7528\u65b9\u6cd5\uff1a\n\n```python\nimport time\nfrom somedecorators import timeout\n@timeout(2)\ndef test_timeit():\n    time.sleep(3)\n\n#somedecorators.timeit.TimeoutError: Operation did not finish within 2 seconds\n```\n\n\n\n#### retry\n\n\u91cd\u8bd5\u88c5\u9970\u5668\n- \u5f53\u88ab\u88c5\u9970\u7684\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u51fd\u6570\u4f1a\u88ab\u91cd\u65b0\u8c03\u7528\u3002\n- \u76f4\u5230\u8fbe\u5230\u6307\u5b9a\u7684\u6700\u5927\u8c03\u7528\u6b21\u6570\u624d\u91cd\u65b0\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u6307\u5b9a\u65f6\u95f4\u95f4\u9694\uff0c\u9ed8\u8ba4 5 \u79d2\u540e\u91cd\u8bd5\u3002\n- traced_exceptions \u4e3a\u76d1\u63a7\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u4e3a None\uff08\u9ed8\u8ba4\uff09\u3001\u5f02\u5e38\u7c7b\u3001\u6216\u8005\u4e00\u4e2a\u5f02\u5e38\u7c7b\u7684\u5217\u8868\u6216\u5143\u7ec4 tuple\u3002\n- traced_exceptions \u5982\u679c\u4e3a None\uff0c\u5219\u76d1\u63a7\u6240\u6709\u7684\u5f02\u5e38\uff1b\u5982\u679c\u6307\u5b9a\u4e86\u5f02\u5e38\u7c7b\uff0c\u5219\u82e5\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u91cd\u65b0\u8c03\u7528\u51fd\u6570\uff0c\u76f4\u81f3\u6210\u529f\u8fd4\u56de\u7ed3\u679c\u3002\n- \u672a\u51fa\u73b0\u76d1\u63a7\u7684\u5f02\u5e38\u65f6\uff0c\u5982\u679c\u6307\u5b9a\u5b9a\u4e86 reraised_exception \u5219\u629b\u51fa reraised_exception\uff0c\u5426\u5219\u629b\u51fa\u539f\u6765\u7684\u5f02\u5e38\u3002\n\n\n```python\nfrom somedecorators import retry \n\n@retry(\n    times=2,\n    wait_seconds=1,\n    traced_exceptions=myException,\n    reraised_exception=CustomException,\n)\ndef test_retry():\n    # time.sleep(1)\n    raise myException\n\n\ntest_retry()\n```\n\n\n\n#### email_on_exception\n\n\u62a5\u9519\u53d1\u90ae\u4ef6\u88c5\u9970\u5668\u3002\u5f53\u88ab\u88c5\u9970\u7684\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u51fd\u6570\u53d1\u9001\u90ae\u4ef6\u7ed9\u6307\u5b9a\u7684\u4eba\u5458\uff0c\u4f7f\u7528\u72ec\u7acb\u7684 [djangomail](https://github.com/somenzz/djangomail) \u53d1\u90ae\u4ef6\u6a21\u5757\uff0c\u975e\u5e38\u597d\u7528\u3002\n\n- recipient_list: \u4e00\u4e2a\u5b57\u7b26\u4e32\u5217\u8868\uff0c\u6bcf\u9879\u90fd\u662f\u4e00\u4e2a\u90ae\u7bb1\u5730\u5740\u3002recipient_list \u4e2d\u7684\u6bcf\u4e2a\u6210\u5458\u90fd\u53ef\u4ee5\u5728\u90ae\u4ef6\u7684 \"\u6536\u4ef6\u4eba:\" \u4e2d\u770b\u5230\u5176\u4ed6\u7684\u6536\u4ef6\u4eba\u3002\n- traced_exceptions \u4e3a\u76d1\u63a7\u7684\u5f02\u5e38\uff0c\u53ef\u4ee5\u4e3a None\uff08\u9ed8\u8ba4\uff09\u3001\u5f02\u5e38\u7c7b\u3001\u6216\u8005\u4e00\u4e2a\u5f02\u5e38\u7c7b\u7684\u5143\u7ec4\u3002\ntraced_exceptions \u5982\u679c\u4e3a None\uff0c\u5219\u76d1\u63a7\u6240\u6709\u7684\u5f02\u5e38\uff1b\u5982\u679c\u6307\u5b9a\u4e86\u5f02\u5e38\u7c7b\uff0c\u5219\u82e5\u51fd\u6570\u8c03\u7528\u629b\u51fa\u6307\u5b9a\u7684\u5f02\u5e38\u65f6\uff0c\u53d1\u9001\u90ae\u4ef6\u3002\n\n**\u4f7f\u7528\u65b9\u6cd5**\uff1a\n\n\u9996\u5148\u5728\u9879\u76ee\u76ee\u5f55\u65b0\u5efa settings.py\uff0c\u914d\u7f6e\u90ae\u4ef6\u670d\u52a1\u5668\u6216\u4f01\u4e1a\u5fae\u4fe1\uff0c\u5185\u5bb9\u5982\u4e0b\uff1a\n\n```python\nEMAIL_USE_LOCALTIME = True\n\n#for unitest\n#EMAIL_BACKEND = 'djangomail.backends.console.EmailBackend'\n#EMAIL_BACKEND = 'djangomail.backends.smtp.EmailBackend'\nEMAIL_USE_SSL = True\nEMAIL_HOST = 'smtp.163.com' #\u53ef\u4ee5\u6362\u5176\u4ed6\u90ae\u7bb1\nEMAIL_PORT = 465\nEMAIL_HOST_USER = 'your-username'\nEMAIL_HOST_PASSWORD = '********'\nDEFAULT_FROM_EMAIL = EMAIL_HOST_USER\nSERVER_EMAIL = EMAIL_HOST_USER\n\n\n# \u7528\u4e8e\u53d1\u9001\u4f01\u4e1a\u5fae\u4fe1\nCORPID=\"**********************\"  # \u4f01\u4e1a ID\nAPPID=\"*******\"  # \u4f01\u4e1a\u5e94\u7528 ID\nCORPSECRET=\"************************\" # \u4f01\u4e1a\u5e94\u7528 Secret\n\n```\n\n\u5982\u679c\u4f60\u7684\u6587\u4ef6\u540d\u4e0d\u662f settings.py\uff0c\u5047\u5982\u662f mysettings.py \u5219\u9700\u8981\u4fee\u6539\u73af\u5883\u53d8\u91cf:\n\n```python\nos.environ.setdefault(\"SETTINGS_MODULE\", \"mysettings\")\n```\n\u7136\u540e\u4e3b\u7a0b\u5e8f\u4e2d\u8fd9\u6837\u4f7f\u7528\uff1a\n\n##### \u76d1\u63a7\u6240\u6709\u7684\u5f02\u5e38\n\n```python\nfrom somedecorators import email_on_exception \n#import os\n#os.environ.setdefault(\"SETTINGS_MODULE\", \"settings\") #\u9ed8\u8ba4\u914d\u7f6e\uff0c\u53ef\u4ee5\u4e0d\u5199\u6b64\u884c\u4ee3\u7801\n\n@email_on_exception(['somenzz@163.com'])\ndef myfunc(arg):\n    1/arg\n\nmyfunc(0)\n```\n\n\u4f60\u4f1a\u6536\u5230\u5982\u4e0b\u7684\u90ae\u4ef6\u4fe1\u606f\uff0c\u975e\u5e38\u4fbf\u4e8e\u6392\u67e5\u9519\u8bef\u3002\n\n```sh\nSubject: myfunc(arg=0) raise Exception\nFrom: your-username\nTo: somenzz@163.com\nDate: Fri, 11 Jun 2021 20:55:01 -0500\nMessage-ID: \n <162346290112.13869.15957310483971819045@1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa>\n\nmyfunc(arg=0) raise Exception: division by zero \n traceback:\n Traceback (most recent call last):\n  File \"/Users/aaron/github/somenzz/somedecorators/somedecorators/email.py\", line 35, in wrapper\n    return func(*args, **kwargs)\n  File \"/Users/aaron/github/somenzz/somedecorators/tests/tests.py\", line 55, in myfunc\n    return 1/arg\nZeroDivisionError: division by zero\n\nextra_msg = \u4e25\u91cd\u9519\u8bef\n```\n\n##### \u76d1\u63a7\u6307\u5b9a\u7684\u5f02\u5e38\n\n```python\n\nfrom somedecorators import email_on_exception\nimport os\nos.environ.setdefault(\"SETTINGS_MODULE\", \"settings\")\n\nclass Exception1(Exception):\n    pass\n\nclass Exception2(Exception):\n    pass\n\nclass Exception3(Exception):\n    pass\n\n@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)\ndef myfunc(args):\n    if args == 1:\n        raise Exception1\n    elif args == 2:\n        raise Exception2\n    else:\n        raise Exception3\n\nmyfunc(2)\n\n```\n\u4e0a\u8ff0\u4ee3\u7801\u53ea\u6709\u5728 raise Exception2 \u65f6\u624d\u4f1a\u53d1\u9001\u90ae\u4ef6\uff1a\n\n##### \u4e0d\u540c\u7684\u5f02\u5e38\u53d1\u7ed9\u4e0d\u540c\u7684\u4eba\n\n```python\n@email_on_exception(['somenzz@163.com'],traced_exceptions = Exception2)\n@email_on_exception(['others@163.com'],traced_exceptions = (Exception1, Exception3))\ndef myfunc(args):\n    if args == 1:\n        raise Exception1\n    elif args == 2:\n        raise Exception2\n    else:\n        raise Exception3\n```\n\n\u662f\u4e0d\u662f\u975e\u5e38\u65b9\u4fbf\uff1f\n\n#### \u53d1\u9001\u4f01\u4e1a\u5fae\u4fe1\n\n\u53d1\u9001\u524d\u9700\u8981\u5728 settings.py \u6587\u4ef6\u4f01\u4e1a\u5fae\u4fe1\u76f8\u5173\u4fe1\u606f\n\nsettings.py \u793a\u4f8b\uff1a\n\n```python\n\nCORPID=\"**********************\"  # \u4f01\u4e1a ID\nAPPID=\"*******\"  # \u4f01\u4e1a\u5e94\u7528 ID\nCORPSECRET=\"************************\" # \u4f01\u4e1a\u5e94\u7528 Secret\n\n```\n\n\u8c03\u7528\u4ee3\u7801 \n\n```python\n@wechat_on_exception(['\u4f01\u4e1a\u5fae\u4fe1\u63a5\u6536\u8005ID'],traced_exceptions = Exception2)\ndef myfunc(args):\n    if args == 1:\n        raise Exception1\n    elif args == 2:\n        raise Exception2\n    else:\n        raise Exception3\n```\n\n\n#### \u5feb\u901f\u914d\u7f6e\u65e5\u5fd7 setup_logger\n\n\u4e00\u4e2a\u7b80\u5355\u7684\u4f7f\u7528\u65e5\u5fd7\u7684\u65b9\u6cd5\n\n```python\nfrom somedecorators import setup_logger\nlogger = setup_logger(\"myapp\")\nlogger.info(\"hello this is myapp log\")\nlogger2 = setup_logger(\"myapp2\", log_path=\"./log/app.log\")\nlogger3 = setup_logger(\"myapp3\",handlers=['console']) \nlogger4 = setup_logger(\"myapp4\",handlers=['console','file']) \n```\n\n#### \u5feb\u901f\u641e\u5b9a\u914d\u7f6e\u6587\u4ef6\n\n```python\nfrom somedecorators import ConfigManager\nconfig_manager = ConfigManager(\"config.yml\")\nconfig_data = config_manager.get_all()\nprint(config_data)\n```\n\n## \u53c2\u4e0e\u9879\u76ee\n\n\u6b22\u8fce\u5206\u4eab\u4f60\u6700\u5e38\u7528\u7684\u88c5\u9970\u5668\u3001\u7c7b\u3001\u51fd\u6570\uff0c\u52a0\u5165\u5230\u8fd9\u91cc\u3002\n\n## \u8054\u7cfb\u6211 \n\n\u5fae\u4fe1\uff1asomenzz-enjoy\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Some useful decorators in Python.",
    "version": "1.2.5",
    "project_urls": {
        "Homepage": "https://github.com/somenzz/somedecorators"
    },
    "split_keywords": [
        "awesome",
        "decorators"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e6ce6efcc44362923de0e5efbb9eb857fb4f6529f0e11e4ba3c17c843517cf03",
                "md5": "586964f66c8149354f6452196911a07b",
                "sha256": "09beb6d83ca64ce54056d3466b528809cf34879d7800ea630d229836c2f12e6c"
            },
            "downloads": -1,
            "filename": "somedecorators-1.2.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "586964f66c8149354f6452196911a07b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 23156,
            "upload_time": "2024-08-28T01:43:34",
            "upload_time_iso_8601": "2024-08-28T01:43:34.468624Z",
            "url": "https://files.pythonhosted.org/packages/e6/ce/6efcc44362923de0e5efbb9eb857fb4f6529f0e11e4ba3c17c843517cf03/somedecorators-1.2.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a55c5fc15a2d43f722cd639d5fffdb868818d79a3de001cddef80b10d72499be",
                "md5": "6baa54715ad4fa337ae3e3e2fd44d945",
                "sha256": "caa213815e97e3b266a4c58d9a12d0f0e27c7150e32318252fdbce245158b482"
            },
            "downloads": -1,
            "filename": "somedecorators-1.2.5.tar.gz",
            "has_sig": false,
            "md5_digest": "6baa54715ad4fa337ae3e3e2fd44d945",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 23544,
            "upload_time": "2024-08-28T01:43:36",
            "upload_time_iso_8601": "2024-08-28T01:43:36.026958Z",
            "url": "https://files.pythonhosted.org/packages/a5/5c/5fc15a2d43f722cd639d5fffdb868818d79a3de001cddef80b10d72499be/somedecorators-1.2.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-08-28 01:43:36",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "somenzz",
    "github_project": "somedecorators",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "tox": true,
    "lcname": "somedecorators"
}
        
Elapsed time: 0.38918s