def test_content(self): responses.add( responses.GET, 'https://api.github.com/gists/1', body=json.dumps({ "files": { "file-A.txt": { "filename": "file-A.txt", "content": b64encode("test-content-A"), }, "file-B.txt": { "filename": "file-B.txt", "content": b64encode("test-content-\u212C"), } }, "description": "test-gist", "public": True, "id": 1, }), status=200, ) content = gist.GistAPI(token='foo').content('1') self.assertEqual(len(content), 2) self.assertTrue('file-A.txt' in content) self.assertTrue('file-B.txt' in content) self.assertEqual(content['file-A.txt'], 'test-content-A') self.assertEqual(content['file-B.txt'], 'test-content-\u212C')
def test_list(self): responses.add( responses.GET, 'https://api.github.com/gists', body=json.dumps([ { 'id': 1, 'description': 'test-desc-A', 'public': True, }, { 'id': 2, 'description': 'test-desc-\u212C', 'public': False, }, ]), status=200, ) gists = gist.GistAPI(token='foo').list() gistA = gists[0] gistB = gists[1] self.assertEqual(gistA.id, 1) self.assertEqual(gistA.desc, 'test-desc-A') self.assertTrue(gistA.public) self.assertEqual(gistB.id, 2) self.assertEqual(gistB.desc, 'test-desc-\u212C') self.assertFalse(gistB.public)
def test_create(self): def request_handler(request): data = json.loads(request.body) self.assertEqual(len(data['files']), 2) self.assertTrue('test-file-A' in data['files']) content = {k: v['content'] for k, v in data['files'].items()} self.assertEqual(content['test-file-A'], 'test-content-A') self.assertEqual(content['test-file-B'], 'test-content-\u212C') status = 200 headers = {} body = json.dumps({'html_url': 'https://gist.github.com/gists/1'}) return status, headers, body responses.add_callback( responses.POST, 'https://api.github.com/gists', callback=request_handler, content_type='application/json', ) public = True desc = 'test-desc' files = { 'test-file-A': { 'content': 'test-content-A' }, 'test-file-B': { 'content': 'test-content-\u212C' }, } gist.GistAPI(token='foo').create(desc, files, public)
def test_list_empty(self): responses.add(responses.GET, 'https://api.github.com/gists', body="", status=200, ) gists = gist.GistAPI(token='foo').list() self.assertTrue(len(gists) == 0)
def main(argv=sys.argv[1:], config=None): args = docopt.docopt( __doc__, argv=argv, version='gist-v{}'.format(gist.__version__), ) # Read in the configuration file if config is None: config = configparser.ConfigParser() config_path = os.path.expanduser('~/.gist') config_path = alternative_config(config_path) config_path = xdg_data_config(config_path) with open(config_path) as fp: config.readfp(fp) # Setup logging fmt = "%(created).3f %(levelname)s[%(name)s] %(message)s" logging.basicConfig(format=fmt) try: log_level = config.get('gist', 'log-level').upper() logging.getLogger('gist').setLevel(log_level) except Exception: logging.getLogger('gist').setLevel(logging.ERROR) # Determine the editor to use editor = None editor = alternative_editor(editor) editor = environment_editor(editor) editor = configuration_editor(config, editor) if editor is None: raise ValueError('Unable to find an editor.') token = config.get('gist', 'token') gapi = gist.GistAPI(token=token, editor=editor) if args['list']: logger.debug(u'action: list') gists = gapi.list() for info in gists: public = '+' if info.public else '-' desc = '' if info.desc is None else info.desc line = u'{} {} {}'.format(info.id, public, desc) try: print(elide(line)) except UnicodeEncodeError: logger.error('unable to write gist {}'.format(info.id)) return if args['info']: gist_id = args['<id>'] logger.debug(u'action: info') logger.debug(u'action: - {}'.format(gist_id)) info = gapi.info(gist_id) print(json.dumps(info, indent=2)) return if args['edit']: gist_id = args['<id>'] logger.debug(u'action: edit') logger.debug(u'action: - {}'.format(gist_id)) gapi.edit(gist_id) return if args['description']: gist_id = args['<id>'] description = args['<desc>'] logger.debug(u'action: description') logger.debug(u'action: - {}'.format(gist_id)) logger.debug(u'action: - {}'.format(description)) gapi.description(gist_id, description) return if args['fork']: gist_id = args['<id>'] logger.debug(u'action: fork') logger.debug(u'action: - {}'.format(gist_id)) info = gapi.fork(gist_id) return if args['clone']: gist_id = args['<id>'] gist_name = args['<name>'] logger.debug(u'action: clone') logger.debug(u'action: - {} as {}'.format(gist_id, gist_name)) gapi.clone(gist_id, gist_name) return if args['content']: gist_id = args['<id>'] logger.debug(u'action: content') logger.debug(u'action: - {}'.format(gist_id)) content = gapi.content(gist_id) gist_file = content.get(args['<filename>']) if args['--decrypt']: if not config.has_option('gist', 'gnupg-homedir'): raise GistError('gnupg-homedir missing from config file') homedir = config.get('gist', 'gnupg-homedir') logger.debug(u'action: - {}'.format(homedir)) gpg = gnupg.GPG(gnupghome=homedir, use_agent=True) if gist_file is not None: print(gpg.decrypt(gist_file).data.decode('utf-8')) else: for name, lines in content.items(): lines = gpg.decrypt(lines).data.decode('utf-8') print(u'{} (decrypted):\n{}\n'.format(name, lines)) else: if gist_file is not None: print(gist_file) else: for name, lines in content.items(): print(u'{}:\n{}\n'.format(name, lines)) return if args['files']: gist_id = args['<id>'] logger.debug(u'action: files') logger.debug(u'action: - {}'.format(gist_id)) for f in gapi.files(gist_id): print(f) return if args['archive']: gist_id = args['<id>'] logger.debug(u'action: archive') logger.debug(u'action: - {}'.format(gist_id)) gapi.archive(gist_id) return if args['delete']: gist_ids = args['<ids>'] logger.debug(u'action: delete') for gist_id in gist_ids: logger.debug(u'action: - {}'.format(gist_id)) gapi.delete(gist_id) return if args['version']: logger.debug(u'action: version') print('v{}'.format(gist.__version__)) return if args['create']: logger.debug('action: create') # If encryption is selected, perform an initial check to make sure that # it is possible before processing any data. if args['--encrypt']: if not config.has_option('gist', 'gnupg-homedir'): raise GistError('gnupg-homedir missing from config file') if not config.has_option('gist', 'gnupg-fingerprint'): raise GistError('gnupg-fingerprint missing from config file') # Retrieve the data to add to the gist if sys.stdin.isatty(): if args['FILES']: logger.debug('action: - reading from files') files = {} for path in args['FILES']: name = os.path.basename(path) with open(path, 'rb') as fp: files[name] = fp.read().decode('utf-8') else: logger.debug('action: - reading from editor') with tempfile.NamedTemporaryFile('wb+') as fp: os.system('{} {}'.format(editor, fp.name)) fp.flush() fp.seek(0) files = {'file1.txt': fp.read().decode('utf-8')} else: logger.debug('action: - reading from stdin') files = {'file1.txt': sys.stdin.read()} description = args['<desc>'] public = args['--public'] # Encrypt the files or leave them unmodified if args['--encrypt']: logger.debug('action: - encrypting content') fingerprint = config.get('gist', 'gnupg-fingerprint') gnupghome = config.get('gist', 'gnupg-homedir') gpg = gnupg.GPG(gnupghome=gnupghome, use_agent=True) data = {} for k, v in files.items(): cypher = gpg.encrypt(v.encode('utf-8'), fingerprint) content = cypher.data.decode('utf-8') data['{}.asc'.format(k)] = {'content': content} else: data = {k: {'content': v} for k, v in files.items()} print(gapi.create(description, data, public)) return