| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent ad8958f commit ac630cc
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,112 @@ | |||
| 1 | + # encoding: utf-8 | ||
| 2 | + | ||
| 3 | + # The MIT License | ||
| 4 | + # | ||
| 5 | + # Copyright (c) 2014-2015 Sebastian Ramacher | ||
| 6 | + # | ||
| 7 | + # Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 8 | + # of this software and associated documentation files (the "Software"), to deal | ||
| 9 | + # in the Software without restriction, including without limitation the rights | ||
| 10 | + # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 11 | + # copies of the Software, and to permit persons to whom the Software is | ||
| 12 | + # furnished to do so, subject to the following conditions: | ||
| 13 | + # | ||
| 14 | + # The above copyright notice and this permission notice shall be included in | ||
| 15 | + # all copies or substantial portions of the Software. | ||
| 16 | + # | ||
| 17 | + # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 18 | + # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 19 | + # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 20 | + # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 21 | + # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 22 | + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 23 | + # THE SOFTWARE. | ||
| 24 | + | ||
| 25 | + from locale import getpreferredencoding | ||
| 26 | + from six.moves.urllib_parse import quote as urlquote, urljoin, urlparse | ||
| 27 | + from string import Template | ||
| 28 | + import errno | ||
| 29 | + import requests | ||
| 30 | + import subprocess | ||
| 31 | + import unicodedata | ||
| 32 | + | ||
| 33 | + from bpython.translations import _ | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + class PasteFailed(Exception): | ||
| 37 | + pass | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + class PastePinnwand(object): | ||
| 41 | + def __init__(self, url, expiry, show_url, removal_url): | ||
| 42 | + self.url = url | ||
| 43 | + self.expiry = expiry | ||
| 44 | + self.show_url = show_url | ||
| 45 | + self.removal_url = removal_url | ||
| 46 | + | ||
| 47 | + def paste(self, s): | ||
| 48 | + """Upload to pastebin via json interface.""" | ||
| 49 | + | ||
| 50 | + url = urljoin(self.url, '/json/new') | ||
| 51 | + payload = { | ||
| 52 | + 'code': s, | ||
| 53 | + 'lexer': 'pycon', | ||
| 54 | + 'expiry': self.expiry | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + try: | ||
| 58 | + response = requests.post(url, data=payload, verify=True) | ||
| 59 | + response.raise_for_status() | ||
| 60 | + except requests.exceptions.RequestException as exc: | ||
| 61 | + raise PasteFailed(exc.message) | ||
| 62 | + | ||
| 63 | + data = response.json() | ||
| 64 | + | ||
| 65 | + paste_url_template = Template(self.show_url) | ||
| 66 | + paste_id = urlquote(data['paste_id']) | ||
| 67 | + paste_url = paste_url_template.safe_substitute(paste_id=paste_id) | ||
| 68 | + | ||
| 69 | + removal_url_template = Template(self.removal_url) | ||
| 70 | + removal_id = urlquote(data['removal_id']) | ||
| 71 | + removal_url = removal_url_template.safe_substitute( | ||
| 72 | + removal_id=removal_id) | ||
| 73 | + | ||
| 74 | + return (paste_url, removal_url) | ||
| 75 | + | ||
| 76 | + | ||
| 77 | + class PasteHelper(object): | ||
| 78 | + def __init__(self, executable): | ||
| 79 | + self.executable = executable | ||
| 80 | + | ||
| 81 | + def paste(self, s): | ||
| 82 | + """Call out to helper program for pastebin upload.""" | ||
| 83 | + | ||
| 84 | + try: | ||
| 85 | + helper = subprocess.Popen('', | ||
| 86 | + executable=self.executable, | ||
| 87 | + stdin=subprocess.PIPE, | ||
| 88 | + stdout=subprocess.PIPE) | ||
| 89 | + helper.stdin.write(s.encode(getpreferredencoding())) | ||
| 90 | + output = helper.communicate()[0].decode(getpreferredencoding()) | ||
| 91 | + paste_url = output.split()[0] | ||
| 92 | + except OSError as e: | ||
| 93 | + if e.errno == errno.ENOENT: | ||
| 94 | + raise PasteFailed(_('Helper program not found.')) | ||
| 95 | + else: | ||
| 96 | + raise PasteFailed(_('Helper program could not be run.')) | ||
| 97 | + | ||
| 98 | + if helper.returncode != 0: | ||
| 99 | + raise PasteFailed(_('Helper program returned non-zero exit ' | ||
| 100 | + 'status %d.' % (helper.returncode, ))) | ||
| 101 | + | ||
| 102 | + if not paste_url: | ||
| 103 | + raise PasteFailed(_('No output from helper program.')) | ||
| 104 | + else: | ||
| 105 | + parsed_url = urlparse(paste_url) | ||
| 106 | + if (not parsed_url.scheme | ||
| 107 | + or any(unicodedata.category(c) == 'Cc' | ||
| 108 | + for c in paste_url)): | ||
| 109 | + raise PasteFailed(_('Failed to recognize the helper ' | ||
| 110 | + 'program\'s output as an URL.')) | ||
| 111 | + | ||
| 112 | + return paste_url, | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,26 +24,21 @@ | |||
| 24 | 24 | # THE SOFTWARE. | |
| 25 | 25 | ||
| 26 | 26 | import code | |
| 27 | - import errno | ||
| 28 | 27 | import inspect | |
| 29 | 28 | import io | |
| 30 | 29 | import os | |
| 31 | 30 | import pkgutil | |
| 32 | 31 | import pydoc | |
| 33 | - import requests | ||
| 34 | 32 | import shlex | |
| 35 | 33 | import subprocess | |
| 36 | 34 | import sys | |
| 37 | 35 | import tempfile | |
| 38 | 36 | import textwrap | |
| 39 | 37 | import time | |
| 40 | 38 | import traceback | |
| 41 | - import unicodedata | ||
| 42 | 39 | from itertools import takewhile | |
| 43 | 40 | from locale import getpreferredencoding | |
| 44 | - from string import Template | ||
| 45 | 41 | from six import itervalues | |
| 46 | - from six.moves.urllib_parse import quote as urlquote, urljoin, urlparse | ||
| 47 | 42 | ||
| 48 | 43 | from pygments.token import Token | |
| 49 | 44 | ||
@@ -53,6 +48,7 @@ | |||
| 53 | 48 | from bpython.clipboard import get_clipboard, CopyFailed | |
| 54 | 49 | from bpython.formatter import Parenthesis | |
| 55 | 50 | from bpython.history import History | |
| 51 | + from bpython.paste import PasteHelper, PastePinnwand, PasteFailed | ||
| 56 | 52 | from bpython.translations import _, ngettext | |
| 57 | 53 | ||
| 58 | 54 | ||
@@ -386,6 +382,13 @@ def __init__(self, interp, config): | |||
| 386 | 382 | ||
| 387 | 383 | self.completers = autocomplete.get_default_completer( | |
| 388 | 384 | config.autocomplete_mode) | |
| 385 | + if self.config.pastebin_helper: | ||
| 386 | + self.paster = PasteHelper(self.config.pastebin_helper) | ||
| 387 | + else: | ||
| 388 | + self.paster = PastePinnwand(self.config.pastebin_url, | ||
| 389 | + self.config.pastebin_expiry, | ||
| 390 | + self.config.pastebin_show_url, | ||
| 391 | + self.config.pastebin_removal_url) | ||
| 389 | 392 | ||
| 390 | 393 | @property | |
| 391 | 394 | def ps1(self): | |
@@ -761,91 +764,24 @@ def do_pastebin(self, s): | |||
| 761 | 764 | self.prev_removal_url), 10) | |
| 762 | 765 | return self.prev_pastebin_url | |
| 763 | 766 | ||
| 764 | - if self.config.pastebin_helper: | ||
| 765 | - return self.do_pastebin_helper(s) | ||
| 766 | - else: | ||
| 767 | - return self.do_pastebin_json(s) | ||
| 768 | - | ||
| 769 | - def do_pastebin_json(self, s): | ||
| 770 | - """Upload to pastebin via json interface.""" | ||
| 771 | - | ||
| 772 | - url = urljoin(self.config.pastebin_url, '/json/new') | ||
| 773 | - payload = { | ||
| 774 | - 'code': s, | ||
| 775 | - 'lexer': 'pycon', | ||
| 776 | - 'expiry': self.config.pastebin_expiry | ||
| 777 | - } | ||
| 778 | 767 | ||
| 779 | 768 | self.interact.notify(_('Posting data to pastebin...')) | |
| 780 | 769 | try: | |
| 781 | - response = requests.post(url, data=payload, verify=True) | ||
| 782 | - response.raise_for_status() | ||
| 783 | - except requests.exceptions.RequestException as exc: | ||
| 784 | - self.interact.notify(_('Upload failed: %s') % (exc, )) | ||
| 770 | + paste_url, removal_url = self.paster.paste(s) | ||
| 771 | + except PasteFailed as e: | ||
| 772 | + self.interact.notify(_('Upload failed: %s') % e) | ||
| 785 | 773 | return | |
| 786 | 774 | ||
| 787 | 775 | self.prev_pastebin_content = s | |
| 788 | - data = response.json() | ||
| 789 | - | ||
| 790 | - paste_url_template = Template(self.config.pastebin_show_url) | ||
| 791 | - paste_id = urlquote(data['paste_id']) | ||
| 792 | - paste_url = paste_url_template.safe_substitute(paste_id=paste_id) | ||
| 793 | - | ||
| 794 | - removal_url_template = Template(self.config.pastebin_removal_url) | ||
| 795 | - removal_id = urlquote(data['removal_id']) | ||
| 796 | - removal_url = removal_url_template.safe_substitute( | ||
| 797 | - removal_id=removal_id) | ||
| 798 | - | ||
| 799 | 776 | self.prev_pastebin_url = paste_url | |
| 800 | 777 | self.prev_removal_url = removal_url | |
| 801 | - self.interact.notify(_('Pastebin URL: %s - Removal URL: %s') % | ||
| 802 | - (paste_url, removal_url), 10) | ||
| 803 | - | ||
| 804 | - return paste_url | ||
| 805 | 778 | ||
| 806 | - def do_pastebin_helper(self, s): | ||
| 807 | - """Call out to helper program for pastebin upload.""" | ||
| 808 | - self.interact.notify(_('Posting data to pastebin...')) | ||
| 809 | - | ||
| 810 | - try: | ||
| 811 | - helper = subprocess.Popen('', | ||
| 812 | - executable=self.config.pastebin_helper, | ||
| 813 | - stdin=subprocess.PIPE, | ||
| 814 | - stdout=subprocess.PIPE) | ||
| 815 | - helper.stdin.write(s.encode(getpreferredencoding())) | ||
| 816 | - output = helper.communicate()[0].decode(getpreferredencoding()) | ||
| 817 | - paste_url = output.split()[0] | ||
| 818 | - except OSError as e: | ||
| 819 | - if e.errno == errno.ENOENT: | ||
| 820 | - self.interact.notify(_('Upload failed: ' | ||
| 821 | - 'Helper program not found.')) | ||
| 822 | - else: | ||
| 823 | - self.interact.notify(_('Upload failed: ' | ||
| 824 | - 'Helper program could not be run.')) | ||
| 825 | - return | ||
| 826 | - | ||
| 827 | - if helper.returncode != 0: | ||
| 828 | - self.interact.notify(_('Upload failed: ' | ||
| 829 | - 'Helper program returned non-zero exit ' | ||
| 830 | - 'status %d.' % (helper.returncode, ))) | ||
| 831 | - return | ||
| 832 | - | ||
| 833 | - if not paste_url: | ||
| 834 | - self.interact.notify(_('Upload failed: ' | ||
| 835 | - 'No output from helper program.')) | ||
| 836 | - return | ||
| 779 | + if removal_url is not None: | ||
| 780 | + self.interact.notify(_('Pastebin URL: %s - Removal URL: %s') % | ||
| 781 | + (paste_url, removal_url), 10) | ||
| 837 | 782 | else: | |
| 838 | - parsed_url = urlparse(paste_url) | ||
| 839 | - if (not parsed_url.scheme | ||
| 840 | - or any(unicodedata.category(c) == 'Cc' | ||
| 841 | - for c in paste_url)): | ||
| 842 | - self.interact.notify(_("Upload failed: " | ||
| 843 | - "Failed to recognize the helper " | ||
| 844 | - "program's output as an URL.")) | ||
| 845 | - return | ||
| 783 | + self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) | ||
| 846 | 784 | ||
| 847 | - self.prev_pastebin_content = s | ||
| 848 | - self.interact.notify(_('Pastebin URL: %s') % (paste_url, ), 10) | ||
| 849 | 785 | return paste_url | |
| 850 | 786 | ||
| 851 | 787 | def push(self, s, insert_into_history=True): | |
| Back | FazBrowse Home | New Git URL |
0 commit comments