1
0
mirror of https://github.com/huggingface/knockknock.git synced 2021-08-28 00:30:42 +03:00

commit lib

This commit is contained in:
VictorSanh
2019-03-20 09:13:20 -04:00
parent 751ebdcda9
commit 2919e489e3
7 changed files with 222 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 Hugging Face
Copyright (c) 2019 Victor SANH and Hugging Face
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,2 +1,53 @@
# knockknock
🚪👋Knock Knock: Be notified when your training is finished with only two additional lines of code
# Knock Knock
A small library to get a notification you when your training is complete or when it crashes during the process with two additional lines of code.
When training deep learning models, it is common to use early stopping. Apart from a rough estimate, it is difficult to predict when the training will finish. Then, it can be interesting to set up automatic notifications for your training. It is also interesting to be notified when your training crashes in the middle of the process for unexpected reasons.
## Installation
Install with `pip` or equivalent.
```bash
pip install .
```
This code has only been tested with Python 3.6.
## Usage
The library is designed to be used in a seamless way, with minimal code modification: you only need to add a decorator on top your main function call.
There are currently two ways to setup notifications: email and Slack.
### Email
The service relies on [Yagmail](https://github.com/kootenpv/yagmail) a GMAIL/SMTP client. You'll need a gmail email address to use it (you can setup one [here](https://accounts.google.com), it's free). I recommend creating a new one (rather than your usual one) since you'll have to modify the account's security settings to allow the Python library to access it by [Turning on less secure apps](https://devanswers.co/allow-less-secure-apps-access-gmail-account/).
```python
from knockknock import email_sender
@email_sender(recipient_email: "<your_email@address.com>", sender_email: "<grandma's_email@gmail.com>")
def train_your_nicest_model(your_nicest_parameters):
import time
time.sleep(10000)
```
If `sender_email` is not specified, then `recipient_email` will be also used for sending.
Note that launching this will asks you for the sender's email password. It will be safely stored in the system keyring service through the [`keyring` Python library](https://pypi.org/project/keyring/).
### Slack
Similarly, you can also use Slack to get notifications. You'll have to get your Slack room [weebhook URL](https://api.slack.com/incoming-webhooks#create_a_webhook) and optionally your [user id](https://api.slack.com/methods/users.identity) (if you want to tag yourself or someone else).
```python
from knockknock import slack_sender
webhook_url = "<webhook_url_to_your_slack_room>"
@slack_sender(webhook_url=webhook_url, channel="<your_favorite_slack_channel>")
def train_your_nicest_model(your_nicest_parameters):
import time
time.sleep(10000)
```
You can also specify an optional argument to tag specific people: `user_mentions=[<your_slack_id>, <grandma's_slack_id>]`.

BIN
knockknock/.DS_Store vendored Normal file

Binary file not shown.

2
knockknock/__init__.py Normal file
View File

@@ -0,0 +1,2 @@
from knockknock.email_sender import email_sender
from knockknock.slack_sender import slack_sender

View File

@@ -0,0 +1,66 @@
import datetime
import traceback
import functools
import socket
import yagmail
DATE_FORMAT = "%Y-%m-%d %H:%M:%d"
def email_sender(recipient_email: str, sender_email: str = None):
"""
Email sender wrapper: execute func, send an email with the end status
(sucessfully finished or crashed) at the end. Also send an email before
executing func.
`recipient_email`: str
The email address to notify.
`sender_email`: str (default=None)
The email adress to send the messages. If None, use the same
address as `recipient_email`.
"""
if sender_email is None:
sender_email = recipient_email
yag_sender = yagmail.SMTP(sender_email)
def decorator_sender(func):
@functools.wraps(func)
def wrapper_sender(*args, **kwargs):
start_time = datetime.datetime.now()
contents = ['Your training has started.',
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: %s' % start_time.strftime(DATE_FORMAT)]
yag_sender.send(recipient_email, 'Training has started 🎬', contents)
try:
value = func(*args, **kwargs)
end_time = datetime.datetime.now()
elapsed_time = end_time - start_time
contents = ["Your training is complete.",
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: %s' % start_time.strftime(DATE_FORMAT),
'End date: %s' % end_time.strftime(DATE_FORMAT),
'Training duration: %s' % str(elapsed_time)]
yag_sender.send(recipient_email, 'Training has sucessfully finished 🎉', contents)
return value
except Exception as ex:
end_time = datetime.datetime.now()
elapsed_time = end_time - start_time
contents = ["Your training has crashed.",
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: %s' % start_time.strftime(DATE_FORMAT),
'Crash date: %s' % end_time.strftime(DATE_FORMAT),
'Crashed training duration: %s\n\n' % str(elapsed_time),
"Here's the error:",
'%s\n\n' % ex,
"Traceback",
'%s' % traceback.format_exc()]
yag_sender.send(recipient_email, 'Training has crashed ☠️', contents)
return wrapper_sender
return decorator_sender

View File

@@ -0,0 +1,82 @@
from typing import List
import datetime
import traceback
import functools
import json
import socket
import requests
DATE_FORMAT = "%Y-%m-%d %H:%M:%d"
def slack_sender(webhook_url: str, channel: str, user_mentions: List[str] = []):
"""
Email sender wrapper: execute func, send an email with the end status
(sucessfully finished or crashed) at the end. Also send an email before
executing func.
`webhook_url`: str
The webhook URL to access your slack room.
Visit https://api.slack.com/incoming-webhooks#create_a_webhook for more details.
`channel`: str
The slack room to log.
`user_mentions`: List[str] (default=[])
Optional users ids to notify.
Visit https://api.slack.com/methods/users.identity for more details.
"""
dump = {
"username": "Knock Knock",
"channel": channel,
"icon_emoji": ":clapper:",
}
def decorator_sender(func):
@functools.wraps(func)
def wrapper_sender(*args, **kwargs):
start_time = datetime.datetime.now()
contents = ['Your training has started 🎬',
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: {start_time.strftime(DATE_FORMAT)}']
contents.append(' '.join(user_mentions))
dump['text'] = '\n'.join(contents)
dump['icon_emoji'] = ':clapper:'
requests.post(webhook_url, json.dumps(dump))
try:
value = func(*args, **kwargs)
end_time = datetime.datetime.now()
elapsed_time = end_time - start_time
contents = ["Your training is complete 🎉",
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: %s' % start_time.strftime(DATE_FORMAT),
'End date: %s' % end_time.strftime(DATE_FORMAT),
'Training duration: %s' % str(elapsed_time)]
contents.append(' '.join(user_mentions))
dump['text'] = '\n'.join(contents)
dump['icon_emoji'] = ':tada:'
requests.post(webhook_url, json.dumps(dump))
return value
except Exception as ex:
end_time = datetime.datetime.now()
elapsed_time = end_time - start_time
contents = ["Your training has crashed ☠️",
'Machine name: %s' % socket.gethostname(),
'Main call: %s' % func.__name__,
'Starting date: %s' % start_time.strftime(DATE_FORMAT),
'Crash date: %s' % end_time.strftime(DATE_FORMAT),
'Crashed training duration: %s\n\n' % str(elapsed_time),
"Here's the error:",
'%s\n\n' % ex,
"Traceback",
'%s' % traceback.format_exc()]
contents.append(' '.join(user_mentions))
dump['text'] = '\n'.join(contents)
dump['icon_emoji'] = ':skull_and_crossbones:'
requests.post(webhook_url, json.dumps(dump))
return wrapper_sender
return decorator_sender

18
setup.py Normal file
View File

@@ -0,0 +1,18 @@
from setuptools import setup, find_packages
setup(
name='knockknock',
version='0.1',
description='Be notified when your training is finished with only two additional lines of code',
url='http://github.com/huggingface/knockknock',
author='Victor SANH',
author_email='victorsanh@gmail.com',
license='MIT',
packages=find_packages(),
zip_safe=False,
python_requires='>=3.6',
install_requires=[
'yagmail>=0.11.214',
'keyring'
]
)