Drop support of Python 2.6

review2691002
This commit is contained in:
Cédric Krier committed 2014-01-31 00:02:03 +01:00
1 parent 4e535164c2
commit bc6acd08ee
20 files changed
+76 -492

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Drop support of Python 2.6
* Deprecate on_change, on_change_with, selection_change_with and autocomplete
field arguments
* Add fields.depends decorator
+19 -17
View File
@@ -3,7 +3,7 @@
#this repository contains the full copyright notices and license terms.
import sys
import os
import optparse
import argparse
DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
'..', '..', 'trytond')))
@@ -17,37 +17,39 @@ from trytond.version import VERSION
def parse_commandline():
options = {}
parser = optparse.OptionParser(version=VERSION)
parser = argparse.ArgumentParser(prog='trytond')
parser.add_option("-c", "--config", dest="config",
parser.add_argument('--version', action='version',
version='%(prog)s ' + VERSION)
parser.add_argument("-c", "--config", dest="config",
help="specify config file")
parser.add_option('--debug', dest='debug_mode', action='store_true',
parser.add_argument('--debug', dest='debug_mode', action='store_true',
help='enable debug mode (start post-mortem debugger if exceptions'
' occur)')
parser.add_option("-v", "--verbose", action="store_true",
parser.add_argument("-v", "--verbose", action="store_true",
dest="verbose", help="enable verbose mode")
parser.add_option("-d", "--database", dest="db_name",
parser.add_argument("-d", "--database", dest="db_name",
help="specify the database name")
parser.add_option("-i", "--init", dest="init",
parser.add_argument("-i", "--init", dest="init",
help="init a module (use \"all\" for all modules)")
parser.add_option("-u", "--update", dest="update",
parser.add_argument("-u", "--update", dest="update",
help="update a module (use \"all\" for all modules)")
parser.add_option("--pidfile", dest="pidfile",
parser.add_argument("--pidfile", dest="pidfile",
help="file where the server pid will be stored")
parser.add_option("--logfile", dest="logfile",
parser.add_argument("--logfile", dest="logfile",
help="file where the server log will be stored")
parser.add_option("--disable-cron", dest="cron",
parser.add_argument("--disable-cron", dest="cron",
action="store_false", help="disable cron")
parser.epilog = 'The first time a database is initialized with "-i" admin'\
' password is read from file defined by TRYTONPASSFILE '\
'environment variable or interactively ask user. '\
'The config file can be specified in the TRYTOND_CONFIG '\
'environment variable.'
parser.epilog = ('The first time a database is initialized with "-i" admin'
' password is read from file defined by TRYTONPASSFILE '
'environment variable or interactively ask user. '
'The config file can be specified in the TRYTOND_CONFIG '
'environment variable.')
(opt, _) = parser.parse_args()
opt = parser.parse_args()
if opt.config:
options['configfile'] = opt.config
+1 -1
View File
@@ -7,7 +7,7 @@ How to install Tryton
Prerequisites
=============
* Python 2.6 or later (http://www.python.org/)
* Python 2.7 or later (http://www.python.org/)
* lxml 2.0 or later (http://codespeak.net/lxml/)
* relatorio 0.2.0 or later (http://relatorio.openhex.org/)
* python-dateutil (http://labix.org/python-dateutil)
-1
View File
@@ -51,7 +51,6 @@ setup(name=PACKAGE,
'Natural Language :: Slovenian',
'Natural Language :: Spanish',
'Operating System :: OS Independent',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Topic :: Software Development :: Libraries :: Application Frameworks',
],
+2 -1
View File
@@ -2,10 +2,11 @@
#this repository contains the full copyright notices and license terms.
import datetime
from threading import Lock
from collections import OrderedDict
from trytond.transaction import Transaction
from trytond.config import CONFIG
from trytond import backend
from trytond.tools import OrderedDict
__all__ = ['Cache', 'LRUDict']
+2 -9
View File
@@ -1,11 +1,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import os
try:
import hashlib
except ImportError:
hashlib = None
import md5
import hashlib
from sql.operators import Concat
from ..model import ModelView, ModelSQL, fields
@@ -147,10 +143,7 @@ class Attachment(ModelSQL, ModelView):
directory = os.path.join(CONFIG['data_path'], db_name)
if not os.path.isdir(directory):
os.makedirs(directory, 0770)
if hashlib:
digest = hashlib.md5(value).hexdigest()
else:
digest = md5.new(value).hexdigest()
digest = hashlib.md5(value).hexdigest()
directory = os.path.join(directory, digest[0:2], digest[2:4])
if not os.path.isdir(directory):
os.makedirs(directory, 0770)
+2 -3
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import contextlib
import datetime
from dateutil.relativedelta import relativedelta
import traceback
@@ -167,8 +166,8 @@ class Cron(ModelSQL, ModelView):
req_user = cron.request_user
language = (req_user.language.code if req_user.language
else Config.get_language())
with contextlib.nested(Transaction().set_user(cron.user.id),
Transaction().set_context(language=language)):
with Transaction().set_user(cron.user.id), \
Transaction().set_context(language=language):
cls.send_error_message(cron)
@classmethod
+4 -5
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import contextlib
import time
import datetime
@@ -215,8 +214,8 @@ class Rule(ModelSQL, ModelView):
clause_global = {}
ctx = cls._get_context()
# Use root user without context to prevent recursion
with contextlib.nested(Transaction().set_user(0),
Transaction().set_context(user=0)):
with Transaction().set_user(0), \
Transaction().set_context(user=0):
for rule in cls.browse(ids):
assert rule.domain, ('Rule domain empty,'
'check if migration was done')
@@ -255,8 +254,8 @@ class Rule(ModelSQL, ModelView):
clause = ['AND', clause_global, clause]
# Use root to prevent infinite recursion
with contextlib.nested(Transaction().set_user(0),
Transaction().set_context(active_test=False, user=0)):
with Transaction().set_user(0), \
Transaction().set_context(active_test=False, user=0):
query = obj.search(clause, order=[], query=True)
cls._domain_get_cache.set(key, query)
+5 -9
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import contextlib
try:
import cStringIO as StringIO
except ImportError:
@@ -10,10 +9,7 @@ import polib
import xml.dom.minidom
from difflib import SequenceMatcher
import os
try:
from hashlib import md5
except ImportError:
from md5 import md5
from hashlib import md5
from lxml import etree
from itertools import izip
from sql import Column
@@ -805,8 +801,8 @@ class Translation(ModelSQL, ModelView):
res_id = model_data.db_id
else:
res_id = -1
with contextlib.nested(Transaction().set_user(0),
Transaction().set_context(module=res_id_module)):
with Transaction().set_user(0), \
Transaction().set_context(module=res_id_module):
translation, = cls.search([
('name', '=', name),
('res_id', '=', res_id),
@@ -868,8 +864,8 @@ class Translation(ModelSQL, ModelView):
translation_ids.extend(ids)
continue
with contextlib.nested(Transaction().set_user(0),
Transaction().set_context(module=module)):
with Transaction().set_user(0), \
Transaction().set_context(module=module):
if not ids:
to_create.append({
'name': name,
+2 -3
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import contextlib
from types import NoneType
from sql import Cast, Literal, Column, Query, Expression
from sql.functions import Substring, Position
@@ -68,8 +67,8 @@ class Reference(Field):
ref_to_check[ref_model][1].append(i)
# Check if reference ids still exist
with contextlib.nested(Transaction().set_context(active_test=False),
Transaction().set_user(0)):
with Transaction().set_context(active_test=False), \
Transaction().set_user(0):
for ref_model, (ref_ids, ids) in ref_to_check.iteritems():
try:
pool.get(ref_model)
+4 -5
View File
@@ -1,6 +1,5 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import contextlib
import re
from functools import reduce
from itertools import islice, izip
@@ -359,8 +358,8 @@ class ModelSQL(ModelStorage):
id_new = cursor.lastid()
new_ids.append(id_new)
except DatabaseIntegrityError, exception:
with contextlib.nested(Transaction().new_cursor(),
Transaction().set_user(0)):
with Transaction().new_cursor(), \
Transaction().set_user(0):
cls.__raise_integrity_error(exception, values)
raise
@@ -703,8 +702,8 @@ class ModelSQL(ModelStorage):
cursor.execute(*table.update(columns, update_values,
where=red_sql))
except DatabaseIntegrityError, exception:
with contextlib.nested(Transaction().new_cursor(),
Transaction().set_user(0)):
with Transaction().new_cursor(), \
Transaction().set_user(0):
cls.__raise_integrity_error(exception, values,
values.keys())
raise
+6 -7
View File
@@ -4,7 +4,6 @@
import datetime
import time
import logging
import contextlib
import traceback
import sys
import csv
@@ -1310,9 +1309,9 @@ class ModelStorage(Model):
model2ids = {}
model2cache = {}
# Read the data
with contextlib.nested(Transaction().set_cursor(self._cursor),
Transaction().set_user(self._user),
Transaction().set_context(self._context)):
with Transaction().set_cursor(self._cursor), \
Transaction().set_user(self._user), \
Transaction().set_context(self._context):
if self.id in self._cache and name in self._cache[self.id]:
# Use values from cache
ids = islice(chain(islice(self._ids, index, None),
@@ -1407,9 +1406,9 @@ class ModelStorage(Model):
self._values = None
if save_values or self.id < 0:
try:
with contextlib.nested(Transaction().set_cursor(self._cursor),
Transaction().set_user(self._user),
Transaction().set_context(self._context)):
with Transaction().set_cursor(self._cursor), \
Transaction().set_user(self._user), \
Transaction().set_context(self._context):
if self.id < 0:
self._ids.remove(self.id)
try:
+12 -8
View File
@@ -4,7 +4,6 @@ import os
import sys
import itertools
import logging
import contextlib
from functools import reduce
import imp
import operator
@@ -365,13 +364,8 @@ def register_classes():
def load_modules(database_name, pool, update=False, lang=None):
res = True
if not Transaction().cursor:
contextmanager = Transaction().start(database_name, 0)
else:
contextmanager = contextlib.nested(Transaction().new_cursor(),
Transaction().set_user(0),
Transaction().reset_context())
with contextmanager:
def _load_modules():
cursor = Transaction().cursor
if update:
# Migration from 2.2: workflow module removed
@@ -428,5 +422,15 @@ def load_modules(database_name, pool, update=False, lang=None):
Module = pool.get('ir.module.module')
Module.update_list()
cursor.commit()
if not Transaction().cursor:
with Transaction().start(database_name, 0):
_load_modules()
else:
with Transaction().new_cursor(), \
Transaction().set_user(0), \
Transaction().reset_context():
_load_modules()
Cache.resets(database_name)
return res
-94
View File
@@ -4,12 +4,6 @@ import errno
import os
import socket
import threading
import sys
import gzip
try:
import cStringIO as StringIO
except ImportError:
import StringIO
from SocketServer import StreamRequestHandler
@@ -57,91 +51,3 @@ class RegisterHandlerMixin:
self.server.handlers.remove(self)
except KeyError:
pass
class GZipRequestHandlerMixin:
if sys.version_info[:2] <= (2, 6):
# Copy from SimpleXMLRPCServer.py with gzip encoding added
def do_POST(self):
"""Handles the HTTP POST request.
Attempts to interpret all HTTP POST requests as XML-RPC calls,
which are forwarded to the server's _dispatch method for handling.
"""
# Check that the path is legal
if not self.is_rpc_path_valid():
self.report_404()
return
try:
# Get arguments by reading body of request.
# We read this in chunks to avoid straining
# socket.read(); around the 10 or 15Mb mark, some platforms
# begin to have problems (bug #792570).
max_chunk_size = 10 * 1024 * 1024
size_remaining = int(self.headers["content-length"])
L = []
while size_remaining:
chunk_size = min(size_remaining, max_chunk_size)
L.append(self.rfile.read(chunk_size))
size_remaining -= len(L[-1])
data = ''.join(L)
data = self.decode_request_content(data)
if data is None:
return # response has been sent
# In previous versions of SimpleXMLRPCServer, _dispatch
# could be overridden in this class, instead of in
# SimpleXMLRPCDispatcher. To maintain backwards compatibility,
# check to see if a subclass implements _dispatch and dispatch
# using that method if present.
response = self.server._marshaled_dispatch(
data, getattr(self, '_dispatch', None)
)
except Exception: # This should only happen if the module is buggy
# internal error, report as HTTP server error
self.send_response(500)
self.end_headers()
else:
# got a valid XML RPC response
self.send_response(200)
self.send_header("Content-type", "text/xml")
# Handle gzip encoding
if ('gzip' in self.headers.get('Accept-Encoding',
'').split(',')
and len(response) > self.encode_threshold):
buffer = StringIO.StringIO()
output = gzip.GzipFile(mode='wb', fileobj=buffer)
output.write(response)
output.close()
buffer.seek(0)
response = buffer.getvalue()
self.send_header('Content-Encoding', 'gzip')
self.send_header("Content-length", str(len(response)))
self.end_headers()
self.wfile.write(response)
def decode_request_content(self, data):
#support gzip encoding of request
encoding = self.headers.get("content-encoding", "identity").lower()
if encoding == "identity":
return data
if encoding == "gzip":
f = StringIO.StringIO(data)
gzf = gzip.GzipFile(mode="rb", fileobj=f)
try:
decoded = gzf.read()
except IOError:
self.send_response(400, "error decoding gzip content")
f.close()
gzf.close()
return decoded
else:
self.send_response(501, "encoding %r not supported" % encoding)
self.send_header("Content-length", "0")
self.end_headers()
+3 -6
View File
@@ -3,8 +3,7 @@
from trytond.protocols.sslsocket import SSLSocket
from trytond.protocols.dispatcher import dispatch
from trytond.config import CONFIG
from trytond.protocols.common import daemon, GZipRequestHandlerMixin, \
RegisterHandlerMixin
from trytond.protocols.common import daemon, RegisterHandlerMixin
from trytond.exceptions import UserError, UserWarning, NotLogged, \
ConcurrencyException
import SimpleXMLRPCServer
@@ -157,8 +156,7 @@ class GenericJSONRPCRequestHandler:
return res
class SimpleJSONRPCRequestHandler(GZipRequestHandlerMixin,
RegisterHandlerMixin,
class SimpleJSONRPCRequestHandler(RegisterHandlerMixin,
GenericJSONRPCRequestHandler,
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler,
SimpleHTTPServer.SimpleHTTPRequestHandler):
@@ -325,14 +323,13 @@ class SimpleThreadedJSONRPCServer(SocketServer.ThreadingMixIn,
SimpleJSONRPCServer):
timeout = 1
daemon_threads = True
disable_nagle_algorithm = True
def server_bind(self):
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_KEEPALIVE, 1)
self.socket.setsockopt(socket.IPPROTO_TCP,
socket.TCP_NODELAY, 1)
SimpleJSONRPCServer.server_bind(self)
+2 -4
View File
@@ -3,8 +3,7 @@
from trytond.protocols.sslsocket import SSLSocket
from trytond.protocols.dispatcher import dispatch
from trytond.config import CONFIG
from trytond.protocols.common import daemon, GZipRequestHandlerMixin, \
RegisterHandlerMixin
from trytond.protocols.common import daemon, RegisterHandlerMixin
from trytond.exceptions import UserError, UserWarning, NotLogged, \
ConcurrencyException
from trytond import security
@@ -145,8 +144,7 @@ class GenericXMLRPCRequestHandler:
security.logout(database_name, user, session)
class SimpleXMLRPCRequestHandler(GZipRequestHandlerMixin,
RegisterHandlerMixin,
class SimpleXMLRPCRequestHandler(RegisterHandlerMixin,
GenericXMLRPCRequestHandler,
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
protocol_version = "HTTP/1.1"
+9 -8
View File
@@ -2,7 +2,7 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import logging
import optparse
import argparse
import os
import time
import unittest
@@ -13,14 +13,15 @@ if __name__ != '__main__':
raise ImportError('%s can not be imported' % __name__)
logging.basicConfig(level=logging.ERROR)
parser = optparse.OptionParser(usage="Usage: %prog [options] [test] [...]")
parser.add_option("-c", "--config", dest="config",
parser = argparse.ArgumentParser()
parser.add_argument("-c", "--config", dest="config",
help="specify config file")
parser.add_option("-m", "--modules", action="store_true", dest="modules",
parser.add_argument("-m", "--modules", action="store_true", dest="modules",
default=False, help="Run also modules tests")
parser.add_option("-v", action="count", default=0, dest="verbosity",
parser.add_argument("-v", action="count", default=0, dest="verbosity",
help="Increase verbosity")
opt, modules = parser.parse_args()
parser.add_argument('tests', metavar='test', nargs='*')
opt = parser.parse_args()
CONFIG['db_type'] = 'sqlite'
CONFIG.update_etc(opt.config)
@@ -35,7 +36,7 @@ os.environ['DB_NAME'] = database_name
from trytond.tests.test_tryton import all_suite, modules_suite
if not opt.modules:
suite = all_suite(modules)
suite = all_suite(opt.tests)
else:
suite = modules_suite(modules)
suite = modules_suite(opt.tests)
unittest.TextTestRunner(verbosity=opt.verbosity).run(suite)
+2 -20
View File
@@ -4,26 +4,8 @@
import unittest
import time
from xmlrpclib import MAXINT
try:
from itertools import combinations
except ImportError:
def combinations(iterable, r):
pool = tuple(iterable)
n = len(pool)
if r > n:
return
indices = range(r)
yield tuple(pool[i] for i in indices)
while True:
for i in reversed(range(r)):
if indices[i] != i + n - r:
break
else:
return
indices[i] += 1
for j in range(i + 1, r):
indices[j] = indices[j - 1] + 1
yield tuple(pool[i] for i in indices)
from itertools import combinations
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
install_module
from trytond.tests.trigger import TRIGGER_LOGS
-4
View File
@@ -2,10 +2,6 @@
#this repository contains the full copyright notices and license terms.
from .misc import *
from .datetime_strftime import *
try:
from collections import OrderedDict
except ImportError:
from .ordereddict import OrderedDict
class ClassProperty(property):
-287
View File
@@ -1,287 +0,0 @@
# Copyright (C) 2009 by Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and
# pypy.
# Passes Python2.7's test suite and incorporates all the latest updates.
try:
from thread import get_ident as _get_ident
except ImportError:
from dummy_thread import get_ident as _get_ident
try:
from _abcoll import KeysView, ValuesView, ItemsView
except ImportError:
pass
class OrderedDict(dict):
'Dictionary that remembers insertion order'
# An inherited dict maps keys to values.
# The inherited dict provides __getitem__, __len__, __contains__, and get.
# The remaining methods are order-aware.
# Big-O running times for all methods are the same as for regular
# dictionaries.
# The internal self.__map dictionary maps keys to links in a doubly linked
# list.
# The circular doubly linked list starts and ends with a sentinel element.
# The sentinel element never gets deleted (this simplifies the algorithm).
# Each link is stored as a list of length three: [PREV, NEXT, KEY].
def __init__(self, *args, **kwds):
'''Initialize an ordered dictionary. Signature is the same as for
regular dictionaries, but keyword arguments are not recommended
because their insertion order is arbitrary.
'''
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__root
except AttributeError:
self.__root = root = [] # sentinel node
root[:] = [root, root, None]
self.__map = {}
self.__update(*args, **kwds)
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
'od.__setitem__(i, y) <==> od[i]=y'
# Setting a new item creates a new link which goes at the end of the
# linked list, and the inherited dictionary is updated with the new
# key/value pair.
if key not in self:
root = self.__root
last = root[0]
last[1] = root[0] = self.__map[key] = [last, root, key]
dict_setitem(self, key, value)
def __delitem__(self, key, dict_delitem=dict.__delitem__):
'od.__delitem__(y) <==> del od[y]'
# Deleting an existing item uses self.__map to find the link which is
# then removed by updating the links in the predecessor and successor
# nodes.
dict_delitem(self, key)
link_prev, link_next, key = self.__map.pop(key)
link_prev[1] = link_next
link_next[0] = link_prev
def __iter__(self):
'od.__iter__() <==> iter(od)'
root = self.__root
curr = root[1]
while curr is not root:
yield curr[2]
curr = curr[1]
def __reversed__(self):
'od.__reversed__() <==> reversed(od)'
root = self.__root
curr = root[0]
while curr is not root:
yield curr[2]
curr = curr[0]
def clear(self):
'od.clear() -> None. Remove all items from od.'
try:
for node in self.__map.itervalues():
del node[:]
root = self.__root
root[:] = [root, root, None]
self.__map.clear()
except AttributeError:
pass
dict.clear(self)
def popitem(self, last=True):
'''od.popitem() -> (k, v), return and remove a (key, value) pair.
Pairs are returned in LIFO order if last is true or FIFO order if
false.
'''
if not self:
raise KeyError('dictionary is empty')
root = self.__root
if last:
link = root[0]
link_prev = link[0]
link_prev[1] = root
root[0] = link_prev
else:
link = root[1]
link_next = link[1]
root[1] = link_next
link_next[0] = root
key = link[2]
del self.__map[key]
value = dict.pop(self, key)
return key, value
# -- the following methods do not depend on the internal structure --
def keys(self):
'od.keys() -> list of keys in od'
return list(self)
def values(self):
'od.values() -> list of values in od'
return [self[key] for key in self]
def items(self):
'od.items() -> list of (key, value) pairs in od'
return [(key, self[key]) for key in self]
def iterkeys(self):
'od.iterkeys() -> an iterator over the keys in od'
return iter(self)
def itervalues(self):
'od.itervalues -> an iterator over the values in od'
for k in self:
yield self[k]
def iteritems(self):
'od.iteritems -> an iterator over the (key, value) items in od'
for k in self:
yield (k, self[k])
def update(*args, **kwds):
'''od.update(E, **F) -> None. Update od from dict/iterable E and F.
If E is a dict instance, does: for k in E: od[k] = E[k]
If E has a .keys() method, does: for k in E.keys(): od[k] = E[k]
Or if E is an iterable of items, does: for k, v in E: od[k] = v
In either case, this is followed by: for k, v in F.items(): od[k] = v
'''
if len(args) > 2:
raise TypeError('update() takes at most 2 positional '
'arguments (%d given)' % (len(args),))
elif not args:
raise TypeError('update() takes at least 1 argument (0 given)')
self = args[0]
# Make progressively weaker assumptions about "other"
other = ()
if len(args) == 2:
other = args[1]
if isinstance(other, dict):
for key in other:
self[key] = other[key]
elif hasattr(other, 'keys'):
for key in other.keys():
self[key] = other[key]
else:
for key, value in other:
self[key] = value
for key, value in kwds.items():
self[key] = value
# let subclasses override update without breaking __init__
__update = update
__marker = object()
def pop(self, key, default=__marker):
'''od.pop(k[,d]) -> v, remove specified key and return the
corresponding value. If key is not found, d is returned if given,
otherwise KeyError is raised.
'''
if key in self:
result = self[key]
del self[key]
return result
if default is self.__marker:
raise KeyError(key)
return default
def setdefault(self, key, default=None):
'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
if key in self:
return self[key]
self[key] = default
return default
def __repr__(self, _repr_running={}):
'od.__repr__() <==> repr(od)'
call_key = id(self), _get_ident()
if call_key in _repr_running:
return '...'
_repr_running[call_key] = 1
try:
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
finally:
del _repr_running[call_key]
def __reduce__(self):
'Return state information for pickling'
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def copy(self):
'od.copy() -> a shallow copy of od'
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
'''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
and values equal to v (which defaults to None).
'''
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
'''od.__eq__(y) <==> od==y. Comparison to another OD is
order-sensitive while comparison to a regular mapping is
order-insensitive.
'''
if isinstance(other, OrderedDict):
return len(self) == len(other) and self.items() == other.items()
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
# -- the following methods are only used in Python 2.7 --
def viewkeys(self):
"od.viewkeys() -> a set-like object providing a view on od's keys"
return KeysView(self)
def viewvalues(self):
"od.viewvalues() -> an object providing a view on od's values"
return ValuesView(self)
def viewitems(self):
"od.viewitems() -> a set-like object providing a view on od's items"
return ItemsView(self)