Compare commits

...
13 Commits
Author SHA1 Message Date
mdipierro b02e8a6d5f fixed problem with custom import and upgraded jquery.js 2015-04-02 16:30:15 -05:00
mdipierro a2b17967cf Merge pull request #898 from ilvalle/issue-896
fix web2py/web2py#896, avoid to select blob fields in sqlform.grid
2015-04-02 16:24:26 -05:00
mdipierro 343ebf1714 Merge pull request #897 from BuhtigithuB/update-contrib/feedparser-py
Update gluon/contrib/feedparser.py from 5.1.2 -> 5.1.3
2015-04-02 16:23:34 -05:00
mdipierro e330791fe3 Merge pull request #894 from niphlod/fix/windows_build
fix windows build
2015-04-02 16:22:49 -05:00
mdipierro 5e1e97ffc4 Merge pull request #893 from niphlod/fix/duplicate_module
not needed anymore module
2015-04-02 16:20:39 -05:00
ilvalle 60f8816a10 fix web2py/web2py#896, avoid to select blob fields in sqlform.grid 2015-04-02 21:38:05 +02:00
Richard Vézina 6187c89ba6 Update gluon/contrib/feedparser.py from 5.1.2 -> 5.1.3 2015-04-02 13:58:48 -04:00
niphlod e441e15907 fix windows build 2015-04-01 21:35:52 +02:00
niphlod e6c3410639 not needed anymore module 2015-04-01 20:55:47 +02:00
mdipierro 6b6cb5839c Merge branch 'master' of github.com:web2py/web2py 2015-04-01 13:55:07 -05:00
mdipierro 2a7e9c0c59 possible fix for issue #892 2015-04-01 13:54:48 -05:00
mdipierro 5b637c0a82 Merge pull request #891 from leonelcamara/cache_cleanup
Fixes issue with locked files during cleanup
2015-04-01 12:41:52 -05:00
Leonel Câmara 5cdd7c1215 Fixes issue with locked files during cleanup 2015-04-01 18:27:05 +01:00
11 changed files with 77 additions and 304 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ update:
echo "remember that pymysql was tweaked" echo "remember that pymysql was tweaked"
src: src:
### Use semantic versioning ### Use semantic versioning
echo 'Version 2.10.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION echo 'Version 2.10.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
### rm -f all junk files ### rm -f all junk files
make clean make clean
### clean up baisc apps ### clean up baisc apps
+1 -1
View File
@@ -1 +1 @@
Version 2.10.2-stable+timestamp.2015.03.31.22.25.23 Version 2.10.3-stable+timestamp.2015.04.02.16.28.49
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -18,7 +18,7 @@
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="alltables"> <div class="tab-pane active" id="alltables">
<table> <table class="table">
{{for db in sorted(databases):}} {{for db in sorted(databases):}}
{{for table in databases[db].tables:}} {{for table in databases[db].tables:}}
{{qry='%s.%s.id>0'%(db,table)}} {{qry='%s.%s.id>0'%(db,table)}}
@@ -40,7 +40,7 @@
{{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}} {{=A("%s.%s" % (db,table),_href=URL('select',args=[db],vars=dict(query=qry)))}}
</th> </th>
<td> <td>
{{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn")}} {{=A(str(T('New Record')),_href=URL('insert',args=[db,table]),_class="btn btn-default")}}
</td> </td>
</tr> </tr>
{{pass}} {{pass}}
@@ -61,7 +61,7 @@
</pre> </pre>
{{pass}} {{pass}}
{{if table:}} {{if table:}}
{{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn")}}<br/><br/> {{=A(str(T('New Record')),_href=URL('insert',args=[request.args[0],table]),_class="btn btn-default")}}<br/><br/>
<h3>{{=T("Rows in Table")}}</h3><br/> <h3>{{=T("Rows in Table")}}</h3><br/>
{{else:}} {{else:}}
<h3>{{=T("Rows selected")}}</h3><br/> <h3>{{=T("Rows selected")}}</h3><br/>
@@ -72,8 +72,8 @@
{{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p> {{=T('"update" is an optional expression like "field1=\'newvalue\'". You cannot update or delete the results of a JOIN')}}</p>
<br/><br/> <br/><br/>
<h4>{{=T("%s selected", nrows)}}</h4> <h4>{{=T("%s selected", nrows)}}</h4>
{{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn")}}{{pass}} {{if start>0:}}{{=A(T('previous %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start-step)),_class="btn btn-default")}}{{pass}}
{{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn")}}{{pass}} {{if stop<nrows:}}{{=A(T('next %s rows') % step,_href=URL('select',args=request.args[0],vars=dict(start=start+step)),_class="btn btn-default")}}{{pass}}
{{if rows:}} {{if rows:}}
<div style="overflow:auto; width:80%;"> <div style="overflow:auto; width:80%;">
{{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}} {{linkto = lambda f, t, r: URL('update', args=[request.args[0], r, f]) if f else "#"}}
@@ -82,7 +82,7 @@
</div> </div>
{{pass}} {{pass}}
<br/><br/><h3>{{=T("Import/Export")}}</h3><br/> <br/><br/><h3>{{=T("Import/Export")}}</h3><br/>
<a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn">{{=T("export as csv file")}}</a> <a href="{{=URL('csv',args=request.args[0],vars=dict(query=query))}}" class="btn btn-default">{{=T("export as csv file")}}</a>
{{=formcsv or ''}} {{=formcsv or ''}}
{{elif request.function=='insert':}} {{elif request.function=='insert':}}
+4 -3
View File
@@ -114,17 +114,18 @@ def app_cleanup(app, request):
for f in os.listdir(path): for f in os.listdir(path):
try: try:
if f[:1] != '.': recursive_unlink(os.path.join(path, f)) if f[:1] != '.': recursive_unlink(os.path.join(path, f))
except IOError: except (OSError, IOError):
r = False r = False
# Remove cache files # Remove cache files
CacheOnDisk(folder=apath('%s/cache/' % app, request)).clear()
path = apath('%s/cache/' % app, request) path = apath('%s/cache/' % app, request)
CacheOnDisk(folder=path).clear()
if os.path.exists(path): if os.path.exists(path):
for f in os.listdir(path): for f in os.listdir(path):
try: try:
if f[:1] != '.': recursive_unlink(os.path.join(path, f)) if f[:1] != '.': recursive_unlink(os.path.join(path, f))
except IOError: except (OSError, IOError):
r = False r = False
return r return r
Executable → Regular
+48 -22
View File
@@ -9,7 +9,7 @@ Required: Python 2.4 or later
Recommended: iconv_codec <http://cjkpython.i18n.org/> Recommended: iconv_codec <http://cjkpython.i18n.org/>
""" """
__version__ = "5.1.2" __version__ = "5.1.3"
__license__ = """ __license__ = """
Copyright (c) 2010-2012 Kurt McKee <contactme@kurtmckee.org> Copyright (c) 2010-2012 Kurt McKee <contactme@kurtmckee.org>
Copyright (c) 2002-2008 Mark Pilgrim Copyright (c) 2002-2008 Mark Pilgrim
@@ -44,7 +44,8 @@ __contributors__ = ["Jason Diamond <http://injektilo.org/>",
"Sam Ruby <http://intertwingly.net/>", "Sam Ruby <http://intertwingly.net/>",
"Ade Oshineye <http://blog.oshineye.com/>", "Ade Oshineye <http://blog.oshineye.com/>",
"Martin Pool <http://sourcefrog.net/>", "Martin Pool <http://sourcefrog.net/>",
"Kurt McKee <http://kurtmckee.org/>"] "Kurt McKee <http://kurtmckee.org/>",
"Bernd Schlapsi <https://github.com/brot>",]
# HTTP "User-Agent" header to send to servers when downloading feeds. # HTTP "User-Agent" header to send to servers when downloading feeds.
# If you are embedding feedparser in a larger application, you should # If you are embedding feedparser in a larger application, you should
@@ -1971,6 +1972,7 @@ class _BaseHTMLProcessor(sgmllib.SGMLParser):
def handle_charref(self, ref): def handle_charref(self, ref):
# called for each character reference, e.g. for '&#160;', ref will be '160' # called for each character reference, e.g. for '&#160;', ref will be '160'
# Reconstruct the original character reference. # Reconstruct the original character reference.
ref = ref.lower()
if ref.startswith('x'): if ref.startswith('x'):
value = int(ref[1:], 16) value = int(ref[1:], 16)
else: else:
@@ -2455,7 +2457,10 @@ class _MicroformatsParser:
linktype.startswith('video/') or \ linktype.startswith('video/') or \
(linktype.startswith('application/') and not linktype.endswith('xml')): (linktype.startswith('application/') and not linktype.endswith('xml')):
return 1 return 1
path = urlparse.urlparse(attrsD['href'])[2] try:
path = urlparse.urlparse(attrsD['href'])[2]
except ValueError:
return 0
if path.find('.') == -1: if path.find('.') == -1:
return 0 return 0
fileext = path.split('.').pop().lower() fileext = path.split('.').pop().lower()
@@ -2541,7 +2546,8 @@ class _RelativeURIResolver(_BaseHTMLProcessor):
('object', 'data'), ('object', 'data'),
('object', 'usemap'), ('object', 'usemap'),
('q', 'cite'), ('q', 'cite'),
('script', 'src')]) ('script', 'src'),
('video', 'poster')])
def __init__(self, baseuri, encoding, _type): def __init__(self, baseuri, encoding, _type):
_BaseHTMLProcessor.__init__(self, encoding, _type) _BaseHTMLProcessor.__init__(self, encoding, _type)
@@ -2618,13 +2624,13 @@ class _HTMLSanitizer(_BaseHTMLProcessor):
'loop', 'loopcount', 'loopend', 'loopstart', 'low', 'lowsrc', 'max', 'loop', 'loopcount', 'loopend', 'loopstart', 'low', 'lowsrc', 'max',
'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'nohref', 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'nohref',
'noshade', 'nowrap', 'open', 'optimum', 'pattern', 'ping', 'point-size', 'noshade', 'nowrap', 'open', 'optimum', 'pattern', 'ping', 'point-size',
'prompt', 'pqg', 'radiogroup', 'readonly', 'rel', 'repeat-max', 'poster', 'pqg', 'preload', 'prompt', 'radiogroup', 'readonly', 'rel',
'repeat-min', 'replace', 'required', 'rev', 'rightspacing', 'rows', 'repeat-max', 'repeat-min', 'replace', 'required', 'rev', 'rightspacing',
'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span', 'src', 'rows', 'rowspan', 'rules', 'scope', 'selected', 'shape', 'size', 'span',
'start', 'step', 'summary', 'suppress', 'tabindex', 'target', 'template', 'src', 'start', 'step', 'summary', 'suppress', 'tabindex', 'target',
'title', 'toppadding', 'type', 'unselectable', 'usemap', 'urn', 'valign', 'template', 'title', 'toppadding', 'type', 'unselectable', 'usemap',
'value', 'variable', 'volume', 'vspace', 'vrml', 'width', 'wrap', 'urn', 'valign', 'value', 'variable', 'volume', 'vspace', 'vrml',
'xml:lang']) 'width', 'wrap', 'xml:lang'])
unacceptable_elements_with_end_tag = set(['script', 'applet', 'style']) unacceptable_elements_with_end_tag = set(['script', 'applet', 'style'])
@@ -2976,9 +2982,9 @@ def _open_resource(url_file_stream_or_string, etag, modified, agent, referrer, h
url_file_stream_or_string = 'http:' + url_file_stream_or_string[5:] url_file_stream_or_string = 'http:' + url_file_stream_or_string[5:]
if not agent: if not agent:
agent = USER_AGENT agent = USER_AGENT
# test for inline user:password for basic auth # Test for inline user:password credentials for HTTP basic auth
auth = None auth = None
if base64: if base64 and not url_file_stream_or_string.startswith('ftp:'):
urltype, rest = urllib.splittype(url_file_stream_or_string) urltype, rest = urllib.splittype(url_file_stream_or_string)
realhost, rest = urllib.splithost(rest) realhost, rest = urllib.splithost(rest)
if realhost: if realhost:
@@ -3471,15 +3477,7 @@ _rfc822_match = re.compile(
"(?:%s, )?%s(?: %s)?" % (_rfc822_dayname, _rfc822_date, _rfc822_time) "(?:%s, )?%s(?: %s)?" % (_rfc822_dayname, _rfc822_date, _rfc822_time)
).match ).match
def _parse_date_rfc822(dt): def _parse_date_group_rfc822(m):
"""Parse RFC 822 dates and times, with one minor
difference: years may be 4DIGIT or 2DIGIT.
http://tools.ietf.org/html/rfc822#section-5"""
try:
m = _rfc822_match(dt.lower()).groupdict(0)
except AttributeError:
return None
# Calculate a date and timestamp # Calculate a date and timestamp
for k in ('year', 'day', 'hour', 'minute', 'second'): for k in ('year', 'day', 'hour', 'minute', 'second'):
m[k] = int(m[k]) m[k] = int(m[k])
@@ -3512,8 +3510,36 @@ def _parse_date_rfc822(dt):
# Return the date and timestamp in UTC # Return the date and timestamp in UTC
return (stamp - delta).utctimetuple() return (stamp - delta).utctimetuple()
def _parse_date_rfc822(dt):
"""Parse RFC 822 dates and times, with one minor
difference: years may be 4DIGIT or 2DIGIT.
http://tools.ietf.org/html/rfc822#section-5"""
try:
m = _rfc822_match(dt.lower()).groupdict(0)
except AttributeError:
return None
return _parse_date_group_rfc822(m)
registerDateHandler(_parse_date_rfc822) registerDateHandler(_parse_date_rfc822)
def _parse_date_rfc822_grubby(dt):
"""Parse date format similar to RFC 822, but
the comma after the dayname is optional and
month/day are inverted"""
_rfc822_date_grubby = "%s %s %s" % (_rfc822_month, _rfc822_day, _rfc822_year)
_rfc822_match_grubby = re.compile(
"(?:%s[,]? )?%s(?: %s)?" % (_rfc822_dayname, _rfc822_date_grubby, _rfc822_time)
).match
try:
m = _rfc822_match_grubby(dt.lower()).groupdict(0)
except AttributeError:
return None
return _parse_date_group_rfc822(m)
registerDateHandler(_parse_date_rfc822_grubby)
def _parse_date_asctime(dt): def _parse_date_asctime(dt):
"""Parse asctime-style dates""" """Parse asctime-style dates"""
dayname, month, day, remainder = dt.split(None, 3) dayname, month, day, remainder = dt.split(None, 3)
-254
View File
@@ -1,254 +0,0 @@
# -*- encoding: utf-8 -*-
from imaplib import ParseFlags
# mockimaplib: A very simple mock server module for imap client APIs
# Copyright (C) 2014 Alan Etkin <spametki@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or(at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/lgpl.html>
"""
mockimaplib allows you to test applications connecting to a dummy imap
service. For more details on the api subset implemented,
refer to the imaplib docs.
The client should configure a dictionary to map imap string queries to sets
of entries stored in a message dummy storage dictionary. The module includes
a small set of default message records (SPAM and MESSAGES), two mailboxes
(Draft and INBOX) and a list of query/resultset entries (RESULTS).
Usage:
>>> import mockimaplib
>>> connection = mockimaplib.IMAP4_SSL(<host>)
>>> connection.login(<user>, <password>)
None
>>> connection.select("INBOX")
("OK", ... <mailbox length>)
# fetch commands specifying single uid or message id
# will try to get messages recorded in SPAM
>>> connection.uid(...)
<search query or fetch result>
# returns a string list of matching message ids
>>> connection.search(<query>)
("OK", ... "1 2 ... n")
"""
MESSAGES = (
'MIME-Version: 1.0\r\nReceived: by 10.140.91.199 with HTTP; Mon, 27 Jan 2014 13:52:30 -0800 (PST)\r\nDate: Mon, 27 Jan 2014 19:52:30 -0200\r\nDelivered-To: nurse@example.com\r\nMessage-ID: <10101010101010010000010101010001010101001010010000001@mail.example.com>\r\nSubject: spam1\r\nFrom: Mr. Gumby <gumby@example.com>\r\nTo: The nurse <nurse@example.com>\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nNurse!\r\n\r\n\r\n',
'MIME-Version: 1.0\r\nReceived: by 10.140.91.199 with HTTP; Mon, 27 Jan 2014 13:52:47 -0800 (PST)\r\nDate: Mon, 27 Jan 2014 19:52:47 -0200\r\nDelivered-To: nurse@example.com\r\nMessage-ID: <101010101010100100000101010100010101010010100100000010@mail.example.com>\r\nSubject: spam2\r\nFrom: Mr. Gumby <gumby@example.com>\r\nTo: The nurse <nurse@example.com>\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nNurse, nurse!',
'MIME-Version: 1.0\r\nReceived: by 10.140.91.199 with HTTP; Mon, 27 Jan 2014 13:54:54 -0800 (PST)\r\nDate: Mon, 27 Jan 2014 19:54:54 -0200\r\nDelivered-To: nurse@example.com\r\nMessage-ID: <1010101010101001000001010101000101010100101001000000101@mail.example.com>\r\nSubject: spamalot1\r\nFrom: Mr. Gumby <gumby@example.com>\r\nTo: The nurse <nurse@example.com>\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nNurse!\r\n\r\n\r\n',
'MIME-Version: 1.0\r\n\r\nReceived: by 10.140.91.199 with HTTP; Mon, 27 Jan 2014 13:54:54 -0800 (PST)\r\nDate: Mon, 27 Jan 2014 19:54:54 -0200\r\nDelivered-To: nurse@example.com\r\nMessage-ID: <101010101010100100000101010100010101010010100100000010101@mail.example.com>\r\nSubject: spamalot2\r\nFrom: Mr. Gumby <gumby@example.com>\r\nTo: The nurse <nurse@example.com>\r\nContent-Type: text/plain; charset=ISO-8859-1\r\n\r\nNurse! ... Nurse! ... Nurse!\r\n\r\n\r\n')
SPAM = {
"INBOX": [
{"uid": "483209",
"headers": MESSAGES[0],
"complete": MESSAGES[0],
"flags": ""},
{"uid": "483211",
"headers": MESSAGES[1],
"complete": MESSAGES[1],
"flags": ""},
{"uid": "483225",
"headers": MESSAGES[2],
"complete": MESSAGES[2],
"flags": ""}],
"Draft":[
{"uid": "483432",
"headers": MESSAGES[3],
"complete": MESSAGES[3],
"flags": ""},]
}
RESULTS = {
# <query string>: [<str uid> | <long id>, ...]
"INBOX": {
"(ALL)": (1, 2, 3),
"(1:3)": (1, 2, 3)},
"Draft": {
"(1:1)": (1,)},
}
class Connection(object):
"""Dummy connection object for the imap client.
By default, uses the module SPAM and RESULT
sets (use Connection.setup for custom values)"""
def login(self, user, password):
pass
def __init__(self):
self._readonly = False
self._mailbox = None
self.setup()
def list(self):
return ('OK', ['(\\HasNoChildren) "/" "%s"' % key for key in self.spam])
def select(self, tablename, readonly=False):
self._readonly = readonly
"""args: mailbox, boolean
result[1][0] -> int last message id / mailbox lenght
result[0] = 'OK'
"""
self._mailbox = tablename
return ('OK', (len(SPAM[self._mailbox]), None))
def uid(self, command, uid, arg):
""" args:
command: "search" | "fetch"
uid: None | uid
parts: "(ALL)" | "(RFC822 FLAGS)" | "(RFC822.HEADER FLAGS)"
"search", None, "(ALL)" -> ("OK", ("uid_1 uid_2 ... uid_<mailbox length>", None))
"search", None, "<query>" -> ("OK", ("uid_1 uid_2 ... uid_n", None))
"fetch", uid, parts -> ("OK", (("<id> ...", "<raw message as specified in parts>"), "<flags>")
[0] [1][0][0] [1][0][1] [1][1]
"""
if command == "search":
return self._search(arg)
elif command == "fetch":
return self._fetch(uid, arg)
def _search(self, query):
return ("OK", (" ".join([str(item["uid"]) for item in self._get_messages(query)]), None))
def _fetch(self, value, arg):
try:
message = self.spam[self._mailbox][value - 1]
message_id = value
except TypeError:
for x, item in enumerate(self.spam[self._mailbox]):
if item["uid"] == value:
message = item
message_id = x + 1
break
parts = "headers"
if arg in ("(ALL)", "(RFC822 FLAGS)"):
parts = "complete"
return ("OK", (("%s " % message_id, message[parts]), message["flags"]))
def _get_messages(self, query):
if query.strip().isdigit():
return [self.spam[self._mailbox][int(query.strip()) - 1],]
elif query[1:-1].strip().isdigit():
return [self.spam[self._mailbox][int(query[1:-1].strip()) -1],]
elif query[1:-1].replace("UID", "").strip().isdigit():
for item in self.spam[self._mailbox]:
if item["uid"] == query[1:-1].replace("UID", "").strip():
return [item,]
messages = []
try:
for m in self.results[self._mailbox][query]:
try:
self.spam[self._mailbox][m - 1]["id"] = m
messages.append(self.spam[self._mailbox][m - 1])
except TypeError:
for x, item in enumerate(self.spam[self._mailbox]):
if item["uid"] == m:
item["id"] = x + 1
messages.append(item)
break
except IndexError:
# message removed
pass
return messages
except KeyError:
raise ValueError("The client issued an unexpected query: %s" % query)
def setup(self, spam={}, results={}):
"""adds custom message and query databases or sets
the values to the module defaults.
"""
self.spam = spam
self.results = results
if not spam:
for key in SPAM:
self.spam[key] = []
for d in SPAM[key]:
self.spam[key].append(d.copy())
if not results:
for key in RESULTS:
self.results[key] = RESULTS[key].copy()
def search(self, first, query):
""" args:
first: None
query: string with mailbox query (flags, date, uid, id, ...)
example: '2:15723 BEFORE 27-Jan-2014 FROM "gumby"'
result[1][0] -> "id_1 id_2 ... id_n"
"""
messages = self._get_messages(query)
ids = " ".join([str(item["id"]) for item in messages])
return ("OK", (ids, None))
def append(self, mailbox, flags, struct_time, message):
"""
result, data = self.connection.append(mailbox, flags, struct_time, message)
if result == "OK":
uid = int(re.findall("\d+", str(data))[-1])
"""
last = self.spam[mailbox][-1]
try:
uid = int(last["uid"]) +1
except ValueError:
alluids = []
for _mailbox in self.spam.keys():
for item in self.spam[_mailbox]:
try:
alluids.append(int(item["uid"]))
except:
pass
if len(alluids) > 0:
uid = max(alluids) + 1
else:
uid = 1
flags = "FLAGS " + flags
item = {"uid": str(uid), "headers": message, "complete": message, "flags": flags}
self.spam[mailbox].append(item)
return ("OK", "spam spam %s spam" % uid)
def store(self, *args):
"""
implements some flag commands
args: ("<id>", "<+|->FLAGS", "(\\Flag1 \\Flag2 ... \\Flagn)")
"""
message = self.spam[self._mailbox][int(args[0] - 1)]
old_flags = ParseFlags(message["flags"])
flags = ParseFlags("FLAGS" + args[2])
if args[1].strip().startswith("+"):
message["flags"] = "FLAGS (%s)" % " ".join(set(flags + old_flags))
elif args[1].strip().startswith("-"):
message["flags"] = "FLAGS (%s)" % " ".join([flag for flag in old_flags if not flag in flags])
def expunge(self):
"""implements removal of deleted flag messages"""
for x, item in enumerate(self.spam[self._mailbox]):
if "\\Deleted" in item["flags"]:
self.spam[self._mailbox].pop(x)
class IMAP4(object):
""">>> connection = IMAP4() # creates the dummy imap4 client object"""
def __new__(self, *args, **kwargs):
# args: (server, port)
return Connection()
IMAP4_SSL = IMAP4
+3
View File
@@ -47,6 +47,9 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
If the import fails, it falls back on naive_importer If the import fails, it falls back on naive_importer
""" """
if isinstance(name, unicode):
name = name.encode('utf8')
globals = globals or {} globals = globals or {}
locals = locals or {} locals = locals or {}
fromlist = fromlist or [] fromlist = fromlist or []
+1 -7
View File
@@ -23,6 +23,7 @@ base_modules = ['aifc', 'anydbm', 'array', 'asynchat', 'asyncore', 'atexit',
'collections', 'colorsys', 'compileall', 'compiler', 'collections', 'colorsys', 'compileall', 'compiler',
'compiler.ast', 'compiler.visitor', 'ConfigParser', 'compiler.ast', 'compiler.visitor', 'ConfigParser',
'contextlib', 'Cookie', 'cookielib', 'copy', 'copy_reg', 'contextlib', 'Cookie', 'cookielib', 'copy', 'copy_reg',
'collections',
'cPickle', 'cProfile', 'cStringIO', 'csv', 'ctypes', 'cPickle', 'cProfile', 'cStringIO', 'csv', 'ctypes',
'datetime', 'decimal', 'difflib', 'dircache', 'dis', 'datetime', 'decimal', 'difflib', 'dircache', 'dis',
'doctest', 'DocXMLRPCServer', 'dumbdbm', 'dummy_thread', 'doctest', 'DocXMLRPCServer', 'dumbdbm', 'dummy_thread',
@@ -67,13 +68,6 @@ base_modules = ['aifc', 'anydbm', 'array', 'asynchat', 'asyncore', 'atexit',
'MimeWriter', 'mimify', 'multifile', 'sets'] 'MimeWriter', 'mimify', 'multifile', 'sets']
contributed_modules = [] contributed_modules = []
for root, dirs, files in os.walk('gluon'):
for candidate in ['.'.join(
os.path.join(root, os.path.splitext(name)[0]).split(os.sep))
for name in files if name.endswith('.py')
and root.split(os.sep) != ['gluon', 'tests']
]:
contributed_modules.append(candidate)
# Python base version # Python base version
python_version = sys.version[:3] python_version = sys.version[:3]
+1 -1
View File
@@ -2148,7 +2148,7 @@ class SQLFORM(FORM):
else: else:
fields = [] fields = []
columns = [] columns = []
filter1 = lambda f: isinstance(f, Field) filter1 = lambda f: isinstance(f, Field) and f.type != 'blob'
filter2 = lambda f: isinstance(f, Field) and f.readable filter2 = lambda f: isinstance(f, Field) and f.readable
for table in tables: for table in tables:
fields += filter(filter1, table) fields += filter(filter1, table)
+4 -1
View File
@@ -42,10 +42,13 @@ from gluon import *
from gluon.contrib.autolinks import expand_one from gluon.contrib.autolinks import expand_one
from gluon.contrib.markmin.markmin2html import \ from gluon.contrib.markmin.markmin2html import \
replace_at_urls, replace_autolinks, replace_components replace_at_urls, replace_autolinks, replace_components
from pydal.objects import Table, Row, Set, Query from pydal.objects import Row, Set, Query
import gluon.serializers as serializers import gluon.serializers as serializers
Table = DAL.Table
Field = DAL.Field
try: try:
# try stdlib (Python 2.6) # try stdlib (Python 2.6)
import json as json_parser import json as json_parser