commit 7c31503b0177d8f4473483f8d472fbd28dc76b3f
parent 2b9a20dffeddbb02298838ca46b3da774a6a806d
Author: Samuel Walladge <swalladge@users.noreply.github.com>
Date: Fri, 27 May 2016 10:12:16 +0930
Merge pull request #22 from swalladge/master
add alternate host config option, support for custom config file, upgrade to python3, fix unicode handling problems, refactor to use requests library
Diffstat:
13 files changed, 278 insertions(+), 278 deletions(-)
diff --git a/README.md b/README.md
@@ -18,8 +18,9 @@ Check your OS distribution for installation packages.
### Requirements
-* [Python 2](http://python.org)
-* [Urwid](http://urwid.org) Python 2 module
+* [Python 3](http://python.org)
+* [Urwid](http://urwid.org) Python 3 module
+* [Requests](https://requests.readthedocs.org/en/master/) Python 3 module
* A love for the command line!
### Features
diff --git a/setup.py b/setup.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
# Copyright (c) 2014 Eric Davis
# Licensed under the MIT License
@@ -13,7 +13,7 @@
author=simplenote_cli.__author__,
author_email=simplenote_cli.__author_email__,
url=simplenote_cli.__url__,
- requires=[ 'urwid' ],
+ requires=[ 'urwid', 'requests' ],
packages=[ 'simplenote_cli' ],
scripts=[ 'sncli' ]
)
diff --git a/simplenote_cli/config.py b/simplenote_cli/config.py
@@ -2,11 +2,11 @@
# Copyright (c) 2014 Eric Davis
# Licensed under the MIT License
-import os, urwid, collections, ConfigParser
+import os, urwid, collections, configparser
class Config:
- def __init__(self):
+ def __init__(self, custom_file=None):
self.home = os.path.abspath(os.path.expanduser('~'))
defaults = \
{
@@ -26,6 +26,7 @@ def __init__(self):
'cfg_max_logs' : '5',
'cfg_log_timeout' : '5',
'cfg_log_reversed' : 'yes',
+ 'cfg_sn_host' : 'simple-note.appspot.com',
'kb_help' : 'h',
'kb_quit' : 'q',
@@ -118,8 +119,11 @@ def __init__(self):
'clr_help_descr_bg' : 'default'
}
- cp = ConfigParser.SafeConfigParser(defaults)
- self.configs_read = cp.read([os.path.join(self.home, '.snclirc')])
+ cp = configparser.SafeConfigParser(defaults)
+ if custom_file is not None:
+ self.configs_read = cp.read([custom_file])
+ else:
+ self.configs_read = cp.read([os.path.join(self.home, '.snclirc')])
cfg_sec = 'sncli'
@@ -131,6 +135,7 @@ def __init__(self):
self.configs = collections.OrderedDict()
self.configs['sn_username'] = [ cp.get(cfg_sec, 'cfg_sn_username', raw=True), 'Simplenote Username' ]
self.configs['sn_password'] = [ cp.get(cfg_sec, 'cfg_sn_password', raw=True), 'Simplenote Password' ]
+ self.configs['sn_host'] = [ cp.get(cfg_sec, 'cfg_sn_host', raw=True), 'Simplenote server hostname' ]
self.configs['db_path'] = [ cp.get(cfg_sec, 'cfg_db_path'), 'Note storage path' ]
self.configs['search_tags'] = [ cp.get(cfg_sec, 'cfg_search_tags'), 'Search tags as well' ]
self.configs['sort_mode'] = [ cp.get(cfg_sec, 'cfg_sort_mode'), 'Sort mode' ]
diff --git a/simplenote_cli/notes_db.py b/simplenote_cli/notes_db.py
@@ -7,10 +7,10 @@
# new BSD license
import os, time, re, glob, json, copy, threading
-import utils
-import simplenote
+from . import utils
+from . import simplenote
simplenote.NOTE_FETCH_LENGTH=100
-from simplenote import Simplenote
+from .simplenote import Simplenote
class ReadError(RuntimeError):
pass
@@ -42,10 +42,10 @@ def __init__(self, config, log, update_view):
for fn in fnlist:
try:
- n = json.load(open(fn, 'rb'))
- except IOError, e:
+ n = json.load(open(fn, 'r'))
+ except IOError as e:
raise ReadError ('Error opening {0}: {1}'.format(fn, str(e)))
- except ValueError, e:
+ except ValueError as e:
raise ReadError ('Error reading {0}: {1}'.format(fn, str(e)))
else:
# we always have a localkey, also when we don't have a note['key'] yet (no sync)
@@ -59,7 +59,8 @@ def __init__(self, config, log, update_view):
# initialise the simplenote instance we're going to use
# this does not yet need network access
self.simplenote = Simplenote(self.config.get_config('sn_username'),
- self.config.get_config('sn_password'))
+ self.config.get_config('sn_password'),
+ self.config.get_config('sn_host'))
# we'll use this to store which notes are currently being synced by
# the background thread, so we don't add them anew if they're still
@@ -69,12 +70,12 @@ def __init__(self, config, log, update_view):
def filtered_notes_sort(self, filtered_notes, sort_mode='date'):
if sort_mode == 'date':
if self.config.get_config('pinned_ontop') == 'yes':
- filtered_notes.sort(utils.sort_by_modify_date_pinned, reverse=True)
+ filtered_notes.sort(key=utils.sort_by_modify_date_pinned, reverse=True)
else:
filtered_notes.sort(key=lambda o: -float(o.note.get('modifydate', 0)))
else:
if self.config.get_config('pinned_ontop') == 'yes':
- filtered_notes.sort(utils.sort_by_title_pinned)
+ filtered_notes.sort(key=utils.sort_by_title_pinned)
else:
filtered_notes.sort(key=lambda o: utils.get_note_title(o.note))
@@ -370,7 +371,7 @@ def helper_key_to_fname(self, k):
def helper_save_note(self, k, note):
# Save a single note to disc.
fn = self.helper_key_to_fname(k)
- json.dump(note, open(fn, 'wb'), indent=2)
+ json.dump(note, open(fn, 'w'), indent=2)
# record that we saved this to disc.
note['savedate'] = time.time()
@@ -540,21 +541,21 @@ def sync_notes(self, server_sync=True, full_sync=True):
# PERMANENT DELETE, remove note from local store
# Only do this when a full sync (i.e. entire index) is performed!
if server_sync and full_sync and not skip_remote_syncing:
- for local_key in self.notes.keys():
+ for local_key in list(self.notes.keys()):
if local_key not in server_keys:
del self.notes[local_key]
local_deletes[local_key] = True
# sync done, now write changes to db_path
- for k in local_updates.keys():
+ for k in list(local_updates.keys()):
try:
self.helper_save_note(k, self.notes[k])
- except WriteError, e:
+ except WriteError as e:
raise WriteError (str(e))
self.log("Saved note to disk (key={0})".format(k))
- for k in local_deletes.keys():
+ for k in list(local_deletes.keys()):
fn = self.helper_key_to_fname(k)
if os.path.exists(fn):
os.unlink(fn)
@@ -596,7 +597,7 @@ def get_note_status(self, key):
def verify_all_saved(self):
all_saved = True
self.sync_lock.acquire()
- for k in self.notes.keys():
+ for k in list(self.notes.keys()):
o = self.get_note_status(k)
if not o.saved:
all_saved = False
diff --git a/simplenote_cli/simplenote.py b/simplenote_cli/simplenote.py
@@ -13,13 +13,13 @@
:license: MIT, see LICENSE for more details.
"""
-import urllib
-import urllib2
-from urllib2 import HTTPError
+import urllib.parse
+from urllib.error import HTTPError
import base64
import time
import datetime
import logging
+import requests
try:
import json
@@ -30,9 +30,6 @@
# For Google AppEngine
from django.utils import simplejson as json
-AUTH_URL = 'https://simple-note.appspot.com/api/login'
-DATA_URL = 'https://simple-note.appspot.com/api2/data'
-INDX_URL = 'https://simple-note.appspot.com/api2/index?'
NOTE_FETCH_LENGTH = 100
class SimplenoteLoginFailed(Exception):
@@ -41,10 +38,13 @@ class SimplenoteLoginFailed(Exception):
class Simplenote(object):
""" Class for interacting with the simplenote web service """
- def __init__(self, username, password):
+ def __init__(self, username, password, host):
""" object constructor """
- self.username = urllib2.quote(username)
- self.password = urllib2.quote(password)
+ self.username = urllib.parse.quote(username)
+ self.password = urllib.parse.quote(password)
+ self.AUTH_URL = 'https://{0}/api/login'.format(host)
+ self.DATA_URL = 'https://{0}/api2/data'.format(host)
+ self.INDX_URL = 'https://{0}/api2/index?'.format(host)
self.token = None
def authenticate(self, user, password):
@@ -59,15 +59,18 @@ def authenticate(self, user, password):
"""
auth_params = "email=%s&password=%s" % (user, password)
- values = base64.encodestring(auth_params)
- request = Request(AUTH_URL, values)
+ values = base64.encodestring(auth_params.encode())
try:
- res = urllib2.urlopen(request).read()
- token = urllib2.quote(res)
- except HTTPError:
+ res = requests.post(self.AUTH_URL, data=values)
+ token = res.text
+ if res.status_code != 200:
+ raise SimplenoteLoginFailed(
+ 'Login to Simplenote API failed! statuscode: {}'.format(res.status_code))
+ except HTTPError as e:
raise SimplenoteLoginFailed('Login to Simplenote API failed!')
except IOError: # no connection exception
token = None
+
return token
def get_token(self):
@@ -104,23 +107,25 @@ def get_note(self, noteid, version=None):
if version is not None:
params_version = '/' + str(version)
- params = '/%s%s?auth=%s&email=%s' % (str(noteid), params_version, self.get_token(), self.username)
- #logging.debug('REQUEST: ' + DATA_URL+params)
- request = Request(DATA_URL+params)
+ params = {'auth': self.get_token(),
+ 'email': self.username }
+ url = '{}/{}{}'.format(self.DATA_URL, str(noteid), params_version)
+ #logging.debug('REQUEST: ' + self.DATA_URL+params)
try:
- response = urllib2.urlopen(request)
- except HTTPError, e:
+ res = requests.get(url, params=params)
+ except HTTPError as e:
#logging.debug('RESPONSE ERROR: ' + str(e))
return e, -1
- except IOError, e:
+ except IOError as e:
#logging.debug('RESPONSE ERROR: ' + str(e))
return e, -1
- note = json.loads(response.read())
- # use UTF-8 encoding
- note["content"] = note["content"].encode('utf-8')
- # For early versions of notes, tags not always available
- if note.has_key("tags"):
- note["tags"] = [t.encode('utf-8') for t in note["tags"]]
+ note = res.json()
+
+ # # use UTF-8 encoding
+ # note["content"] = note["content"].encode('utf-8')
+ # # For early versions of notes, tags not always available
+ # if "tags" in note:
+ # note["tags"] = [t.encode('utf-8') for t in note["tags"]]
#logging.debug('RESPONSE OK: ' + str(note))
return note, 0
@@ -138,43 +143,42 @@ def update_note(self, note):
- status (int): 0 on sucesss and -1 otherwise
"""
- # use UTF-8 encoding
- # cpbotha: in both cases check if it's not unicode already
- # otherwise you get "TypeError: decoding Unicode is not supported"
- if note.has_key("content"):
- if isinstance(note["content"], str):
- note["content"] = unicode(note["content"], 'utf-8')
-
- if note.has_key("tags"):
- # if a tag is a string, unicode it, otherwise pass it through
- # unchanged (it's unicode already)
- # using the ternary operator, because I like it: a if test else b
- note["tags"] = [unicode(t, 'utf-8') if isinstance(t, str) else t for t in note["tags"]]
+ # # use UTF-8 encoding
+ # # cpbotha: in both cases check if it's not unicode already
+ # # otherwise you get "TypeError: decoding Unicode is not supported"
+ # if "content" in note:
+ # if isinstance(note["content"], str):
+ # note["content"] = str(note["content"], 'utf-8')
+ #
+ # if "tags" in note:
+ # # if a tag is a string, unicode it, otherwise pass it through
+ # # unchanged (it's unicode already)
+ # # using the ternary operator, because I like it: a if test else b
+ # note["tags"] = [str(t, 'utf-8') if isinstance(t, str) else t for t in note["tags"]]
# determine whether to create a new note or updated an existing one
+ params = {'auth': self.get_token(),
+ 'email': self.username}
if "key" in note:
# set modification timestamp if not set by client
if 'modifydate' not in note:
note["modifydate"] = time.time()
- url = '%s/%s?auth=%s&email=%s' % (DATA_URL, note["key"],
- self.get_token(), self.username)
+ url = '%s/%s' % (self.DATA_URL, note["key"])
else:
- url = '%s?auth=%s&email=%s' % (DATA_URL, self.get_token(), self.username)
+ url = self.DATA_URL
#logging.debug('REQUEST: ' + url + ' - ' + str(note))
- request = Request(url, urllib.quote(json.dumps(note)))
- response = ""
try:
- response = urllib2.urlopen(request)
- except IOError, e:
+ res = requests.post(url, data=json.dumps(note), params=params)
+ except IOError as e:
#logging.debug('RESPONSE ERROR: ' + str(e))
return e, -1
- note = json.loads(response.read())
- if note.has_key("content"):
- # use UTF-8 encoding
- note["content"] = note["content"].encode('utf-8')
- if note.has_key("tags"):
- note["tags"] = [t.encode('utf-8') for t in note["tags"]]
+ note = res.json()
+ # if "content" in note:
+ # # use UTF-8 encoding
+ # note["content"] = note["content"].encode('utf-8')
+ # if "tags" in note:
+ # note["tags"] = [t.encode('utf-8') for t in note["tags"]]
#logging.debug('RESPONSE OK: ' + str(note))
return note, 0
@@ -232,35 +236,38 @@ def get_note_list(self, since=None, tags=[]):
notes = { "data" : [] }
# get the note index
- params = 'auth=%s&email=%s&length=%s' % (self.get_token(), self.username,
- NOTE_FETCH_LENGTH)
+ params = {'auth': self.get_token(),
+ 'email': self.username,
+ 'length': NOTE_FETCH_LENGTH
+ }
if since is not None:
- params += '&since=%s' % since
+ params['since'] = since
# perform initial HTTP request
try:
- #logging.debug('REQUEST: ' + INDX_URL+params)
- request = Request(INDX_URL+params)
- response = json.loads(urllib2.urlopen(request).read())
- #logging.debug('RESPONSE OK: ' + str(response))
- notes["data"].extend(response["data"])
+ #logging.debug('REQUEST: ' + self.INDX_URL+params)
+ res = requests.get(self.INDX_URL, params=params)
+ #logging.debug('RESPONSE OK: ' + str(res))
+ notes["data"].extend(res.json()["data"])
except IOError:
status = -1
# get additional notes if bookmark was set in response
while "mark" in response:
- vals = (self.get_token(), self.username, response["mark"], NOTE_FETCH_LENGTH)
- params = 'auth=%s&email=%s&mark=%s&length=%s' % vals
+ params = {'auth': self.get_token(),
+ 'email': self.username,
+ 'mark': response['mark'],
+ 'length': NOTE_FETCH_LENGTH
+ }
if since is not None:
- params += '&since=%s' % since
+ params['since'] = since
# perform the actual HTTP request
try:
- #logging.debug('REQUEST: ' + INDX_URL+params)
- request = Request(INDX_URL+params)
- response = json.loads(urllib2.urlopen(request).read())
+ #logging.debug('REQUEST: ' + self.INDX_URL+params)
+ res = requests.get(self.INDX_URL, params=params)
#logging.debug('RESPONSE OK: ' + str(response))
- notes["data"].extend(response["data"])
+ notes["data"].extend(res.json()["data"])
except IOError:
status = -1
@@ -314,30 +321,17 @@ def delete_note(self, note_id):
if (status == -1):
return note, status
- params = '/%s?auth=%s&email=%s' % (str(note_id), self.get_token(),
- self.username)
- #logging.debug('REQUEST DELETE: ' + DATA_URL+params)
- request = Request(url=DATA_URL+params, method='DELETE')
+ params = {'auth': self.get_token(),
+ 'email': self.username }
+ url = '{}/{}'.format(self.DATA_URL, str(note_id))
+
+ #logging.debug('REQUEST DELETE: ' + self.DATA_URL+params)
+ request = Request(url=self.DATA_URL+params, method='DELETE')
try:
- urllib2.urlopen(request)
- except IOError, e:
+ res = requests.delete(url, params=params)
+ # TODO: check error handling stuff - probably use res.status_code to check if was able to delete, etc.
+ # (same must be done for other note actions)
+ except IOError as e:
return e, -1
return {}, 0
-
-class Request(urllib2.Request):
- """ monkey patched version of urllib2's Request to support HTTP DELETE
- Taken from http://python-requests.org, thanks @kennethreitz
- """
-
- def __init__(self, url, data=None, headers={}, origin_req_host=None,
- unverifiable=False, method=None):
- urllib2.Request.__init__(self, url, data, headers, origin_req_host, unverifiable)
- self.method = method
-
- def get_method(self):
- if self.method:
- return self.method
-
- return urllib2.Request.get_method(self)
-
diff --git a/simplenote_cli/sncli.py b/simplenote_cli/sncli.py
@@ -2,20 +2,20 @@
# Copyright (c) 2014 Eric Davis
# Licensed under the MIT License
-import os, sys, getopt, re, signal, time, datetime, shlex, md5
-import subprocess, thread, threading, logging
+import os, sys, getopt, re, signal, time, datetime, shlex, hashlib
+import subprocess, threading, logging
import copy, json, urwid, datetime
-import view_titles, view_note, view_help, view_log, user_input
-import utils, temp
-from config import Config
-from simplenote import Simplenote
-from notes_db import NotesDB, ReadError, WriteError
+from . import view_titles, view_note, view_help, view_log, user_input
+from . import utils, temp
+from .config import Config
+from .simplenote import Simplenote
+from .notes_db import NotesDB, ReadError, WriteError
from logging.handlers import RotatingFileHandler
class sncli:
- def __init__(self, do_server_sync, verbose=False):
- self.config = Config()
+ def __init__(self, do_server_sync, verbose=False, config_file=None):
+ self.config = Config(config_file)
self.do_server_sync = do_server_sync
self.verbose = verbose
self.do_gui = False
@@ -41,7 +41,7 @@ def __init__(self, do_server_sync, verbose=False):
try:
self.ndb = NotesDB(self.config, self.log, self.gui_update_view)
- except Exception, e:
+ except Exception as e:
self.log(str(e))
sys.exit(1)
@@ -51,7 +51,7 @@ def __init__(self, do_server_sync, verbose=False):
# with hundreds of notes will cause a recursion panic under
# urwid. This simple workaround gets the job done. :-)
self.verbose = True
- self.log(u'sncli database doesn\'t exist, forcing full sync...')
+ self.log('sncli database doesn\'t exist, forcing full sync...')
self.sync_notes()
self.verbose = verbose
@@ -60,26 +60,26 @@ def sync_notes(self):
def get_editor(self):
editor = self.config.get_config('editor')
- if os.environ.has_key('EDITOR'):
+ if 'EDITOR' in os.environ:
editor = os.environ['EDITOR']
if not editor:
- self.log(u'No editor configured!')
+ self.log('No editor configured!')
return None
return editor
def get_pager(self):
pager = self.config.get_config('pager')
- if os.environ.has_key('PAGER'):
+ if 'PAGER' in os.environ:
pager = os.environ['PAGER']
if not pager:
- self.log(u'No pager configured!')
+ self.log('No pager configured!')
return None
return pager
def get_diff(self):
diff = self.config.get_config('diff')
if not diff:
- self.log(u'No diff command configured!')
+ self.log('No diff command configured!')
return None
return diff
@@ -93,16 +93,16 @@ def exec_cmd_on_note(self, note, cmd=None, raw=False):
tf = temp.tempfile_create(note if note else None, raw=raw)
try:
- subprocess.check_call(cmd + u' ' + temp.tempfile_name(tf), shell=True)
- except Exception, e:
- self.log(u'Command error: ' + str(e))
+ subprocess.check_call(cmd + ' ' + temp.tempfile_name(tf), shell=True)
+ except Exception as e:
+ self.log('Command error: ' + str(e))
temp.tempfile_delete(tf)
return None
content = None
if not raw:
content = ''.join(temp.tempfile_content(tf))
- if not content or content == u'\n':
+ if not content or content == '\n':
content = None
temp.tempfile_delete(tf)
@@ -123,16 +123,16 @@ def exec_diff_on_note(self, note, old_note):
out = temp.tempfile_create(None)
try:
- subprocess.call(diff + u' ' +
- temp.tempfile_name(ltf) + u' ' +
- temp.tempfile_name(otf) + u' > ' +
+ subprocess.call(diff + ' ' +
+ temp.tempfile_name(ltf) + ' ' +
+ temp.tempfile_name(otf) + ' > ' +
temp.tempfile_name(out),
shell=True)
- subprocess.check_call(pager + u' ' +
+ subprocess.check_call(pager + ' ' +
temp.tempfile_name(out),
shell=True)
- except Exception, e:
- self.log(u'Command error: ' + str(e))
+ except Exception as e:
+ self.log('Command error: ' + str(e))
temp.tempfile_delete(ltf)
temp.tempfile_delete(otf)
temp.tempfile_delete(out)
@@ -215,7 +215,9 @@ def log_timeout(self, loop, arg):
self.gui_footer_log_clear()
self.logs = []
else:
- self.logs.pop(0)
+ # for some reason having problems with this being empty?
+ if len(self.logs) > 0:
+ self.logs.pop(0)
log_pile = []
@@ -232,7 +234,7 @@ def log(self, msg):
if not self.do_gui:
if self.verbose:
- print msg
+ print(msg)
return
self.log_lock.acquire()
@@ -240,7 +242,7 @@ def log(self, msg):
self.log_alarms += 1
self.logs.append(msg)
- if len(self.logs) > self.config.get_config('max_logs'):
+ if len(self.logs) > int(self.config.get_config('max_logs')):
self.log_alarms -= 1
self.logs.pop(0)
@@ -263,7 +265,7 @@ def gui_update_view(self):
try:
cur_key = self.view_titles.note_list[self.view_titles.focus_position].note['key']
- except IndexError, e:
+ except IndexError as e:
cur_key = None
pass
self.view_titles.update_note_list(self.view_titles.search_string)
@@ -312,7 +314,7 @@ def restore_note_callback(self, key, yes):
return
# restore the contents of the old_note
- self.log(u'Restoring version v{0} (key={1})'.
+ self.log('Restoring version v{0} (key={1})'.
format(self.view_note.old_note['version'], key))
self.ndb.set_note_content(key, self.view_note.old_note['content'])
@@ -348,8 +350,8 @@ def gui_version_input(self, args, version):
try:
# verify input is a number
int(version)
- except ValueError, e:
- self.log(u'ERROR: Invalid version value')
+ except ValueError as e:
+ self.log('ERROR: Invalid version value')
return
self.view_note.update_note_view(version=version)
self.gui_update_status_bar()
@@ -391,8 +393,8 @@ def gui_pipe_input(self, args, cmd):
pipe.communicate(note['content'])
pipe.stdin.close()
pipe.wait()
- except OSError, e:
- self.log(u'Pipe error: ' + str(e))
+ except OSError as e:
+ self.log('Pipe error: ' + str(e))
finally:
self.gui_reset()
@@ -540,7 +542,7 @@ def gui_frame_keypress(self, size, key):
return key
if not self.view_note.old_note:
- self.log(u'Already at latest version (key={0})'.
+ self.log('Already at latest version (key={0})'.
format(self.view_note.key))
return None
@@ -554,7 +556,7 @@ def gui_frame_keypress(self, size, key):
return key
if not self.view_note.old_note:
- self.log(u'Already at latest version (key={0})'.
+ self.log('Already at latest version (key={0})'.
format(self.view_note.key))
return None
@@ -607,7 +609,7 @@ def gui_frame_keypress(self, size, key):
self.gui_reset()
if content:
- self.log(u'New note created')
+ self.log('New note created')
self.ndb.create_note(content)
self.gui_update_view()
self.ndb.sync_worker_go()
@@ -642,11 +644,11 @@ def gui_frame_keypress(self, size, key):
if not content:
return None
- md5_old = md5.new(self.encode_utf_8(note['content'])).digest()
- md5_new = md5.new(self.encode_utf_8(content)).digest()
+ md5_old = hashlib.md5(self.encode_utf_8(note['content'])).digest()
+ md5_new = hashlib.md5(self.encode_utf_8(content)).digest()
if md5_old != md5_new:
- self.log(u'Note updated')
+ self.log('Note updated')
self.ndb.set_note_content(note['key'], content)
if self.gui_body_get().__class__ == view_titles.ViewTitles:
lb.update_note_title()
@@ -654,7 +656,7 @@ def gui_frame_keypress(self, size, key):
lb.update_note_view()
self.ndb.sync_worker_go()
else:
- self.log(u'Note unchanged')
+ self.log('Note unchanged')
elif key == self.config.get_keybind('view_note'):
if self.gui_body_get().__class__ != view_titles.ViewTitles:
@@ -863,7 +865,7 @@ def gui_frame_keypress(self, size, key):
def encode_utf_8(self, string):
# This code also exists in temp.py. Move into an encoding or utility class if other areas need encoding.
- return string.encode("utf-8") if isinstance(string, unicode) else string
+ return string.encode("utf-8") if isinstance(string, str) else string
def gui_init_view(self, loop, view_note):
self.master_frame.keypress = self.gui_frame_keypress
@@ -876,7 +878,7 @@ def gui_init_view(self, loop, view_note):
self.thread_sync.start()
def gui_clear(self):
- self.sncli_loop.widget = urwid.Filler(urwid.Text(u''))
+ self.sncli_loop.widget = urwid.Filler(urwid.Text(''))
self.sncli_loop.draw_screen()
def gui_reset(self):
@@ -1000,7 +1002,7 @@ def gui(self, key):
self.config.get_color('help_descr_bg') )
]
- self.master_frame = urwid.Frame(body=urwid.Filler(urwid.Text(u'')),
+ self.master_frame = urwid.Frame(body=urwid.Filler(urwid.Text('')),
header=None,
footer=urwid.Pile([ urwid.Pile([]),
urwid.Pile([]) ]),
@@ -1023,38 +1025,38 @@ def cli_list_notes(self, regex, search_string):
search_mode='regex' if regex else 'gstyle')
for n in note_list:
flags = utils.get_note_flags(n.note)
- print n.key + \
- u' [' + flags + u'] ' + \
- utils.get_note_title(n.note)
+ print((n.key + \
+ ' [' + flags + '] ' + \
+ utils.get_note_title(n.note)))
def cli_note_dump(self, key):
note = self.ndb.get_note(key)
if not note:
- self.log(u'ERROR: Key does not exist')
+ self.log('ERROR: Key does not exist')
return
w = 60
- sep = u'+' + u'-'*(w+2) + u'+'
+ sep = '+' + '-'*(w+2) + '+'
t = time.localtime(float(note['modifydate']))
mod_time = time.strftime('%a, %d %b %Y %H:%M:%S', t)
title = utils.get_note_title(note)
flags = utils.get_note_flags(note)
tags = utils.get_note_tags(note)
- print sep
- print (u'| {:<' + str(w) + u'} |').format((u' Title: ' + title)[:w])
- print (u'| {:<' + str(w) + u'} |').format((u' Key: ' + note['key'])[:w])
- print (u'| {:<' + str(w) + u'} |').format((u' Date: ' + mod_time)[:w])
- print (u'| {:<' + str(w) + u'} |').format((u' Tags: ' + tags)[:w])
- print (u'| {:<' + str(w) + u'} |').format((u' Version: v' + str(note['version']))[:w])
- print (u'| {:<' + str(w) + u'} |').format((u' Flags: [' + flags + u']')[:w])
+ print(sep)
+ print(('| {:<' + str(w) + '} |').format((' Title: ' + title)[:w]))
+ print(('| {:<' + str(w) + '} |').format((' Key: ' + note['key'])[:w]))
+ print(('| {:<' + str(w) + '} |').format((' Date: ' + mod_time)[:w]))
+ print(('| {:<' + str(w) + '} |').format((' Tags: ' + tags)[:w]))
+ print(('| {:<' + str(w) + '} |').format((' Version: v' + str(note['version']))[:w]))
+ print(('| {:<' + str(w) + '} |').format((' Flags: [' + flags + ']')[:w]))
if utils.note_published(note) and 'publishkey' in note:
- print (u'| {:<' + str(w) + u'} |').format((u'Published: http://simp.ly/publish/' + note['publishkey'])[:w])
+ print(('| {:<' + str(w) + '} |').format(('Published: http://simp.ly/publish/' + note['publishkey'])[:w]))
else:
- print (u'| {:<' + str(w) + u'} |').format((u'Published: n/a')[:w])
- print sep
- print note['content']
+ print(('| {:<' + str(w) + '} |').format(('Published: n/a')[:w]))
+ print(sep)
+ print((note['content']))
def cli_dump_notes(self, regex, search_string):
@@ -1073,10 +1075,10 @@ def cli_note_create(self, from_stdin, title):
content = self.exec_cmd_on_note(None)
if title:
- content = title + '\n\n' + content if content else u''
+ content = title + '\n\n' + content if content else ''
if content:
- self.log(u'New note created')
+ self.log('New note created')
self.ndb.create_note(content)
self.sync_notes()
@@ -1084,28 +1086,28 @@ def cli_note_edit(self, key):
note = self.ndb.get_note(key)
if not note:
- self.log(u'ERROR: Key does not exist')
+ self.log('ERROR: Key does not exist')
return
content = self.exec_cmd_on_note(note)
if not content:
return
- md5_old = md5.new(self.encode_utf_8(note['content'])).digest()
- md5_new = md5.new(self.encode_utf_8(content)).digest()
+ md5_old = hashlib.md5(self.encode_utf_8(note['content'])).digest()
+ md5_new = hashlib.md5(self.encode_utf_8(content)).digest()
if md5_old != md5_new:
- self.log(u'Note updated')
+ self.log('Note updated')
self.ndb.set_note_content(note['key'], content)
self.sync_notes()
else:
- self.log(u'Note unchanged')
+ self.log('Note unchanged')
def cli_note_trash(self, key, trash):
note = self.ndb.get_note(key)
if not note:
- self.log(u'ERROR: Key does not exist')
+ self.log('ERROR: Key does not exist')
return
self.ndb.set_note_deleted(key, trash)
@@ -1115,7 +1117,7 @@ def cli_note_pin(self, key, pin):
note = self.ndb.get_note(key)
if not note:
- self.log(u'ERROR: Key does not exist')
+ self.log('ERROR: Key does not exist')
return
self.ndb.set_note_pinned(key, pin)
@@ -1125,7 +1127,7 @@ def cli_note_markdown(self, key, markdown):
note = self.ndb.get_note(key)
if not note:
- self.log(u'ERROR: Key does not exist')
+ self.log('ERROR: Key does not exist')
return
self.ndb.set_note_markdown(key, markdown)
@@ -1133,13 +1135,13 @@ def cli_note_markdown(self, key, markdown):
def SIGINT_handler(signum, frame):
- print u'\nSignal caught, bye!'
+ print('\nSignal caught, bye!')
sys.exit(1)
signal.signal(signal.SIGINT, SIGINT_handler)
def usage():
- print u'''
+ print ('''
Usage:
sncli [OPTIONS] [COMMAND] [COMMAND_ARGS]
@@ -1150,6 +1152,7 @@ def usage():
-r, --regex - search string is a regular expression
-k <key>, --key=<key> - note key
-t <title>, --title=<title> - title of note for create (cli mode)
+ -c <file>, --config=<file> - config file to read from (defaults to ~/.snclirc)
COMMANDS:
<none> - console gui mode when no command specified
@@ -1162,7 +1165,7 @@ def usage():
< trash | untrash > - trash/untrash a note (specified by <key>)
< pin | unpin > - pin/unpin a note (specified by <key>)
< markdown | unmarkdown > - markdown/unmarkdown a note (specified by <key>)
-'''
+''')
sys.exit(0)
def main(argv):
@@ -1171,11 +1174,12 @@ def main(argv):
regex = False
key = None
title = None
+ config = None
try:
opts, args = getopt.getopt(argv,
- 'hvnrk:t:',
- [ 'help', 'verbose', 'nosync', 'regex', 'key=', 'title=' ])
+ 'hvnrk:t:c:',
+ [ 'help', 'verbose', 'nosync', 'regex', 'key=', 'title=', 'config=' ])
except:
usage()
@@ -1192,30 +1196,32 @@ def main(argv):
key = arg
elif opt in [ '-t', '--title']:
title = arg
+ elif opt in [ '-c', '--config']:
+ config = arg
else:
- print u'ERROR: Unhandled option'
+ print('ERROR: Unhandled option')
usage()
if not args:
- sncli(sync).gui(key)
+ sncli(sync, verbose, config).gui(key)
return
- def sncli_start(sync, verbose):
- sn = sncli(sync, verbose)
+ def sncli_start(sync=sync, verbose=verbose, config=config):
+ sn = sncli(sync, verbose, config)
if sync: sn.sync_notes()
return sn
if args[0] == 'sync':
- sn = sncli_start(True, verbose)
+ sn = sncli_start(True)
elif args[0] == 'list':
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_list_notes(regex, ' '.join(args[1:]))
elif args[0] == 'dump':
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
if key:
sn.cli_note_dump(key)
else:
@@ -1224,10 +1230,10 @@ def sncli_start(sync, verbose):
elif args[0] == 'create':
if len(args) == 1:
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_create(False, title)
elif len(args) == 2 and args[1] == '-':
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_create(True, title)
else:
usage()
@@ -1237,7 +1243,7 @@ def sncli_start(sync, verbose):
if not key:
usage()
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_edit(key)
elif args[0] == 'trash' or args[0] == 'untrash':
@@ -1245,7 +1251,7 @@ def sncli_start(sync, verbose):
if not key:
usage()
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_trash(key, 1 if args[0] == 'trash' else 0)
elif args[0] == 'pin' or args[0] == 'unpin':
@@ -1253,7 +1259,7 @@ def sncli_start(sync, verbose):
if not key:
usage()
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_pin(key, 1 if args[0] == 'pin' else 0)
elif args[0] == 'markdown' or args[0] == 'unmarkdown':
@@ -1261,7 +1267,7 @@ def sncli_start(sync, verbose):
if not key:
usage()
- sn = sncli_start(sync, verbose)
+ sn = sncli_start()
sn.cli_note_markdown(key, 1 if args[0] == 'markdown' else 0)
else:
diff --git a/simplenote_cli/temp.py b/simplenote_cli/temp.py
@@ -25,7 +25,7 @@ def tempfile_create(note, raw=False):
def encode_utf_8(string):
# This code also exists in sncli.py. Move into an encoding or utility class if other areas need encoding.
- return string.encode("utf-8") if isinstance(string, unicode) else string
+ return string.encode("utf-8") if isinstance(string, str) else string
def tempfile_delete(tf):
if tf:
@@ -40,5 +40,5 @@ def tempfile_content(tf):
# This seems like a hack. When editing with Gedit, tf file contents weren't getting
# updated in memory, even though it successfully saved on disk.
updated_tf_contents = open(tf.name, 'r').read()
- tf.write(updated_tf_contents)
+ tf.write(updated_tf_contents.encode("utf-8"))
return updated_tf_contents
diff --git a/simplenote_cli/utils.py b/simplenote_cli/utils.py
@@ -22,10 +22,10 @@ def get_note_tags(note):
if 'tags' in note:
tags = '%s' % ','.join(note['tags'])
if 'deleted' in note and note['deleted']:
- if tags: tags += u',trash'
- else: tags = u'trash'
+ if tags: tags += ',trash'
+ else: tags = 'trash'
else:
- tags = u''
+ tags = ''
return tags
# Returns a fixed length string:
@@ -36,12 +36,12 @@ def get_note_tags(note):
# 'm' - markdown
def get_note_flags(note):
flags = ''
- flags += u'X' if float(note['modifydate']) > float(note['syncdate']) else u' '
- flags += u'T' if 'deleted' in note and note['deleted'] else u' '
+ flags += 'X' if float(note['modifydate']) > float(note['syncdate']) else ' '
+ flags += 'T' if 'deleted' in note and note['deleted'] else ' '
if 'systemtags' in note:
- flags += u'*' if 'pinned' in note['systemtags'] else u' '
- flags += u'S' if 'published' in note['systemtags'] else u' '
- flags += u'm' if 'markdown' in note['systemtags'] else u' '
+ flags += '*' if 'pinned' in note['systemtags'] else ' '
+ flags += 'S' if 'published' in note['systemtags'] else ' '
+ flags += 'm' if 'markdown' in note['systemtags'] else ' '
else:
flags += ' '
return flags
@@ -63,9 +63,9 @@ def get_note_title_file(note):
return ''
if isinstance(fn, str):
- fn = unicode(fn, 'utf-8')
+ fn = str(fn, 'utf-8')
else:
- fn = unicode(fn)
+ fn = str(fn)
if note_markdown(note):
fn += '.mkdn'
@@ -145,21 +145,14 @@ def sanitise_tags(tags):
else:
return illegals_removed.split(',')
-def sort_by_title_pinned(a, b):
- if note_pinned(a.note) and not note_pinned(b.note):
- return -1
- elif not note_pinned(a.note) and note_pinned(b.note):
- return 1
- else:
- return cmp(get_note_title(a.note), get_note_title(b.note))
+def sort_by_title_pinned(a):
+ return (not note_pinned(a.note), get_note_title(a.note))
-def sort_by_modify_date_pinned(a, b):
- if note_pinned(a.note) and not note_pinned(b.note):
- return 1
- elif not note_pinned(a.note) and note_pinned(b.note):
- return -1
+def sort_by_modify_date_pinned(a):
+ if note_pinned(a.note):
+ return 100.0 * float(a.note.get('modifydate', 0))
else:
- return cmp(float(a.note.get('modifydate', 0)), float(b.note.get('modifydate', 0)))
+ return float(a.note.get('modifydate', 0))
class KeyValueObject:
"""Store key=value pairs in this object and retrieve with o.key.
diff --git a/simplenote_cli/view_help.py b/simplenote_cli/view_help.py
@@ -13,12 +13,12 @@ def __init__(self, config):
self.config_width = 29
lines = []
- lines.extend(self.create_kb_help_lines(u'Keybinds Common', 'common'))
- lines.extend(self.create_kb_help_lines(u'Keybinds Note List', 'titles'))
- lines.extend(self.create_kb_help_lines(u'Keybinds Note Content', 'notes'))
+ lines.extend(self.create_kb_help_lines('Keybinds Common', 'common'))
+ lines.extend(self.create_kb_help_lines('Keybinds Note List', 'titles'))
+ lines.extend(self.create_kb_help_lines('Keybinds Note Content', 'notes'))
lines.extend(self.create_config_help_lines())
lines.extend(self.create_color_help_lines())
- lines.append(urwid.Text(('help_header', u'')))
+ lines.append(urwid.Text(('help_header', '')))
super(ViewHelp, self).__init__(urwid.SimpleFocusListWalker(lines))
@@ -30,13 +30,13 @@ def get_status_bar(self):
total = len(self.body.positions())
status_title = \
- urwid.AttrMap(urwid.Text(u'Help',
+ urwid.AttrMap(urwid.Text('Help',
wrap='clip'),
'status_bar')
status_index = \
- ('pack', urwid.AttrMap(urwid.Text(u' ' +
+ ('pack', urwid.AttrMap(urwid.Text(' ' +
str(cur + 1) +
- u'/' +
+ '/' +
str(total)),
'status_bar'))
return \
@@ -44,10 +44,10 @@ def get_status_bar(self):
'status_bar')
def create_kb_help_lines(self, header, use):
- lines = [ urwid.AttrMap(urwid.Text(u''),
+ lines = [ urwid.AttrMap(urwid.Text(''),
'help_header',
'help_focus') ]
- lines.append(urwid.AttrMap(urwid.Text(u' ' + header),
+ lines.append(urwid.AttrMap(urwid.Text(' ' + header),
'help_header',
'help_focus'))
for c in self.config.keybinds:
@@ -58,8 +58,8 @@ def create_kb_help_lines(self, header, use):
urwid.Text(
[
('help_descr', ('{:>' + str(self.descr_width) + '} ').format(self.config.get_keybind_descr(c))),
- ('help_config', ('{:>' + str(self.config_width) + '} ').format(u'kb_' + c)),
- ('help_value', u"'" + self.config.get_keybind(c) + u"'")
+ ('help_config', ('{:>' + str(self.config_width) + '} ').format('kb_' + c)),
+ ('help_value', "'" + self.config.get_keybind(c) + "'")
]
),
attr_map = None,
@@ -72,10 +72,10 @@ def create_kb_help_lines(self, header, use):
return lines
def create_config_help_lines(self):
- lines = [ urwid.AttrMap(urwid.Text(u''),
+ lines = [ urwid.AttrMap(urwid.Text(''),
'help_header',
'help_focus') ]
- lines.append(urwid.AttrMap(urwid.Text(u' Configuration'),
+ lines.append(urwid.AttrMap(urwid.Text(' Configuration'),
'help_header',
'help_focus'))
for c in self.config.configs:
@@ -85,8 +85,8 @@ def create_config_help_lines(self):
urwid.Text(
[
('help_descr', ('{:>' + str(self.descr_width) + '} ').format(self.config.get_config_descr(c))),
- ('help_config', ('{:>' + str(self.config_width) + '} ').format(u'cfg_' + c)),
- ('help_value', u"'" + self.config.get_config(c) + u"'")
+ ('help_config', ('{:>' + str(self.config_width) + '} ').format('cfg_' + c)),
+ ('help_value', "'" + self.config.get_config(c) + "'")
]
),
attr_map = None,
@@ -99,10 +99,10 @@ def create_config_help_lines(self):
return lines
def create_color_help_lines(self):
- lines = [ urwid.AttrMap(urwid.Text(u''),
+ lines = [ urwid.AttrMap(urwid.Text(''),
'help_header',
'help_focus') ]
- lines.append(urwid.AttrMap(urwid.Text(u' Colors'),
+ lines.append(urwid.AttrMap(urwid.Text(' Colors'),
'help_header',
'help_focus'))
fmap = {}
@@ -114,8 +114,8 @@ def create_color_help_lines(self):
urwid.Text(
[
('help_descr', ('{:>' + str(self.descr_width) + '} ').format(self.config.get_color_descr(c))),
- ('help_config', ('{:>' + str(self.config_width) + '} ').format(u'clr_' + c)),
- (re.search('^(.*)(_fg|_bg)$', c).group(1), u"'" + self.config.get_color(c) + u"'")
+ ('help_config', ('{:>' + str(self.config_width) + '} ').format('clr_' + c)),
+ (re.search('^(.*)(_fg|_bg)$', c).group(1), "'" + self.config.get_color(c) + "'")
]
),
attr_map = None,
diff --git a/simplenote_cli/view_log.py b/simplenote_cli/view_log.py
@@ -32,13 +32,13 @@ def get_status_bar(self):
total = len(self.body.positions())
status_title = \
- urwid.AttrMap(urwid.Text(u'Sync Log',
+ urwid.AttrMap(urwid.Text('Sync Log',
wrap='clip'),
'status_bar')
status_index = \
- ('pack', urwid.AttrMap(urwid.Text(u' ' +
+ ('pack', urwid.AttrMap(urwid.Text(' ' +
str(cur + 1) +
- u'/' +
+ '/' +
str(total)),
'status_bar'))
return \
diff --git a/simplenote_cli/view_note.py b/simplenote_cli/view_note.py
@@ -3,9 +3,9 @@
# Licensed under the MIT License
import time, urwid
-import utils
+from . import utils
import re
-from clipboard import Clipboard
+from .clipboard import Clipboard
class ViewNote(urwid.ListBox):
@@ -40,7 +40,7 @@ def get_note_content_as_list(self):
urwid.AttrMap(urwid.Text(l.replace('\t', ' ' * self.tabstop)),
'note_content',
'note_content_focus'))
- lines.append(urwid.AttrMap(urwid.Divider(u'-'), 'default'))
+ lines.append(urwid.AttrMap(urwid.Divider('-'), 'default'))
return lines
def update_note_view(self, key=None, version=None):
@@ -52,22 +52,22 @@ def update_note_view(self, key=None, version=None):
if self.key and version:
# verify version is within range
if int(version) <= 0 or int(version) >= self.note['version'] + 1:
- self.log(u'Version v{0} is unavailable (key={1})'.
+ self.log('Version v{0} is unavailable (key={1})'.
format(version, self.key))
return
if (not version and self.old_note) or \
(self.key and version and version == self.note['version']):
- self.log(u'Displaying latest version v{0} of note (key={1})'.
+ self.log('Displaying latest version v{0} of note (key={1})'.
format(self.note['version'], self.key))
self.old_note = None
elif self.key and version:
# get a previous version of the note
- self.log(u'Fetching version v{0} of note (key={1})'.
+ self.log('Fetching version v{0} of note (key={1})'.
format(version, self.key))
version_note = self.ndb.get_note_version(self.key, version)
if not version_note:
- self.log(u'Failed to get version v{0} of note (key={1})'.
+ self.log('Failed to get version v{0} of note (key={1})'.
format(version, self.key))
# don't do anything, keep current note/version
else:
@@ -79,11 +79,11 @@ def update_note_view(self, key=None, version=None):
self.focus_position = 0
def lines_after_current_position(self):
- lines_after_current_position = range(self.focus_position + 1, len(self.body.positions()) - 1)
+ lines_after_current_position = list(range(self.focus_position + 1, len(self.body.positions()) - 1))
return lines_after_current_position
def lines_before_current_position(self):
- lines_before_current_position = range(0, self.focus_position)
+ lines_before_current_position = list(range(0, self.focus_position))
lines_before_current_position.reverse()
return lines_before_current_position
@@ -121,7 +121,7 @@ def is_match(self, term, full_text):
def get_status_bar(self):
if not self.key:
return \
- urwid.AttrMap(urwid.Text(u'No note...'),
+ urwid.AttrMap(urwid.Text('No note...'),
'status_bar')
cur = -1
@@ -141,20 +141,20 @@ def get_status_bar(self):
tags = utils.get_note_tags(self.note)
version = self.note['version']
- mod_time = time.strftime(u'Date: %a, %d %b %Y %H:%M:%S', t)
+ mod_time = time.strftime('Date: %a, %d %b %Y %H:%M:%S', t)
status_title = \
- urwid.AttrMap(urwid.Text(u'Title: ' +
+ urwid.AttrMap(urwid.Text('Title: ' +
title,
wrap='clip'),
'status_bar')
status_key_index = \
- ('pack', urwid.AttrMap(urwid.Text(u' [' +
+ ('pack', urwid.AttrMap(urwid.Text(' [' +
self.key +
- u'] ' +
+ '] ' +
str(cur + 1) +
- u'/' +
+ '/' +
str(total)),
'status_bar'))
@@ -165,19 +165,19 @@ def get_status_bar(self):
if self.old_note:
status_tags_flags = \
- ('pack', urwid.AttrMap(urwid.Text(u'[OLD:v' +
+ ('pack', urwid.AttrMap(urwid.Text('[OLD:v' +
str(version) +
- u']'),
+ ']'),
'status_bar'))
else:
status_tags_flags = \
- ('pack', urwid.AttrMap(urwid.Text(u'[' +
+ ('pack', urwid.AttrMap(urwid.Text('[' +
tags +
- u'] [v' +
+ '] [v' +
str(version) +
- u'] [' +
+ '] [' +
flags +
- u']'),
+ ']'),
'status_bar'))
pile_top = urwid.Columns([ status_title, status_key_index ])
@@ -189,7 +189,7 @@ def get_status_bar(self):
'status_bar')
pile_publish = \
- urwid.AttrMap(urwid.Text(u'Published: http://simp.ly/publish/' +
+ urwid.AttrMap(urwid.Text('Published: http://simp.ly/publish/' +
self.note['publishkey']),
'status_bar')
return \
diff --git a/simplenote_cli/view_titles.py b/simplenote_cli/view_titles.py
@@ -3,7 +3,7 @@
# Licensed under the MIT License
import re, time, datetime, urwid, subprocess
-import utils, view_note
+from . import utils, view_note
class ViewTitles(urwid.ListBox):
@@ -24,7 +24,7 @@ def update_note_list(self, search_string, search_mode='gstyle'):
self.body[:] = \
urwid.SimpleFocusListWalker(self.get_note_titles())
if len(self.note_list) == 0:
- self.log(u'No notes found!')
+ self.log('No notes found!')
else:
self.focus_position = 0
@@ -150,7 +150,7 @@ def get_status_bar(self):
cur = self.focus_position
total = len(self.body.positions())
- hdr = u'Simplenote'
+ hdr = 'Simplenote'
if self.search_string != None:
hdr += ' - Search: ' + self.search_string
@@ -159,9 +159,9 @@ def get_status_bar(self):
wrap='clip'),
'status_bar')
status_index = \
- ('pack', urwid.AttrMap(urwid.Text(u' ' +
+ ('pack', urwid.AttrMap(urwid.Text(' ' +
str(cur + 1) +
- u'/' +
+ '/' +
str(total)),
'status_bar'))
return \
@@ -173,12 +173,12 @@ def update_note_title(self, key=None):
self.body[self.focus_position] = \
self.get_note_title(self.note_list[self.focus_position].note)
else:
- for i in xrange(len(self.note_list)):
+ for i in range(len(self.note_list)):
if self.note_list[i].note['key'] == key:
self.body[i] = self.get_note_title(self.note_list[i].note)
def focus_note(self, key):
- for i in xrange(len(self.note_list)):
+ for i in range(len(self.note_list)):
if 'key' in self.note_list[i].note and \
self.note_list[i].note['key'] == key:
self.focus_position = i
diff --git a/sncli b/sncli
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
#
# ** The MIT License **