-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
439 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
name: Publish on Test PyPI and PyPI | ||
|
||
on: | ||
push: | ||
branches: | ||
# Commits pushed to release/ branches are published on Test PyPI if they | ||
# have a new version number. | ||
- "release/**" | ||
tags: | ||
# Tags that start with the "v" prefix are published on PyPI. | ||
- "v*" | ||
|
||
jobs: | ||
|
||
build-and-publish-test: | ||
|
||
name: Build and publish on TestPyPI | ||
if: startsWith(github.ref, 'refs/heads/release/') | ||
|
||
runs-on: ubuntu-latest | ||
environment: | ||
name: Test PyPI | ||
url: https://test.pypi.org/project/aiidalab-widgets-base/ | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Set up Python 3.8 | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
|
||
- name: Install pypa/build | ||
run: python -m pip install build | ||
|
||
- name: Build a binary wheel and a source tarball | ||
run: >- | ||
python -m | ||
build | ||
--sdist | ||
--wheel | ||
--outdir dist/ | ||
. | ||
- name: Publish distribution on Test PyPI | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
user: __token__ | ||
password: ${{ secrets.PYPI_API_TOKEN }} | ||
repository_url: https://test.pypi.org/legacy/ | ||
|
||
build-and-publish: | ||
|
||
name: Build and publish on PyPI | ||
if: startsWith(github.ref, 'refs/tags') | ||
|
||
runs-on: ubuntu-latest | ||
environment: | ||
name: PyPI | ||
url: https://pypi.org/project/aiidalab-widgets-base/ | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- name: Set up Python 3.8 | ||
uses: actions/setup-python@v2 | ||
with: | ||
python-version: 3.8 | ||
|
||
- name: Install pypa/build | ||
run: python -m pip install build | ||
|
||
- name: Build a binary wheel and a source tarball | ||
run: >- | ||
python -m | ||
build | ||
--sdist | ||
--wheel | ||
--outdir dist/ | ||
. | ||
- name: Publish distribution on PyPI | ||
uses: pypa/gh-action-pypi-publish@release/v1 | ||
with: | ||
user: __token__ | ||
password: ${{ secrets.PYPI_API_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
"""Provide more user friendly error messages and automated reporting. | ||
Authors: | ||
* Carl Simon Adorf <[email protected]> | ||
""" | ||
import base64 | ||
import json | ||
import platform | ||
import re | ||
import sys | ||
import zlib | ||
from textwrap import wrap | ||
from urllib.parse import urlencode, urlsplit, urlunsplit | ||
|
||
import ipywidgets as ipw | ||
from aiidalab.utils import find_installed_packages | ||
from ansi2html import Ansi2HTMLConverter | ||
|
||
|
||
def get_environment_fingerprint(encoding="utf-8"): | ||
packages = find_installed_packages() | ||
data = { | ||
"version": 1, | ||
"platform": { | ||
"architecture": platform.architecture(), | ||
"python_version": platform.python_version(), | ||
"version": platform.version(), | ||
}, | ||
"packages": {package.name: package.version for package in packages}, | ||
} | ||
json_data = json.dumps(data, separators=(",", ":")) | ||
return base64.urlsafe_b64encode(zlib.compress(json_data.encode(encoding), level=9)) | ||
|
||
|
||
def parse_environment_fingerprint(data, encoding="utf-8"): | ||
packages = json.loads( | ||
zlib.decompress(base64.urlsafe_b64decode(data)).decode(encoding) | ||
) | ||
return packages | ||
|
||
|
||
ERROR_MESSAGE = """<div class="alert alert-danger"> | ||
<p><strong> | ||
<i class="fa fa-bug" aria-hidden="true"></i> Oh no... the application crashed due to an unexpected error. | ||
</strong></p> | ||
<a href="{issue_url}" target="_blank" class="btn btn-primary"> | ||
<i class="fa fa-share" aria-hidden="true"></i> Create bug report | ||
</a> | ||
<button | ||
onclick="Jupyter.notebook.clear_all_output(); Jupyter.notebook.restart_run_all({{confirm: false}})" | ||
type="button" | ||
class="btn btn-success"> | ||
<i class="fa fa-refresh" aria-hidden="true"></i> Restart app | ||
</button> | ||
<div style="padding-top: 1em"> | ||
<details style="border: 1px solid #aaa; border-radius: 4px; padding: .5em .5em 0; "> | ||
<summary style="font-weight: bold; margin: -.5em -.5em 0; padding: .5em"> | ||
<i class="fa fa-code" aria-hidden="true"></i> View the full traceback | ||
</summary> | ||
<pre style="color: #333; background: #f8f8f8;"><code>{traceback}</code></pre> | ||
</details> | ||
</div></div>""" | ||
|
||
|
||
BUG_REPORT_TITLE = """Bug report: Application crashed with {exception_type}""" | ||
|
||
BUG_REPORT_BODY = """## Automated report | ||
_This issue was created with the app's automated bug reporting feature. | ||
Attached to this issue is the full traceback as well as an environment | ||
fingerprint that contains information about the operating system as well as all | ||
installed libraries._ | ||
## Additional comments (optional): | ||
_Example: I submitted a band structure calculation for Silica._ | ||
## Attachments | ||
<details> | ||
<summary>Traceback</summary> | ||
```python-traceback | ||
{traceback} | ||
``` | ||
</details> | ||
<details> | ||
<summary>Environment fingerprint</summary> | ||
<pre>{environment_fingerprint}</pre> | ||
</details> | ||
**By submitting this issue I confirm that I am aware that this information can | ||
potentially be used to determine what kind of calculation was performed at the | ||
time of error.** | ||
""" | ||
|
||
|
||
def _strip_ansi_codes(msg): | ||
"""Remove any ANSI codes (e.g. color codes).""" | ||
return re.sub(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])", "", msg) | ||
|
||
|
||
def _convert_ansi_codes_to_html(msg): | ||
"""Convert any ANSI codes (e.g. color codes) into HTML.""" | ||
converter = Ansi2HTMLConverter() | ||
return converter.produce_headers().strip() + converter.convert(msg, full=False) | ||
|
||
|
||
def _format_truncated_traceback(traceback, max_num_chars=3000): | ||
"""Truncate the traceback to the given character length.""" | ||
n = 0 | ||
for i, line in enumerate(reversed(traceback)): | ||
n += len(_strip_ansi_codes(line)) + 2 # add 2 for newline control characters | ||
if n > max_num_chars: | ||
break | ||
return _strip_ansi_codes("\n".join(traceback[-i:])) | ||
|
||
|
||
_ORIGINAL_EXCEPTION_HANDLER = None | ||
|
||
|
||
def install_create_github_issue_exception_handler(output, url, labels=None): | ||
"""Install a GitHub bug report exception handler. | ||
After installing this handler, kernel exception will show a generic error | ||
message to the user, with the option to file an automatic bug report at the | ||
given URL. | ||
""" | ||
global _ORIGINAL_EXCEPTION_HANDLER | ||
|
||
if labels is None: | ||
labels = [] | ||
|
||
ipython = get_ipython() # noqa | ||
_ORIGINAL_EXCEPTION_HANDLER = _ORIGINAL_EXCEPTION_HANDLER or ipython._showtraceback | ||
|
||
def create_github_issue_exception_handler(exception_type, exception, traceback): | ||
try: | ||
output.clear_output() | ||
|
||
bug_report_query = { | ||
"title": BUG_REPORT_TITLE.format( | ||
exception_type=str(exception_type.__name__) | ||
), | ||
"body": BUG_REPORT_BODY.format( | ||
# Truncate the traceback to a maximum of 3000 characters | ||
# and strip all ansi control characters: | ||
traceback=_format_truncated_traceback(traceback, 3000), | ||
# Determine and format the environment fingerprint to be | ||
# included with the bug report: | ||
environment_fingerprint="\n".join( | ||
wrap(get_environment_fingerprint().decode("utf-8"), 100) | ||
), | ||
), | ||
"labels": ",".join(labels), | ||
} | ||
issue_url = urlunsplit( | ||
urlsplit(url)._replace(query=urlencode(bug_report_query)) | ||
) | ||
|
||
with output: | ||
msg = ipw.HTML( | ||
ERROR_MESSAGE.format( | ||
issue_url=issue_url, | ||
traceback=_convert_ansi_codes_to_html("\n".join(traceback)), | ||
len_url=len(issue_url), | ||
) | ||
) | ||
display(msg) # noqa | ||
except Exception as error: | ||
print(f"Error while generating bug report: {error}", file=sys.stderr) | ||
_ORIGINAL_EXCEPTION_HANDLER(exception_type, exception, traceback) | ||
|
||
def restore_original_exception_handler(): | ||
ipython._showtraceback = _ORIGINAL_EXCEPTION_HANDLER | ||
|
||
ipython._showtraceback = create_github_issue_exception_handler | ||
|
||
return restore_original_exception_handler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.