[googlecl] 03/05: Imported Upstream version 0.9.13
Luke Faraone
lfaraone at moszumanska.debian.org
Sat Dec 7 22:51:23 UTC 2013
This is an automated email from the git hooks/post-receive script.
lfaraone pushed a commit to branch master
in repository googlecl.
commit 4e4881bb7061f08e9d92a2c4547138fd43cfa08d
Author: Luke Faraone <luke at faraone.cc>
Date: Sat Dec 7 17:51:08 2013 -0500
Imported Upstream version 0.9.13
---
PKG-INFO | 2 +-
README.config | 4 +++-
README.new-usage | 3 +++
changelog | 9 ++++++++
man/google.1 | 4 ++--
setup.py | 2 +-
src/google | 20 ++++++++++++----
src/googlecl/__init__.py | 16 ++++++++++---
src/googlecl/authentication.py | 3 ++-
src/googlecl/base.py | 2 ++
src/googlecl/calendar/__init__.py | 24 ++++++++++++++------
src/googlecl/calendar/service.py | 48 ++++++++++++++++++++++-----------------
src/googlecl/config/__init__.py | 3 +++
src/googlecl/docs/base.py | 34 +++++++++++++++++++++++----
src/googlecl/picasa/service.py | 2 +-
15 files changed, 129 insertions(+), 47 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 7312743..ae11361 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: googlecl
-Version: 0.9.12
+Version: 0.9.13
Summary: Use (some) Google services from the command line
Home-page: http://code.google.com/p/googlecl
Author: Tom H. Miller
diff --git a/README.config b/README.config
index 8fe9faa..7b678b5 100644
--- a/README.config
+++ b/README.config
@@ -32,9 +32,11 @@ Each of these values can be found in any section. The service being run will try
* editor: [<editor>], The editor to use by default if the document type is not defined by an xxx_editor option. If this is not defined, will use the EDITOR environment variable instead.
* format: [<extension>], The extension to use by default if the document type is not defined by an xxx_format option.
* impatient_editors: [<editor1>,<editor2>...], Comma separated list of editors that will not wait for you to finish editing before exiting / returning from the command line. For example, setting this equal to "openoffice.org" (without the quotes) will stop GoogleCL from uploading any changes to Docs until you give it the OK.
+ * invalid_filename_character_sub: [<string>] String to replace invalid filename characters with when editing or downloading documents. For example, if this is set to !, downloading the file "unfriendly/filename" will rename the file to "unfriendly!filename". Note that for editing, only the temporary file's name is changed -- it should remain the same online.
1.4 General
- * auth_browser: [<browser>], Browser to launch when authenticating the OAuth request token. Set this to "disabled" to prevent the launch of any browsers.
+ * auth_browser: [<browser>], Browser to launch when authenticating the OAuth request token. Set this to "disabled" or "none" to prevent the launch of any browsers.
* date_print_format: [<format string>], Format to use when printing date information. See the Python "time" documentation for formats (http://docs.python.org/library/time.html#time.strftime). For example: "%m %d at %H" for "<month> <day> at <hour>"
+ * default_encoding: [<encoding>], If the terminal encoding is undefined, use this encoding. Odds are, if you are having unicode/ascii decode/encode issues, you'll need to use this setting (almost always 'utf-8' for non-windows users).
* missing_field_value: [<string>], Placeholder string to use when listing an invalid attribute, for example, the url of a contact.
* url_style: [site, direct], Which sub-style to use for listing urls. "Site" will typically put you at the website, while "direct" is usually a link directly to the resource.
diff --git a/README.new-usage b/README.new-usage
index 45c4bd7..64c410b 100644
--- a/README.new-usage
+++ b/README.new-usage
@@ -1,5 +1,8 @@
This document is a quick-guide on getting up to speed with the new version of GoogleCL.
+version 0.9.13
+ * Bugfixes only. Booooooring.
+
version 0.9.12
* --access will take a variety of text to set access levels on the following items during creation:
Blogger posts
diff --git a/changelog b/changelog
index a0c4e1c..673920b 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,12 @@
+version 0.9.13
+ Bugfixes
+ * default_encoding config option allows user to specify a default encoding other than ASCII (was a bug for some uses, namely cron jobs).
+ * Appropriate intermediate directories are created during authentication token storage.
+ * Catch previously uncaught exception when webbrowser does not find a default or specified browser.
+ * Deletion of recurring calendar events does not cause AttributeError.
+ * Deletion of recurring calendar events with --yes flag only deletes all events if --date is not specified.
+ * File extensions for Picasa are case insensitive.
+
version 0.9.12
Enhancements
* Added support for Google Finance (thanks, bartosh!)
diff --git a/man/google.1 b/man/google.1
index 0e9d034..31ddad5 100644
--- a/man/google.1
+++ b/man/google.1
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
-.TH GOOGLE "1" "January 2011" "google 0.9.12" "User Commands"
+.TH GOOGLE "1" "March 2011" "google 0.9.13" "User Commands"
.SH NAME
google \- command-line access to (some) Google services
.SH SYNOPSIS
@@ -347,7 +347,7 @@ google blogger post \-\-title 'foo' 'command line posting'
google calendar add 'Lunch with Jim at noon tomorrow'
-google contacts list name,email >contacts.csv
+google contacts list \-\-title '.*' \-\-fields name,email,phone > contacts.csv
google docs edit \-\-title 'Shopping list'
diff --git a/setup.py b/setup.py
index 8639ac7..40dedea 100644
--- a/setup.py
+++ b/setup.py
@@ -66,7 +66,7 @@ command-line tool that makes it easy to do things like posting to a Blogger
blog, uploading files to Picasa, or editing a Google Docs file."""
setup(name="googlecl",
- version="0.9.12",
+ version="0.9.13",
description="Use (some) Google services from the command line",
author="Tom H. Miller",
author_email="tom.h.miller at gmail.com",
diff --git a/src/google b/src/google
index 2eeb945..6c973dc 100755
--- a/src/google
+++ b/src/google
@@ -60,7 +60,7 @@ safe_encode = googlecl.safe_encode
safe_decode = googlecl.safe_decode
-VERSION = '0.9.12'
+VERSION = '0.9.13'
AVAILABLE_SERVICES = ['picasa', 'blogger', 'youtube', 'docs', 'contacts',
'calendar', 'finance']
@@ -109,12 +109,21 @@ def authenticate(auth_manager, options, config, section_header):
browser_str = config.lazy_get(section_header, 'auth_browser',
default=None)
if browser_str:
- if browser_str.lower() == 'disabled':
+ if browser_str.lower() == 'disabled' or browser_str.lower() == 'none':
browser = None
else:
- browser = webbrowser.get(browser_str)
+ try:
+ browser = webbrowser.get(browser_str)
+ except webbrowser.Error, err:
+ LOG.warn(safe_encode(u'Could not get browser "%s": %s' %
+ (browser_str, err)))
+ browser = None
else:
- browser = webbrowser.get()
+ try:
+ browser = webbrowser.get()
+ except webbrowser.Error, err:
+ LOG.warn(safe_encode(u'Could not get default browser: %s' % err))
+ browser = None
valid_token = auth_manager.retrieve_access_token(display_name, browser)
if valid_token:
@@ -442,7 +451,8 @@ def run_interactive(parser):
parser: Object capable of parsing a list of arguments via parse_args.
"""
- history_file = googlecl.get_data_path(googlecl.HISTORY_FILENAME)
+ history_file = googlecl.get_data_path(googlecl.HISTORY_FILENAME,
+ create_missing_dir=True)
try:
import readline
try:
diff --git a/src/googlecl/__init__.py b/src/googlecl/__init__.py
index 92e78c5..44ddddf 100644
--- a/src/googlecl/__init__.py
+++ b/src/googlecl/__init__.py
@@ -33,7 +33,7 @@ LOGGER_NAME = __name__
LOG = logging.getLogger(LOGGER_NAME)
-def determine_terminal_encoding():
+def determine_terminal_encoding(config=None):
import sys
in_enc = ''
out_enc = ''
@@ -45,9 +45,15 @@ def determine_terminal_encoding():
# Sometimes these are both defined, and hopefully they are both equal.
# I'm not sure if they are guaranteed to be equal.
if in_enc.lower() == out_enc.lower():
- # If they're not defined, return the python system-wide default encoding
+ # If they're not defined, return the encoding specific in the config file,
+ # or the python system-wide default encoding (if the above is not defined)
+ # Apparently the above values aren't set when run as a cron job or piped?
if not in_enc:
- return_enc = sys.getdefaultencoding()
+ return_enc = None
+ if config is not None:
+ return_enc = config.safe_get('GENERAL', 'default_encoding')
+ if return_enc is None:
+ return_enc = sys.getdefaultencoding()
else:
return_enc = in_enc
# If they are not equal, at least one of them must be defined.
@@ -62,6 +68,10 @@ def determine_terminal_encoding():
return return_enc
+# Because this gets done at googlecl module load, there's no config parser
+# to pass in.
+#XXX: googlecl.config.load_configuration() currently sets this again,
+# but that's less than optimal...
TERMINAL_ENCODING = determine_terminal_encoding()
diff --git a/src/googlecl/authentication.py b/src/googlecl/authentication.py
index 4c752ae..0830037 100644
--- a/src/googlecl/authentication.py
+++ b/src/googlecl/authentication.py
@@ -44,7 +44,8 @@ class AuthenticationManager(object):
self.tokens_path = tokens_path
else:
self.tokens_path = googlecl.get_data_path(TOKENS_FILENAME_FORMAT %
- client.email)
+ client.email,
+ create_missing_dir=True)
def check_access_token(self):
"""Checks that the client's access token is valid, remove it if not.
diff --git a/src/googlecl/base.py b/src/googlecl/base.py
index b15b30f..b6b9279 100644
--- a/src/googlecl/base.py
+++ b/src/googlecl/base.py
@@ -673,10 +673,12 @@ def compile_entry_string(wrapped_entry, attribute_list, delimiter,
except ValueError, err:
LOG.debug(err.args[0] + ' (Did not add value for field ' + attr + ')')
except AttributeError, err:
+ LOG.debug(err.args[0] + ' (value for field ' + attr + ')')
try:
# Last ditch effort to blindly grab the attribute
val = getattr(wrapped_entry.entry, attr).text or missing_field_value
except AttributeError:
+ LOG.debug(err.args[0] + ' (value for field ' + attr + ')')
val = missing_field_value
# Apparently, atom(?) doesn't always return a Unicode type when there are
# non-latin characters, so force everything to Unicode.
diff --git a/src/googlecl/calendar/__init__.py b/src/googlecl/calendar/__init__.py
index 8b3c23b..9cef7fb 100644
--- a/src/googlecl/calendar/__init__.py
+++ b/src/googlecl/calendar/__init__.py
@@ -235,12 +235,22 @@ def parse_recurrence(time_string):
class CalendarEntryToStringWrapper(googlecl.base.BaseEntryToStringWrapper):
+ def __init__(self, entry, config):
+ """Initialize a CalendarEntry wrapper.
+
+ Args:
+ entry: CalendarEntry to interpret to strings.
+ config: Configuration parser. Needed for some values.
+ """
+ googlecl.base.BaseEntryToStringWrapper.__init__(self, entry)
+ self.config_parser = config
+
@property
def when(self):
"""When event takes place."""
start_date, end_date, freq = get_datetimes(self.entry)
- print_format = googlecl.CONFIG.lazy_get(SECTION_HEADER,
- 'date_print_format')
+ print_format = self.config_parser.lazy_get(SECTION_HEADER,
+ 'date_print_format')
start_text = time.strftime(print_format, start_date)
end_text = time.strftime(print_format, end_date)
value = start_text + ' - ' + end_text
@@ -277,9 +287,9 @@ def _list(client, options, args):
for entry in single_events:
print googlecl.base.compile_entry_string(
- CalendarEntryToStringWrapper(entry),
- options.fields.split(','),
- delimiter=options.delimiter)
+ CalendarEntryToStringWrapper(entry, client.config),
+ options.fields.split(','),
+ delimiter=options.delimiter)
#===============================================================================
@@ -356,10 +366,10 @@ def _run_delete(client, options, args):
if date_range.specified_as_range:
# if the user specified a date that was a range...
client.delete_recurring_events(recurring_events, date_range.start,
- date_range.end, cal.user)
+ date_range.end, cal.user, options.prompt)
else:
client.delete_recurring_events(recurring_events, date_range.start,
- None, cal.user)
+ None, cal.user, options.prompt)
if not (single_events or recurring_events):
LOG.warning('No events found that match your options!')
diff --git a/src/googlecl/calendar/service.py b/src/googlecl/calendar/service.py
index c820284..d890ca8 100644
--- a/src/googlecl/calendar/service.py
+++ b/src/googlecl/calendar/service.py
@@ -130,7 +130,8 @@ class CalendarServiceCL(gdata.calendar.service.CalendarService,
AddReminders = add_reminders
- def delete_recurring_events(self, events, start_date, end_date, cal_user):
+ def delete_recurring_events(self, events, start_date, end_date, cal_user,
+ prompt):
"""Delete recurring events from a calendar.
Keyword arguments:
@@ -139,6 +140,7 @@ class CalendarServiceCL(gdata.calendar.service.CalendarService,
end_date: Date specifying the end of events (inclusive). None for no end
date.
cal_user: "User" of the calendar to delete events from.
+ prompt: True if we should prompt before deleting events, False otherwise.
"""
# option_list is a list of tuples, (prompt_string, deletion_instruction)
@@ -150,15 +152,18 @@ class CalendarServiceCL(gdata.calendar.service.CalendarService,
# 'TWIXT' -- delete events between start_date and end_date.
# 'ON' -- delete events on the single date given.
# 'ONAFTER' -- delete events on and after the date given.
- option_list = [('All events in this series', 'ALL')]
+ deletion_choice = 'ALL'
+ option_list = [('All events in this series', deletion_choice)]
if start_date and end_date:
+ deletion_choice = 'TWIXT'
option_list.append(('Instances between %s and %s' %
- (start_date, end_date), 'TWIXT'))
+ (start_date, end_date), deletion_choice))
elif start_date or end_date:
delete_date = (start_date or end_date)
option_list.append(('Instances on %s' % delete_date, 'ON'))
option_list.append(('All events on and after %s' % delete_date,
'ONAFTER'))
+ deletion_choice = 'ON'
option_list.append(('Do not delete', 'NONE'))
prompt_str = ''
for i, option in enumerate(option_list):
@@ -167,7 +172,7 @@ class CalendarServiceCL(gdata.calendar.service.CalendarService,
# multiple times. This is assuming that recurring events have been expanded.
events = googlecl.calendar.condense_recurring_events(events)
for event in events:
- if self.prompt_for_delete:
+ if prompt:
delete_selection = -1
while delete_selection < 0 or delete_selection > len(option_list)-1:
msg = 'Delete "%s"?\n%s' %\
@@ -176,25 +181,26 @@ class CalendarServiceCL(gdata.calendar.service.CalendarService,
delete_selection = int(raw_input(safe_encode(msg)))
except ValueError:
continue
- option = option_list[delete_selection]
- if option[1] == 'ALL':
- self._delete_original_event(event, cal_user)
- elif option[1] == 'TWIXT':
- self._batch_delete_recur(event, cal_user,
- start_date=start_date,
- end_date=end_date)
- elif option[1] == 'ON':
- self._batch_delete_recur(event, cal_user,
- start_date=delete_date,
- end_date=delete_date)
- elif option[1] == 'ONAFTER':
- self._batch_delete_recur(event, cal_user,
- start_date=delete_date)
- elif option[1] != 'NONE':
- raise CalendarError('Got unexpected batch deletion command!')
+ deletion_choice = option_list[delete_selection][1]
- else:
+ # deletion_choice has either been picked by the prompt, or is the default
+ # value. The default value is determined by the date info passed in,
+ # and should be the "least destructive" option.
+ if deletion_choice == 'ALL':
self._delete_original_event(event, cal_user)
+ elif deletion_choice == 'TWIXT':
+ self._batch_delete_recur(event, cal_user,
+ start_date=start_date,
+ end_date=end_date)
+ elif deletion_choice == 'ON':
+ self._batch_delete_recur(event, cal_user,
+ start_date=delete_date,
+ end_date=delete_date)
+ elif deletion_choice == 'ONAFTER':
+ self._batch_delete_recur(event, cal_user,
+ start_date=delete_date)
+ elif deletion_choice != 'NONE':
+ raise CalendarError('Got unexpected batch deletion command!')
DeleteRecurringEvents = delete_recurring_events
diff --git a/src/googlecl/config/__init__.py b/src/googlecl/config/__init__.py
index 48c580e..8e439de 100644
--- a/src/googlecl/config/__init__.py
+++ b/src/googlecl/config/__init__.py
@@ -84,4 +84,7 @@ def load_configuration(path=None):
made_changes = config.ensure_basic_options(_create_basic_options())
if made_changes:
config.write_out_parser()
+ # Set the encoding again, now that the config file is loaded.
+ # (the config file may have a default encoding setting)
+ googlecl.TERMINAL_ENCODING = googlecl.determine_terminal_encoding(config)
return config
diff --git a/src/googlecl/docs/base.py b/src/googlecl/docs/base.py
index a646d72..26286c4 100644
--- a/src/googlecl/docs/base.py
+++ b/src/googlecl/docs/base.py
@@ -34,6 +34,7 @@ import logging
import os
import shlex
import shutil
+import sys
import googlecl
from googlecl.docs import SECTION_HEADER
@@ -44,6 +45,12 @@ safe_decode = googlecl.safe_decode
LOG = logging.getLogger(googlecl.docs.LOGGER_NAME + '.base')
+# For to_safe_filename
+if sys.platform == 'win32':
+ UNSAFE_FILE_CHARS = '\\/:*?"<>|'
+else:
+ UNSAFE_FILE_CHARS = '/'
+
class DocsError(googlecl.base.Error):
"""Base error for Docs errors."""
@@ -100,9 +107,11 @@ class DocsBaseCL(object):
base_path = os.path.join(temp_dir, base_folder)
total_basename = os.path.join(temp_dir, folder_path)
os.makedirs(total_basename)
- path = os.path.join(total_basename, doc_title + '.' + file_ext)
+ path = os.path.join(total_basename,
+ self.to_safe_filename(doc_title) + '.' + file_ext)
else:
- path = os.path.join(temp_dir, doc_title + '.' + file_ext)
+ path = os.path.join(temp_dir,
+ self.to_safe_filename(doc_title) + '.' + file_ext)
base_path = path
if not new_doc:
@@ -134,7 +143,7 @@ class DocsBaseCL(object):
if new_doc:
if isinstance(folder_entry_or_path, basestring):
# Let code in upload_docs handle the creation of new folder(s)
- self.upload_docs([base_path])
+ self.upload_docs([base_path], doc_title)
else:
# folder_entry_or_path is None or a GDataEntry.
doc_entry = self.upload_single_doc(path,
@@ -209,7 +218,8 @@ class DocsBaseCL(object):
entry_title = safe_decode(entry.title.text)
if os.path.isdir(base_path):
- path = os.path.join(base_path, entry_title + extension)
+ entry_title_safe = self.to_safe_filename(entry_title)
+ path = os.path.join(base_path, entry_title_safe + extension)
else:
path = base_path + extension
LOG.info(safe_encode('Downloading ' + entry_title + ' to ' + path))
@@ -231,6 +241,22 @@ class DocsBaseCL(object):
"""Modify the file data associated with a document entry."""
raise NotImplementedError('_modify_entry must be defined!')
+ def to_safe_filename(self, text):
+ """Translate string to something that can be safely used as a filename.
+
+ Behavior of this function depends on the operating system.
+
+ Args:
+ text: Text to check for invalid characters
+ Returns:
+ Parameter with unsafe characters escaped or removed.
+ Type (unicode vs string)will match that of the parameter.
+ """
+ sub = self.config.lazy_get(SECTION_HEADER, 'invalid_filename_character_sub',
+ default='')
+ sub = safe_decode(sub)
+ return ''.join([sub if c in UNSAFE_FILE_CHARS else c for c in text])
+
def upload_docs(self, paths, title=None, folder_entry=None,
file_ext=None, **kwargs):
"""Upload a list of documents or directories.
diff --git a/src/googlecl/picasa/service.py b/src/googlecl/picasa/service.py
index c0891d0..0367693 100644
--- a/src/googlecl/picasa/service.py
+++ b/src/googlecl/picasa/service.py
@@ -294,7 +294,7 @@ class PhotosServiceCL(PhotosService, googlecl.service.BaseServiceCL):
try:
content_type = SUPPORTED_VIDEO_TYPES[ext]
except KeyError:
- content_type = 'image/' + ext
+ content_type = 'image/' + ext.lower()
if not photo_name:
photo_name = os.path.split(path)[1]
try:
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-google/googlecl.git
More information about the Pkg-google-commits
mailing list