Compare commits

...

78 Commits

Author SHA1 Message Date
Kenneth Reitz 40c9e09578 Merge branch 'release/0.6.2' 2010-09-13 17:26:56 -04:00
Kenneth Reitz 9f5379fcc7 Version Bump (0.6.2). 2010-09-13 17:24:39 -04:00
Kenneth Reitz 9ecc57dbf7 Added header property to prevent invalid headers being set. 2010-09-13 17:22:02 -04:00
Kenneth Reitz a7471f7302 Testing fixtures for fixed bugs. 2010-09-13 17:21:40 -04:00
Kenneth Reitz 70211b71e0 Updated Readme.rst 2010-09-13 17:18:25 -04:00
Kenneth Reitz ddf4b441b0 Fixed exception catch, Fixes Issue #5. 2010-09-13 16:50:08 -04:00
Kenneth Reitz a0509126e0 Added simple unit-testing structure. 2010-09-13 16:49:11 -04:00
Kenneth Reitz ec5b1cf3e0 Merge branch 'develop' 2010-09-13 16:14:34 -04:00
Kenneth Reitz 3fb729aac6 Removed non-working unit-tests. 2010-09-13 16:11:07 -04:00
Kenneth Reitz 647f69044f Cleaning up code a bit. 2010-09-13 16:07:27 -04:00
Kenneth Reitz 3da34af76f Removed un-implimented junk from core.py 2010-09-13 16:06:37 -04:00
Kenneth Reitz 5b42824871 Removed vendorized packages. 2010-09-13 16:06:14 -04:00
Kenneth Reitz 89209b6bd3 Moving tabbed cli to future feature branch. 2010-09-13 16:03:11 -04:00
Kenneth Reitz 9362d3283b Version bump (v0.6.1) 2010-09-13 15:51:15 -04:00
Kenneth Reitz 123851a737 README.rst update. 2010-09-13 15:49:18 -04:00
Kenneth Reitz 54973c276c Added reqs.txt 2010-09-13 15:48:08 -04:00
Kenneth Reitz 275ac9d194 Setup.py typo 2010-09-12 14:12:30 -04:00
Kenneth Reitz 4ecd5888af Readme issue 2010-09-12 14:03:26 -04:00
Kenneth Reitz 359f12c83c Another readme update. 2010-09-12 13:55:52 -04:00
Kenneth Reitz de8d76fdae Merge branch 'develop' 2010-09-12 13:52:05 -04:00
Kenneth Reitz f188e3dd87 Heavy readme update. 2010-09-12 13:50:59 -04:00
Kenneth Reitz 3dff8f5b79 updated readme a bit 2010-09-12 13:28:55 -04:00
Kenneth Reitz c24d2dd45d Docstring updates. 2010-09-12 13:17:21 -04:00
Kenneth Reitz 4e98563483 Encodings are important. 2010-09-12 13:16:05 -04:00
Kenneth Reitz ca17c9f965 Proper usage of MANIFEST. 2010-09-12 13:15:38 -04:00
Kenneth Reitz 41c4fcc59f Added authors and others to manifest. 2010-09-12 13:15:21 -04:00
Kenneth Reitz e9166b14fd Cleaned up fabfile. 2010-09-12 13:13:43 -04:00
Kenneth Reitz a5528d731e Updated verbage in AUTHORS. 2010-09-12 13:13:08 -04:00
Kenneth Reitz 1a122f2a4d gitignore 2010-09-12 13:12:21 -04:00
Kenneth Reitz e9d9350e43 merge for version bump into master 2010-09-12 12:51:13 -04:00
Kenneth Reitz ac4b568cba Updates for push. 2010-09-12 11:45:31 -04:00
Kenneth Reitz 8be372b8cc Readme cleanups. 2010-09-11 23:14:56 -04:00
Kenneth Reitz f8d8d3058a Hmm 2010-09-11 23:09:13 -04:00
Kenneth Reitz d03ba7e532 Optimizations. 2010-09-11 23:09:06 -04:00
Kenneth Reitz 35102ab951 Prepping for distribution. 2010-09-11 23:08:57 -04:00
Kenneth Reitz b8587e5cb0 Packaging for distribution. 2010-09-11 23:08:48 -04:00
Kenneth Reitz da4f2013f1 Unvendorized packages. 2010-09-11 23:08:31 -04:00
Kenneth Reitz ff069b1604 version bump 2010-09-08 18:07:52 -04:00
Kenneth Reitz 2994a9fc0d Merge branch 'release/0.0.5' 2010-09-08 18:06:40 -04:00
Kenneth Reitz 310400af5b Merge branch 'feature/paged' into develop 2010-09-08 18:06:25 -04:00
Kenneth Reitz d52537b75b Added workbook feature for xls support.
Other formats expected.
2010-09-08 18:05:32 -04:00
Kenneth Reitz 40490d1ba5 Added base DataBook object. 2010-09-08 17:35:13 -04:00
Kenneth Reitz 9f025dc111 Added name to corelib. 2010-09-08 15:55:08 -04:00
Kenneth Reitz 335e3b1134 Updated setup file. 2010-09-08 15:55:01 -04:00
Kenneth Reitz 6b4afc38d1 Roadmap Update 2010-09-02 00:21:03 -04:00
Kenneth Reitz bd3099897c Merge branch 'hotfix/readme' into develop 2010-09-02 00:04:13 -04:00
Kenneth Reitz 4b6fbe9225 Merge branch 'hotfix/readme' 2010-09-02 00:04:07 -04:00
Kenneth Reitz f22357f1bc Readme fix 2010-09-02 00:03:48 -04:00
Kenneth Reitz 37ffbc71c0 index and append methods 2010-08-30 05:31:45 -04:00
Kenneth Reitz 6f7c64eb03 Better xlwt handling. 2010-08-30 05:18:22 -04:00
Kenneth Reitz 89be8f402f Merge branch 'release/0.0.4' into develop 2010-08-30 03:58:44 -04:00
Kenneth Reitz 607ea4a8aa Merge branch 'release/0.0.4' 2010-08-30 03:58:36 -04:00
Kenneth Reitz 7044896d56 0.0.4. 2010-08-30 03:58:27 -04:00
Kenneth Reitz 8fca234388 test 2010-08-30 03:55:24 -04:00
Kenneth Reitz 0862b35905 Readme update. 2010-08-30 03:46:30 -04:00
Kenneth Reitz e8bf07da1a Test tests. 2010-08-30 03:45:49 -04:00
Kenneth Reitz 5c70fe0a07 Cleanup. 2010-08-30 03:45:35 -04:00
Kenneth Reitz 6c37412c76 Updated readme, commenting out unimplimented features. 2010-08-30 03:45:26 -04:00
Kenneth Reitz 54a83602e4 Removed unnecessary typecheck module. 2010-08-30 03:38:45 -04:00
Kenneth Reitz f486b77a7a Added XLS export support. 2010-08-30 03:23:56 -04:00
Kenneth Reitz fecfecfd16 xlwt patch for compatibility reasons (may be unnecessary) 2010-08-30 03:22:50 -04:00
Kenneth Reitz 9a65b8deed Added CSV Export Support. 2010-08-30 02:59:22 -04:00
Kenneth Reitz 61231b38ac Epic. 2010-08-30 02:38:59 -04:00
Kenneth Reitz b7a8b65c00 Validate method refactor.
Removal of Digest method.
2010-08-30 02:37:49 -04:00
Kenneth Reitz 6dd71c8830 Updated history.rst formatting 2010-08-30 02:35:56 -04:00
Kenneth Reitz 8d44ad8a12 YAML export support complete. 2010-08-30 02:32:57 -04:00
Kenneth Reitz 1850a934aa JSON support working well. 2010-08-30 01:39:38 -04:00
Kenneth Reitz ee953512b7 Merge branch 'feature/base-object' into develop 2010-08-30 01:38:30 -04:00
Kenneth Reitz 6405ec3baf General improvments 2010-08-30 01:01:32 -04:00
Kenneth Reitz ea64e4cfac Dataset Title Metatdata.
Improved dataset repr.
2010-08-30 00:33:44 -04:00
Kenneth Reitz 0bea48ccc3 Imports. 2010-08-30 00:28:54 -04:00
Kenneth Reitz 687670762f Added PyYaml into vendorized packages. 2010-08-30 00:28:47 -04:00
Kenneth Reitz 254ce62b2a .append 2010-08-30 00:22:11 -04:00
Kenneth Reitz 2b3f277138 Time for some testing. 2010-08-29 23:38:03 -04:00
Kenneth Reitz a2f59584e4 Version bump (v0.0.3) 2010-08-29 23:21:37 -04:00
Kenneth Reitz 4d3a31e19f API change. 2010-08-29 23:20:59 -04:00
Kenneth Reitz 95c98861da Object structure in place 2010-08-29 22:41:34 -04:00
Kenneth Reitz 59d1f9fded Changed Data class to Dataset. 2010-08-29 20:12:39 -04:00
110 changed files with 457 additions and 20845 deletions
+2
View File
@@ -1,6 +1,7 @@
# application builds
build/*
dist/*
MANIFEST
# python skin
.pyc
@@ -13,3 +14,4 @@ profile
# pycharm noise
.idea
.idea/*
+1 -1
View File
@@ -1,4 +1,4 @@
GistAPI.py is written and maintained by Kenneth Reitz and
Tablib is written and maintained by Kenneth Reitz and
various contributors:
Development Lead
+23
View File
@@ -0,0 +1,23 @@
History
=======
0.6.2 (2010-09-13)
------------------
* Fixed Dataset.append() error on empty dataset.
* Updated Dataset.headers property w/ validation.
* Added Testing Fixtures.
0.6.1 (2010-09-12)
------------------
* Packaging hotfixes.
0.6.0 (2010-09-11)
------------------
* Public Release.
* Export Support for XLS, JSON, YAML, and CSV.
* DataBook Export for XLS, JSON, and YAML.
* Python Dict Property Support.
+1 -1
View File
@@ -1 +1 @@
include HISTORY.rst README.rst tabbed
include HISTORY.rst README.rst LICENSE AUTHORS
+100 -58
View File
@@ -1,97 +1,139 @@
Tabbed: format-agnostic tabular dataset library
Tablib: format-agnostic tabular dataset library
===============================================
::
_____ ______ ______ _________
__ /_______ ____ /_ ___ /_ _____ ______ /
_ __/_ __ `/__ __ \__ __ \_ _ \_ __ /
/ /_ / /_/ / _ /_/ /_ /_/ // __// /_/ /
\__/ \__,_/ /_.___/ /_.___/ \___/ \__,_/
*Tabbed is under active documentation-driven development.*
_____ ______ ___________ ______
__ /_______ ____ /_ ___ /___(_)___ /_
_ __/_ __ `/__ __ \__ / __ / __ __ \
/ /_ / /_/ / _ /_/ /_ / _ / _ /_/ /
\__/ \__,_/ /_.___/ /_/ /_/ /_.___/
Tabbed is a format-agnostic tabular dataset library, written in Python.
It is a full python module which doubles as a CLI application for quick
dataset conversions.
Formats supported:
Tablib is a format-agnostic tabular dataset library, written in Python.
Output formats supported:
- Excel
- JSON
- YAML
- Excel
- CSV
- HTML
Please note that tabbed *purposefully* excludes XML support. It always will.
At this time, Tablib supports the **export** of it's powerful Dataset object instances into any of the above formats. Import is underway.
Note that tablib *purposefully* excludes XML support. It always will.
Features
--------
Usage
-----
Convert datafile formats via API: ::
tablib.import(filename='data.csv').export('data.json')
Convert datafile formats via CLI: ::
$ tabbed data.csv data.json
Convert data formats via CLI pipe interface: ::
$ curl http://domain.dev/dataset.json | tabbed --to excel | gist -p
Populate fresh data files: ::
headers = ('first_name', 'last_name', 'gpa')
data = [
('John', 'Adams', 4.0),
('George', 'Washington', 2.6),
('Henry', 'Ford', 2.3)
('John', 'Adams', 90),
('George', 'Washington', 67)
]
data = tablib.Data(*data, headers=headers)
data = tablib.Dataset(*data, headers=headers)
# Establish file location and save
data.save('test.xls')
Intelligently add new rows: ::
data.add_row('Bob', 'Dylan')
# >>> Warning: Existing column count is 3
>>> data.append(('Henry', 'Ford', 83))
print data.headers
# >>> ('first_name', 'last_name', 'gpa')
Slice rows: ::
print data[0:1]
# >>> [('John', 'Adams', 4.0), ('George', 'Washington', 2.6)]
>>> print data[:2]
[('John', 'Adams', 90), ('George', 'Washington', 67)]
Slice columns by header: ::
print data['first_name']
# >>> ['John', 'George', 'Henry']
>>> print data['first_name']
['John', 'George', 'Henry']
Easily delete rows: ::
>>> del data[1]
Drumroll please...........
JSON!
+++++
::
>>> print data.json
[
{
"last_name": "Adams",
"age": 90,
"first_name": "John"
},
{
"last_name": "Ford",
"age": 83,
"first_name": "Henry"
}
]
YAML!
+++++
::
>>> print data.yaml
- {age: 90, first_name: John, last_name: Adams}
- {age: 83, first_name: Henry, last_name: Ford}
CSV...
++++++
::
>>> print data.csv
first_name,last_name,age
John,Adams,90
Henry,Ford,83
EXCEL!
++++++
::
>>> open('people.xls').write(data.xls)
It's that easy.
Installation
------------
To install tablib, simply: ::
$ pip install tablib
Or, if you absolutely must: ::
$ easy_install tablib
Manipulate rows by index: ::
Contribute
----------
data.delRow(0)
print data[0:1]
# >>> [('George', 'Washington', 2.6), ('Henry', 'Ford', 2.3)]
# Update saved file
data.save()
If you'd like to contribute, simply fork `the repository`_, commit your changes, and send a pull request. Make sure you add yourself to AUTHORS_.
Export to various formats: ::
# Save copy as CSV
data.export('backup.csv')
Roadmap
-------
- Add ability to add/remove full columns
- Import datasets from CSV, JSON, YAML
- Release CLI Interface
- Auto-detect import format
- Add possible other exports (SQL?)
- Possibly plugin-ify format architecture
- Plugin support
.. _`the repository`: http://github.com/kennethreitz/tablib
.. _AUTHORS: http://github.com/kennethreitz/tablib/blob/master/AUTHORS
Vendored
-20
View File
@@ -5,23 +5,3 @@ def scrub():
""" Death to the bytecode! """
local("rm -fr dist build")
local("find . -name \"*.pyc\" -exec rm '{}' ';'")
def test():
""" Test parsing! """
local("rm output/*")
local("./strata.py --nsanity_files 'strata/tests/samples/nsanity' -d")
def build():
""" Build application"""
pass
def init():
""" Initialize Environment """
# TODO: Possibly add Virtual Environment?
local("sudo pip install -r REQUIREMENTS")
if __name__ == '__main__':
# TODO: Remove (for testing purposes)
# TODO: [Possibly] add doctests
test()
+3
View File
@@ -0,0 +1,3 @@
xlwt
simplejson
PyYAML
+32 -24
View File
@@ -1,36 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import tablib
from distutils.core import setup
def publish():
"""Publish to PyPi"""
os.system("python setup.py sdist upload")
"""Publish to PyPi"""
os.system("python setup.py sdist upload")
if sys.argv[-1] == "publish":
publish()
sys.exit()
publish()
sys.exit()
setup(name='tablib',
version=tablib.__version__,
description='Python wrapper for Gist API',
long_description=open('README.rst').read() + '\n\n' +
open('HISTORY.rst').read(),
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
url='http://github.com/kennethreitz/tabbed',
packages=['tablib'],
license='MIT',
classifiers=(
"Development Status :: 4 - Beta",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2.5",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
)
)
setup(
name='tablib',
version='0.6.2',
description='Format agnostic tabular data library (XLS, JSON, YAML, CSV)',
long_description=open('README.rst').read() + '\n\n' +
open('HISTORY.rst').read(),
author='Kenneth Reitz',
author_email='me@kennethreitz.com',
url='http://github.com/kennethreitz/tablib',
packages=['tablib'],
install_requires=['xlwt', 'simplejson', 'PyYAML'],
license='MIT',
classifiers=(
'Development Status :: 4 - Beta',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python',
# 'Programming Language :: Python :: 2.5',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
),
# entry_points={
# 'console_scripts': [
# 'tabbed = tablib.cli:start',
# ],
# }
)
-14
View File
@@ -1,14 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tabbed
Copyright (c) 2010 Kenneth Reitz. MIT License.
"""
import tablib.cli
if __name__ == '__main__':
tablib.cli.start()
-85
View File
@@ -1,85 +0,0 @@
#!/usr/bin/env python
# encoding: utf-8
""" Tabbed CLI Inteface Application
"""
import io
import sys
from helpers import *
import tablib.core
from packages import opster
FORMATS = ('json', 'yaml', 'xls', 'csv', 'html')
opts = []
opts.append(('v', 'version', False, 'Report tabbed version'))
for format in FORMATS:
opts.append(('', format, False, 'Output to %s' % (format.upper())))
@opster.command(options=opts, usage='[FILE] [--FORMAT | FILE]')
def start(in_file=None, out_file=None, **opts):
"""Covertly convert dataset formats"""
opts = Object(**opts)
if opts.version:
print('Tabbed, Ver. %s' % tabbed.core.__version__)
sys.sys.exit(0)
stdin = piped()
if stdin:
print stdin
elif in_file:
try:
in_file = io.open(in_file, 'r')
except Exception, e:
print(' %s cannot be read.' % in_file)
sys.exit(65)
file_ext = in_file.name.split('.')[-1]
if file_ext.lower() in FORMATS:
setattr(opts, file_ext, True)
else:
print('Import format not supported.')
sys.exit(65)
else:
print('Please provide input.')
sys.exit(65)
_formats_sum = sum(opts[f] for f in FORMATS)
# Multiple output formats given
if _formats_sum > 1:
print('Please specify a single output format.')
sys.exit(64)
# No output formats given
elif _formats_sum < 1:
print('Please specify an output format.')
sys.exit(64)
# fetch options.formats list
# if sum(()) > 1
# log only one data format please
# if sum of formats == 0, specity format
# look for filename
print opts.__dict__
print in_file
print out_file
+248 -17
View File
@@ -6,33 +6,264 @@
# / /_ / /_/ / _ /_/ /_ /_/ // __// /_/ /
# \__/ \__,_/ /_.___/ /_.___/ \___/ \__,_/
__version__ = '0.0.3'
__build__ = '0x000003'
import csv
import cStringIO
import random
import simplejson as json
import xlwt
import yaml
from helpers import *
# __all__ = ['Dataset', 'DataBook']
__name__ = 'tablib'
__version__ = '0.6.1'
__build__ = 0x000601
__author__ = 'Kenneth Reitz'
__license__ = 'MIT'
__copyright__ = 'Copyright 2010 Kenneth Reitz'
def importer():
"""docstring for import"""
class Dataset(object):
"""Epic Tabular-Dataset object. """
def __init__(self, *args, **kwargs):
self._data = None
self._saved_file = None
self._saved_format = None
self._data = list(args)
self.__headers = None
try:
self.headers = kwargs['headers']
except KeyError, why:
self.headers = None
try:
self.title = kwargs['title']
except KeyError, why:
self.title = None
def __len__(self):
return self.height
class Data(object):
"""test"""
def __init__(self):
pass
self.headers = None
def __getitem__(self, key):
if is_string(key):
if key in self.headers:
pos = self.headers.index(key) # get 'key' index from each data
return [row[pos] for row in self._data]
else:
raise KeyError
else:
return self._data[key]
def __setitem__(self, key, value):
self._validate(value)
self._data[key] = tuple(value)
def __delitem__(self, key):
del self._data[key]
def __repr__(self):
try:
return '<%s dataset>' % (self.title.lower())
except AttributeError:
return '<dataset object>'
def _validate(self, row=None, safety=False):
"""Assures size of every row in dataset is of proper proportions."""
if row:
is_valid = (len(row) == self.width) if self.width else True
else:
is_valid = all((len(x)== self.width for x in self._data))
if is_valid:
return True
else:
if not safety:
raise InvalidDimensions
return False
def _package(self, dicts=True):
"""Packages Dataset into lists of dictionaries for transmission."""
if self.headers:
if dicts:
data = [dict(zip(self.headers, data_row)) for data_row in self ._data]
else:
data = [list(self.headers)] + list(self._data)
else:
data = [list(row) for row in self._data]
return data
@property
def height(self):
"""Returns the height of the Dataset."""
return len(self._data)
@property
def width(self):
"""Returns the width of the Dataset."""
try:
return len(self._data[0])
except IndexError, why:
try:
return len(self.headers)
except TypeError, e:
return 0
@property
def headers(self):
"""Headers property."""
return self.__headers
@headers.setter
def headers(self, collection):
"""Validating headers setter."""
self._validate(collection)
self.__headers = collection
@property
def dict(self):
"""Returns python dict of Dataset."""
return self._package()
@property
def json(self):
"""Returns JSON representation of Dataset."""
return json.dumps(self.dict)
@property
def yaml(self):
"""Returns YAML representation of Dataset."""
return yaml.dump(self.dict)
@property
def csv(self):
"""Returns CSV representation of Dataset."""
stream = cStringIO.StringIO()
_csv = csv.writer(stream)
for row in self._package(dicts=False):
_csv.writerow(row)
return stream.getvalue()
@property
def xls(self):
"""Returns XLS representation of Dataset."""
stream = cStringIO.StringIO()
wb = xlwt.Workbook()
ws = wb.add_sheet(self.title if self.title else 'Tabbed Dataset')
for i, row in enumerate(self._package(dicts=False)):
for j, col in enumerate(row):
ws.write(i, j, str(col))
wb.save(stream)
return stream.getvalue()
def append(self, row):
"""Adds a row to the end of Dataset"""
self._validate(row)
self._data.append(tuple(row))
def index(self, i, row):
"""Inserts a row at given position in Dataset"""
self._validate(row)
self._data.insert(i, tuple(row))
class DataBook(object):
"""A book of Dataset objects.
Currently, this exists only for XLS workbook support.
"""
def __init__(self, sets=[]):
self._datasets = sets
def __repr__(self):
try:
return '<%s databook>' % (self.title.lower())
except AttributeError:
return '<databook object>'
def add_sheet(self, dataset):
"""Add given dataset ."""
if type(dataset) is Dataset:
self._datasets.append(dataset)
else:
raise InvalidDatasetType
def _package(self):
collector = []
for dset in self._datasets:
collector.append(dict(
title = dset.title,
data = dset.dict
))
return collector
@property
def size(self):
"""The number of the Datasets within DataBook."""
return len(self._datasets)
@property
def xls(self):
"""Returns XLS representation of DataBook."""
stream = cStringIO.StringIO()
wb = xlwt.Workbook()
for dset in self._datasets:
ws = wb.add_sheet(dset.title if dset.title else 'Tabbed Dataset %s' % (int(random.random() * 100000000)))
#for row in self._package(dicts=False):
for i, row in enumerate(dset._package(dicts=False)):
for j, col in enumerate(row):
ws.write(i, j, str(col))
wb.save(stream)
return stream.getvalue()
@property
def json(self):
"""Returns JSON representation of Databook."""
return json.dumps(self._package())
@property
def yaml(self):
"""Returns YAML representation of Databook."""
return yaml.dump(self._package())
class InvalidDatasetType(Exception):
"Only Datasets can be added to a DataBook"
def add_row(self, index=None):
pass
def del_row(self):
pass
def save(self):
pass
class InvalidDimensions(Exception):
"Invalid size"
class UnsupportedFormat(NotImplementedError):
"Format is not supported"
View File
View File
View File
View File
View File
+7 -2
View File
@@ -3,7 +3,7 @@
import sys
class Object(object):
class Struct(object):
"""Your attributes are belong to us."""
def __init__(self, **entries):
@@ -15,6 +15,11 @@ class Object(object):
def piped():
"""Returns piped input via stdin, else False"""
with sys.stdin as stdin:
return stdin.read() if not stdin.isatty() else None
def is_string(obj):
"""Tests if an object is a string"""
return True if type(obj).__name__ == 'str' else False
-1
View File
@@ -1 +0,0 @@
all = ['simplejson', 'typecheck', 'xlwt', 'opster']
-612
View File
@@ -1,612 +0,0 @@
# (c) Alexander Solovyov, 2009, under terms of the new BSD License
'''Command line arguments parser
'''
import sys, traceback, getopt, types, textwrap, inspect, os
from itertools import imap
__all__ = ['command', 'dispatch']
__version__ = '0.9.10'
__author__ = 'Alexander Solovyov'
__email__ = 'piranha@piranha.org.ua'
write = sys.stdout.write
err = sys.stderr.write
CMDTABLE = {}
# --------
# Public interface
# --------
def command(options=None, usage=None, name=None, shortlist=False, hide=False):
'''Decorator to mark function to be used for command line processing.
All arguments are optional:
- ``options``: options in format described in docs. If not supplied,
will be determined from function.
- ``usage``: usage string for function, replaces ``%name`` with name
of program or subcommand. In case if it's subcommand and ``%name``
is not present, usage is prepended by ``name``
- ``name``: used for multiple subcommands. Defaults to wrapped
function name
- ``shortlist``: if command should be included in shortlist. Used
only with multiple subcommands
- ``hide``: if command should be hidden from help listing. Used only
with multiple subcommands, overrides ``shortlist``
'''
def wrapper(func):
try:
options_ = list(guess_options(func))
except TypeError:
options_ = []
try:
options_ = options_ + list(options)
except TypeError:
pass
name_ = name or func.__name__.replace('_', '-')
if usage is None:
usage_ = guess_usage(func, options_)
else:
usage_ = usage
prefix = hide and '~' or (shortlist and '^' or '')
CMDTABLE[prefix + name_] = (func, options_, usage_)
def help_func(name=None):
return help_cmd(func, replace_name(usage_, sysname()), options_)
@wraps(func)
def inner(*args, **opts):
# look if we need to add 'help' option
try:
(True for option in reversed(options_)
if option[1] == 'help').next()
except StopIteration:
options_.append(('h', 'help', False, 'show help'))
argv = opts.pop('argv', sys.argv[1:])
if opts.pop('help', False):
return help_func()
if args or opts:
# no catcher here because this is call from Python
return call_cmd_regular(func, options_)(*args, **opts)
try:
opts, args = catcher(lambda: parse(argv, options_), help_func)
except Abort:
return -1
try:
if opts.pop('help', False):
return help_func()
return catcher(lambda: call_cmd(name_, func)(*args, **opts),
help_func)
except Abort:
return -1
return inner
return wrapper
def dispatch(args=None, cmdtable=None, globaloptions=None,
middleware=lambda x: x):
'''Dispatch command arguments based on subcommands.
- ``args``: list of arguments, default: ``sys.argv[1:]``
- ``cmdtable``: dict of commands in format described below.
If not supplied, will use functions decorated with ``@command``.
- ``globaloptions``: list of options which are applied to all
commands, will contain ``--help`` option at least.
- ``middleware``: global decorator for all commands.
cmdtable format description::
{'name': (function, options, usage)}
- ``name`` is the name used on command-line. Can contain aliases
(separate them with ``|``), pointer to a fact that this command
should be displayed in short help (start name with ``^``), or to
a fact that this command should be hidden (start name with ``~``)
- ``function`` is the actual callable
- ``options`` is options list in format described in docs
- ``usage`` is the short string of usage
'''
args = args or sys.argv[1:]
cmdtable = cmdtable or CMDTABLE
globaloptions = globaloptions or []
globaloptions.append(('h', 'help', False, 'display help'))
cmdtable['help'] = (help_(cmdtable, globaloptions), [], '[TOPIC]')
help_func = cmdtable['help'][0]
autocomplete(cmdtable, args)
try:
name, func, args, kwargs = catcher(
lambda: _dispatch(args, cmdtable, globaloptions),
help_func)
return catcher(
lambda: call_cmd(name, middleware(func))(*args, **kwargs),
help_func)
except Abort:
return -1
# --------
# Help
# --------
def help_(cmdtable, globalopts):
def help_inner(name=None):
'''Show help for a given help topic or a help overview
With no arguments, print a list of commands with short help messages.
Given a command name, print help for that command.
'''
def helplist():
hlp = {}
# determine if any command is marked for shortlist
shortlist = (name == 'shortlist' and
any(imap(lambda x: x.startswith('^'), cmdtable)))
for cmd, info in cmdtable.items():
if cmd.startswith('~'):
continue # do not display hidden commands
if shortlist and not cmd.startswith('^'):
continue # short help contains only marked commands
cmd = cmd.lstrip('^~')
doc = info[0].__doc__ or '(no help text available)'
hlp[cmd] = doc.splitlines()[0].rstrip()
hlplist = sorted(hlp)
maxlen = max(map(len, hlplist))
write('usage: %s <command> [options]\n' % sysname())
write('\ncommands:\n\n')
for cmd in hlplist:
doc = hlp[cmd]
if False: # verbose?
write(' %s:\n %s\n' % (cmd.replace('|', ', '), doc))
else:
write(' %-*s %s\n' % (maxlen, cmd.split('|', 1)[0],
doc))
if not cmdtable:
return err('No commands specified!\n')
if not name or name == 'shortlist':
return helplist()
aliases, (cmd, options, usage) = findcmd(name, cmdtable)
return help_cmd(cmd,
replace_name(usage, sysname() + ' ' + aliases[0]),
options + globalopts)
return help_inner
def help_cmd(func, usage, options):
'''show help for given command
- ``func``: function to generate help for (``func.__doc__`` is taken)
- ``usage``: usage string
- ``options``: options in usual format
>>> def test(*args, **opts):
... """that's a test command
...
... you can do nothing with this command"""
... pass
>>> opts = [('l', 'listen', 'localhost',
... 'ip to listen on'),
... ('p', 'port', 8000,
... 'port to listen on'),
... ('d', 'daemonize', False,
... 'daemonize process'),
... ('', 'pid-file', '',
... 'name of file to write process ID to')]
>>> help_cmd(test, 'test [-l HOST] [NAME]', opts)
test [-l HOST] [NAME]
<BLANKLINE>
that's a test command
<BLANKLINE>
you can do nothing with this command
<BLANKLINE>
options:
<BLANKLINE>
-l --listen ip to listen on (default: localhost)
-p --port port to listen on (default: 8000)
-d --daemonize daemonize process
--pid-file name of file to write process ID to
<BLANKLINE>
'''
write(usage + '\n')
doc = func.__doc__
if not doc:
doc = '(no help text available)'
write('\n' + doc.strip() + '\n\n')
if options:
write(''.join(help_options(options)))
def help_options(options):
yield 'options:\n\n'
output = []
for short, name, default, desc in options:
if hasattr(default, '__call__'):
default = default(None)
default = default and ' (default: %s)' % default or ''
output.append(('%2s%s' % (short and '-%s' % short,
name and ' --%s' % name),
'%s%s' % (desc, default)))
opts_len = max([len(first) for first, second in output if second] or [0])
for first, second in output:
if second:
# wrap description at 78 chars
second = textwrap.wrap(second, width=(78 - opts_len - 3))
pad = '\n' + ' ' * (opts_len + 3)
yield ' %-*s %s\n' % (opts_len, first, pad.join(second))
else:
yield '%s\n' % first
# --------
# Options parsing
# --------
def parse(args, options):
'''
>>> opts = [('l', 'listen', 'localhost',
... 'ip to listen on'),
... ('p', 'port', 8000,
... 'port to listen on'),
... ('d', 'daemonize', False,
... 'daemonize process'),
... ('', 'pid-file', '',
... 'name of file to write process ID to')]
>>> print parse(['-l', '0.0.0.0', '--pi', 'test', 'all'], opts)
({'pid_file': 'test', 'daemonize': False, 'port': 8000, 'listen': '0.0.0.0'}, ['all'])
'''
argmap, defmap, state = {}, {}, {}
shortlist, namelist, funlist = '', [], []
for short, name, default, comment in options:
if short and len(short) != 1:
raise FOError('Short option should be only a single'
' character: %s' % short)
if not name:
raise FOError(
'Long name should be defined for every option')
# change name to match Python styling
pyname = name.replace('-', '_')
argmap['-' + short] = argmap['--' + name] = pyname
defmap[pyname] = default
# copy defaults to state
if isinstance(default, list):
state[pyname] = default[:]
elif hasattr(default, '__call__'):
funlist.append(pyname)
state[pyname] = None
else:
state[pyname] = default
# getopt wants indication that it takes a parameter
if not (default is None or default is True or default is False):
if short: short += ':'
if name: name += '='
if short:
shortlist += short
if name:
namelist.append(name)
opts, args = getopt.gnu_getopt(args, shortlist, namelist)
# transfer result to state
for opt, val in opts:
name = argmap[opt]
t = type(defmap[name])
if t is types.FunctionType:
del funlist[funlist.index(name)]
state[name] = defmap[name](val)
elif t is types.ListType:
state[name].append(val)
elif t in (types.NoneType, types.BooleanType):
state[name] = not defmap[name]
else:
state[name] = t(val)
for name in funlist:
state[name] = defmap[name](None)
return state, args
# --------
# Subcommand system
# --------
def _dispatch(args, cmdtable, globalopts):
cmd, func, args, options = cmdparse(args, cmdtable, globalopts)
if options.pop('help', False):
return 'help', cmdtable['help'][0], [cmd], {}
elif not cmd:
return 'help', cmdtable['help'][0], ['shortlist'], {}
return cmd, func, args, options
def cmdparse(args, cmdtable, globalopts):
# command is the first non-option
cmd = None
for arg in args:
if not arg.startswith('-'):
cmd = arg
break
if cmd:
args.pop(args.index(cmd))
aliases, info = findcmd(cmd, cmdtable)
cmd = aliases[0]
possibleopts = list(info[1])
else:
possibleopts = []
possibleopts.extend(globalopts)
try:
options, args = parse(args, possibleopts)
except getopt.GetoptError, e:
raise ParseError(cmd, e)
return (cmd, cmd and info[0] or None, args, options)
def aliases_(cmdtable_key):
return cmdtable_key.lstrip("^~").split("|")
def findpossible(cmd, table):
"""
Return cmd -> (aliases, command table entry)
for each matching command.
"""
choice = {}
for e in table.keys():
aliases = aliases_(e)
found = None
if cmd in aliases:
found = cmd
else:
for a in aliases:
if a.startswith(cmd):
found = a
break
if found is not None:
choice[found] = (aliases, table[e])
return choice
def findcmd(cmd, table):
"""Return (aliases, command table entry) for command string."""
choice = findpossible(cmd, table)
if cmd in choice:
return choice[cmd]
if len(choice) > 1:
clist = choice.keys()
clist.sort()
raise AmbiguousCommand(cmd, clist)
if choice:
return choice.values()[0]
raise UnknownCommand(cmd)
# --------
# Helpers
# --------
def guess_options(func):
args, varargs, varkw, defaults = inspect.getargspec(func)
for name, option in zip(args[-len(defaults):], defaults):
try:
sname, default, hlp = option
yield (sname, name.replace('_', '-'), default, hlp)
except TypeError:
pass
def guess_usage(func, options):
usage = '%name '
if options:
usage += '[OPTIONS] '
args, varargs = inspect.getargspec(func)[:2]
argnum = len(args) - len(options)
if argnum > 0:
usage += args[0].upper()
if argnum > 1:
usage += 'S'
elif varargs:
usage += '[%s]' % varargs.upper()
return usage
def catcher(target, help_func):
'''Catches all exceptions and prints human-readable information on them
'''
try:
return target()
except UnknownCommand, e:
err("unknown command: '%s'\n" % e)
except AmbiguousCommand, e:
err("command '%s' is ambiguous:\n %s\n" %
(e.args[0], ' '.join(e.args[1])))
except ParseError, e:
err('%s: %s\n' % (e.args[0], e.args[1]))
help_func(e.args[0])
except getopt.GetoptError, e:
err('error: %s\n' % e)
help_func()
except FOError, e:
err('%s\n' % e)
except KeyboardInterrupt:
err('interrupted!\n')
except SystemExit:
raise
except:
err('unknown exception encountered')
raise
raise Abort
def call_cmd(name, func):
def inner(*args, **kwargs):
try:
return func(*args, **kwargs)
except TypeError:
if len(traceback.extract_tb(sys.exc_info()[2])) == 1:
raise ParseError(name, "invalid arguments")
raise
return inner
def call_cmd_regular(func, opts):
def inner(*args, **kwargs):
funcargs, _, varkw, defaults = inspect.getargspec(func)
if len(args) > len(funcargs):
raise TypeError('You have supplied more positional arguments'
' than applicable')
funckwargs = dict((lname.replace('-', '_'), default)
for _, lname, default, _ in opts)
if 'help' not in (defaults or ()) and not varkw:
funckwargs.pop('help', None)
funckwargs.update(kwargs)
return func(*args, **funckwargs)
return inner
def replace_name(usage, name):
if '%name' in usage:
return usage.replace('%name', name, 1)
return name + ' ' + usage
def sysname():
name = sys.argv[0]
if name.startswith('./'):
return name[2:]
return name
try:
from functools import wraps
except ImportError:
def wraps(wrapped, assigned=('__module__', '__name__', '__doc__'),
updated=('__dict__',)):
def inner(wrapper):
for attr in assigned:
setattr(wrapper, attr, getattr(wrapped, attr))
for attr in updated:
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
return wrapper
return inner
# --------
# Autocomplete system
# --------
# Borrowed from PIP
def autocomplete(cmdtable, args):
"""Command and option completion.
Enable by sourcing one of the completion shell scripts (bash or zsh).
"""
# Don't complete if user hasn't sourced bash_completion file.
if not os.environ.has_key('OPSTER_AUTO_COMPLETE'):
return
cwords = os.environ['COMP_WORDS'].split()[1:]
cword = int(os.environ['COMP_CWORD'])
try:
current = cwords[cword-1]
except IndexError:
current = ''
commands = []
for k in cmdtable.keys():
commands += aliases_(k)
# command
if cword == 1:
print ' '.join(filter(lambda x: x.startswith(current), commands))
# command options
elif cwords[0] in commands:
options = []
aliases, (cmd, opts, usage) = findcmd(cwords[0], cmdtable)
for (short, long, default, help) in opts:
options.append('-%s' % short)
options.append('--%s' % long)
options = [o for o in options if o.startswith(current)]
print ' '.join(filter(lambda x: x.startswith(current), options))
sys.exit(1)
COMPLETIONS = {
'bash':
"""
# opster bash completion start
_opster_completion()
{
COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\
COMP_CWORD=$COMP_CWORD \\
OPSTER_AUTO_COMPLETE=1 $1 ) )
}
complete -o default -F _opster_completion %s
# opster bash completion end
""",
'zsh':
"""
# opster zsh completion start
function _opster_completion {
local words cword
read -Ac words
read -cn cword
reply=( $( COMP_WORDS="$words[*]" \\
COMP_CWORD=$(( cword-1 )) \\
OPSTER_AUTO_COMPLETE=1 $words[1] ) )
}
compctl -K _opster_completion %s
# opster zsh completion end
"""
}
@command(name='_completion', hide=True)
def completion(type=('t', 'bash', 'Completion type (bash or zsh)')):
"""Outputs completion script for bash or zsh."""
prog_name = os.path.split(sys.argv[0])[1]
print COMPLETIONS[type] % prog_name
# --------
# Exceptions
# --------
# Command exceptions
class CommandException(Exception):
'Base class for command exceptions'
class AmbiguousCommand(CommandException):
'Raised if command is ambiguous'
class UnknownCommand(CommandException):
'Raised if command is unknown'
class ParseError(CommandException):
'Raised on error in command line parsing'
class Abort(CommandException):
'Abort execution'
class FOError(CommandException):
'Raised on trouble with opster configuration'
-437
View File
@@ -1,437 +0,0 @@
r"""JSON (JavaScript Object Notation) <http://json.org> is a subset of
JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
interchange format.
:mod:`simplejson` exposes an API familiar to users of the standard library
:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained
version of the :mod:`json` library contained in Python 2.6, but maintains
compatibility with Python 2.4 and Python 2.5 and (currently) has
significant performance advantages, even without using the optional C
extension for speedups.
Encoding basic Python object hierarchies::
>>> import simplejson as json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print json.dumps("\"foo\bar")
"\"foo\bar"
>>> print json.dumps(u'\u1234')
"\u1234"
>>> print json.dumps('\\')
"\\"
>>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
{"a": 0, "b": 0, "c": 0}
>>> from StringIO import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'
Compact encoding::
>>> import simplejson as json
>>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
'[1,2,3,{"4":5,"6":7}]'
Pretty printing::
>>> import simplejson as json
>>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ')
>>> print '\n'.join([l.rstrip() for l in s.splitlines()])
{
"4": 5,
"6": 7
}
Decoding JSON::
>>> import simplejson as json
>>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj
True
>>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar'
True
>>> from StringIO import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)[0] == 'streaming API'
True
Specializing JSON object decoding::
>>> import simplejson as json
>>> def as_complex(dct):
... if '__complex__' in dct:
... return complex(dct['real'], dct['imag'])
... return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
... object_hook=as_complex)
(1+2j)
>>> from decimal import Decimal
>>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1')
True
Specializing JSON object encoding::
>>> import simplejson as json
>>> def encode_complex(obj):
... if isinstance(obj, complex):
... return [obj.real, obj.imag]
... raise TypeError(repr(o) + " is not JSON serializable")
...
>>> json.dumps(2 + 1j, default=encode_complex)
'[2.0, 1.0]'
>>> json.JSONEncoder(default=encode_complex).encode(2 + 1j)
'[2.0, 1.0]'
>>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j))
'[2.0, 1.0]'
Using simplejson.tool from the shell to validate and pretty-print::
$ echo '{"json":"obj"}' | python -m simplejson.tool
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m simplejson.tool
Expecting property name: line 1 column 2 (char 2)
"""
__version__ = '2.1.1'
__all__ = [
'dump', 'dumps', 'load', 'loads',
'JSONDecoder', 'JSONDecodeError', 'JSONEncoder',
'OrderedDict',
]
__author__ = 'Bob Ippolito <bob@redivi.com>'
from decimal import Decimal
from decoder import JSONDecoder, JSONDecodeError
from encoder import JSONEncoder
def _import_OrderedDict():
import collections
try:
return collections.OrderedDict
except AttributeError:
import ordered_dict
return ordered_dict.OrderedDict
OrderedDict = _import_OrderedDict()
def _import_c_make_encoder():
try:
from simplejson._speedups import make_encoder
return make_encoder
except ImportError:
return None
_default_encoder = JSONEncoder(
skipkeys=False,
ensure_ascii=True,
check_circular=True,
allow_nan=True,
indent=None,
separators=None,
encoding='utf-8',
default=None,
use_decimal=False,
)
def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=False, **kw):
"""Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
``.write()``-supporting file-like object).
If ``skipkeys`` is true then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
If ``ensure_ascii`` is false, then the some chunks written to ``fp``
may be ``unicode`` instances, subject to normal Python ``str`` to
``unicode`` coercion rules. Unless ``fp.write()`` explicitly
understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
to cause an error.
If ``check_circular`` is false, then the circular reference check
for container types will be skipped and a circular reference will
result in an ``OverflowError`` (or worse).
If ``allow_nan`` is false, then it will be a ``ValueError`` to
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
in strict compliance of the JSON specification, instead of using the
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
If *indent* is a string, then JSON array elements and object members
will be pretty-printed with a newline followed by that string repeated
for each level of nesting. ``None`` (the default) selects the most compact
representation without any newlines. For backwards compatibility with
versions of simplejson earlier than 2.1.0, an integer is also accepted
and is converted to a string with that many spaces.
If ``separators`` is an ``(item_separator, dict_separator)`` tuple
then it will be used instead of the default ``(', ', ': ')`` separators.
``(',', ':')`` is the most compact JSON representation.
``encoding`` is the character encoding for str instances, default is UTF-8.
``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
If *use_decimal* is true (default: ``False``) then decimal.Decimal
will be natively serialized to JSON with full precision.
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg.
"""
# cached encoder
if (not skipkeys and ensure_ascii and
check_circular and allow_nan and
cls is None and indent is None and separators is None and
encoding == 'utf-8' and default is None and not kw):
iterable = _default_encoder.iterencode(obj)
else:
if cls is None:
cls = JSONEncoder
iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, encoding=encoding,
default=default, use_decimal=use_decimal, **kw).iterencode(obj)
# could accelerate with writelines in some versions of Python, at
# a debuggability cost
for chunk in iterable:
fp.write(chunk)
def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
allow_nan=True, cls=None, indent=None, separators=None,
encoding='utf-8', default=None, use_decimal=False, **kw):
"""Serialize ``obj`` to a JSON formatted ``str``.
If ``skipkeys`` is false then ``dict`` keys that are not basic types
(``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
will be skipped instead of raising a ``TypeError``.
If ``ensure_ascii`` is false, then the return value will be a
``unicode`` instance subject to normal Python ``str`` to ``unicode``
coercion rules instead of being escaped to an ASCII ``str``.
If ``check_circular`` is false, then the circular reference check
for container types will be skipped and a circular reference will
result in an ``OverflowError`` (or worse).
If ``allow_nan`` is false, then it will be a ``ValueError`` to
serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
strict compliance of the JSON specification, instead of using the
JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
If ``indent`` is a string, then JSON array elements and object members
will be pretty-printed with a newline followed by that string repeated
for each level of nesting. ``None`` (the default) selects the most compact
representation without any newlines. For backwards compatibility with
versions of simplejson earlier than 2.1.0, an integer is also accepted
and is converted to a string with that many spaces.
If ``separators`` is an ``(item_separator, dict_separator)`` tuple
then it will be used instead of the default ``(', ', ': ')`` separators.
``(',', ':')`` is the most compact JSON representation.
``encoding`` is the character encoding for str instances, default is UTF-8.
``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
If *use_decimal* is true (default: ``False``) then decimal.Decimal
will be natively serialized to JSON with full precision.
To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
``.default()`` method to serialize additional types), specify it with
the ``cls`` kwarg.
"""
# cached encoder
if (not skipkeys and ensure_ascii and
check_circular and allow_nan and
cls is None and indent is None and separators is None and
encoding == 'utf-8' and default is None and not use_decimal
and not kw):
return _default_encoder.encode(obj)
if cls is None:
cls = JSONEncoder
return cls(
skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, encoding=encoding, default=default,
use_decimal=use_decimal, **kw).encode(obj)
_default_decoder = JSONDecoder(encoding=None, object_hook=None,
object_pairs_hook=None)
def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None,
use_decimal=False, **kw):
"""Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
a JSON document) to a Python object.
*encoding* determines the encoding used to interpret any
:class:`str` objects decoded by this instance (``'utf-8'`` by
default). It has no effect when decoding :class:`unicode` objects.
Note that currently only encodings that are a superset of ASCII work,
strings of other encodings should be passed in as :class:`unicode`.
*object_hook*, if specified, will be called with the result of every
JSON object decoded and its return value will be used in place of the
given :class:`dict`. This can be used to provide custom
deserializations (e.g. to support JSON-RPC class hinting).
*object_pairs_hook* is an optional function that will be called with
the result of any object literal decode with an ordered list of pairs.
The return value of *object_pairs_hook* will be used instead of the
:class:`dict`. This feature can be used to implement custom decoders
that rely on the order that the key and value pairs are decoded (for
example, :func:`collections.OrderedDict` will remember the order of
insertion). If *object_hook* is also defined, the *object_pairs_hook*
takes priority.
*parse_float*, if specified, will be called with the string of every
JSON float to be decoded. By default, this is equivalent to
``float(num_str)``. This can be used to use another datatype or parser
for JSON floats (e.g. :class:`decimal.Decimal`).
*parse_int*, if specified, will be called with the string of every
JSON int to be decoded. By default, this is equivalent to
``int(num_str)``. This can be used to use another datatype or parser
for JSON integers (e.g. :class:`float`).
*parse_constant*, if specified, will be called with one of the
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This
can be used to raise an exception if invalid JSON numbers are
encountered.
If *use_decimal* is true (default: ``False``) then it implies
parse_float=decimal.Decimal for parity with ``dump``.
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
kwarg.
"""
return loads(fp.read(),
encoding=encoding, cls=cls, object_hook=object_hook,
parse_float=parse_float, parse_int=parse_int,
parse_constant=parse_constant, object_pairs_hook=object_pairs_hook,
use_decimal=use_decimal, **kw)
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None,
use_decimal=False, **kw):
"""Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
document) to a Python object.
*encoding* determines the encoding used to interpret any
:class:`str` objects decoded by this instance (``'utf-8'`` by
default). It has no effect when decoding :class:`unicode` objects.
Note that currently only encodings that are a superset of ASCII work,
strings of other encodings should be passed in as :class:`unicode`.
*object_hook*, if specified, will be called with the result of every
JSON object decoded and its return value will be used in place of the
given :class:`dict`. This can be used to provide custom
deserializations (e.g. to support JSON-RPC class hinting).
*object_pairs_hook* is an optional function that will be called with
the result of any object literal decode with an ordered list of pairs.
The return value of *object_pairs_hook* will be used instead of the
:class:`dict`. This feature can be used to implement custom decoders
that rely on the order that the key and value pairs are decoded (for
example, :func:`collections.OrderedDict` will remember the order of
insertion). If *object_hook* is also defined, the *object_pairs_hook*
takes priority.
*parse_float*, if specified, will be called with the string of every
JSON float to be decoded. By default, this is equivalent to
``float(num_str)``. This can be used to use another datatype or parser
for JSON floats (e.g. :class:`decimal.Decimal`).
*parse_int*, if specified, will be called with the string of every
JSON int to be decoded. By default, this is equivalent to
``int(num_str)``. This can be used to use another datatype or parser
for JSON integers (e.g. :class:`float`).
*parse_constant*, if specified, will be called with one of the
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This
can be used to raise an exception if invalid JSON numbers are
encountered.
If *use_decimal* is true (default: ``False``) then it implies
parse_float=decimal.Decimal for parity with ``dump``.
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
kwarg.
"""
if (cls is None and encoding is None and object_hook is None and
parse_int is None and parse_float is None and
parse_constant is None and object_pairs_hook is None
and not use_decimal and not kw):
return _default_decoder.decode(s)
if cls is None:
cls = JSONDecoder
if object_hook is not None:
kw['object_hook'] = object_hook
if object_pairs_hook is not None:
kw['object_pairs_hook'] = object_pairs_hook
if parse_float is not None:
kw['parse_float'] = parse_float
if parse_int is not None:
kw['parse_int'] = parse_int
if parse_constant is not None:
kw['parse_constant'] = parse_constant
if use_decimal:
if parse_float is not None:
raise TypeError("use_decimal=True implies parse_float=Decimal")
kw['parse_float'] = Decimal
return cls(encoding=encoding, **kw).decode(s)
def _toggle_speedups(enabled):
import simplejson.decoder as dec
import simplejson.encoder as enc
import simplejson.scanner as scan
c_make_encoder = _import_c_make_encoder()
if enabled:
dec.scanstring = dec.c_scanstring or dec.py_scanstring
enc.c_make_encoder = c_make_encoder
enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or
enc.py_encode_basestring_ascii)
scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner
else:
dec.scanstring = dec.py_scanstring
enc.c_make_encoder = None
enc.encode_basestring_ascii = enc.py_encode_basestring_ascii
scan.make_scanner = scan.py_make_scanner
dec.make_scanner = scan.make_scanner
global _default_decoder
_default_decoder = JSONDecoder(
encoding=None,
object_hook=None,
object_pairs_hook=None,
)
global _default_encoder
_default_encoder = JSONEncoder(
skipkeys=False,
ensure_ascii=True,
check_circular=True,
allow_nan=True,
indent=None,
separators=None,
encoding='utf-8',
default=None,
)
File diff suppressed because it is too large Load Diff
-421
View File
@@ -1,421 +0,0 @@
"""Implementation of JSONDecoder
"""
import re
import sys
import struct
from simplejson.scanner import make_scanner
def _import_c_scanstring():
try:
from simplejson._speedups import scanstring
return scanstring
except ImportError:
return None
c_scanstring = _import_c_scanstring()
__all__ = ['JSONDecoder']
FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
def _floatconstants():
_BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
# The struct module in Python 2.4 would get frexp() out of range here
# when an endian is specified in the format string. Fixed in Python 2.5+
if sys.byteorder != 'big':
_BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
nan, inf = struct.unpack('dd', _BYTES)
return nan, inf, -inf
NaN, PosInf, NegInf = _floatconstants()
class JSONDecodeError(ValueError):
"""Subclass of ValueError with the following additional properties:
msg: The unformatted error message
doc: The JSON document being parsed
pos: The start index of doc where parsing failed
end: The end index of doc where parsing failed (may be None)
lineno: The line corresponding to pos
colno: The column corresponding to pos
endlineno: The line corresponding to end (may be None)
endcolno: The column corresponding to end (may be None)
"""
def __init__(self, msg, doc, pos, end=None):
ValueError.__init__(self, errmsg(msg, doc, pos, end=end))
self.msg = msg
self.doc = doc
self.pos = pos
self.end = end
self.lineno, self.colno = linecol(doc, pos)
if end is not None:
self.endlineno, self.endcolno = linecol(doc, pos)
else:
self.endlineno, self.endcolno = None, None
def linecol(doc, pos):
lineno = doc.count('\n', 0, pos) + 1
if lineno == 1:
colno = pos
else:
colno = pos - doc.rindex('\n', 0, pos)
return lineno, colno
def errmsg(msg, doc, pos, end=None):
# Note that this function is called from _speedups
lineno, colno = linecol(doc, pos)
if end is None:
#fmt = '{0}: line {1} column {2} (char {3})'
#return fmt.format(msg, lineno, colno, pos)
fmt = '%s: line %d column %d (char %d)'
return fmt % (msg, lineno, colno, pos)
endlineno, endcolno = linecol(doc, end)
#fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})'
#return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end)
fmt = '%s: line %d column %d - line %d column %d (char %d - %d)'
return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end)
_CONSTANTS = {
'-Infinity': NegInf,
'Infinity': PosInf,
'NaN': NaN,
}
STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS)
BACKSLASH = {
'"': u'"', '\\': u'\\', '/': u'/',
'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t',
}
DEFAULT_ENCODING = "utf-8"
def py_scanstring(s, end, encoding=None, strict=True,
_b=BACKSLASH, _m=STRINGCHUNK.match):
"""Scan the string s for a JSON string. End is the index of the
character in s after the quote that started the JSON string.
Unescapes all valid JSON string escape sequences and raises ValueError
on attempt to decode an invalid string. If strict is False then literal
control characters are allowed in the string.
Returns a tuple of the decoded string and the index of the character in s
after the end quote."""
if encoding is None:
encoding = DEFAULT_ENCODING
chunks = []
_append = chunks.append
begin = end - 1
while 1:
chunk = _m(s, end)
if chunk is None:
raise JSONDecodeError(
"Unterminated string starting at", s, begin)
end = chunk.end()
content, terminator = chunk.groups()
# Content is contains zero or more unescaped string characters
if content:
if not isinstance(content, unicode):
content = unicode(content, encoding)
_append(content)
# Terminator is the end of string, a literal control character,
# or a backslash denoting that an escape sequence follows
if terminator == '"':
break
elif terminator != '\\':
if strict:
msg = "Invalid control character %r at" % (terminator,)
#msg = "Invalid control character {0!r} at".format(terminator)
raise JSONDecodeError(msg, s, end)
else:
_append(terminator)
continue
try:
esc = s[end]
except IndexError:
raise JSONDecodeError(
"Unterminated string starting at", s, begin)
# If not a unicode escape sequence, must be in the lookup table
if esc != 'u':
try:
char = _b[esc]
except KeyError:
msg = "Invalid \\escape: " + repr(esc)
raise JSONDecodeError(msg, s, end)
end += 1
else:
# Unicode escape sequence
esc = s[end + 1:end + 5]
next_end = end + 5
if len(esc) != 4:
msg = "Invalid \\uXXXX escape"
raise JSONDecodeError(msg, s, end)
uni = int(esc, 16)
# Check for surrogate pair on UCS-4 systems
if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535:
msg = "Invalid \\uXXXX\\uXXXX surrogate pair"
if not s[end + 5:end + 7] == '\\u':
raise JSONDecodeError(msg, s, end)
esc2 = s[end + 7:end + 11]
if len(esc2) != 4:
raise JSONDecodeError(msg, s, end)
uni2 = int(esc2, 16)
uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00))
next_end += 6
char = unichr(uni)
end = next_end
# Append the unescaped character
_append(char)
return u''.join(chunks), end
# Use speedup if available
scanstring = c_scanstring or py_scanstring
WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS)
WHITESPACE_STR = ' \t\n\r'
def JSONObject((s, end), encoding, strict, scan_once, object_hook,
object_pairs_hook, memo=None,
_w=WHITESPACE.match, _ws=WHITESPACE_STR):
# Backwards compatibility
if memo is None:
memo = {}
memo_get = memo.setdefault
pairs = []
# Use a slice to prevent IndexError from being raised, the following
# check will raise a more specific ValueError if the string is empty
nextchar = s[end:end + 1]
# Normally we expect nextchar == '"'
if nextchar != '"':
if nextchar in _ws:
end = _w(s, end).end()
nextchar = s[end:end + 1]
# Trivial empty object
if nextchar == '}':
if object_pairs_hook is not None:
result = object_pairs_hook(pairs)
return result, end
pairs = {}
if object_hook is not None:
pairs = object_hook(pairs)
return pairs, end + 1
elif nextchar != '"':
raise JSONDecodeError("Expecting property name", s, end)
end += 1
while True:
key, end = scanstring(s, end, encoding, strict)
key = memo_get(key, key)
# To skip some function call overhead we optimize the fast paths where
# the JSON key separator is ": " or just ":".
if s[end:end + 1] != ':':
end = _w(s, end).end()
if s[end:end + 1] != ':':
raise JSONDecodeError("Expecting : delimiter", s, end)
end += 1
try:
if s[end] in _ws:
end += 1
if s[end] in _ws:
end = _w(s, end + 1).end()
except IndexError:
pass
try:
value, end = scan_once(s, end)
except StopIteration:
raise JSONDecodeError("Expecting object", s, end)
pairs.append((key, value))
try:
nextchar = s[end]
if nextchar in _ws:
end = _w(s, end + 1).end()
nextchar = s[end]
except IndexError:
nextchar = ''
end += 1
if nextchar == '}':
break
elif nextchar != ',':
raise JSONDecodeError("Expecting , delimiter", s, end - 1)
try:
nextchar = s[end]
if nextchar in _ws:
end += 1
nextchar = s[end]
if nextchar in _ws:
end = _w(s, end + 1).end()
nextchar = s[end]
except IndexError:
nextchar = ''
end += 1
if nextchar != '"':
raise JSONDecodeError("Expecting property name", s, end - 1)
if object_pairs_hook is not None:
result = object_pairs_hook(pairs)
return result, end
pairs = dict(pairs)
if object_hook is not None:
pairs = object_hook(pairs)
return pairs, end
def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
values = []
nextchar = s[end:end + 1]
if nextchar in _ws:
end = _w(s, end + 1).end()
nextchar = s[end:end + 1]
# Look-ahead for trivial empty array
if nextchar == ']':
return values, end + 1
_append = values.append
while True:
try:
value, end = scan_once(s, end)
except StopIteration:
raise JSONDecodeError("Expecting object", s, end)
_append(value)
nextchar = s[end:end + 1]
if nextchar in _ws:
end = _w(s, end + 1).end()
nextchar = s[end:end + 1]
end += 1
if nextchar == ']':
break
elif nextchar != ',':
raise JSONDecodeError("Expecting , delimiter", s, end)
try:
if s[end] in _ws:
end += 1
if s[end] in _ws:
end = _w(s, end + 1).end()
except IndexError:
pass
return values, end
class JSONDecoder(object):
"""Simple JSON <http://json.org> decoder
Performs the following translations in decoding by default:
+---------------+-------------------+
| JSON | Python |
+===============+===================+
| object | dict |
+---------------+-------------------+
| array | list |
+---------------+-------------------+
| string | unicode |
+---------------+-------------------+
| number (int) | int, long |
+---------------+-------------------+
| number (real) | float |
+---------------+-------------------+
| true | True |
+---------------+-------------------+
| false | False |
+---------------+-------------------+
| null | None |
+---------------+-------------------+
It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
their corresponding ``float`` values, which is outside the JSON spec.
"""
def __init__(self, encoding=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, strict=True,
object_pairs_hook=None):
"""
*encoding* determines the encoding used to interpret any
:class:`str` objects decoded by this instance (``'utf-8'`` by
default). It has no effect when decoding :class:`unicode` objects.
Note that currently only encodings that are a superset of ASCII work,
strings of other encodings should be passed in as :class:`unicode`.
*object_hook*, if specified, will be called with the result of every
JSON object decoded and its return value will be used in place of the
given :class:`dict`. This can be used to provide custom
deserializations (e.g. to support JSON-RPC class hinting).
*object_pairs_hook* is an optional function that will be called with
the result of any object literal decode with an ordered list of pairs.
The return value of *object_pairs_hook* will be used instead of the
:class:`dict`. This feature can be used to implement custom decoders
that rely on the order that the key and value pairs are decoded (for
example, :func:`collections.OrderedDict` will remember the order of
insertion). If *object_hook* is also defined, the *object_pairs_hook*
takes priority.
*parse_float*, if specified, will be called with the string of every
JSON float to be decoded. By default, this is equivalent to
``float(num_str)``. This can be used to use another datatype or parser
for JSON floats (e.g. :class:`decimal.Decimal`).
*parse_int*, if specified, will be called with the string of every
JSON int to be decoded. By default, this is equivalent to
``int(num_str)``. This can be used to use another datatype or parser
for JSON integers (e.g. :class:`float`).
*parse_constant*, if specified, will be called with one of the
following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This
can be used to raise an exception if invalid JSON numbers are
encountered.
*strict* controls the parser's behavior when it encounters an
invalid control character in a string. The default setting of
``True`` means that unescaped control characters are parse errors, if
``False`` then control characters will be allowed in strings.
"""
self.encoding = encoding
self.object_hook = object_hook
self.object_pairs_hook = object_pairs_hook
self.parse_float = parse_float or float
self.parse_int = parse_int or int
self.parse_constant = parse_constant or _CONSTANTS.__getitem__
self.strict = strict
self.parse_object = JSONObject
self.parse_array = JSONArray
self.parse_string = scanstring
self.memo = {}
self.scan_once = make_scanner(self)
def decode(self, s, _w=WHITESPACE.match):
"""Return the Python representation of ``s`` (a ``str`` or ``unicode``
instance containing a JSON document)
"""
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
end = _w(s, end).end()
if end != len(s):
raise JSONDecodeError("Extra data", s, end, len(s))
return obj
def raw_decode(self, s, idx=0):
"""Decode a JSON document from ``s`` (a ``str`` or ``unicode``
beginning with a JSON document) and return a 2-tuple of the Python
representation and the index in ``s`` where the document ended.
This can be used to decode a JSON document from a string that may
have extraneous data at the end.
"""
try:
obj, end = self.scan_once(s, idx)
except StopIteration:
raise JSONDecodeError("No JSON object could be decoded", s, idx)
return obj, end
-501
View File
@@ -1,501 +0,0 @@
"""Implementation of JSONEncoder
"""
import re
from decimal import Decimal
def _import_speedups():
try:
from simplejson import _speedups
return _speedups.encode_basestring_ascii, _speedups.make_encoder
except ImportError:
return None, None
c_encode_basestring_ascii, c_make_encoder = _import_speedups()
from simplejson.decoder import PosInf
ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
HAS_UTF8 = re.compile(r'[\x80-\xff]')
ESCAPE_DCT = {
'\\': '\\\\',
'"': '\\"',
'\b': '\\b',
'\f': '\\f',
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
}
for i in range(0x20):
#ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
FLOAT_REPR = repr
def encode_basestring(s):
"""Return a JSON representation of a Python string
"""
if isinstance(s, str) and HAS_UTF8.search(s) is not None:
s = s.decode('utf-8')
def replace(match):
return ESCAPE_DCT[match.group(0)]
return u'"' + ESCAPE.sub(replace, s) + u'"'
def py_encode_basestring_ascii(s):
"""Return an ASCII-only JSON representation of a Python string
"""
if isinstance(s, str) and HAS_UTF8.search(s) is not None:
s = s.decode('utf-8')
def replace(match):
s = match.group(0)
try:
return ESCAPE_DCT[s]
except KeyError:
n = ord(s)
if n < 0x10000:
#return '\\u{0:04x}'.format(n)
return '\\u%04x' % (n,)
else:
# surrogate pair
n -= 0x10000
s1 = 0xd800 | ((n >> 10) & 0x3ff)
s2 = 0xdc00 | (n & 0x3ff)
#return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
return '\\u%04x\\u%04x' % (s1, s2)
return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
encode_basestring_ascii = (
c_encode_basestring_ascii or py_encode_basestring_ascii)
class JSONEncoder(object):
"""Extensible JSON <http://json.org> encoder for Python data structures.
Supports the following objects and types by default:
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str, unicode | string |
+-------------------+---------------+
| int, long, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
To extend this to recognize other objects, subclass and implement a
``.default()`` method with another method that returns a serializable
object for ``o`` if possible, otherwise it should call the superclass
implementation (to raise ``TypeError``).
"""
item_separator = ', '
key_separator = ': '
def __init__(self, skipkeys=False, ensure_ascii=True,
check_circular=True, allow_nan=True, sort_keys=False,
indent=None, separators=None, encoding='utf-8', default=None,
use_decimal=False):
"""Constructor for JSONEncoder, with sensible defaults.
If skipkeys is false, then it is a TypeError to attempt
encoding of keys that are not str, int, long, float or None. If
skipkeys is True, such items are simply skipped.
If ensure_ascii is true, the output is guaranteed to be str
objects with all incoming unicode characters escaped. If
ensure_ascii is false, the output will be unicode object.
If check_circular is true, then lists, dicts, and custom encoded
objects will be checked for circular references during encoding to
prevent an infinite recursion (which would cause an OverflowError).
Otherwise, no such check takes place.
If allow_nan is true, then NaN, Infinity, and -Infinity will be
encoded as such. This behavior is not JSON specification compliant,
but is consistent with most JavaScript based encoders and decoders.
Otherwise, it will be a ValueError to encode such floats.
If sort_keys is true, then the output of dictionaries will be
sorted by key; this is useful for regression tests to ensure
that JSON serializations can be compared on a day-to-day basis.
If indent is a string, then JSON array elements and object members
will be pretty-printed with a newline followed by that string repeated
for each level of nesting. ``None`` (the default) selects the most compact
representation without any newlines. For backwards compatibility with
versions of simplejson earlier than 2.1.0, an integer is also accepted
and is converted to a string with that many spaces.
If specified, separators should be a (item_separator, key_separator)
tuple. The default is (', ', ': '). To get the most compact JSON
representation you should specify (',', ':') to eliminate whitespace.
If specified, default is a function that gets called for objects
that can't otherwise be serialized. It should return a JSON encodable
version of the object or raise a ``TypeError``.
If encoding is not None, then all input strings will be
transformed into unicode using that encoding prior to JSON-encoding.
The default is UTF-8.
If use_decimal is true (not the default), ``decimal.Decimal`` will
be supported directly by the encoder. For the inverse, decode JSON
with ``parse_float=decimal.Decimal``.
"""
self.skipkeys = skipkeys
self.ensure_ascii = ensure_ascii
self.check_circular = check_circular
self.allow_nan = allow_nan
self.sort_keys = sort_keys
self.use_decimal = use_decimal
if isinstance(indent, (int, long)):
indent = ' ' * indent
self.indent = indent
if separators is not None:
self.item_separator, self.key_separator = separators
if default is not None:
self.default = default
self.encoding = encoding
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
return JSONEncoder.default(self, o)
"""
raise TypeError(repr(o) + " is not JSON serializable")
def encode(self, o):
"""Return a JSON string representation of a Python data structure.
>>> from simplejson import JSONEncoder
>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
'{"foo": ["bar", "baz"]}'
"""
# This is for extremely simple cases and benchmarks.
if isinstance(o, basestring):
if isinstance(o, str):
_encoding = self.encoding
if (_encoding is not None
and not (_encoding == 'utf-8')):
o = o.decode(_encoding)
if self.ensure_ascii:
return encode_basestring_ascii(o)
else:
return encode_basestring(o)
# This doesn't pass the iterator directly to ''.join() because the
# exceptions aren't as detailed. The list call should be roughly
# equivalent to the PySequence_Fast that ''.join() would do.
chunks = self.iterencode(o, _one_shot=True)
if not isinstance(chunks, (list, tuple)):
chunks = list(chunks)
if self.ensure_ascii:
return ''.join(chunks)
else:
return u''.join(chunks)
def iterencode(self, o, _one_shot=False):
"""Encode the given object and yield each string
representation as available.
For example::
for chunk in JSONEncoder().iterencode(bigobject):
mysocket.write(chunk)
"""
if self.check_circular:
markers = {}
else:
markers = None
if self.ensure_ascii:
_encoder = encode_basestring_ascii
else:
_encoder = encode_basestring
if self.encoding != 'utf-8':
def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
if isinstance(o, str):
o = o.decode(_encoding)
return _orig_encoder(o)
def floatstr(o, allow_nan=self.allow_nan,
_repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf):
# Check for specials. Note that this type of test is processor
# and/or platform-specific, so do tests which don't depend on
# the internals.
if o != o:
text = 'NaN'
elif o == _inf:
text = 'Infinity'
elif o == _neginf:
text = '-Infinity'
else:
return _repr(o)
if not allow_nan:
raise ValueError(
"Out of range float values are not JSON compliant: " +
repr(o))
return text
key_memo = {}
if (_one_shot and c_make_encoder is not None
and not self.indent and not self.sort_keys):
_iterencode = c_make_encoder(
markers, self.default, _encoder, self.indent,
self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, self.allow_nan, key_memo, self.use_decimal)
else:
_iterencode = _make_iterencode(
markers, self.default, _encoder, self.indent, floatstr,
self.key_separator, self.item_separator, self.sort_keys,
self.skipkeys, _one_shot, self.use_decimal)
try:
return _iterencode(o, 0)
finally:
key_memo.clear()
class JSONEncoderForHTML(JSONEncoder):
"""An encoder that produces JSON safe to embed in HTML.
To embed JSON content in, say, a script tag on a web page, the
characters &, < and > should be escaped. They cannot be escaped
with the usual entities (e.g. &amp;) because they are not expanded
within <script> tags.
"""
def encode(self, o):
# Override JSONEncoder.encode because it has hacks for
# performance that make things more complicated.
chunks = self.iterencode(o, True)
if self.ensure_ascii:
return ''.join(chunks)
else:
return u''.join(chunks)
def iterencode(self, o, _one_shot=False):
chunks = super(JSONEncoderForHTML, self).iterencode(o, _one_shot)
for chunk in chunks:
chunk = chunk.replace('&', '\\u0026')
chunk = chunk.replace('<', '\\u003c')
chunk = chunk.replace('>', '\\u003e')
yield chunk
def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
_key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
_use_decimal,
## HACK: hand-optimized bytecode; turn globals into locals
False=False,
True=True,
ValueError=ValueError,
basestring=basestring,
Decimal=Decimal,
dict=dict,
float=float,
id=id,
int=int,
isinstance=isinstance,
list=list,
long=long,
str=str,
tuple=tuple,
):
def _iterencode_list(lst, _current_indent_level):
if not lst:
yield '[]'
return
if markers is not None:
markerid = id(lst)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = lst
buf = '['
if _indent is not None:
_current_indent_level += 1
newline_indent = '\n' + (_indent * _current_indent_level)
separator = _item_separator + newline_indent
buf += newline_indent
else:
newline_indent = None
separator = _item_separator
first = True
for value in lst:
if first:
first = False
else:
buf = separator
if isinstance(value, basestring):
yield buf + _encoder(value)
elif value is None:
yield buf + 'null'
elif value is True:
yield buf + 'true'
elif value is False:
yield buf + 'false'
elif isinstance(value, (int, long)):
yield buf + str(value)
elif isinstance(value, float):
yield buf + _floatstr(value)
elif _use_decimal and isinstance(value, Decimal):
yield buf + str(value)
else:
yield buf
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
else:
chunks = _iterencode(value, _current_indent_level)
for chunk in chunks:
yield chunk
if newline_indent is not None:
_current_indent_level -= 1
yield '\n' + (_indent * _current_indent_level)
yield ']'
if markers is not None:
del markers[markerid]
def _iterencode_dict(dct, _current_indent_level):
if not dct:
yield '{}'
return
if markers is not None:
markerid = id(dct)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = dct
yield '{'
if _indent is not None:
_current_indent_level += 1
newline_indent = '\n' + (_indent * _current_indent_level)
item_separator = _item_separator + newline_indent
yield newline_indent
else:
newline_indent = None
item_separator = _item_separator
first = True
if _sort_keys:
items = dct.items()
items.sort(key=lambda kv: kv[0])
else:
items = dct.iteritems()
for key, value in items:
if isinstance(key, basestring):
pass
# JavaScript is weakly typed for these, so it makes sense to
# also allow them. Many encoders seem to do something like this.
elif isinstance(key, float):
key = _floatstr(key)
elif key is True:
key = 'true'
elif key is False:
key = 'false'
elif key is None:
key = 'null'
elif isinstance(key, (int, long)):
key = str(key)
elif _skipkeys:
continue
else:
raise TypeError("key " + repr(key) + " is not a string")
if first:
first = False
else:
yield item_separator
yield _encoder(key)
yield _key_separator
if isinstance(value, basestring):
yield _encoder(value)
elif value is None:
yield 'null'
elif value is True:
yield 'true'
elif value is False:
yield 'false'
elif isinstance(value, (int, long)):
yield str(value)
elif isinstance(value, float):
yield _floatstr(value)
elif _use_decimal and isinstance(value, Decimal):
yield str(value)
else:
if isinstance(value, (list, tuple)):
chunks = _iterencode_list(value, _current_indent_level)
elif isinstance(value, dict):
chunks = _iterencode_dict(value, _current_indent_level)
else:
chunks = _iterencode(value, _current_indent_level)
for chunk in chunks:
yield chunk
if newline_indent is not None:
_current_indent_level -= 1
yield '\n' + (_indent * _current_indent_level)
yield '}'
if markers is not None:
del markers[markerid]
def _iterencode(o, _current_indent_level):
if isinstance(o, basestring):
yield _encoder(o)
elif o is None:
yield 'null'
elif o is True:
yield 'true'
elif o is False:
yield 'false'
elif isinstance(o, (int, long)):
yield str(o)
elif isinstance(o, float):
yield _floatstr(o)
elif isinstance(o, (list, tuple)):
for chunk in _iterencode_list(o, _current_indent_level):
yield chunk
elif isinstance(o, dict):
for chunk in _iterencode_dict(o, _current_indent_level):
yield chunk
elif _use_decimal and isinstance(o, Decimal):
yield str(o)
else:
if markers is not None:
markerid = id(o)
if markerid in markers:
raise ValueError("Circular reference detected")
markers[markerid] = o
o = _default(o)
for chunk in _iterencode(o, _current_indent_level):
yield chunk
if markers is not None:
del markers[markerid]
return _iterencode
-119
View File
@@ -1,119 +0,0 @@
"""Drop-in replacement for collections.OrderedDict by Raymond Hettinger
http://code.activestate.com/recipes/576693/
"""
from UserDict import DictMixin
# Modified from original to support Python 2.4, see
# http://code.google.com/p/simplejson/issues/detail?id=53
try:
all
except NameError:
def all(seq):
for elem in seq:
if not elem:
return False
return True
class OrderedDict(dict, DictMixin):
def __init__(self, *args, **kwds):
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__end
except AttributeError:
self.clear()
self.update(*args, **kwds)
def clear(self):
self.__end = end = []
end += [None, end, end] # sentinel node for doubly linked list
self.__map = {} # key --> [key, prev, next]
dict.clear(self)
def __setitem__(self, key, value):
if key not in self:
end = self.__end
curr = end[1]
curr[2] = end[1] = self.__map[key] = [key, curr, end]
dict.__setitem__(self, key, value)
def __delitem__(self, key):
dict.__delitem__(self, key)
key, prev, next = self.__map.pop(key)
prev[2] = next
next[1] = prev
def __iter__(self):
end = self.__end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]
def __reversed__(self):
end = self.__end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]
def popitem(self, last=True):
if not self:
raise KeyError('dictionary is empty')
# Modified from original to support Python 2.4, see
# http://code.google.com/p/simplejson/issues/detail?id=53
if last:
key = reversed(self).next()
else:
key = iter(self).next()
value = self.pop(key)
return key, value
def __reduce__(self):
items = [[k, self[k]] for k in self]
tmp = self.__map, self.__end
del self.__map, self.__end
inst_dict = vars(self).copy()
self.__map, self.__end = tmp
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
def keys(self):
return list(self)
setdefault = DictMixin.setdefault
update = DictMixin.update
pop = DictMixin.pop
values = DictMixin.values
items = DictMixin.items
iterkeys = DictMixin.iterkeys
itervalues = DictMixin.itervalues
iteritems = DictMixin.iteritems
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
def copy(self):
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
for key in iterable:
d[key] = value
return d
def __eq__(self, other):
if isinstance(other, OrderedDict):
return len(self)==len(other) and \
all(p==q for p, q in zip(self.items(), other.items()))
return dict.__eq__(self, other)
def __ne__(self, other):
return not self == other
-77
View File
@@ -1,77 +0,0 @@
"""JSON token scanner
"""
import re
def _import_c_make_scanner():
try:
from simplejson._speedups import make_scanner
return make_scanner
except ImportError:
return None
c_make_scanner = _import_c_make_scanner()
__all__ = ['make_scanner']
NUMBER_RE = re.compile(
r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?',
(re.VERBOSE | re.MULTILINE | re.DOTALL))
def py_make_scanner(context):
parse_object = context.parse_object
parse_array = context.parse_array
parse_string = context.parse_string
match_number = NUMBER_RE.match
encoding = context.encoding
strict = context.strict
parse_float = context.parse_float
parse_int = context.parse_int
parse_constant = context.parse_constant
object_hook = context.object_hook
object_pairs_hook = context.object_pairs_hook
memo = context.memo
def _scan_once(string, idx):
try:
nextchar = string[idx]
except IndexError:
raise StopIteration
if nextchar == '"':
return parse_string(string, idx + 1, encoding, strict)
elif nextchar == '{':
return parse_object((string, idx + 1), encoding, strict,
_scan_once, object_hook, object_pairs_hook, memo)
elif nextchar == '[':
return parse_array((string, idx + 1), _scan_once)
elif nextchar == 'n' and string[idx:idx + 4] == 'null':
return None, idx + 4
elif nextchar == 't' and string[idx:idx + 4] == 'true':
return True, idx + 4
elif nextchar == 'f' and string[idx:idx + 5] == 'false':
return False, idx + 5
m = match_number(string, idx)
if m is not None:
integer, frac, exp = m.groups()
if frac or exp:
res = parse_float(integer + (frac or '') + (exp or ''))
else:
res = parse_int(integer)
return res, m.end()
elif nextchar == 'N' and string[idx:idx + 3] == 'NaN':
return parse_constant('NaN'), idx + 3
elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity':
return parse_constant('Infinity'), idx + 8
elif nextchar == '-' and string[idx:idx + 9] == '-Infinity':
return parse_constant('-Infinity'), idx + 9
else:
raise StopIteration
def scan_once(string, idx):
try:
return _scan_once(string, idx)
finally:
memo.clear()
return scan_once
make_scanner = c_make_scanner or py_make_scanner
@@ -1,63 +0,0 @@
import unittest
import doctest
class OptionalExtensionTestSuite(unittest.TestSuite):
def run(self, result):
import simplejson
run = unittest.TestSuite.run
run(self, result)
simplejson._toggle_speedups(False)
run(self, result)
simplejson._toggle_speedups(True)
return result
def additional_tests(suite=None):
import simplejson
import simplejson.encoder
import simplejson.decoder
if suite is None:
suite = unittest.TestSuite()
for mod in (simplejson, simplejson.encoder, simplejson.decoder):
suite.addTest(doctest.DocTestSuite(mod))
suite.addTest(doctest.DocFileSuite('../../index.rst'))
return suite
def all_tests_suite():
suite = unittest.TestLoader().loadTestsFromNames([
'simplejson.tests.test_check_circular',
'simplejson.tests.test_decode',
'simplejson.tests.test_default',
'simplejson.tests.test_dump',
'simplejson.tests.test_encode_basestring_ascii',
'simplejson.tests.test_encode_for_html',
'simplejson.tests.test_fail',
'simplejson.tests.test_float',
'simplejson.tests.test_indent',
'simplejson.tests.test_pass1',
'simplejson.tests.test_pass2',
'simplejson.tests.test_pass3',
'simplejson.tests.test_recursion',
'simplejson.tests.test_scanstring',
'simplejson.tests.test_separators',
'simplejson.tests.test_speedups',
'simplejson.tests.test_unicode',
'simplejson.tests.test_decimal',
])
suite = additional_tests(suite)
return OptionalExtensionTestSuite([suite])
def main():
runner = unittest.TextTestRunner()
suite = all_tests_suite()
runner.run(suite)
if __name__ == '__main__':
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
main()
@@ -1,30 +0,0 @@
from unittest import TestCase
import simplejson as json
def default_iterable(obj):
return list(obj)
class TestCheckCircular(TestCase):
def test_circular_dict(self):
dct = {}
dct['a'] = dct
self.assertRaises(ValueError, json.dumps, dct)
def test_circular_list(self):
lst = []
lst.append(lst)
self.assertRaises(ValueError, json.dumps, lst)
def test_circular_composite(self):
dct2 = {}
dct2['a'] = []
dct2['a'].append(dct2)
self.assertRaises(ValueError, json.dumps, dct2)
def test_circular_default(self):
json.dumps([set()], default=default_iterable)
self.assertRaises(TypeError, json.dumps, [set()])
def test_circular_off_default(self):
json.dumps([set()], default=default_iterable, check_circular=False)
self.assertRaises(TypeError, json.dumps, [set()], check_circular=False)
@@ -1,33 +0,0 @@
from decimal import Decimal
from unittest import TestCase
import simplejson as json
class TestDecimal(TestCase):
NUMS = "1.0", "10.00", "1.1", "1234567890.1234567890", "500"
def test_decimal_encode(self):
for d in map(Decimal, self.NUMS):
self.assertEquals(json.dumps(d, use_decimal=True), str(d))
def test_decimal_decode(self):
for s in self.NUMS:
self.assertEquals(json.loads(s, parse_float=Decimal), Decimal(s))
def test_decimal_roundtrip(self):
for d in map(Decimal, self.NUMS):
# The type might not be the same (int and Decimal) but they
# should still compare equal.
self.assertEquals(
json.loads(
json.dumps(d, use_decimal=True), parse_float=Decimal),
d)
self.assertEquals(
json.loads(
json.dumps([d], use_decimal=True), parse_float=Decimal),
[d])
def test_decimal_defaults(self):
d = Decimal(1)
# use_decimal=False is the default
self.assertRaises(TypeError, json.dumps, d, use_decimal=False)
self.assertRaises(TypeError, json.dumps, d)
@@ -1,73 +0,0 @@
import decimal
from unittest import TestCase
from StringIO import StringIO
import simplejson as json
from simplejson import OrderedDict
class TestDecode(TestCase):
if not hasattr(TestCase, 'assertIs'):
def assertIs(self, a, b):
self.assertTrue(a is b, '%r is %r' % (a, b))
def test_decimal(self):
rval = json.loads('1.1', parse_float=decimal.Decimal)
self.assertTrue(isinstance(rval, decimal.Decimal))
self.assertEquals(rval, decimal.Decimal('1.1'))
def test_float(self):
rval = json.loads('1', parse_int=float)
self.assertTrue(isinstance(rval, float))
self.assertEquals(rval, 1.0)
def test_decoder_optimizations(self):
# Several optimizations were made that skip over calls to
# the whitespace regex, so this test is designed to try and
# exercise the uncommon cases. The array cases are already covered.
rval = json.loads('{ "key" : "value" , "k":"v" }')
self.assertEquals(rval, {"key":"value", "k":"v"})
def test_empty_objects(self):
s = '{}'
self.assertEqual(json.loads(s), eval(s))
s = '[]'
self.assertEqual(json.loads(s), eval(s))
s = '""'
self.assertEqual(json.loads(s), eval(s))
def test_object_pairs_hook(self):
s = '{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}'
p = [("xkd", 1), ("kcw", 2), ("art", 3), ("hxm", 4),
("qrt", 5), ("pad", 6), ("hoy", 7)]
self.assertEqual(json.loads(s), eval(s))
self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p)
self.assertEqual(json.load(StringIO(s),
object_pairs_hook=lambda x: x), p)
od = json.loads(s, object_pairs_hook=OrderedDict)
self.assertEqual(od, OrderedDict(p))
self.assertEqual(type(od), OrderedDict)
# the object_pairs_hook takes priority over the object_hook
self.assertEqual(json.loads(s,
object_pairs_hook=OrderedDict,
object_hook=lambda x: None),
OrderedDict(p))
def check_keys_reuse(self, source, loads):
rval = loads(source)
(a, b), (c, d) = sorted(rval[0]), sorted(rval[1])
self.assertIs(a, c)
self.assertIs(b, d)
def test_keys_reuse_str(self):
s = u'[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]'.encode('utf8')
self.check_keys_reuse(s, json.loads)
def test_keys_reuse_unicode(self):
s = u'[{"a_key": 1, "b_\xe9": 2}, {"a_key": 3, "b_\xe9": 4}]'
self.check_keys_reuse(s, json.loads)
def test_empty_strings(self):
self.assertEqual(json.loads('""'), "")
self.assertEqual(json.loads(u'""'), u"")
self.assertEqual(json.loads('[""]'), [""])
self.assertEqual(json.loads(u'[""]'), [u""])
@@ -1,9 +0,0 @@
from unittest import TestCase
import simplejson as json
class TestDefault(TestCase):
def test_default(self):
self.assertEquals(
json.dumps(type, default=repr),
json.dumps(repr(type)))
@@ -1,27 +0,0 @@
from unittest import TestCase
from cStringIO import StringIO
import simplejson as json
class TestDump(TestCase):
def test_dump(self):
sio = StringIO()
json.dump({}, sio)
self.assertEquals(sio.getvalue(), '{}')
def test_dumps(self):
self.assertEquals(json.dumps({}), '{}')
def test_encode_truefalse(self):
self.assertEquals(json.dumps(
{True: False, False: True}, sort_keys=True),
'{"false": true, "true": false}')
self.assertEquals(json.dumps(
{2: 3.0, 4.0: 5L, False: 1, 6L: True, "7": 0}, sort_keys=True),
'{"false": 1, "2": 3.0, "4.0": 5, "6": true, "7": 0}')
def test_ordered_dict(self):
# http://bugs.python.org/issue6105
items = [('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
s = json.dumps(json.OrderedDict(items))
self.assertEqual(s, '{"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}')
@@ -1,41 +0,0 @@
from unittest import TestCase
import simplejson.encoder
CASES = [
(u'/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'),
(u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'),
(u'controls', '"controls"'),
(u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'),
(u'{"object with 1 member":["array with 1 element"]}', '"{\\"object with 1 member\\":[\\"array with 1 element\\"]}"'),
(u' s p a c e d ', '" s p a c e d "'),
(u'\U0001d120', '"\\ud834\\udd20"'),
(u'\u03b1\u03a9', '"\\u03b1\\u03a9"'),
('\xce\xb1\xce\xa9', '"\\u03b1\\u03a9"'),
(u'\u03b1\u03a9', '"\\u03b1\\u03a9"'),
('\xce\xb1\xce\xa9', '"\\u03b1\\u03a9"'),
(u'\u03b1\u03a9', '"\\u03b1\\u03a9"'),
(u'\u03b1\u03a9', '"\\u03b1\\u03a9"'),
(u"`1~!@#$%^&*()_+-={':[,]}|;.</>?", '"`1~!@#$%^&*()_+-={\':[,]}|;.</>?"'),
(u'\x08\x0c\n\r\t', '"\\b\\f\\n\\r\\t"'),
(u'\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'),
]
class TestEncodeBaseStringAscii(TestCase):
def test_py_encode_basestring_ascii(self):
self._test_encode_basestring_ascii(simplejson.encoder.py_encode_basestring_ascii)
def test_c_encode_basestring_ascii(self):
if not simplejson.encoder.c_encode_basestring_ascii:
return
self._test_encode_basestring_ascii(simplejson.encoder.c_encode_basestring_ascii)
def _test_encode_basestring_ascii(self, encode_basestring_ascii):
fname = encode_basestring_ascii.__name__
for input_string, expect in CASES:
result = encode_basestring_ascii(input_string)
#self.assertEquals(result, expect,
# '{0!r} != {1!r} for {2}({3!r})'.format(
# result, expect, fname, input_string))
self.assertEquals(result, expect,
'%r != %r for %s(%r)' % (result, expect, fname, input_string))
@@ -1,32 +0,0 @@
import unittest
import simplejson.decoder
import simplejson.encoder
class TestEncodeForHTML(unittest.TestCase):
def setUp(self):
self.decoder = simplejson.decoder.JSONDecoder()
self.encoder = simplejson.encoder.JSONEncoderForHTML()
def test_basic_encode(self):
self.assertEqual(r'"\u0026"', self.encoder.encode('&'))
self.assertEqual(r'"\u003c"', self.encoder.encode('<'))
self.assertEqual(r'"\u003e"', self.encoder.encode('>'))
def test_basic_roundtrip(self):
for char in '&<>':
self.assertEqual(
char, self.decoder.decode(
self.encoder.encode(char)))
def test_prevent_script_breakout(self):
bad_string = '</script><script>alert("gotcha")</script>'
self.assertEqual(
r'"\u003c/script\u003e\u003cscript\u003e'
r'alert(\"gotcha\")\u003c/script\u003e"',
self.encoder.encode(bad_string))
self.assertEqual(
bad_string, self.decoder.decode(
self.encoder.encode(bad_string)))
@@ -1,91 +0,0 @@
from unittest import TestCase
import simplejson as json
# Fri Dec 30 18:57:26 2005
JSONDOCS = [
# http://json.org/JSON_checker/test/fail1.json
'"A JSON payload should be an object or array, not a string."',
# http://json.org/JSON_checker/test/fail2.json
'["Unclosed array"',
# http://json.org/JSON_checker/test/fail3.json
'{unquoted_key: "keys must be quoted}',
# http://json.org/JSON_checker/test/fail4.json
'["extra comma",]',
# http://json.org/JSON_checker/test/fail5.json
'["double extra comma",,]',
# http://json.org/JSON_checker/test/fail6.json
'[ , "<-- missing value"]',
# http://json.org/JSON_checker/test/fail7.json
'["Comma after the close"],',
# http://json.org/JSON_checker/test/fail8.json
'["Extra close"]]',
# http://json.org/JSON_checker/test/fail9.json
'{"Extra comma": true,}',
# http://json.org/JSON_checker/test/fail10.json
'{"Extra value after close": true} "misplaced quoted value"',
# http://json.org/JSON_checker/test/fail11.json
'{"Illegal expression": 1 + 2}',
# http://json.org/JSON_checker/test/fail12.json
'{"Illegal invocation": alert()}',
# http://json.org/JSON_checker/test/fail13.json
'{"Numbers cannot have leading zeroes": 013}',
# http://json.org/JSON_checker/test/fail14.json
'{"Numbers cannot be hex": 0x14}',
# http://json.org/JSON_checker/test/fail15.json
'["Illegal backslash escape: \\x15"]',
# http://json.org/JSON_checker/test/fail16.json
'["Illegal backslash escape: \\\'"]',
# http://json.org/JSON_checker/test/fail17.json
'["Illegal backslash escape: \\017"]',
# http://json.org/JSON_checker/test/fail18.json
'[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]',
# http://json.org/JSON_checker/test/fail19.json
'{"Missing colon" null}',
# http://json.org/JSON_checker/test/fail20.json
'{"Double colon":: null}',
# http://json.org/JSON_checker/test/fail21.json
'{"Comma instead of colon", null}',
# http://json.org/JSON_checker/test/fail22.json
'["Colon instead of comma": false]',
# http://json.org/JSON_checker/test/fail23.json
'["Bad value", truth]',
# http://json.org/JSON_checker/test/fail24.json
"['single quote']",
# http://code.google.com/p/simplejson/issues/detail?id=3
u'["A\u001FZ control characters in string"]',
]
SKIPS = {
1: "why not have a string payload?",
18: "spec doesn't specify any nesting limitations",
}
class TestFail(TestCase):
def test_failures(self):
for idx, doc in enumerate(JSONDOCS):
idx = idx + 1
if idx in SKIPS:
json.loads(doc)
continue
try:
json.loads(doc)
except json.JSONDecodeError:
pass
else:
#self.fail("Expected failure for fail{0}.json: {1!r}".format(idx, doc))
self.fail("Expected failure for fail%d.json: %r" % (idx, doc))
def test_array_decoder_issue46(self):
# http://code.google.com/p/simplejson/issues/detail?id=46
for doc in [u'[,]', '[,]']:
try:
json.loads(doc)
except json.JSONDecodeError, e:
self.assertEquals(e.pos, 1)
self.assertEquals(e.lineno, 1)
self.assertEquals(e.colno, 1)
except Exception, e:
self.fail("Unexpected exception raised %r %s" % (e, e))
else:
self.fail("Unexpected success parsing '[,]'")
@@ -1,19 +0,0 @@
import math
from unittest import TestCase
import simplejson as json
class TestFloat(TestCase):
def test_floats(self):
for num in [1617161771.7650001, math.pi, math.pi**100,
math.pi**-100, 3.1]:
self.assertEquals(float(json.dumps(num)), num)
self.assertEquals(json.loads(json.dumps(num)), num)
self.assertEquals(json.loads(unicode(json.dumps(num))), num)
def test_ints(self):
for num in [1, 1L, 1<<32, 1<<64]:
self.assertEquals(json.dumps(num), str(num))
self.assertEquals(int(json.dumps(num)), num)
self.assertEquals(json.loads(json.dumps(num)), num)
self.assertEquals(json.loads(unicode(json.dumps(num))), num)
@@ -1,53 +0,0 @@
from unittest import TestCase
import simplejson as json
import textwrap
class TestIndent(TestCase):
def test_indent(self):
h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh',
'i-vhbjkhnth',
{'nifty': 87}, {'field': 'yes', 'morefield': False} ]
expect = textwrap.dedent("""\
[
\t[
\t\t"blorpie"
\t],
\t[
\t\t"whoops"
\t],
\t[],
\t"d-shtaeou",
\t"d-nthiouh",
\t"i-vhbjkhnth",
\t{
\t\t"nifty": 87
\t},
\t{
\t\t"field": "yes",
\t\t"morefield": false
\t}
]""")
d1 = json.dumps(h)
d2 = json.dumps(h, indent='\t', sort_keys=True, separators=(',', ': '))
d3 = json.dumps(h, indent=' ', sort_keys=True, separators=(',', ': '))
d4 = json.dumps(h, indent=2, sort_keys=True, separators=(',', ': '))
h1 = json.loads(d1)
h2 = json.loads(d2)
h3 = json.loads(d3)
h4 = json.loads(d4)
self.assertEquals(h1, h)
self.assertEquals(h2, h)
self.assertEquals(h3, h)
self.assertEquals(h4, h)
self.assertEquals(d3, expect.replace('\t', ' '))
self.assertEquals(d4, expect.replace('\t', ' '))
# NOTE: Python 2.4 textwrap.dedent converts tabs to spaces,
# so the following is expected to fail. Python 2.4 is not a
# supported platform in simplejson 2.1.0+.
self.assertEquals(d2, expect)
@@ -1,76 +0,0 @@
from unittest import TestCase
import simplejson as json
# from http://json.org/JSON_checker/test/pass1.json
JSON = r'''
[
"JSON Test Pattern pass1",
{"object with 1 member":["array with 1 element"]},
{},
[],
-42,
true,
false,
null,
{
"integer": 1234567890,
"real": -9876.543210,
"e": 0.123456789e-12,
"E": 1.234567890E+34,
"": 23456789012E666,
"zero": 0,
"one": 1,
"space": " ",
"quote": "\"",
"backslash": "\\",
"controls": "\b\f\n\r\t",
"slash": "/ & \/",
"alpha": "abcdefghijklmnopqrstuvwyz",
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
"digit": "0123456789",
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
"true": true,
"false": false,
"null": null,
"array":[ ],
"object":{ },
"address": "50 St. James Street",
"url": "http://www.JSON.org/",
"comment": "// /* <!-- --",
"# -- --> */": " ",
" s p a c e d " :[1,2 , 3
,
4 , 5 , 6 ,7 ],
"compact": [1,2,3,4,5,6,7],
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
"quotes": "&#34; \u0022 %22 0x22 034 &#x22;",
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
: "A key can be any string"
},
0.5 ,98.6
,
99.44
,
1066
,"rosebud"]
'''
class TestPass1(TestCase):
def test_parse(self):
# test in/out equivalence and parsing
res = json.loads(JSON)
out = json.dumps(res)
self.assertEquals(res, json.loads(out))
try:
json.dumps(res, allow_nan=False)
except ValueError:
pass
else:
self.fail("23456789012E666 should be out of range")
@@ -1,14 +0,0 @@
from unittest import TestCase
import simplejson as json
# from http://json.org/JSON_checker/test/pass2.json
JSON = r'''
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
'''
class TestPass2(TestCase):
def test_parse(self):
# test in/out equivalence and parsing
res = json.loads(JSON)
out = json.dumps(res)
self.assertEquals(res, json.loads(out))
@@ -1,20 +0,0 @@
from unittest import TestCase
import simplejson as json
# from http://json.org/JSON_checker/test/pass3.json
JSON = r'''
{
"JSON Test Pattern pass3": {
"The outermost value": "must be an object or array.",
"In this test": "It is an object."
}
}
'''
class TestPass3(TestCase):
def test_parse(self):
# test in/out equivalence and parsing
res = json.loads(JSON)
out = json.dumps(res)
self.assertEquals(res, json.loads(out))
@@ -1,67 +0,0 @@
from unittest import TestCase
import simplejson as json
class JSONTestObject:
pass
class RecursiveJSONEncoder(json.JSONEncoder):
recurse = False
def default(self, o):
if o is JSONTestObject:
if self.recurse:
return [JSONTestObject]
else:
return 'JSONTestObject'
return json.JSONEncoder.default(o)
class TestRecursion(TestCase):
def test_listrecursion(self):
x = []
x.append(x)
try:
json.dumps(x)
except ValueError:
pass
else:
self.fail("didn't raise ValueError on list recursion")
x = []
y = [x]
x.append(y)
try:
json.dumps(x)
except ValueError:
pass
else:
self.fail("didn't raise ValueError on alternating list recursion")
y = []
x = [y, y]
# ensure that the marker is cleared
json.dumps(x)
def test_dictrecursion(self):
x = {}
x["test"] = x
try:
json.dumps(x)
except ValueError:
pass
else:
self.fail("didn't raise ValueError on dict recursion")
x = {}
y = {"a": x, "b": x}
# ensure that the marker is cleared
json.dumps(x)
def test_defaultrecursion(self):
enc = RecursiveJSONEncoder()
self.assertEquals(enc.encode(JSONTestObject), '"JSONTestObject"')
enc.recurse = True
try:
enc.encode(JSONTestObject)
except ValueError:
pass
else:
self.fail("didn't raise ValueError on default recursion")
@@ -1,117 +0,0 @@
import sys
from unittest import TestCase
import simplejson as json
import simplejson.decoder
class TestScanString(TestCase):
def test_py_scanstring(self):
self._test_scanstring(simplejson.decoder.py_scanstring)
def test_c_scanstring(self):
if not simplejson.decoder.c_scanstring:
return
self._test_scanstring(simplejson.decoder.c_scanstring)
def _test_scanstring(self, scanstring):
self.assertEquals(
scanstring('"z\\ud834\\udd20x"', 1, None, True),
(u'z\U0001d120x', 16))
if sys.maxunicode == 65535:
self.assertEquals(
scanstring(u'"z\U0001d120x"', 1, None, True),
(u'z\U0001d120x', 6))
else:
self.assertEquals(
scanstring(u'"z\U0001d120x"', 1, None, True),
(u'z\U0001d120x', 5))
self.assertEquals(
scanstring('"\\u007b"', 1, None, True),
(u'{', 8))
self.assertEquals(
scanstring('"A JSON payload should be an object or array, not a string."', 1, None, True),
(u'A JSON payload should be an object or array, not a string.', 60))
self.assertEquals(
scanstring('["Unclosed array"', 2, None, True),
(u'Unclosed array', 17))
self.assertEquals(
scanstring('["extra comma",]', 2, None, True),
(u'extra comma', 14))
self.assertEquals(
scanstring('["double extra comma",,]', 2, None, True),
(u'double extra comma', 21))
self.assertEquals(
scanstring('["Comma after the close"],', 2, None, True),
(u'Comma after the close', 24))
self.assertEquals(
scanstring('["Extra close"]]', 2, None, True),
(u'Extra close', 14))
self.assertEquals(
scanstring('{"Extra comma": true,}', 2, None, True),
(u'Extra comma', 14))
self.assertEquals(
scanstring('{"Extra value after close": true} "misplaced quoted value"', 2, None, True),
(u'Extra value after close', 26))
self.assertEquals(
scanstring('{"Illegal expression": 1 + 2}', 2, None, True),
(u'Illegal expression', 21))
self.assertEquals(
scanstring('{"Illegal invocation": alert()}', 2, None, True),
(u'Illegal invocation', 21))
self.assertEquals(
scanstring('{"Numbers cannot have leading zeroes": 013}', 2, None, True),
(u'Numbers cannot have leading zeroes', 37))
self.assertEquals(
scanstring('{"Numbers cannot be hex": 0x14}', 2, None, True),
(u'Numbers cannot be hex', 24))
self.assertEquals(
scanstring('[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]', 21, None, True),
(u'Too deep', 30))
self.assertEquals(
scanstring('{"Missing colon" null}', 2, None, True),
(u'Missing colon', 16))
self.assertEquals(
scanstring('{"Double colon":: null}', 2, None, True),
(u'Double colon', 15))
self.assertEquals(
scanstring('{"Comma instead of colon", null}', 2, None, True),
(u'Comma instead of colon', 25))
self.assertEquals(
scanstring('["Colon instead of comma": false]', 2, None, True),
(u'Colon instead of comma', 25))
self.assertEquals(
scanstring('["Bad value", truth]', 2, None, True),
(u'Bad value', 12))
def test_issue3623(self):
self.assertRaises(ValueError, json.decoder.scanstring, "xxx", 1,
"xxx")
self.assertRaises(UnicodeDecodeError,
json.encoder.encode_basestring_ascii, "xx\xff")
def test_overflow(self):
# Python 2.5 does not have maxsize
maxsize = getattr(sys, 'maxsize', sys.maxint)
self.assertRaises(OverflowError, json.decoder.scanstring, "xxx",
maxsize + 1)
@@ -1,42 +0,0 @@
import textwrap
from unittest import TestCase
import simplejson as json
class TestSeparators(TestCase):
def test_separators(self):
h = [['blorpie'], ['whoops'], [], 'd-shtaeou', 'd-nthiouh', 'i-vhbjkhnth',
{'nifty': 87}, {'field': 'yes', 'morefield': False} ]
expect = textwrap.dedent("""\
[
[
"blorpie"
] ,
[
"whoops"
] ,
[] ,
"d-shtaeou" ,
"d-nthiouh" ,
"i-vhbjkhnth" ,
{
"nifty" : 87
} ,
{
"field" : "yes" ,
"morefield" : false
}
]""")
d1 = json.dumps(h)
d2 = json.dumps(h, indent=' ', sort_keys=True, separators=(' ,', ' : '))
h1 = json.loads(d1)
h2 = json.loads(d2)
self.assertEquals(h1, h)
self.assertEquals(h2, h)
self.assertEquals(d2, expect)
@@ -1,21 +0,0 @@
import decimal
from unittest import TestCase
from simplejson import decoder, encoder, scanner
def has_speedups():
return encoder.c_make_encoder is not None
class TestDecode(TestCase):
def test_make_scanner(self):
if not has_speedups():
return
self.assertRaises(AttributeError, scanner.c_make_scanner, 1)
def test_make_encoder(self):
if not has_speedups():
return
self.assertRaises(TypeError, encoder.c_make_encoder,
None,
"\xCD\x7D\x3D\x4E\x12\x4C\xF9\x79\xD7\x52\xBA\x82\xF2\x27\x4A\x7D\xA0\xCA\x75",
None)
@@ -1,99 +0,0 @@
from unittest import TestCase
import simplejson as json
class TestUnicode(TestCase):
def test_encoding1(self):
encoder = json.JSONEncoder(encoding='utf-8')
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
s = u.encode('utf-8')
ju = encoder.encode(u)
js = encoder.encode(s)
self.assertEquals(ju, js)
def test_encoding2(self):
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
s = u.encode('utf-8')
ju = json.dumps(u, encoding='utf-8')
js = json.dumps(s, encoding='utf-8')
self.assertEquals(ju, js)
def test_encoding3(self):
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
j = json.dumps(u)
self.assertEquals(j, '"\\u03b1\\u03a9"')
def test_encoding4(self):
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
j = json.dumps([u])
self.assertEquals(j, '["\\u03b1\\u03a9"]')
def test_encoding5(self):
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
j = json.dumps(u, ensure_ascii=False)
self.assertEquals(j, u'"' + u + u'"')
def test_encoding6(self):
u = u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK CAPITAL LETTER OMEGA}'
j = json.dumps([u], ensure_ascii=False)
self.assertEquals(j, u'["' + u + u'"]')
def test_big_unicode_encode(self):
u = u'\U0001d120'
self.assertEquals(json.dumps(u), '"\\ud834\\udd20"')
self.assertEquals(json.dumps(u, ensure_ascii=False), u'"\U0001d120"')
def test_big_unicode_decode(self):
u = u'z\U0001d120x'
self.assertEquals(json.loads('"' + u + '"'), u)
self.assertEquals(json.loads('"z\\ud834\\udd20x"'), u)
def test_unicode_decode(self):
for i in range(0, 0xd7ff):
u = unichr(i)
#s = '"\\u{0:04x}"'.format(i)
s = '"\\u%04x"' % (i,)
self.assertEquals(json.loads(s), u)
def test_object_pairs_hook_with_unicode(self):
s = u'{"xkd":1, "kcw":2, "art":3, "hxm":4, "qrt":5, "pad":6, "hoy":7}'
p = [(u"xkd", 1), (u"kcw", 2), (u"art", 3), (u"hxm", 4),
(u"qrt", 5), (u"pad", 6), (u"hoy", 7)]
self.assertEqual(json.loads(s), eval(s))
self.assertEqual(json.loads(s, object_pairs_hook=lambda x: x), p)
od = json.loads(s, object_pairs_hook=json.OrderedDict)
self.assertEqual(od, json.OrderedDict(p))
self.assertEqual(type(od), json.OrderedDict)
# the object_pairs_hook takes priority over the object_hook
self.assertEqual(json.loads(s,
object_pairs_hook=json.OrderedDict,
object_hook=lambda x: None),
json.OrderedDict(p))
def test_default_encoding(self):
self.assertEquals(json.loads(u'{"a": "\xe9"}'.encode('utf-8')),
{'a': u'\xe9'})
def test_unicode_preservation(self):
self.assertEquals(type(json.loads(u'""')), unicode)
self.assertEquals(type(json.loads(u'"a"')), unicode)
self.assertEquals(type(json.loads(u'["a"]')[0]), unicode)
def test_ensure_ascii_false_returns_unicode(self):
# http://code.google.com/p/simplejson/issues/detail?id=48
self.assertEquals(type(json.dumps([], ensure_ascii=False)), unicode)
self.assertEquals(type(json.dumps(0, ensure_ascii=False)), unicode)
self.assertEquals(type(json.dumps({}, ensure_ascii=False)), unicode)
self.assertEquals(type(json.dumps("", ensure_ascii=False)), unicode)
def test_ensure_ascii_false_bytestring_encoding(self):
# http://code.google.com/p/simplejson/issues/detail?id=48
doc1 = {u'quux': 'Arr\xc3\xaat sur images'}
doc2 = {u'quux': u'Arr\xeat sur images'}
doc_ascii = '{"quux": "Arr\\u00eat sur images"}'
doc_unicode = u'{"quux": "Arr\xeat sur images"}'
self.assertEquals(json.dumps(doc1), doc_ascii)
self.assertEquals(json.dumps(doc2), doc_ascii)
self.assertEquals(json.dumps(doc1, ensure_ascii=False), doc_unicode)
self.assertEquals(json.dumps(doc2, ensure_ascii=False), doc_unicode)
-39
View File
@@ -1,39 +0,0 @@
r"""Command-line tool to validate and pretty-print JSON
Usage::
$ echo '{"json":"obj"}' | python -m simplejson.tool
{
"json": "obj"
}
$ echo '{ 1.2:3.4}' | python -m simplejson.tool
Expecting property name: line 1 column 2 (char 2)
"""
import sys
import simplejson as json
def main():
if len(sys.argv) == 1:
infile = sys.stdin
outfile = sys.stdout
elif len(sys.argv) == 2:
infile = open(sys.argv[1], 'rb')
outfile = sys.stdout
elif len(sys.argv) == 3:
infile = open(sys.argv[1], 'rb')
outfile = open(sys.argv[2], 'wb')
else:
raise SystemExit(sys.argv[0] + " [infile [outfile]]")
try:
obj = json.load(infile,
object_pairs_hook=json.OrderedDict,
use_decimal=True)
except ValueError, e:
raise SystemExit(e)
json.dump(obj, outfile, sort_keys=True, indent=' ', use_decimal=True)
outfile.write('\n')
if __name__ == '__main__':
main()
File diff suppressed because it is too large Load Diff
@@ -1,36 +0,0 @@
"""
This module allows doctest to find typechecked functions.
Currently, doctest verifies functions to make sure that their
globals() dict is the __dict__ of their module. In the case of
decorated functions, the globals() dict *is* not the right one.
To enable support for doctest do:
import typecheck.doctest_support
This import must occur before any calls to doctest methods.
"""
def __DocTestFinder_from_module(self, module, object):
"""
Return true if the given object is defined in the given
module.
"""
import inspect
if module is None:
return True
elif inspect.isfunction(object) or inspect.isclass(object):
return module.__name__ == object.__module__
elif inspect.getmodule(object) is not None:
return module is inspect.getmodule(object)
elif hasattr(object, '__module__'):
return module.__name__ == object.__module__
elif isinstance(object, property):
return True # [XX] no way not be sure.
else:
raise ValueError("object must be a class or function")
import doctest as __doctest
__doctest.DocTestFinder._from_module = __DocTestFinder_from_module
-84
View File
@@ -1,84 +0,0 @@
from typecheck import _TC_NestedError, _TC_TypeError, check_type, Or
from typecheck import register_type, _TC_Exception
class _TC_IterationError(_TC_NestedError):
def __init__(self, iteration, value, inner_exception):
_TC_NestedError.__init__(self, inner_exception)
self.iteration = iteration
self.value = value
def error_message(self):
return ("at iteration %d (value: %s)" % (self.iteration, repr(self.value))) + _TC_NestedError.error_message(self)
### This is the shadow class behind UnorderedIteratorMixin.
### Again, it tries to pretend it doesn't exist by mimicing
### the class of <obj> as much as possible.
###
### This mixin provides typechecking for iterator classes
### where you don't care about the order of the types (ie,
### you simply Or() the types together, as opposed to patterned
### lists, which would be ordered mixins)
class _UnorderedIteratorMixin(object):
def __init__(self, class_name, obj):
vals = [o for o in obj]
self.type = self
self._type = Or(*vals)
self.__cls = obj.__class__
self.__vals = vals
# This is necessary because it's a huge pain in the ass
# to get the "raw" name of the class once it's created
self.__cls_name = class_name
def __typecheck__(self, func, to_check):
if not isinstance(to_check, self.__cls):
raise _TC_TypeError(to_check, self)
for i, item in enumerate(to_check):
try:
check_type(self._type, func, item)
except _TC_Exception, e:
raise _TC_IterationError(i, item, e)
@classmethod
def __typesig__(cls, obj):
if isinstance(obj, cls):
return obj
def __str__(self):
return "%s(%s)" % (self.__cls_name, str(self._type))
__repr__ = __str__
### This is included in a class's parent-class section like so:
### class MyClass(UnorderedIteratorMixin("MyClass")):
### blah blah blah
###
### This serves as a class factory, whose produced classes
### attempt to mask the fact they exist. Their purpose
### is to redirect __typesig__ calls to appropriate
### instances of _UnorderedIteratorMixin
def UnorderedIteratorMixin(class_name):
class UIM(object):
@classmethod
def __typesig__(cls, obj):
if isinstance(obj, cls):
return _UnorderedIteratorMixin(class_name, obj)
def __repr__(self):
return "%s%s" % (class_name, str(tuple(e for e in self)))
# We register each produced class anew
# If someone needs to unregister these classes, they should
# save a copy of it before including it in the class-definition:
#
# my_UIM = UnorderedIteratorMixin("FooClass")
# class FooClass(my_UIM):
# ...
#
# Alternatively, you could just look in FooClass.__bases__ later; whatever
register_type(UIM)
return UIM
register_type(_UnorderedIteratorMixin)
-62
View File
@@ -1,62 +0,0 @@
from typecheck import CheckType, _TC_TypeError, check_type, Type
from typecheck import register_type, Or, _TC_Exception, _TC_KeyError
from typecheck import _TC_LengthError
### Provide typechecking for the built-in set() class
###
### XXX: Investigate rewriting this in terms of
### UnorderedIteratorMixin or Or()
class Set(CheckType):
def __init__(self, set_list):
self.type = set(set_list)
self._types = [Type(t) for t in self.type]
# self._type is used to build _TC_TypeError
if len(self._types) > 1:
self._type = Or(*self.type)
elif len(self._types) == 1:
# XXX Is there an easier way to get this?
t = self.type.pop()
self._type = t
self.type.add(t)
def __str__(self):
return "Set(" + str([e for e in self.type]) + ")"
__repr__ = __str__
def __typecheck__(self, func, to_check):
if not isinstance(to_check, set):
raise _TC_TypeError(to_check, self.type)
if len(self._types) == 0 and len(to_check) > 0:
raise _TC_LengthError(len(to_check), 0)
for obj in to_check:
error = False
for type in self._types:
try:
check_type(type, func, obj)
except _TC_Exception:
error = True
continue
else:
error = False
break
if error:
raise _TC_KeyError(obj, _TC_TypeError(obj, self._type))
def __eq__(self, other):
if self.__class__ is not other.__class__:
return False
return self.type == other.type
def __hash__(self):
return hash(str(hash(self.__class__)) + str(hash(frozenset(self.type))))
@classmethod
def __typesig__(self, obj):
if isinstance(obj, set):
return Set(obj)
register_type(Set)
-35
View File
@@ -1,35 +0,0 @@
from typecheck import Typeclass
### Number
####################################################
_numbers = [int, float, complex, long, bool]
try:
from decimal import Decimal
_numbers.append(Decimal)
del Decimal
except ImportError:
pass
Number = Typeclass(*_numbers)
del _numbers
### String -- subinstance of ImSequence
####################################################
String = Typeclass(str, unicode)
### ImSequence -- immutable sequences
####################################################
ImSequence = Typeclass(tuple, xrange, String)
### MSequence -- mutable sequences
####################################################
MSequence = Typeclass(list)
### Mapping
####################################################
Mapping = Typeclass(dict)
File diff suppressed because it is too large Load Diff
-262
View File
@@ -1,262 +0,0 @@
# -*- coding: windows-1251 -*-
# Portions are Copyright (C) 2005 Roman V. Kiseliov
# Portions are Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net>
# Portions are Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel)
from BIFFRecords import BiffRecord
from struct import *
def _size_col(sheet, col):
return sheet.col_width(col)
def _size_row(sheet, row):
return sheet.row_height(row)
def _position_image(sheet, row_start, col_start, x1, y1, width, height):
"""Calculate the vertices that define the position of the image as required by
the OBJ record.
+------------+------------+
| A | B |
+-----+------------+------------+
| |(x1,y1) | |
| 1 |(A1)._______|______ |
| | | | |
| | | | |
+-----+----| BITMAP |-----+
| | | | |
| 2 | |______________. |
| | | (B2)|
| | | (x2,y2)|
+---- +------------+------------+
Example of a bitmap that covers some of the area from cell A1 to cell B2.
Based on the width and height of the bitmap we need to calculate 8 vars:
col_start, row_start, col_end, row_end, x1, y1, x2, y2.
The width and height of the cells are also variable and have to be taken into
account.
The values of col_start and row_start are passed in from the calling
function. The values of col_end and row_end are calculated by subtracting
the width and height of the bitmap from the width and height of the
underlying cells.
The vertices are expressed as a percentage of the underlying cell width as
follows (rhs values are in pixels):
x1 = X / W *1024
y1 = Y / H *256
x2 = (X-1) / W *1024
y2 = (Y-1) / H *256
Where: X is distance from the left side of the underlying cell
Y is distance from the top of the underlying cell
W is the width of the cell
H is the height of the cell
Note: the SDK incorrectly states that the height should be expressed as a
percentage of 1024.
col_start - Col containing upper left corner of object
row_start - Row containing top left corner of object
x1 - Distance to left side of object
y1 - Distance to top of object
width - Width of image frame
height - Height of image frame
"""
# Adjust start column for offsets that are greater than the col width
while x1 >= _size_col(sheet, col_start):
x1 -= _size_col(sheet, col_start)
col_start += 1
# Adjust start row for offsets that are greater than the row height
while y1 >= _size_row(sheet, row_start):
y1 -= _size_row(sheet, row_start)
row_start += 1
# Initialise end cell to the same as the start cell
row_end = row_start # Row containing bottom right corner of object
col_end = col_start # Col containing lower right corner of object
width = width + x1 - 1
height = height + y1 - 1
# Subtract the underlying cell widths to find the end cell of the image
while (width >= _size_col(sheet, col_end)):
width -= _size_col(sheet, col_end)
col_end += 1
# Subtract the underlying cell heights to find the end cell of the image
while (height >= _size_row(sheet, row_end)):
height -= _size_row(sheet, row_end)
row_end += 1
# Bitmap isn't allowed to start or finish in a hidden cell, i.e. a cell
# with zero height or width.
if ((_size_col(sheet, col_start) == 0) or (_size_col(sheet, col_end) == 0)
or (_size_row(sheet, row_start) == 0) or (_size_row(sheet, row_end) == 0)):
return
# Convert the pixel values to the percentage value expected by Excel
x1 = int(float(x1) / _size_col(sheet, col_start) * 1024)
y1 = int(float(y1) / _size_row(sheet, row_start) * 256)
# Distance to right side of object
x2 = int(float(width) / _size_col(sheet, col_end) * 1024)
# Distance to bottom of object
y2 = int(float(height) / _size_row(sheet, row_end) * 256)
return (col_start, x1, row_start, y1, col_end, x2, row_end, y2)
class ObjBmpRecord(BiffRecord):
_REC_ID = 0x005D # Record identifier
def __init__(self, row, col, sheet, im_data_bmp, x, y, scale_x, scale_y):
# Scale the frame of the image.
width = im_data_bmp.width * scale_x
height = im_data_bmp.height * scale_y
# Calculate the vertices of the image and write the OBJ record
coordinates = _position_image(sheet, row, col, x, y, width, height)
# print coordinates
col_start, x1, row_start, y1, col_end, x2, row_end, y2 = coordinates
"""Store the OBJ record that precedes an IMDATA record. This could be generalise
to support other Excel objects.
"""
cObj = 0x0001 # Count of objects in file (set to 1)
OT = 0x0008 # Object type. 8 = Picture
id = 0x0001 # Object ID
grbit = 0x0614 # Option flags
colL = col_start # Col containing upper left corner of object
dxL = x1 # Distance from left side of cell
rwT = row_start # Row containing top left corner of object
dyT = y1 # Distance from top of cell
colR = col_end # Col containing lower right corner of object
dxR = x2 # Distance from right of cell
rwB = row_end # Row containing bottom right corner of object
dyB = y2 # Distance from bottom of cell
cbMacro = 0x0000 # Length of FMLA structure
Reserved1 = 0x0000 # Reserved
Reserved2 = 0x0000 # Reserved
icvBack = 0x09 # Background colour
icvFore = 0x09 # Foreground colour
fls = 0x00 # Fill pattern
fAuto = 0x00 # Automatic fill
icv = 0x08 # Line colour
lns = 0xff # Line style
lnw = 0x01 # Line weight
fAutoB = 0x00 # Automatic border
frs = 0x0000 # Frame style
cf = 0x0009 # Image format, 9 = bitmap
Reserved3 = 0x0000 # Reserved
cbPictFmla = 0x0000 # Length of FMLA structure
Reserved4 = 0x0000 # Reserved
grbit2 = 0x0001 # Option flags
Reserved5 = 0x0000 # Reserved
data = pack("<L", cObj)
data += pack("<H", OT)
data += pack("<H", id)
data += pack("<H", grbit)
data += pack("<H", colL)
data += pack("<H", dxL)
data += pack("<H", rwT)
data += pack("<H", dyT)
data += pack("<H", colR)
data += pack("<H", dxR)
data += pack("<H", rwB)
data += pack("<H", dyB)
data += pack("<H", cbMacro)
data += pack("<L", Reserved1)
data += pack("<H", Reserved2)
data += pack("<B", icvBack)
data += pack("<B", icvFore)
data += pack("<B", fls)
data += pack("<B", fAuto)
data += pack("<B", icv)
data += pack("<B", lns)
data += pack("<B", lnw)
data += pack("<B", fAutoB)
data += pack("<H", frs)
data += pack("<L", cf)
data += pack("<H", Reserved3)
data += pack("<H", cbPictFmla)
data += pack("<H", Reserved4)
data += pack("<H", grbit2)
data += pack("<L", Reserved5)
self._rec_data = data
def _process_bitmap(bitmap):
"""Convert a 24 bit bitmap into the modified internal format used by Windows.
This is described in BITMAPCOREHEADER and BITMAPCOREINFO structures in the
MSDN library.
"""
# Open file and binmode the data in case the platform needs it.
fh = file(bitmap, "rb")
try:
# Slurp the file into a string.
data = fh.read()
finally:
fh.close()
# Check that the file is big enough to be a bitmap.
if len(data) <= 0x36:
raise Exception("bitmap doesn't contain enough data.")
# The first 2 bytes are used to identify the bitmap.
if (data[:2] != "BM"):
raise Exception("bitmap doesn't appear to to be a valid bitmap image.")
# Remove bitmap data: ID.
data = data[2:]
# Read and remove the bitmap size. This is more reliable than reading
# the data size at offset 0x22.
#
size = unpack("<L", data[:4])[0]
size -= 0x36 # Subtract size of bitmap header.
size += 0x0C # Add size of BIFF header.
data = data[4:]
# Remove bitmap data: reserved, offset, header length.
data = data[12:]
# Read and remove the bitmap width and height. Verify the sizes.
width, height = unpack("<LL", data[:8])
data = data[8:]
if (width > 0xFFFF):
raise Exception("bitmap: largest image width supported is 65k.")
if (height > 0xFFFF):
raise Exception("bitmap: largest image height supported is 65k.")
# Read and remove the bitmap planes and bpp data. Verify them.
planes, bitcount = unpack("<HH", data[:4])
data = data[4:]
if (bitcount != 24):
raise Exception("bitmap isn't a 24bit true color bitmap.")
if (planes != 1):
raise Exception("bitmap: only 1 plane supported in bitmap image.")
# Read and remove the bitmap compression. Verify compression.
compression = unpack("<L", data[:4])[0]
data = data[4:]
if (compression != 0):
raise Exception("bitmap: compression not supported in bitmap image.")
# Remove bitmap data: data size, hres, vres, colours, imp. colours.
data = data[20:]
# Add the BITMAPCOREHEADER data
header = pack("<LHHHH", 0x000c, width, height, 0x01, 0x18)
data = header + data
return (width, height, size, data)
class ImDataBmpRecord(BiffRecord):
_REC_ID = 0x007F
def __init__(self, filename):
"""Insert a 24bit bitmap image in a worksheet. The main record required is
IMDATA but it must be proceeded by a OBJ record to define its position.
"""
BiffRecord.__init__(self)
self.width, self.height, self.size, data = _process_bitmap(filename)
# Write the IMDATA record to store the bitmap data
cf = 0x09
env = 0x01
lcb = self.size
self._rec_data = pack("<HHL", cf, env, lcb) + data
-243
View File
@@ -1,243 +0,0 @@
# -*- coding: windows-1252 -*-
from struct import unpack, pack
import BIFFRecords
class StrCell(object):
__slots__ = ["rowx", "colx", "xf_idx", "sst_idx"]
def __init__(self, rowx, colx, xf_idx, sst_idx):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
self.sst_idx = sst_idx
def get_biff_data(self):
# return BIFFRecords.LabelSSTRecord(self.rowx, self.colx, self.xf_idx, self.sst_idx).get()
return pack('<5HL', 0x00FD, 10, self.rowx, self.colx, self.xf_idx, self.sst_idx)
class BlankCell(object):
__slots__ = ["rowx", "colx", "xf_idx"]
def __init__(self, rowx, colx, xf_idx):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
def get_biff_data(self):
# return BIFFRecords.BlankRecord(self.rowx, self.colx, self.xf_idx).get()
return pack('<5H', 0x0201, 6, self.rowx, self.colx, self.xf_idx)
class MulBlankCell(object):
__slots__ = ["rowx", "colx1", "colx2", "xf_idx"]
def __init__(self, rowx, colx1, colx2, xf_idx):
self.rowx = rowx
self.colx1 = colx1
self.colx2 = colx2
self.xf_idx = xf_idx
def get_biff_data(self):
return BIFFRecords.MulBlankRecord(self.rowx,
self.colx1, self.colx2, self.xf_idx).get()
class NumberCell(object):
__slots__ = ["rowx", "colx", "xf_idx", "number"]
def __init__(self, rowx, colx, xf_idx, number):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
self.number = float(number)
def get_encoded_data(self):
rk_encoded = 0
num = self.number
# The four possible kinds of RK encoding are *not* mutually exclusive.
# The 30-bit integer variety picks up the most.
# In the code below, the four varieties are checked in descending order
# of bangs per buck, or not at all.
# SJM 2007-10-01
if -0x20000000 <= num < 0x20000000: # fits in 30-bit *signed* int
inum = int(num)
if inum == num: # survives round-trip
# print "30-bit integer RK", inum, hex(inum)
rk_encoded = 2 | (inum << 2)
return 1, rk_encoded
temp = num * 100
if -0x20000000 <= temp < 0x20000000:
# That was step 1: the coded value will fit in
# a 30-bit signed integer.
itemp = int(round(temp, 0))
# That was step 2: "itemp" is the best candidate coded value.
# Now for step 3: simulate the decoding,
# to check for round-trip correctness.
if itemp / 100.0 == num:
# print "30-bit integer RK*100", itemp, hex(itemp)
rk_encoded = 3 | (itemp << 2)
return 1, rk_encoded
if 0: # Cost of extra pack+unpack not justified by tiny yield.
packed = pack('<d', num)
w01, w23 = unpack('<2i', packed)
if not w01 and not(w23 & 3):
# 34 lsb are 0
# print "float RK", w23, hex(w23)
return 1, w23
packed100 = pack('<d', temp)
w01, w23 = unpack('<2i', packed100)
if not w01 and not(w23 & 3):
# 34 lsb are 0
# print "float RK*100", w23, hex(w23)
return 1, w23 | 1
#print "Number"
#print
return 0, pack('<5Hd', 0x0203, 14, self.rowx, self.colx, self.xf_idx, num)
def get_biff_data(self):
isRK, value = self.get_encoded_data()
if isRK:
return pack('<5Hi', 0x27E, 10, self.rowx, self.colx, self.xf_idx, value)
return value # NUMBER record already packed
class BooleanCell(object):
__slots__ = ["rowx", "colx", "xf_idx", "number"]
def __init__(self, rowx, colx, xf_idx, number):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
self.number = number
def get_biff_data(self):
return BIFFRecords.BoolErrRecord(self.rowx,
self.colx, self.xf_idx, self.number, 0).get()
error_code_map = {
0x00: 0, # Intersection of two cell ranges is empty
0x07: 7, # Division by zero
0x0F: 15, # Wrong type of operand
0x17: 23, # Illegal or deleted cell reference
0x1D: 29, # Wrong function or range name
0x24: 36, # Value range overflow
0x2A: 42, # Argument or function not available
'#NULL!' : 0, # Intersection of two cell ranges is empty
'#DIV/0!': 7, # Division by zero
'#VALUE!': 36, # Wrong type of operand
'#REF!' : 23, # Illegal or deleted cell reference
'#NAME?' : 29, # Wrong function or range name
'#NUM!' : 36, # Value range overflow
'#N/A!' : 42, # Argument or function not available
}
class ErrorCell(object):
__slots__ = ["rowx", "colx", "xf_idx", "number"]
def __init__(self, rowx, colx, xf_idx, error_string_or_code):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
try:
self.number = error_code_map[error_string_or_code]
except KeyError:
raise Exception('Illegal error value (%r)' % error_string_or_code)
def get_biff_data(self):
return BIFFRecords.BoolErrRecord(self.rowx,
self.colx, self.xf_idx, self.number, 1).get()
class FormulaCell(object):
__slots__ = ["rowx", "colx", "xf_idx", "frmla", "calc_flags"]
def __init__(self, rowx, colx, xf_idx, frmla, calc_flags=0):
self.rowx = rowx
self.colx = colx
self.xf_idx = xf_idx
self.frmla = frmla
self.calc_flags = calc_flags
def get_biff_data(self):
return BIFFRecords.FormulaRecord(self.rowx,
self.colx, self.xf_idx, self.frmla.rpn(), self.calc_flags).get()
# module-level function for *internal* use by the Row module
def _get_cells_biff_data_mul(rowx, cell_items):
# Return the BIFF data for all cell records in the row.
# Adjacent BLANK|RK records are combined into MUL(BLANK|RK) records.
pieces = []
nitems = len(cell_items)
i = 0
while i < nitems:
icolx, icell = cell_items[i]
if isinstance(icell, NumberCell):
isRK, value = icell.get_encoded_data()
if not isRK:
pieces.append(value) # pre-packed NUMBER record
i += 1
continue
muldata = [(value, icell.xf_idx)]
target = NumberCell
elif isinstance(icell, BlankCell):
muldata = [icell.xf_idx]
target = BlankCell
else:
pieces.append(icell.get_biff_data())
i += 1
continue
lastcolx = icolx
j = i
packed_record = ''
for j in xrange(i+1, nitems):
jcolx, jcell = cell_items[j]
if jcolx != lastcolx + 1:
nexti = j
break
if not isinstance(jcell, target):
nexti = j
break
if target == NumberCell:
isRK, value = jcell.get_encoded_data()
if not isRK:
packed_record = value
nexti = j + 1
break
muldata.append((value, jcell.xf_idx))
else:
muldata.append(jcell.xf_idx)
lastcolx = jcolx
else:
nexti = j + 1
if target == NumberCell:
if lastcolx == icolx:
# RK record
value, xf_idx = muldata[0]
pieces.append(pack('<5Hi', 0x027E, 10, rowx, icolx, xf_idx, value))
else:
# MULRK record
nc = lastcolx - icolx + 1
pieces.append(pack('<4H', 0x00BD, 6 * nc + 6, rowx, icolx))
pieces.append(''.join([pack('<Hi', xf_idx, value) for value, xf_idx in muldata]))
pieces.append(pack('<H', lastcolx))
else:
if lastcolx == icolx:
# BLANK record
xf_idx = muldata[0]
pieces.append(pack('<5H', 0x0201, 6, rowx, icolx, xf_idx))
else:
# MULBLANK record
nc = lastcolx - icolx + 1
pieces.append(pack('<4H', 0x00BE, 2 * nc + 6, rowx, icolx))
pieces.append(''.join([pack('<H', xf_idx) for xf_idx in muldata]))
pieces.append(pack('<H', lastcolx))
if packed_record:
pieces.append(packed_record)
i = nexti
return ''.join(pieces)
-34
View File
@@ -1,34 +0,0 @@
# -*- coding: windows-1252 -*-
from BIFFRecords import ColInfoRecord
class Column(object):
def __init__(self, colx, parent_sheet):
if not(isinstance(colx, int) and 0 <= colx <= 255):
raise ValueError("column index (%r) not an int in range(256)" % colx)
self._index = colx
self._parent = parent_sheet
self._parent_wb = parent_sheet.get_parent()
self._xf_index = 0x0F
self.width = 0x0B92
self.hidden = 0
self.level = 0
self.collapse = 0
def set_style(self, style):
self._xf_index = self._parent_wb.add_style(style)
def width_in_pixels(self):
# *** Approximation ****
return int(round(self.width * 0.0272 + 0.446, 0))
def get_biff_record(self):
options = (self.hidden & 0x01) << 0
options |= (self.level & 0x07) << 8
options |= (self.collapse & 0x01) << 12
return ColInfoRecord(self._index, self._index, self.width, self._xf_index, options).get()
-516
View File
@@ -1,516 +0,0 @@
# -*- coding: windows-1252 -*-
import sys
import struct
class Reader:
def __init__(self, filename, dump = False):
self.dump = dump
self.STREAMS = {}
doc = file(filename, 'rb').read()
self.header, self.data = doc[0:512], doc[512:]
del doc
self.__build_header()
self.__build_MSAT()
self.__build_SAT()
self.__build_directory()
self.__build_short_sectors_data()
if len(self.short_sectors_data) > 0:
self.__build_SSAT()
else:
if self.dump and (self.total_ssat_sectors != 0 or self.ssat_start_sid != -2):
print 'NOTE: header says that must be', self.total_ssat_sectors, 'short sectors'
print 'NOTE: starting at', self.ssat_start_sid, 'sector'
print 'NOTE: but file does not contains data in short sectors'
self.ssat_start_sid = -2
self.total_ssat_sectors = 0
self.SSAT = [-2]
for dentry in self.dir_entry_list[1:]:
(did,
sz, name,
t, c,
did_left, did_right, did_root,
dentry_start_sid,
stream_size
) = dentry
stream_data = ''
if stream_size > 0:
if stream_size >= self.min_stream_size:
args = (self.data, self.SAT, dentry_start_sid, self.sect_size)
else:
args = (self.short_sectors_data, self.SSAT, dentry_start_sid, self.short_sect_size)
stream_data = self.get_stream_data(*args)
if name != '':
# BAD IDEA: names may be equal. NEED use full paths...
self.STREAMS[name] = stream_data
def __build_header(self):
self.doc_magic = self.header[0:8]
if self.doc_magic != '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1':
raise Exception, 'Not an OLE file.'
self.file_uid = self.header[8:24]
self.rev_num = self.header[24:26]
self.ver_num = self.header[26:28]
self.byte_order = self.header[28:30]
self.log2_sect_size, = struct.unpack('<H', self.header[30:32])
self.log2_short_sect_size, = struct.unpack('<H', self.header[32:34])
self.total_sat_sectors, = struct.unpack('<L', self.header[44:48])
self.dir_start_sid, = struct.unpack('<l', self.header[48:52])
self.min_stream_size, = struct.unpack('<L', self.header[56:60])
self.ssat_start_sid, = struct.unpack('<l', self.header[60:64])
self.total_ssat_sectors, = struct.unpack('<L', self.header[64:68])
self.msat_start_sid, = struct.unpack('<l', self.header[68:72])
self.total_msat_sectors, = struct.unpack('<L', self.header[72:76])
self.sect_size = 1 << self.log2_sect_size
self.short_sect_size = 1 << self.log2_short_sect_size
if self.dump:
print 'file magic: '
print_bin_data(self.doc_magic)
print 'file uid: '
print_bin_data(self.file_uid)
print 'revision number: '
print_bin_data(self.rev_num)
print 'version number: '
print_bin_data(self.ver_num)
print 'byte order: '
print_bin_data(self.byte_order)
print 'sector size :', hex(self.sect_size), self.sect_size
#print 'total sectors in file :', hex(self.total_sectors), self.total_sectors
print 'short sector size :', hex(self.short_sect_size), self.short_sect_size
print 'Total number of sectors used for the SAT :', hex(self.total_sat_sectors), self.total_sat_sectors
print 'SID of first sector of the directory stream:', hex(self.dir_start_sid), self.dir_start_sid
print 'Minimum size of a standard stream :', hex(self.min_stream_size), self.min_stream_size
print 'SID of first sector of the SSAT :', hex(self.ssat_start_sid), self.ssat_start_sid
print 'Total number of sectors used for the SSAT :', hex(self.total_ssat_sectors), self.total_ssat_sectors
print 'SID of first additional sector of the MSAT :', hex(self.msat_start_sid), self.msat_start_sid
print 'Total number of sectors used for the MSAT :', hex(self.total_msat_sectors), self.total_msat_sectors
def __build_MSAT(self):
self.MSAT = list(struct.unpack('<109l', self.header[76:]))
next = self.msat_start_sid
while next > 0:
msat_sector = struct.unpack('<128l', self.data[next*self.sect_size:(next+1)*self.sect_size])
self.MSAT.extend(msat_sector[:127])
next = msat_sector[-1]
if self.dump:
print 'MSAT (header part): \n', self.MSAT[:109]
print 'additional MSAT sectors: \n', self.MSAT[109:]
def __build_SAT(self):
sat_stream = ''.join([self.data[i*self.sect_size:(i+1)*self.sect_size] for i in self.MSAT if i >= 0])
sat_sids_count = len(sat_stream) >> 2
self.SAT = struct.unpack('<%dl' % sat_sids_count, sat_stream) # SIDs tuple
if self.dump:
print 'SAT sid count:\n', sat_sids_count
print 'SAT content:\n', self.SAT
def __build_SSAT(self):
ssat_stream = self.get_stream_data(self.data, self.SAT, self.ssat_start_sid, self.sect_size)
ssids_count = len(ssat_stream) >> 2
self.SSAT = struct.unpack('<%dl' % ssids_count, ssat_stream)
if self.dump:
print 'SSID count:', ssids_count
print 'SSAT content:\n', self.SSAT
def __build_directory(self):
dir_stream = self.get_stream_data(self.data, self.SAT, self.dir_start_sid, self.sect_size)
self.dir_entry_list = []
i = 0
while i < len(dir_stream):
dentry = dir_stream[i:i+128] # 128 -- dir entry size
i += 128
did = len(self.dir_entry_list)
sz, = struct.unpack('<H', dentry[64:66])
if sz > 0 :
name = dentry[0:sz-2].decode('utf_16_le', 'replace')
else:
name = u''
t, = struct.unpack('B', dentry[66])
c, = struct.unpack('B', dentry[67])
did_left , = struct.unpack('<l', dentry[68:72])
did_right , = struct.unpack('<l', dentry[72:76])
did_root , = struct.unpack('<l', dentry[76:80])
dentry_start_sid , = struct.unpack('<l', dentry[116:120])
stream_size , = struct.unpack('<L', dentry[120:124])
self.dir_entry_list.extend([(did, sz, name, t, c,
did_left, did_right, did_root,
dentry_start_sid, stream_size)])
if self.dump:
dentry_types = {
0x00: 'Empty',
0x01: 'User storage',
0x02: 'User stream',
0x03: 'LockBytes',
0x04: 'Property',
0x05: 'Root storage'
}
node_colours = {
0x00: 'Red',
0x01: 'Black'
}
print 'total directory entries:', len(self.dir_entry_list)
for dentry in self.dir_entry_list:
(did, sz, name, t, c,
did_left, did_right, did_root,
dentry_start_sid, stream_size) = dentry
print 'DID', did
print 'Size of the used area of the character buffer of the name:', sz
print 'dir entry name:', repr(name)
print 'type of entry:', t, dentry_types[t]
print 'entry colour:', c, node_colours[c]
print 'left child DID :', did_left
print 'right child DID:', did_right
print 'root DID :', did_root
print 'start SID :', dentry_start_sid
print 'stream size :', stream_size
if stream_size == 0:
print 'stream is empty'
elif stream_size >= self.min_stream_size:
print 'stream stored as normal stream'
else:
print 'stream stored as short-stream'
def __build_short_sectors_data(self):
(did, sz, name, t, c,
did_left, did_right, did_root,
dentry_start_sid, stream_size) = self.dir_entry_list[0]
assert t == 0x05 # Short-Stream Container Stream (SSCS) resides in Root Storage
if stream_size == 0:
self.short_sectors_data = ''
else:
self.short_sectors_data = self.get_stream_data(self.data, self.SAT, dentry_start_sid, self.sect_size)
def get_stream_data(self, data, SAT, start_sid, sect_size):
sid = start_sid
chunks = [(sid, sid)]
stream_data = ''
while SAT[sid] >= 0:
next_in_chain = SAT[sid]
last_chunk_start, last_chunk_finish = chunks[-1]
if next_in_chain == last_chunk_finish + 1:
chunks[-1] = last_chunk_start, next_in_chain
else:
chunks.extend([(next_in_chain, next_in_chain)])
sid = next_in_chain
for s, f in chunks:
stream_data += data[s*sect_size:(f+1)*sect_size]
#print chunks
return stream_data
def print_bin_data(data):
i = 0
while i < len(data):
j = 0
while (i < len(data)) and (j < 16):
c = '0x%02X' % ord(data[i])
sys.stdout.write(c)
sys.stdout.write(' ')
i += 1
j += 1
print
if i == 0:
print '<NO DATA>'
# This implementation writes only 'Root Entry', 'Workbook' streams
# and 2 empty streams for aligning directory stream on sector boundary
#
# LAYOUT:
# 0 header
# 76 MSAT (1st part: 109 SID)
# 512 workbook stream
# ... additional MSAT sectors if streams' size > about 7 Mb == (109*512 * 128)
# ... SAT
# ... directory stream
#
# NOTE: this layout is "ad hoc". It can be more general. RTFM
class XlsDoc:
SECTOR_SIZE = 0x0200
MIN_LIMIT = 0x1000
SID_FREE_SECTOR = -1
SID_END_OF_CHAIN = -2
SID_USED_BY_SAT = -3
SID_USED_BY_MSAT = -4
def __init__(self):
#self.book_stream = '' # padded
self.book_stream_sect = []
self.dir_stream = ''
self.dir_stream_sect = []
self.packed_SAT = ''
self.SAT_sect = []
self.packed_MSAT_1st = ''
self.packed_MSAT_2nd = ''
self.MSAT_sect_2nd = []
self.header = ''
def __build_directory(self): # align on sector boundary
self.dir_stream = ''
dentry_name = '\x00'.join('Root Entry\x00') + '\x00'
dentry_name_sz = len(dentry_name)
dentry_name_pad = '\x00'*(64 - dentry_name_sz)
dentry_type = 0x05 # root storage
dentry_colour = 0x01 # black
dentry_did_left = -1
dentry_did_right = -1
dentry_did_root = 1
dentry_start_sid = -2
dentry_stream_sz = 0
self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
dentry_name + dentry_name_pad,
dentry_name_sz,
dentry_type,
dentry_colour,
dentry_did_left,
dentry_did_right,
dentry_did_root,
0, 0, 0, 0, 0, 0, 0, 0, 0,
dentry_start_sid,
dentry_stream_sz,
0
)
dentry_name = '\x00'.join('Workbook\x00') + '\x00'
dentry_name_sz = len(dentry_name)
dentry_name_pad = '\x00'*(64 - dentry_name_sz)
dentry_type = 0x02 # user stream
dentry_colour = 0x01 # black
dentry_did_left = -1
dentry_did_right = -1
dentry_did_root = -1
dentry_start_sid = 0
dentry_stream_sz = self.book_stream_len
self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
dentry_name + dentry_name_pad,
dentry_name_sz,
dentry_type,
dentry_colour,
dentry_did_left,
dentry_did_right,
dentry_did_root,
0, 0, 0, 0, 0, 0, 0, 0, 0,
dentry_start_sid,
dentry_stream_sz,
0
)
# padding
dentry_name = ''
dentry_name_sz = len(dentry_name)
dentry_name_pad = '\x00'*(64 - dentry_name_sz)
dentry_type = 0x00 # empty
dentry_colour = 0x01 # black
dentry_did_left = -1
dentry_did_right = -1
dentry_did_root = -1
dentry_start_sid = -2
dentry_stream_sz = 0
self.dir_stream += struct.pack('<64s H 2B 3l 9L l L L',
dentry_name + dentry_name_pad,
dentry_name_sz,
dentry_type,
dentry_colour,
dentry_did_left,
dentry_did_right,
dentry_did_root,
0, 0, 0, 0, 0, 0, 0, 0, 0,
dentry_start_sid,
dentry_stream_sz,
0
) * 2
def __build_sat(self):
# Build SAT
book_sect_count = self.book_stream_len >> 9
dir_sect_count = len(self.dir_stream) >> 9
total_sect_count = book_sect_count + dir_sect_count
SAT_sect_count = 0
MSAT_sect_count = 0
SAT_sect_count_limit = 109
while total_sect_count > 128*SAT_sect_count or SAT_sect_count > SAT_sect_count_limit:
SAT_sect_count += 1
total_sect_count += 1
if SAT_sect_count > SAT_sect_count_limit:
MSAT_sect_count += 1
total_sect_count += 1
SAT_sect_count_limit += 127
SAT = [self.SID_FREE_SECTOR]*128*SAT_sect_count
sect = 0
while sect < book_sect_count - 1:
self.book_stream_sect.append(sect)
SAT[sect] = sect + 1
sect += 1
self.book_stream_sect.append(sect)
SAT[sect] = self.SID_END_OF_CHAIN
sect += 1
while sect < book_sect_count + MSAT_sect_count:
self.MSAT_sect_2nd.append(sect)
SAT[sect] = self.SID_USED_BY_MSAT
sect += 1
while sect < book_sect_count + MSAT_sect_count + SAT_sect_count:
self.SAT_sect.append(sect)
SAT[sect] = self.SID_USED_BY_SAT
sect += 1
while sect < book_sect_count + MSAT_sect_count + SAT_sect_count + dir_sect_count - 1:
self.dir_stream_sect.append(sect)
SAT[sect] = sect + 1
sect += 1
self.dir_stream_sect.append(sect)
SAT[sect] = self.SID_END_OF_CHAIN
sect += 1
self.packed_SAT = struct.pack('<%dl' % (SAT_sect_count*128), *SAT)
MSAT_1st = [self.SID_FREE_SECTOR]*109
for i, SAT_sect_num in zip(range(0, 109), self.SAT_sect):
MSAT_1st[i] = SAT_sect_num
self.packed_MSAT_1st = struct.pack('<109l', *MSAT_1st)
MSAT_2nd = [self.SID_FREE_SECTOR]*128*MSAT_sect_count
if MSAT_sect_count > 0:
MSAT_2nd[- 1] = self.SID_END_OF_CHAIN
i = 109
msat_sect = 0
sid_num = 0
while i < SAT_sect_count:
if (sid_num + 1) % 128 == 0:
#print 'link: ',
msat_sect += 1
if msat_sect < len(self.MSAT_sect_2nd):
MSAT_2nd[sid_num] = self.MSAT_sect_2nd[msat_sect]
else:
#print 'sid: ',
MSAT_2nd[sid_num] = self.SAT_sect[i]
i += 1
#print sid_num, MSAT_2nd[sid_num]
sid_num += 1
self.packed_MSAT_2nd = struct.pack('<%dl' % (MSAT_sect_count*128), *MSAT_2nd)
#print vars()
#print zip(range(0, sect), SAT)
#print self.book_stream_sect
#print self.MSAT_sect_2nd
#print MSAT_2nd
#print self.SAT_sect
#print self.dir_stream_sect
def __build_header(self):
doc_magic = '\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1'
file_uid = '\x00'*16
rev_num = '\x3E\x00'
ver_num = '\x03\x00'
byte_order = '\xFE\xFF'
log_sect_size = struct.pack('<H', 9)
log_short_sect_size = struct.pack('<H', 6)
not_used0 = '\x00'*10
total_sat_sectors = struct.pack('<L', len(self.SAT_sect))
dir_start_sid = struct.pack('<l', self.dir_stream_sect[0])
not_used1 = '\x00'*4
min_stream_size = struct.pack('<L', 0x1000)
ssat_start_sid = struct.pack('<l', -2)
total_ssat_sectors = struct.pack('<L', 0)
if len(self.MSAT_sect_2nd) == 0:
msat_start_sid = struct.pack('<l', -2)
else:
msat_start_sid = struct.pack('<l', self.MSAT_sect_2nd[0])
total_msat_sectors = struct.pack('<L', len(self.MSAT_sect_2nd))
self.header = ''.join([ doc_magic,
file_uid,
rev_num,
ver_num,
byte_order,
log_sect_size,
log_short_sect_size,
not_used0,
total_sat_sectors,
dir_start_sid,
not_used1,
min_stream_size,
ssat_start_sid,
total_ssat_sectors,
msat_start_sid,
total_msat_sectors
])
def save(self, file_name_or_filelike_obj, stream):
# 1. Align stream on 0x1000 boundary (and therefore on sector boundary)
padding = '\x00' * (0x1000 - (len(stream) % 0x1000))
self.book_stream_len = len(stream) + len(padding)
self.__build_directory()
self.__build_sat()
self.__build_header()
f = file_name_or_filelike_obj
we_own_it = not hasattr(f, 'write')
if we_own_it:
f = open(file_name_or_filelike_obj, 'wb')
f.write(self.header)
f.write(self.packed_MSAT_1st)
f.write(stream)
f.write(padding)
f.write(self.packed_MSAT_2nd)
f.write(self.packed_SAT)
f.write(self.dir_stream)
if we_own_it:
f.close()
-43
View File
@@ -1,43 +0,0 @@
# -*- coding: windows-1252 -*-
import ExcelFormulaParser, ExcelFormulaLexer
import struct
from antlr import ANTLRException
class Formula(object):
__slots__ = ["__init__", "__s", "__parser", "__sheet_refs", "__xcall_refs"]
def __init__(self, s):
try:
self.__s = s
lexer = ExcelFormulaLexer.Lexer(s)
self.__parser = ExcelFormulaParser.Parser(lexer)
self.__parser.formula()
self.__sheet_refs = self.__parser.sheet_references
self.__xcall_refs = self.__parser.xcall_references
except ANTLRException, e:
# print e
raise ExcelFormulaParser.FormulaParseException, "can't parse formula " + s
def get_references(self):
return self.__sheet_refs, self.__xcall_refs
def patch_references(self, patches):
for offset, idx in patches:
self.__parser.rpn = self.__parser.rpn[:offset] + struct.pack('<H', idx) + self.__parser.rpn[offset+2:]
def text(self):
return self.__s
def rpn(self):
'''
Offset Size Contents
0 2 Size of the following formula data (sz)
2 sz Formula data (RPN token array)
[2+sz] var. (optional) Additional data for specific tokens
'''
return struct.pack("<H", len(self.__parser.rpn)) + self.__parser.rpn
-128
View File
@@ -1,128 +0,0 @@
# -*- coding: windows-1252 -*-
import sys
from antlr import EOF, CommonToken as Tok, TokenStream, TokenStreamException
import struct
import ExcelFormulaParser
from re import compile as recompile, match, LOCALE, UNICODE, IGNORECASE, VERBOSE
int_const_pattern = r"\d+\b"
flt_const_pattern = r"""
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \. ) # 1. 12. 123. etc
)
# followed by optional exponent part
(?: [Ee] [+-]? \d+ ) ?
"""
str_const_pattern = r'"(?:[^"]|"")*"'
#range2d_pattern = recompile(r"\$?[A-I]?[A-Z]\$?\d+:\$?[A-I]?[A-Z]\$?\d+"
ref2d_r1c1_pattern = r"[Rr]0*[1-9][0-9]*[Cc]0*[1-9][0-9]*"
ref2d_pattern = r"\$?[A-I]?[A-Z]\$?0*[1-9][0-9]*"
true_pattern = r"TRUE\b"
false_pattern = r"FALSE\b"
if_pattern = r"IF\b"
choose_pattern = r"CHOOSE\b"
name_pattern = r"\w[\.\w]*"
quotename_pattern = r"'(?:[^']|'')*'" #### It's essential that this bracket be non-grouping.
ne_pattern = r"<>"
ge_pattern = r">="
le_pattern = r"<="
pattern_type_tuples = (
(flt_const_pattern, ExcelFormulaParser.NUM_CONST),
(int_const_pattern, ExcelFormulaParser.INT_CONST),
(str_const_pattern, ExcelFormulaParser.STR_CONST),
# (range2d_pattern , ExcelFormulaParser.RANGE2D),
(ref2d_r1c1_pattern, ExcelFormulaParser.REF2D_R1C1),
(ref2d_pattern , ExcelFormulaParser.REF2D),
(true_pattern , ExcelFormulaParser.TRUE_CONST),
(false_pattern , ExcelFormulaParser.FALSE_CONST),
(if_pattern , ExcelFormulaParser.FUNC_IF),
(choose_pattern , ExcelFormulaParser.FUNC_CHOOSE),
(name_pattern , ExcelFormulaParser.NAME),
(quotename_pattern, ExcelFormulaParser.QUOTENAME),
(ne_pattern, ExcelFormulaParser.NE),
(ge_pattern, ExcelFormulaParser.GE),
(le_pattern, ExcelFormulaParser.LE),
)
_re = recompile(
'(' + ')|('.join([i[0] for i in pattern_type_tuples]) + ')',
VERBOSE+LOCALE+IGNORECASE)
_toktype = [None] + [i[1] for i in pattern_type_tuples]
# need dummy at start because re.MatchObject.lastindex counts from 1
single_char_lookup = {
'=': ExcelFormulaParser.EQ,
'<': ExcelFormulaParser.LT,
'>': ExcelFormulaParser.GT,
'+': ExcelFormulaParser.ADD,
'-': ExcelFormulaParser.SUB,
'*': ExcelFormulaParser.MUL,
'/': ExcelFormulaParser.DIV,
':': ExcelFormulaParser.COLON,
';': ExcelFormulaParser.SEMICOLON,
',': ExcelFormulaParser.COMMA,
'(': ExcelFormulaParser.LP,
')': ExcelFormulaParser.RP,
'&': ExcelFormulaParser.CONCAT,
'%': ExcelFormulaParser.PERCENT,
'^': ExcelFormulaParser.POWER,
'!': ExcelFormulaParser.BANG,
}
class Lexer(TokenStream):
def __init__(self, text):
self._text = text[:]
self._pos = 0
self._line = 0
def isEOF(self):
return len(self._text) <= self._pos
def curr_ch(self):
return self._text[self._pos]
def next_ch(self, n = 1):
self._pos += n
def is_whitespace(self):
return self.curr_ch() in " \t\n\r\f\v"
def match_pattern(self):
m = _re.match(self._text, self._pos)
if not m:
return None
self._pos = m.end(0)
return Tok(type = _toktype[m.lastindex], text = m.group(0), col = m.start(0) + 1)
def nextToken(self):
# skip whitespace
while not self.isEOF() and self.is_whitespace():
self.next_ch()
if self.isEOF():
return Tok(type = EOF)
# first, try to match token with 2 or more chars
t = self.match_pattern()
if t:
return t
# second, we want 1-char tokens
te = self.curr_ch()
try:
ty = single_char_lookup[te]
except KeyError:
raise TokenStreamException(
"Unexpected char %r in column %u." % (self.curr_ch(), self._pos))
self.next_ch()
return Tok(type=ty, text=te, col=self._pos)
if __name__ == '__main__':
try:
for t in Lexer(""" 1.23 456 "abcd" R2C2 a1 iv65536 true false if choose a_name 'qname' <> >= <= """):
print t
except TokenStreamException, e:
print "error:", e
-677
View File
@@ -1,677 +0,0 @@
### $ANTLR 2.7.7 (20060930): "xlwt/excel-formula.g" -> "ExcelFormulaParser.py"$
### import antlr and other modules ..
import sys
import antlr
version = sys.version.split()[0]
if version < '2.2.1':
False = 0
if version < '2.3':
True = not False
### header action >>>
import struct
import Utils
from UnicodeUtils import upack1
from ExcelMagic import *
_RVAdelta = {"R": 0, "V": 0x20, "A": 0x40}
_RVAdeltaRef = {"R": 0, "V": 0x20, "A": 0x40, "D": 0x20}
_RVAdeltaArea = {"R": 0, "V": 0x20, "A": 0x40, "D": 0}
class FormulaParseException(Exception):
"""
An exception indicating that a Formula could not be successfully parsed.
"""
### header action <<<
### preamble action>>>
### preamble action <<<
### import antlr.Token
from antlr import Token
### >>>The Known Token Types <<<
SKIP = antlr.SKIP
INVALID_TYPE = antlr.INVALID_TYPE
EOF_TYPE = antlr.EOF_TYPE
EOF = antlr.EOF
NULL_TREE_LOOKAHEAD = antlr.NULL_TREE_LOOKAHEAD
MIN_USER_TYPE = antlr.MIN_USER_TYPE
TRUE_CONST = 4
FALSE_CONST = 5
STR_CONST = 6
NUM_CONST = 7
INT_CONST = 8
FUNC_IF = 9
FUNC_CHOOSE = 10
NAME = 11
QUOTENAME = 12
EQ = 13
NE = 14
GT = 15
LT = 16
GE = 17
LE = 18
ADD = 19
SUB = 20
MUL = 21
DIV = 22
POWER = 23
PERCENT = 24
LP = 25
RP = 26
LB = 27
RB = 28
COLON = 29
COMMA = 30
SEMICOLON = 31
REF2D = 32
REF2D_R1C1 = 33
BANG = 34
CONCAT = 35
class Parser(antlr.LLkParser):
### user action >>>
### user action <<<
def __init__(self, *args, **kwargs):
antlr.LLkParser.__init__(self, *args, **kwargs)
self.tokenNames = _tokenNames
### __init__ header action >>>
self.rpn = ""
self.sheet_references = []
self.xcall_references = []
### __init__ header action <<<
def formula(self):
pass
self.expr("V")
def expr(self,
arg_type
):
pass
self.prec0_expr(arg_type)
while True:
if ((self.LA(1) >= EQ and self.LA(1) <= LE)):
pass
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [EQ]:
pass
self.match(EQ)
op = struct.pack('B', ptgEQ)
elif la1 and la1 in [NE]:
pass
self.match(NE)
op = struct.pack('B', ptgNE)
elif la1 and la1 in [GT]:
pass
self.match(GT)
op = struct.pack('B', ptgGT)
elif la1 and la1 in [LT]:
pass
self.match(LT)
op = struct.pack('B', ptgLT)
elif la1 and la1 in [GE]:
pass
self.match(GE)
op = struct.pack('B', ptgGE)
elif la1 and la1 in [LE]:
pass
self.match(LE)
op = struct.pack('B', ptgLE)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.prec0_expr(arg_type)
self.rpn += op
else:
break
def prec0_expr(self,
arg_type
):
pass
self.prec1_expr(arg_type)
while True:
if (self.LA(1)==CONCAT):
pass
pass
self.match(CONCAT)
op = struct.pack('B', ptgConcat)
self.prec1_expr(arg_type)
self.rpn += op
else:
break
def prec1_expr(self,
arg_type
):
pass
self.prec2_expr(arg_type)
while True:
if (self.LA(1)==ADD or self.LA(1)==SUB):
pass
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [ADD]:
pass
self.match(ADD)
op = struct.pack('B', ptgAdd)
elif la1 and la1 in [SUB]:
pass
self.match(SUB)
op = struct.pack('B', ptgSub)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.prec2_expr(arg_type)
self.rpn += op;
# print "**prec1_expr4 %s" % arg_type
else:
break
def prec2_expr(self,
arg_type
):
pass
self.prec3_expr(arg_type)
while True:
if (self.LA(1)==MUL or self.LA(1)==DIV):
pass
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [MUL]:
pass
self.match(MUL)
op = struct.pack('B', ptgMul)
elif la1 and la1 in [DIV]:
pass
self.match(DIV)
op = struct.pack('B', ptgDiv)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.prec3_expr(arg_type)
self.rpn += op
else:
break
def prec3_expr(self,
arg_type
):
pass
self.prec4_expr(arg_type)
while True:
if (self.LA(1)==POWER):
pass
pass
self.match(POWER)
op = struct.pack('B', ptgPower)
self.prec4_expr(arg_type)
self.rpn += op
else:
break
def prec4_expr(self,
arg_type
):
pass
self.prec5_expr(arg_type)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [PERCENT]:
pass
self.match(PERCENT)
self.rpn += struct.pack('B', ptgPercent)
elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,RP,COMMA,SEMICOLON,CONCAT]:
pass
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
def prec5_expr(self,
arg_type
):
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,LP,REF2D]:
pass
self.primary(arg_type)
elif la1 and la1 in [SUB]:
pass
self.match(SUB)
self.primary(arg_type)
self.rpn += struct.pack('B', ptgUminus)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
def primary(self,
arg_type
):
str_tok = None
int_tok = None
num_tok = None
ref2d_tok = None
ref2d1_tok = None
ref2d2_tok = None
ref3d_ref2d = None
ref3d_ref2d2 = None
name_tok = None
func_tok = None
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [TRUE_CONST]:
pass
self.match(TRUE_CONST)
self.rpn += struct.pack("2B", ptgBool, 1)
elif la1 and la1 in [FALSE_CONST]:
pass
self.match(FALSE_CONST)
self.rpn += struct.pack("2B", ptgBool, 0)
elif la1 and la1 in [STR_CONST]:
pass
str_tok = self.LT(1)
self.match(STR_CONST)
self.rpn += struct.pack("B", ptgStr) + upack1(str_tok.text[1:-1].replace("\"\"", "\""))
elif la1 and la1 in [NUM_CONST]:
pass
num_tok = self.LT(1)
self.match(NUM_CONST)
self.rpn += struct.pack("<Bd", ptgNum, float(num_tok.text))
elif la1 and la1 in [FUNC_IF]:
pass
self.match(FUNC_IF)
self.match(LP)
self.expr("V")
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [SEMICOLON]:
pass
self.match(SEMICOLON)
elif la1 and la1 in [COMMA]:
pass
self.match(COMMA)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.rpn += struct.pack("<BBH", ptgAttr, 0x02, 0) # tAttrIf
pos0 = len(self.rpn) - 2
self.expr(arg_type)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [SEMICOLON]:
pass
self.match(SEMICOLON)
elif la1 and la1 in [COMMA]:
pass
self.match(COMMA)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 0) # tAttrSkip
pos1 = len(self.rpn) - 2
self.rpn = self.rpn[:pos0] + struct.pack("<H", pos1-pos0) + self.rpn[pos0+2:]
self.expr(arg_type)
self.match(RP)
self.rpn += struct.pack("<BBH", ptgAttr, 0x08, 3) # tAttrSkip
self.rpn += struct.pack("<BBH", ptgFuncVarR, 3, 1) # 3 = nargs, 1 = IF func
pos2 = len(self.rpn)
self.rpn = self.rpn[:pos1] + struct.pack("<H", pos2-(pos1+2)-1) + self.rpn[pos1+2:]
elif la1 and la1 in [FUNC_CHOOSE]:
pass
self.match(FUNC_CHOOSE)
arg_type = "R"
rpn_chunks = []
self.match(LP)
self.expr("V")
rpn_start = len(self.rpn)
ref_markers = [len(self.sheet_references)]
while True:
if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON):
pass
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [SEMICOLON]:
pass
self.match(SEMICOLON)
elif la1 and la1 in [COMMA]:
pass
self.match(COMMA)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
mark = len(self.rpn)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
pass
self.expr(arg_type)
elif la1 and la1 in [RP,COMMA,SEMICOLON]:
pass
self.rpn += struct.pack("B", ptgMissArg)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
rpn_chunks.append(self.rpn[mark:])
ref_markers.append(len(self.sheet_references))
else:
break
self.match(RP)
self.rpn = self.rpn[:rpn_start]
nc = len(rpn_chunks)
chunklens = [len(chunk) for chunk in rpn_chunks]
skiplens = [0] * nc
skiplens[-1] = 3
for ic in xrange(nc-1, 0, -1):
skiplens[ic-1] = skiplens[ic] + chunklens[ic] + 4
jump_pos = [2 * nc + 2]
for ic in xrange(nc):
jump_pos.append(jump_pos[-1] + chunklens[ic] + 4)
chunk_shift = 2 * nc + 6 # size of tAttrChoose
for ic in xrange(nc):
for refx in xrange(ref_markers[ic], ref_markers[ic+1]):
ref = self.sheet_references[refx]
self.sheet_references[refx] = (ref[0], ref[1], ref[2] + chunk_shift)
chunk_shift += 4 # size of tAttrSkip
choose_rpn = []
choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x04, nc)) # 0x04 is tAttrChoose
choose_rpn.append(struct.pack("<%dH" % (nc+1), *jump_pos))
for ic in xrange(nc):
choose_rpn.append(rpn_chunks[ic])
choose_rpn.append(struct.pack("<BBH", ptgAttr, 0x08, skiplens[ic])) # 0x08 is tAttrSkip
choose_rpn.append(struct.pack("<BBH", ptgFuncVarV, nc+1, 100)) # 100 is CHOOSE fn
self.rpn += "".join(choose_rpn)
elif la1 and la1 in [LP]:
pass
self.match(LP)
self.expr(arg_type)
self.match(RP)
self.rpn += struct.pack("B", ptgParen)
else:
if (self.LA(1)==INT_CONST) and (_tokenSet_0.member(self.LA(2))):
pass
int_tok = self.LT(1)
self.match(INT_CONST)
# print "**int_const", int_tok.text
int_value = int(int_tok.text)
if int_value <= 65535:
self.rpn += struct.pack("<BH", ptgInt, int_value)
else:
self.rpn += struct.pack("<Bd", ptgNum, float(int_value))
elif (self.LA(1)==REF2D) and (_tokenSet_0.member(self.LA(2))):
pass
ref2d_tok = self.LT(1)
self.match(REF2D)
# print "**ref2d %s %s" % (ref2d_tok.text, arg_type)
r, c = Utils.cell_to_packed_rowcol(ref2d_tok.text)
ptg = ptgRefR + _RVAdeltaRef[arg_type]
self.rpn += struct.pack("<B2H", ptg, r, c)
elif (self.LA(1)==REF2D) and (self.LA(2)==COLON):
pass
ref2d1_tok = self.LT(1)
self.match(REF2D)
self.match(COLON)
ref2d2_tok = self.LT(1)
self.match(REF2D)
r1, c1 = Utils.cell_to_packed_rowcol(ref2d1_tok.text)
r2, c2 = Utils.cell_to_packed_rowcol(ref2d2_tok.text)
ptg = ptgAreaR + _RVAdeltaArea[arg_type]
self.rpn += struct.pack("<B4H", ptg, r1, r2, c1, c2)
elif (self.LA(1)==INT_CONST or self.LA(1)==NAME or self.LA(1)==QUOTENAME) and (self.LA(2)==COLON or self.LA(2)==BANG):
pass
sheet1=self.sheet()
sheet2 = sheet1
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [COLON]:
pass
self.match(COLON)
sheet2=self.sheet()
elif la1 and la1 in [BANG]:
pass
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.match(BANG)
ref3d_ref2d = self.LT(1)
self.match(REF2D)
ptg = ptgRef3dR + _RVAdeltaRef[arg_type]
rpn_ref2d = ""
r1, c1 = Utils.cell_to_packed_rowcol(ref3d_ref2d.text)
rpn_ref2d = struct.pack("<3H", 0x0000, r1, c1)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [COLON]:
pass
self.match(COLON)
ref3d_ref2d2 = self.LT(1)
self.match(REF2D)
ptg = ptgArea3dR + _RVAdeltaArea[arg_type]
r2, c2 = Utils.cell_to_packed_rowcol(ref3d_ref2d2.text)
rpn_ref2d = struct.pack("<5H", 0x0000, r1, r2, c1, c2)
elif la1 and la1 in [EOF,EQ,NE,GT,LT,GE,LE,ADD,SUB,MUL,DIV,POWER,PERCENT,RP,COMMA,SEMICOLON,CONCAT]:
pass
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
self.rpn += struct.pack("<B", ptg)
self.sheet_references.append((sheet1, sheet2, len(self.rpn)))
self.rpn += rpn_ref2d
elif (self.LA(1)==NAME) and (_tokenSet_0.member(self.LA(2))):
pass
name_tok = self.LT(1)
self.match(NAME)
raise Exception("[formula] found unexpected NAME token (%r)" % name_tok.txt)
# #### TODO: handle references to defined names here
elif (self.LA(1)==NAME) and (self.LA(2)==LP):
pass
func_tok = self.LT(1)
self.match(NAME)
func_toku = func_tok.text.upper()
if func_toku in all_funcs_by_name:
(opcode,
min_argc,
max_argc,
func_type,
arg_type_str) = all_funcs_by_name[func_toku]
arg_type_list = list(arg_type_str)
else:
raise Exception("[formula] unknown function (%s)" % func_tok.text)
# print "**func_tok1 %s %s" % (func_toku, func_type)
xcall = opcode < 0
if xcall:
# The name of the add-in function is passed as the 1st arg
# of the hidden XCALL function
self.xcall_references.append((func_toku, len(self.rpn) + 1))
self.rpn += struct.pack("<BHHH",
ptgNameXR,
0xadde, # ##PATCHME## index to REF entry in EXTERNSHEET record
0xefbe, # ##PATCHME## one-based index to EXTERNNAME record
0x0000) # unused
self.match(LP)
arg_count=self.expr_list(arg_type_list, min_argc, max_argc)
self.match(RP)
if arg_count > max_argc or arg_count < min_argc:
raise Exception, "%d parameters for function: %s" % (arg_count, func_tok.text)
if xcall:
func_ptg = ptgFuncVarR + _RVAdelta[func_type]
self.rpn += struct.pack("<2BH", func_ptg, arg_count + 1, 255) # 255 is magic XCALL function
elif min_argc == max_argc:
func_ptg = ptgFuncR + _RVAdelta[func_type]
self.rpn += struct.pack("<BH", func_ptg, opcode)
elif arg_count == 1 and func_tok.text.upper() == "SUM":
self.rpn += struct.pack("<BBH", ptgAttr, 0x10, 0) # tAttrSum
else:
func_ptg = ptgFuncVarR + _RVAdelta[func_type]
self.rpn += struct.pack("<2BH", func_ptg, arg_count, opcode)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
def sheet(self):
ref = None
sheet_ref_name = None
sheet_ref_int = None
sheet_ref_quote = None
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [NAME]:
pass
sheet_ref_name = self.LT(1)
self.match(NAME)
ref = sheet_ref_name.text
elif la1 and la1 in [INT_CONST]:
pass
sheet_ref_int = self.LT(1)
self.match(INT_CONST)
ref = sheet_ref_int.text
elif la1 and la1 in [QUOTENAME]:
pass
sheet_ref_quote = self.LT(1)
self.match(QUOTENAME)
ref = sheet_ref_quote.text[1:-1].replace("''", "'")
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
return ref
def expr_list(self,
arg_type_list, min_argc, max_argc
):
arg_cnt = None
arg_cnt = 0
arg_type = arg_type_list[arg_cnt]
# print "**expr_list1[%d] req=%s" % (arg_cnt, arg_type)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
pass
self.expr(arg_type)
arg_cnt += 1
while True:
if (self.LA(1)==COMMA or self.LA(1)==SEMICOLON):
pass
if arg_cnt < len(arg_type_list):
arg_type = arg_type_list[arg_cnt]
else:
arg_type = arg_type_list[-1]
if arg_type == "+":
arg_type = arg_type_list[-2]
# print "**expr_list2[%d] req=%s" % (arg_cnt, arg_type)
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [SEMICOLON]:
pass
self.match(SEMICOLON)
elif la1 and la1 in [COMMA]:
pass
self.match(COMMA)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
la1 = self.LA(1)
if False:
pass
elif la1 and la1 in [TRUE_CONST,FALSE_CONST,STR_CONST,NUM_CONST,INT_CONST,FUNC_IF,FUNC_CHOOSE,NAME,QUOTENAME,SUB,LP,REF2D]:
pass
self.expr(arg_type)
elif la1 and la1 in [RP,COMMA,SEMICOLON]:
pass
self.rpn += struct.pack("B", ptgMissArg)
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
arg_cnt += 1
else:
break
elif la1 and la1 in [RP]:
pass
else:
raise antlr.NoViableAltException(self.LT(1), self.getFilename())
return arg_cnt
_tokenNames = [
"<0>",
"EOF",
"<2>",
"NULL_TREE_LOOKAHEAD",
"TRUE_CONST",
"FALSE_CONST",
"STR_CONST",
"NUM_CONST",
"INT_CONST",
"FUNC_IF",
"FUNC_CHOOSE",
"NAME",
"QUOTENAME",
"EQ",
"NE",
"GT",
"LT",
"GE",
"LE",
"ADD",
"SUB",
"MUL",
"DIV",
"POWER",
"PERCENT",
"LP",
"RP",
"LB",
"RB",
"COLON",
"COMMA",
"SEMICOLON",
"REF2D",
"REF2D_R1C1",
"BANG",
"CONCAT"
]
### generate bit set
def mk_tokenSet_0():
### var1
data = [ 37681618946L, 0L]
return data
_tokenSet_0 = antlr.BitSet(mk_tokenSet_0())
-862
View File
@@ -1,862 +0,0 @@
# -*- coding: ascii -*-
"""
lots of Excel Magic Numbers
"""
# Boundaries BIFF8+
MAX_ROW = 65536
MAX_COL = 256
biff_records = {
0x0000: "DIMENSIONS",
0x0001: "BLANK",
0x0002: "INTEGER",
0x0003: "NUMBER",
0x0004: "LABEL",
0x0005: "BOOLERR",
0x0006: "FORMULA",
0x0007: "STRING",
0x0008: "ROW",
0x0009: "BOF",
0x000A: "EOF",
0x000B: "INDEX",
0x000C: "CALCCOUNT",
0x000D: "CALCMODE",
0x000E: "PRECISION",
0x000F: "REFMODE",
0x0010: "DELTA",
0x0011: "ITERATION",
0x0012: "PROTECT",
0x0013: "PASSWORD",
0x0014: "HEADER",
0x0015: "FOOTER",
0x0016: "EXTERNCOUNT",
0x0017: "EXTERNSHEET",
0x0018: "NAME",
0x0019: "WINDOWPROTECT",
0x001A: "VERTICALPAGEBREAKS",
0x001B: "HORIZONTALPAGEBREAKS",
0x001C: "NOTE",
0x001D: "SELECTION",
0x001E: "FORMAT",
0x001F: "FORMATCOUNT",
0x0020: "COLUMNDEFAULT",
0x0021: "ARRAY",
0x0022: "1904",
0x0023: "EXTERNNAME",
0x0024: "COLWIDTH",
0x0025: "DEFAULTROWHEIGHT",
0x0026: "LEFTMARGIN",
0x0027: "RIGHTMARGIN",
0x0028: "TOPMARGIN",
0x0029: "BOTTOMMARGIN",
0x002A: "PRINTHEADERS",
0x002B: "PRINTGRIDLINES",
0x002F: "FILEPASS",
0x0031: "FONT",
0x0036: "TABLE",
0x003C: "CONTINUE",
0x003D: "WINDOW1",
0x003E: "WINDOW2",
0x0040: "BACKUP",
0x0041: "PANE",
0x0042: "CODEPAGE",
0x0043: "XF",
0x0044: "IXFE",
0x0045: "EFONT",
0x004D: "PLS",
0x0050: "DCON",
0x0051: "DCONREF",
0x0053: "DCONNAME",
0x0055: "DEFCOLWIDTH",
0x0056: "BUILTINFMTCNT",
0x0059: "XCT",
0x005A: "CRN",
0x005B: "FILESHARING",
0x005C: "WRITEACCESS",
0x005D: "OBJ",
0x005E: "UNCALCED",
0x005F: "SAFERECALC",
0x0060: "TEMPLATE",
0x0063: "OBJPROTECT",
0x007D: "COLINFO",
0x007E: "RK",
0x007F: "IMDATA",
0x0080: "GUTS",
0x0081: "WSBOOL",
0x0082: "GRIDSET",
0x0083: "HCENTER",
0x0084: "VCENTER",
0x0085: "BOUNDSHEET",
0x0086: "WRITEPROT",
0x0087: "ADDIN",
0x0088: "EDG",
0x0089: "PUB",
0x008C: "COUNTRY",
0x008D: "HIDEOBJ",
0x008E: "BUNDLESOFFSET",
0x008F: "BUNDLEHEADER",
0x0090: "SORT",
0x0091: "SUB",
0x0092: "PALETTE",
0x0093: "STYLE",
0x0094: "LHRECORD",
0x0095: "LHNGRAPH",
0x0096: "SOUND",
0x0098: "LPR",
0x0099: "STANDARDWIDTH",
0x009A: "FNGROUPNAME",
0x009B: "FILTERMODE",
0x009C: "FNGROUPCOUNT",
0x009D: "AUTOFILTERINFO",
0x009E: "AUTOFILTER",
0x00A0: "SCL",
0x00A1: "SETUP",
0x00A9: "COORDLIST",
0x00AB: "GCW",
0x00AE: "SCENMAN",
0x00AF: "SCENARIO",
0x00B0: "SXVIEW",
0x00B1: "SXVD",
0x00B2: "SXVI",
0x00B4: "SXIVD",
0x00B5: "SXLI",
0x00B6: "SXPI",
0x00B8: "DOCROUTE",
0x00B9: "RECIPNAME",
0x00BC: "SHRFMLA",
0x00BD: "MULRK",
0x00BE: "MULBLANK",
0x00C1: "MMS",
0x00C2: "ADDMENU",
0x00C3: "DELMENU",
0x00C5: "SXDI",
0x00C6: "SXDB",
0x00C7: "SXFIELD",
0x00C8: "SXINDEXLIST",
0x00C9: "SXDOUBLE",
0x00CD: "SXSTRING",
0x00CE: "SXDATETIME",
0x00D0: "SXTBL",
0x00D1: "SXTBRGITEM",
0x00D2: "SXTBPG",
0x00D3: "OBPROJ",
0x00D5: "SXIDSTM",
0x00D6: "RSTRING",
0x00D7: "DBCELL",
0x00DA: "BOOKBOOL",
0x00DC: "SXEXT|PARAMQRY",
0x00DD: "SCENPROTECT",
0x00DE: "OLESIZE",
0x00DF: "UDDESC",
0x00E0: "XF",
0x00E1: "INTERFACEHDR",
0x00E2: "INTERFACEEND",
0x00E3: "SXVS",
0x00E5: "MERGEDCELLS",
0x00E9: "BITMAP",
0x00EB: "MSODRAWINGGROUP",
0x00EC: "MSODRAWING",
0x00ED: "MSODRAWINGSELECTION",
0x00F0: "SXRULE",
0x00F1: "SXEX",
0x00F2: "SXFILT",
0x00F6: "SXNAME",
0x00F7: "SXSELECT",
0x00F8: "SXPAIR",
0x00F9: "SXFMLA",
0x00FB: "SXFORMAT",
0x00FC: "SST",
0x00FD: "LABELSST",
0x00FF: "EXTSST",
0x0100: "SXVDEX",
0x0103: "SXFORMULA",
0x0122: "SXDBEX",
0x0137: "CHTRINSERT",
0x0138: "CHTRINFO",
0x013B: "CHTRCELLCONTENT",
0x013D: "TABID",
0x0140: "CHTRMOVERANGE",
0x014D: "CHTRINSERTTAB",
0x015F: "LABELRANGES",
0x0160: "USESELFS",
0x0161: "DSF",
0x0162: "XL5MODIFY",
0x0196: "CHTRHEADER",
0x01A9: "USERBVIEW",
0x01AA: "USERSVIEWBEGIN",
0x01AB: "USERSVIEWEND",
0x01AD: "QSI",
0x01AE: "SUPBOOK",
0x01AF: "PROT4REV",
0x01B0: "CONDFMT",
0x01B1: "CF",
0x01B2: "DVAL",
0x01B5: "DCONBIN",
0x01B6: "TXO",
0x01B7: "REFRESHALL",
0x01B8: "HLINK",
0x01BA: "CODENAME",
0x01BB: "SXFDBTYPE",
0x01BC: "PROT4REVPASS",
0x01BE: "DV",
0x01C0: "XL9FILE",
0x01C1: "RECALCID",
0x0200: "DIMENSIONS",
0x0201: "BLANK",
0x0203: "NUMBER",
0x0204: "LABEL",
0x0205: "BOOLERR",
0x0206: "FORMULA",
0x0207: "STRING",
0x0208: "ROW",
0x0209: "BOF",
0x020B: "INDEX",
0x0218: "NAME",
0x0221: "ARRAY",
0x0223: "EXTERNNAME",
0x0225: "DEFAULTROWHEIGHT",
0x0231: "FONT",
0x0236: "TABLE",
0x023E: "WINDOW2",
0x0243: "XF",
0x027E: "RK",
0x0293: "STYLE",
0x0406: "FORMULA",
0x0409: "BOF",
0x041E: "FORMAT",
0x0443: "XF",
0x04BC: "SHRFMLA",
0x0800: "SCREENTIP",
0x0803: "WEBQRYSETTINGS",
0x0804: "WEBQRYTABLES",
0x0809: "BOF",
0x0862: "SHEETLAYOUT",
0x0867: "SHEETPROTECTION",
0x1001: "UNITS",
0x1002: "ChartChart",
0x1003: "ChartSeries",
0x1006: "ChartDataformat",
0x1007: "ChartLineformat",
0x1009: "ChartMarkerformat",
0x100A: "ChartAreaformat",
0x100B: "ChartPieformat",
0x100C: "ChartAttachedlabel",
0x100D: "ChartSeriestext",
0x1014: "ChartChartformat",
0x1015: "ChartLegend",
0x1016: "ChartSerieslist",
0x1017: "ChartBar",
0x1018: "ChartLine",
0x1019: "ChartPie",
0x101A: "ChartArea",
0x101B: "ChartScatter",
0x101C: "ChartChartline",
0x101D: "ChartAxis",
0x101E: "ChartTick",
0x101F: "ChartValuerange",
0x1020: "ChartCatserrange",
0x1021: "ChartAxislineformat",
0x1022: "ChartFormatlink",
0x1024: "ChartDefaulttext",
0x1025: "ChartText",
0x1026: "ChartFontx",
0x1027: "ChartObjectLink",
0x1032: "ChartFrame",
0x1033: "BEGIN",
0x1034: "END",
0x1035: "ChartPlotarea",
0x103A: "Chart3D",
0x103C: "ChartPicf",
0x103D: "ChartDropbar",
0x103E: "ChartRadar",
0x103F: "ChartSurface",
0x1040: "ChartRadararea",
0x1041: "ChartAxisparent",
0x1043: "ChartLegendxn",
0x1044: "ChartShtprops",
0x1045: "ChartSertocrt",
0x1046: "ChartAxesused",
0x1048: "ChartSbaseref",
0x104A: "ChartSerparent",
0x104B: "ChartSerauxtrend",
0x104E: "ChartIfmt",
0x104F: "ChartPos",
0x1050: "ChartAlruns",
0x1051: "ChartAI",
0x105B: "ChartSerauxerrbar",
0x105D: "ChartSerfmt",
0x105F: "Chart3DDataFormat",
0x1060: "ChartFbi",
0x1061: "ChartBoppop",
0x1062: "ChartAxcext",
0x1063: "ChartDat",
0x1064: "ChartPlotgrowth",
0x1065: "ChartSiindex",
0x1066: "ChartGelframe",
0x1067: "ChartBoppcustom",
0xFFFF: ""
}
all_funcs_by_name = {
# Includes Analysis ToolPak aka ATP aka add-in aka xcall functions,
# distinguished by -ve opcode.
# name: (opcode, min # args, max # args, func return type, func arg types)
# + in func arg types means more of the same.
'ABS' : ( 24, 1, 1, 'V', 'V'),
'ACCRINT' : ( -1, 6, 7, 'V', 'VVVVVVV'),
'ACCRINTM' : ( -1, 3, 5, 'V', 'VVVVV'),
'ACOS' : ( 99, 1, 1, 'V', 'V'),
'ACOSH' : (233, 1, 1, 'V', 'V'),
'ADDRESS' : (219, 2, 5, 'V', 'VVVVV'),
'AMORDEGRC' : ( -1, 7, 7, 'V', 'VVVVVVV'),
'AMORLINC' : ( -1, 7, 7, 'V', 'VVVVVVV'),
'AND' : ( 36, 1, 30, 'V', 'D+'),
'AREAS' : ( 75, 1, 1, 'V', 'R'),
'ASC' : (214, 1, 1, 'V', 'V'),
'ASIN' : ( 98, 1, 1, 'V', 'V'),
'ASINH' : (232, 1, 1, 'V', 'V'),
'ATAN' : ( 18, 1, 1, 'V', 'V'),
'ATAN2' : ( 97, 2, 2, 'V', 'VV'),
'ATANH' : (234, 1, 1, 'V', 'V'),
'AVEDEV' : (269, 1, 30, 'V', 'D+'),
'AVERAGE' : ( 5, 1, 30, 'V', 'D+'),
'AVERAGEA' : (361, 1, 30, 'V', 'D+'),
'BAHTTEXT' : (368, 1, 1, 'V', 'V'),
'BESSELI' : ( -1, 2, 2, 'V', 'VV'),
'BESSELJ' : ( -1, 2, 2, 'V', 'VV'),
'BESSELK' : ( -1, 2, 2, 'V', 'VV'),
'BESSELY' : ( -1, 2, 2, 'V', 'VV'),
'BETADIST' : (270, 3, 5, 'V', 'VVVVV'),
'BETAINV' : (272, 3, 5, 'V', 'VVVVV'),
'BIN2DEC' : ( -1, 1, 1, 'V', 'V'),
'BIN2HEX' : ( -1, 1, 2, 'V', 'VV'),
'BIN2OCT' : ( -1, 1, 2, 'V', 'VV'),
'BINOMDIST' : (273, 4, 4, 'V', 'VVVV'),
'CEILING' : (288, 2, 2, 'V', 'VV'),
'CELL' : (125, 1, 2, 'V', 'VR'),
'CHAR' : (111, 1, 1, 'V', 'V'),
'CHIDIST' : (274, 2, 2, 'V', 'VV'),
'CHIINV' : (275, 2, 2, 'V', 'VV'),
'CHITEST' : (306, 2, 2, 'V', 'AA'),
'CHOOSE' : (100, 2, 30, 'R', 'VR+'),
'CLEAN' : (162, 1, 1, 'V', 'V'),
'CODE' : (121, 1, 1, 'V', 'V'),
'COLUMN' : ( 9, 0, 1, 'V', 'R'),
'COLUMNS' : ( 77, 1, 1, 'V', 'R'),
'COMBIN' : (276, 2, 2, 'V', 'VV'),
'COMPLEX' : ( -1, 2, 3, 'V', 'VVV'),
'CONCATENATE' : (336, 1, 30, 'V', 'V+'),
'CONFIDENCE' : (277, 3, 3, 'V', 'VVV'),
'CONVERT' : ( -1, 3, 3, 'V', 'VVV'),
'CORREL' : (307, 2, 2, 'V', 'AA'),
'COS' : ( 16, 1, 1, 'V', 'V'),
'COSH' : (230, 1, 1, 'V', 'V'),
'COUNT' : ( 0, 1, 30, 'V', 'D+'),
'COUNTA' : (169, 1, 30, 'V', 'D+'),
'COUNTBLANK' : (347, 1, 1, 'V', 'R'),
'COUNTIF' : (346, 2, 2, 'V', 'RV'),
'COUPDAYBS' : ( -1, 3, 5, 'V', 'VVVVV'),
'COUPDAYS' : ( -1, 3, 5, 'V', 'VVVVV'),
'COUPDAYSNC' : ( -1, 3, 5, 'V', 'VVVVV'),
'COUPNCD' : ( -1, 3, 5, 'V', 'VVVVV'),
'COUPNUM' : ( -1, 3, 5, 'V', 'VVVVV'),
'COUPPCD' : ( -1, 3, 5, 'V', 'VVVVV'),
'COVAR' : (308, 2, 2, 'V', 'AA'),
'CRITBINOM' : (278, 3, 3, 'V', 'VVV'),
'CUMIPMT' : ( -1, 6, 6, 'V', 'VVVVVV'),
'CUMPRINC' : ( -1, 6, 6, 'V', 'VVVVVV'),
'DATE' : ( 65, 3, 3, 'V', 'VVV'),
'DATEDIF' : (351, 3, 3, 'V', 'VVV'),
'DATEVALUE' : (140, 1, 1, 'V', 'V'),
'DAVERAGE' : ( 42, 3, 3, 'V', 'RRR'),
'DAY' : ( 67, 1, 1, 'V', 'V'),
'DAYS360' : (220, 2, 3, 'V', 'VVV'),
'DB' : (247, 4, 5, 'V', 'VVVVV'),
'DBCS' : (215, 1, 1, 'V', 'V'),
'DCOUNT' : ( 40, 3, 3, 'V', 'RRR'),
'DCOUNTA' : (199, 3, 3, 'V', 'RRR'),
'DDB' : (144, 4, 5, 'V', 'VVVVV'),
'DEC2BIN' : ( -1, 1, 2, 'V', 'VV'),
'DEC2HEX' : ( -1, 1, 2, 'V', 'VV'),
'DEC2OCT' : ( -1, 1, 2, 'V', 'VV'),
'DEGREES' : (343, 1, 1, 'V', 'V'),
'DELTA' : ( -1, 1, 2, 'V', 'VV'),
'DEVSQ' : (318, 1, 30, 'V', 'D+'),
'DGET' : (235, 3, 3, 'V', 'RRR'),
'DISC' : ( -1, 4, 5, 'V', 'VVVVV'),
'DMAX' : ( 44, 3, 3, 'V', 'RRR'),
'DMIN' : ( 43, 3, 3, 'V', 'RRR'),
'DOLLAR' : ( 13, 1, 2, 'V', 'VV'),
'DOLLARDE' : ( -1, 2, 2, 'V', 'VV'),
'DOLLARFR' : ( -1, 2, 2, 'V', 'VV'),
'DPRODUCT' : (189, 3, 3, 'V', 'RRR'),
'DSTDEV' : ( 45, 3, 3, 'V', 'RRR'),
'DSTDEVP' : (195, 3, 3, 'V', 'RRR'),
'DSUM' : ( 41, 3, 3, 'V', 'RRR'),
'DURATION' : ( -1, 5, 6, 'V', 'VVVVVV'),
'DVAR' : ( 47, 3, 3, 'V', 'RRR'),
'DVARP' : (196, 3, 3, 'V', 'RRR'),
'EDATE' : ( -1, 2, 2, 'V', 'VV'),
'EFFECT' : ( -1, 2, 2, 'V', 'VV'),
'EOMONTH' : ( -1, 1, 2, 'V', 'VV'),
'ERF' : ( -1, 1, 2, 'V', 'VV'),
'ERFC' : ( -1, 1, 1, 'V', 'V'),
'ERROR.TYPE' : (261, 1, 1, 'V', 'V'),
'EVEN' : (279, 1, 1, 'V', 'V'),
'EXACT' : (117, 2, 2, 'V', 'VV'),
'EXP' : ( 21, 1, 1, 'V', 'V'),
'EXPONDIST' : (280, 3, 3, 'V', 'VVV'),
'FACT' : (184, 1, 1, 'V', 'V'),
'FACTDOUBLE' : ( -1, 1, 1, 'V', 'V'),
'FALSE' : ( 35, 0, 0, 'V', '-'),
'FDIST' : (281, 3, 3, 'V', 'VVV'),
'FIND' : (124, 2, 3, 'V', 'VVV'),
'FINDB' : (205, 2, 3, 'V', 'VVV'),
'FINV' : (282, 3, 3, 'V', 'VVV'),
'FISHER' : (283, 1, 1, 'V', 'V'),
'FISHERINV' : (284, 1, 1, 'V', 'V'),
'FIXED' : ( 14, 2, 3, 'V', 'VVV'),
'FLOOR' : (285, 2, 2, 'V', 'VV'),
'FORECAST' : (309, 3, 3, 'V', 'VAA'),
'FREQUENCY' : (252, 2, 2, 'A', 'RR'),
'FTEST' : (310, 2, 2, 'V', 'AA'),
'FV' : ( 57, 3, 5, 'V', 'VVVVV'),
'FVSCHEDULE' : ( -1, 2, 2, 'V', 'VA'),
'GAMMADIST' : (286, 4, 4, 'V', 'VVVV'),
'GAMMAINV' : (287, 3, 3, 'V', 'VVV'),
'GAMMALN' : (271, 1, 1, 'V', 'V'),
'GCD' : ( -1, 1, 29, 'V', 'V+'),
'GEOMEAN' : (319, 1, 30, 'V', 'D+'),
'GESTEP' : ( -1, 1, 2, 'V', 'VV'),
'GETPIVOTDATA': (358, 2, 30, 'A', 'VAV+'),
'GROWTH' : ( 52, 1, 4, 'A', 'RRRV'),
'HARMEAN' : (320, 1, 30, 'V', 'D+'),
'HEX2BIN' : ( -1, 1, 2, 'V', 'VV'),
'HEX2DEC' : ( -1, 1, 1, 'V', 'V'),
'HEX2OCT' : ( -1, 1, 2, 'V', 'VV'),
'HLOOKUP' : (101, 3, 4, 'V', 'VRRV'),
'HOUR' : ( 71, 1, 1, 'V', 'V'),
'HYPERLINK' : (359, 1, 2, 'V', 'VV'),
'HYPGEOMDIST' : (289, 4, 4, 'V', 'VVVV'),
'IF' : ( 1, 2, 3, 'R', 'VRR'),
'IMABS' : ( -1, 1, 1, 'V', 'V'),
'IMAGINARY' : ( -1, 1, 1, 'V', 'V'),
'IMARGUMENT' : ( -1, 1, 1, 'V', 'V'),
'IMCONJUGATE' : ( -1, 1, 1, 'V', 'V'),
'IMCOS' : ( -1, 1, 1, 'V', 'V'),
'IMDIV' : ( -1, 2, 2, 'V', 'VV'),
'IMEXP' : ( -1, 1, 1, 'V', 'V'),
'IMLN' : ( -1, 1, 1, 'V', 'V'),
'IMLOG10' : ( -1, 1, 1, 'V', 'V'),
'IMLOG2' : ( -1, 1, 1, 'V', 'V'),
'IMPOWER' : ( -1, 2, 2, 'V', 'VV'),
'IMPRODUCT' : ( -1, 2, 2, 'V', 'VV'),
'IMREAL' : ( -1, 1, 1, 'V', 'V'),
'IMSIN' : ( -1, 1, 1, 'V', 'V'),
'IMSQRT' : ( -1, 1, 1, 'V', 'V'),
'IMSUB' : ( -1, 2, 2, 'V', 'VV'),
'IMSUM' : ( -1, 1, 29, 'V', 'V+'),
'INDEX' : ( 29, 2, 4, 'R', 'RVVV'),
'INDIRECT' : (148, 1, 2, 'R', 'VV'),
'INFO' : (244, 1, 1, 'V', 'V'),
'INT' : ( 25, 1, 1, 'V', 'V'),
'INTERCEPT' : (311, 2, 2, 'V', 'AA'),
'INTRATE' : ( -1, 4, 5, 'V', 'VVVVV'),
'IPMT' : (167, 4, 6, 'V', 'VVVVVV'),
'IRR' : ( 62, 1, 2, 'V', 'RV'),
'ISBLANK' : (129, 1, 1, 'V', 'V'),
'ISERR' : (126, 1, 1, 'V', 'V'),
'ISERROR' : ( 3, 1, 1, 'V', 'V'),
'ISEVEN' : ( -1, 1, 1, 'V', 'V'),
'ISLOGICAL' : (198, 1, 1, 'V', 'V'),
'ISNA' : ( 2, 1, 1, 'V', 'V'),
'ISNONTEXT' : (190, 1, 1, 'V', 'V'),
'ISNUMBER' : (128, 1, 1, 'V', 'V'),
'ISODD' : ( -1, 1, 1, 'V', 'V'),
'ISPMT' : (350, 4, 4, 'V', 'VVVV'),
'ISREF' : (105, 1, 1, 'V', 'R'),
'ISTEXT' : (127, 1, 1, 'V', 'V'),
'KURT' : (322, 1, 30, 'V', 'D+'),
'LARGE' : (325, 2, 2, 'V', 'RV'),
'LCM' : ( -1, 1, 29, 'V', 'V+'),
'LEFT' : (115, 1, 2, 'V', 'VV'),
'LEFTB' : (208, 1, 2, 'V', 'VV'),
'LEN' : ( 32, 1, 1, 'V', 'V'),
'LENB' : (211, 1, 1, 'V', 'V'),
'LINEST' : ( 49, 1, 4, 'A', 'RRVV'),
'LN' : ( 22, 1, 1, 'V', 'V'),
'LOG' : (109, 1, 2, 'V', 'VV'),
'LOG10' : ( 23, 1, 1, 'V', 'V'),
'LOGEST' : ( 51, 1, 4, 'A', 'RRVV'),
'LOGINV' : (291, 3, 3, 'V', 'VVV'),
'LOGNORMDIST' : (290, 3, 3, 'V', 'VVV'),
'LOOKUP' : ( 28, 2, 3, 'V', 'VRR'),
'LOWER' : (112, 1, 1, 'V', 'V'),
'MATCH' : ( 64, 2, 3, 'V', 'VRR'),
'MAX' : ( 7, 1, 30, 'V', 'D+'),
'MAXA' : (362, 1, 30, 'V', 'D+'),
'MDETERM' : (163, 1, 1, 'V', 'A'),
'MDURATION' : ( -1, 5, 6, 'V', 'VVVVVV'),
'MEDIAN' : (227, 1, 30, 'V', 'D+'),
'MID' : ( 31, 3, 3, 'V', 'VVV'),
'MIDB' : (210, 3, 3, 'V', 'VVV'),
'MIN' : ( 6, 1, 30, 'V', 'D+'),
'MINA' : (363, 1, 30, 'V', 'D+'),
'MINUTE' : ( 72, 1, 1, 'V', 'V'),
'MINVERSE' : (164, 1, 1, 'A', 'A'),
'MIRR' : ( 61, 3, 3, 'V', 'RVV'),
'MMULT' : (165, 2, 2, 'A', 'AA'),
'MOD' : ( 39, 2, 2, 'V', 'VV'),
'MODE' : (330, 1, 30, 'V', 'A+'), ################ weird #################
'MONTH' : ( 68, 1, 1, 'V', 'V'),
'MROUND' : ( -1, 2, 2, 'V', 'VV'),
'MULTINOMIAL' : ( -1, 1, 29, 'V', 'V+'),
'N' : (131, 1, 1, 'V', 'R'),
'NA' : ( 10, 0, 0, 'V', '-'),
'NEGBINOMDIST': (292, 3, 3, 'V', 'VVV'),
'NETWORKDAYS' : ( -1, 2, 3, 'V', 'VVR'),
'NOMINAL' : ( -1, 2, 2, 'V', 'VV'),
'NORMDIST' : (293, 4, 4, 'V', 'VVVV'),
'NORMINV' : (295, 3, 3, 'V', 'VVV'),
'NORMSDIST' : (294, 1, 1, 'V', 'V'),
'NORMSINV' : (296, 1, 1, 'V', 'V'),
'NOT' : ( 38, 1, 1, 'V', 'V'),
'NOW' : ( 74, 0, 0, 'V', '-'),
'NPER' : ( 58, 3, 5, 'V', 'VVVVV'),
'NPV' : ( 11, 2, 30, 'V', 'VD+'),
'OCT2BIN' : ( -1, 1, 2, 'V', 'VV'),
'OCT2DEC' : ( -1, 1, 1, 'V', 'V'),
'OCT2HEX' : ( -1, 1, 2, 'V', 'VV'),
'ODD' : (298, 1, 1, 'V', 'V'),
'ODDFPRICE' : ( -1, 9, 9, 'V', 'VVVVVVVVV'),
'ODDFYIELD' : ( -1, 9, 9, 'V', 'VVVVVVVVV'),
'ODDLPRICE' : ( -1, 8, 8, 'V', 'VVVVVVVV'),
'ODDLYIELD' : ( -1, 8, 8, 'V', 'VVVVVVVV'),
'OFFSET' : ( 78, 3, 5, 'R', 'RVVVV'),
'OR' : ( 37, 1, 30, 'V', 'D+'),
'PEARSON' : (312, 2, 2, 'V', 'AA'),
'PERCENTILE' : (328, 2, 2, 'V', 'RV'),
'PERCENTRANK' : (329, 2, 3, 'V', 'RVV'),
'PERMUT' : (299, 2, 2, 'V', 'VV'),
'PHONETIC' : (360, 1, 1, 'V', 'R'),
'PI' : ( 19, 0, 0, 'V', '-'),
'PMT' : ( 59, 3, 5, 'V', 'VVVVV'),
'POISSON' : (300, 3, 3, 'V', 'VVV'),
'POWER' : (337, 2, 2, 'V', 'VV'),
'PPMT' : (168, 4, 6, 'V', 'VVVVVV'),
'PRICE' : ( -1, 6, 7, 'V', 'VVVVVVV'),
'PRICEDISC' : ( -1, 4, 5, 'V', 'VVVVV'),
'PRICEMAT' : ( -1, 5, 6, 'V', 'VVVVVV'),
'PROB' : (317, 3, 4, 'V', 'AAVV'),
'PRODUCT' : (183, 1, 30, 'V', 'D+'),
'PROPER' : (114, 1, 1, 'V', 'V'),
'PV' : ( 56, 3, 5, 'V', 'VVVVV'),
'QUARTILE' : (327, 2, 2, 'V', 'RV'),
'QUOTIENT' : ( -1, 2, 2, 'V', 'VV'),
'RADIANS' : (342, 1, 1, 'V', 'V'),
'RAND' : ( 63, 0, 0, 'V', '-'),
'RANDBETWEEN' : ( -1, 2, 2, 'V', 'VV'),
'RANK' : (216, 2, 3, 'V', 'VRV'),
'RATE' : ( 60, 3, 6, 'V', 'VVVVVV'),
'RECEIVED' : ( -1, 4, 5, 'V', 'VVVVV'),
'REPLACE' : (119, 4, 4, 'V', 'VVVV'),
'REPLACEB' : (207, 4, 4, 'V', 'VVVV'),
'REPT' : ( 30, 2, 2, 'V', 'VV'),
'RIGHT' : (116, 1, 2, 'V', 'VV'),
'RIGHTB' : (209, 1, 2, 'V', 'VV'),
'ROMAN' : (354, 1, 2, 'V', 'VV'),
'ROUND' : ( 27, 2, 2, 'V', 'VV'),
'ROUNDDOWN' : (213, 2, 2, 'V', 'VV'),
'ROUNDUP' : (212, 2, 2, 'V', 'VV'),
'ROW' : ( 8, 0, 1, 'V', 'R'),
'ROWS' : ( 76, 1, 1, 'V', 'R'),
'RSQ' : (313, 2, 2, 'V', 'AA'),
'RTD' : (379, 3, 30, 'A', 'VVV+'),
'SEARCH' : ( 82, 2, 3, 'V', 'VVV'),
'SEARCHB' : (206, 2, 3, 'V', 'VVV'),
'SECOND' : ( 73, 1, 1, 'V', 'V'),
'SERIESSUM' : ( -1, 4, 4, 'V', 'VVVA'),
'SIGN' : ( 26, 1, 1, 'V', 'V'),
'SIN' : ( 15, 1, 1, 'V', 'V'),
'SINH' : (229, 1, 1, 'V', 'V'),
'SKEW' : (323, 1, 30, 'V', 'D+'),
'SLN' : (142, 3, 3, 'V', 'VVV'),
'SLOPE' : (315, 2, 2, 'V', 'AA'),
'SMALL' : (326, 2, 2, 'V', 'RV'),
'SQRT' : ( 20, 1, 1, 'V', 'V'),
'SQRTPI' : ( -1, 1, 1, 'V', 'V'),
'STANDARDIZE' : (297, 3, 3, 'V', 'VVV'),
'STDEV' : ( 12, 1, 30, 'V', 'D+'),
'STDEVA' : (366, 1, 30, 'V', 'D+'),
'STDEVP' : (193, 1, 30, 'V', 'D+'),
'STDEVPA' : (364, 1, 30, 'V', 'D+'),
'STEYX' : (314, 2, 2, 'V', 'AA'),
'SUBSTITUTE' : (120, 3, 4, 'V', 'VVVV'),
'SUBTOTAL' : (344, 2, 30, 'V', 'VR+'),
'SUM' : ( 4, 1, 30, 'V', 'D+'),
'SUMIF' : (345, 2, 3, 'V', 'RVR'),
'SUMPRODUCT' : (228, 1, 30, 'V', 'A+'),
'SUMSQ' : (321, 1, 30, 'V', 'D+'),
'SUMX2MY2' : (304, 2, 2, 'V', 'AA'),
'SUMX2PY2' : (305, 2, 2, 'V', 'AA'),
'SUMXMY2' : (303, 2, 2, 'V', 'AA'),
'SYD' : (143, 4, 4, 'V', 'VVVV'),
'T' : (130, 1, 1, 'V', 'R'),
'TAN' : ( 17, 1, 1, 'V', 'V'),
'TANH' : (231, 1, 1, 'V', 'V'),
'TBILLEQ' : ( -1, 3, 3, 'V', 'VVV'),
'TBILLPRICE' : ( -1, 3, 3, 'V', 'VVV'),
'TBILLYIELD' : ( -1, 3, 3, 'V', 'VVV'),
'TDIST' : (301, 3, 3, 'V', 'VVV'),
'TEXT' : ( 48, 2, 2, 'V', 'VV'),
'TIME' : ( 66, 3, 3, 'V', 'VVV'),
'TIMEVALUE' : (141, 1, 1, 'V', 'V'),
'TINV' : (332, 2, 2, 'V', 'VV'),
'TODAY' : (221, 0, 0, 'V', '-'),
'TRANSPOSE' : ( 83, 1, 1, 'A', 'A'),
'TREND' : ( 50, 1, 4, 'A', 'RRRV'),
'TRIM' : (118, 1, 1, 'V', 'V'),
'TRIMMEAN' : (331, 2, 2, 'V', 'RV'),
'TRUE' : ( 34, 0, 0, 'V', '-'),
'TRUNC' : (197, 1, 2, 'V', 'VV'),
'TTEST' : (316, 4, 4, 'V', 'AAVV'),
'TYPE' : ( 86, 1, 1, 'V', 'V'),
'UPPER' : (113, 1, 1, 'V', 'V'),
'USDOLLAR' : (204, 1, 2, 'V', 'VV'),
'VALUE' : ( 33, 1, 1, 'V', 'V'),
'VAR' : ( 46, 1, 30, 'V', 'D+'),
'VARA' : (367, 1, 30, 'V', 'D+'),
'VARP' : (194, 1, 30, 'V', 'D+'),
'VARPA' : (365, 1, 30, 'V', 'D+'),
'VDB' : (222, 5, 7, 'V', 'VVVVVVV'),
'VLOOKUP' : (102, 3, 4, 'V', 'VRRV'),
'WEEKDAY' : ( 70, 1, 2, 'V', 'VV'),
'WEEKNUM' : ( -1, 1, 2, 'V', 'VV'),
'WEIBULL' : (302, 4, 4, 'V', 'VVVV'),
'WORKDAY' : ( -1, 2, 3, 'V', 'VVR'),
'XIRR' : ( -1, 2, 3, 'V', 'AAV'),
'XNPV' : ( -1, 3, 3, 'V', 'VAA'),
'YEAR' : ( 69, 1, 1, 'V', 'V'),
'YEARFRAC' : ( -1, 2, 3, 'V', 'VVV'),
'YIELD' : ( -1, 6, 7, 'V', 'VVVVVVV'),
'YIELDDISC' : ( -1, 4, 5, 'V', 'VVVVV'),
'YIELDMAT' : ( -1, 5, 6, 'V', 'VVVVVV'),
'ZTEST' : (324, 2, 3, 'V', 'RVV'),
}
# Formulas Parse things
ptgExp = 0x01
ptgTbl = 0x02
ptgAdd = 0x03
ptgSub = 0x04
ptgMul = 0x05
ptgDiv = 0x06
ptgPower = 0x07
ptgConcat = 0x08
ptgLT = 0x09
ptgLE = 0x0a
ptgEQ = 0x0b
ptgGE = 0x0c
ptgGT = 0x0d
ptgNE = 0x0e
ptgIsect = 0x0f
ptgUnion = 0x10
ptgRange = 0x11
ptgUplus = 0x12
ptgUminus = 0x13
ptgPercent = 0x14
ptgParen = 0x15
ptgMissArg = 0x16
ptgStr = 0x17
ptgExtend = 0x18
ptgAttr = 0x19
ptgSheet = 0x1a
ptgEndSheet = 0x1b
ptgErr = 0x1c
ptgBool = 0x1d
ptgInt = 0x1e
ptgNum = 0x1f
ptgArrayR = 0x20
ptgFuncR = 0x21
ptgFuncVarR = 0x22
ptgNameR = 0x23
ptgRefR = 0x24
ptgAreaR = 0x25
ptgMemAreaR = 0x26
ptgMemErrR = 0x27
ptgMemNoMemR = 0x28
ptgMemFuncR = 0x29
ptgRefErrR = 0x2a
ptgAreaErrR = 0x2b
ptgRefNR = 0x2c
ptgAreaNR = 0x2d
ptgMemAreaNR = 0x2e
ptgMemNoMemNR = 0x2f
ptgNameXR = 0x39
ptgRef3dR = 0x3a
ptgArea3dR = 0x3b
ptgRefErr3dR = 0x3c
ptgAreaErr3dR = 0x3d
ptgArrayV = 0x40
ptgFuncV = 0x41
ptgFuncVarV = 0x42
ptgNameV = 0x43
ptgRefV = 0x44
ptgAreaV = 0x45
ptgMemAreaV = 0x46
ptgMemErrV = 0x47
ptgMemNoMemV = 0x48
ptgMemFuncV = 0x49
ptgRefErrV = 0x4a
ptgAreaErrV = 0x4b
ptgRefNV = 0x4c
ptgAreaNV = 0x4d
ptgMemAreaNV = 0x4e
ptgMemNoMemNV = 0x4f
ptgFuncCEV = 0x58
ptgNameXV = 0x59
ptgRef3dV = 0x5a
ptgArea3dV = 0x5b
ptgRefErr3dV = 0x5c
ptgAreaErr3dV = 0x5d
ptgArrayA = 0x60
ptgFuncA = 0x61
ptgFuncVarA = 0x62
ptgNameA = 0x63
ptgRefA = 0x64
ptgAreaA = 0x65
ptgMemAreaA = 0x66
ptgMemErrA = 0x67
ptgMemNoMemA = 0x68
ptgMemFuncA = 0x69
ptgRefErrA = 0x6a
ptgAreaErrA = 0x6b
ptgRefNA = 0x6c
ptgAreaNA = 0x6d
ptgMemAreaNA = 0x6e
ptgMemNoMemNA = 0x6f
ptgFuncCEA = 0x78
ptgNameXA = 0x79
ptgRef3dA = 0x7a
ptgArea3dA = 0x7b
ptgRefErr3dA = 0x7c
ptgAreaErr3dA = 0x7d
PtgNames = {
ptgExp : "ptgExp",
ptgTbl : "ptgTbl",
ptgAdd : "ptgAdd",
ptgSub : "ptgSub",
ptgMul : "ptgMul",
ptgDiv : "ptgDiv",
ptgPower : "ptgPower",
ptgConcat : "ptgConcat",
ptgLT : "ptgLT",
ptgLE : "ptgLE",
ptgEQ : "ptgEQ",
ptgGE : "ptgGE",
ptgGT : "ptgGT",
ptgNE : "ptgNE",
ptgIsect : "ptgIsect",
ptgUnion : "ptgUnion",
ptgRange : "ptgRange",
ptgUplus : "ptgUplus",
ptgUminus : "ptgUminus",
ptgPercent : "ptgPercent",
ptgParen : "ptgParen",
ptgMissArg : "ptgMissArg",
ptgStr : "ptgStr",
ptgExtend : "ptgExtend",
ptgAttr : "ptgAttr",
ptgSheet : "ptgSheet",
ptgEndSheet : "ptgEndSheet",
ptgErr : "ptgErr",
ptgBool : "ptgBool",
ptgInt : "ptgInt",
ptgNum : "ptgNum",
ptgArrayR : "ptgArrayR",
ptgFuncR : "ptgFuncR",
ptgFuncVarR : "ptgFuncVarR",
ptgNameR : "ptgNameR",
ptgRefR : "ptgRefR",
ptgAreaR : "ptgAreaR",
ptgMemAreaR : "ptgMemAreaR",
ptgMemErrR : "ptgMemErrR",
ptgMemNoMemR : "ptgMemNoMemR",
ptgMemFuncR : "ptgMemFuncR",
ptgRefErrR : "ptgRefErrR",
ptgAreaErrR : "ptgAreaErrR",
ptgRefNR : "ptgRefNR",
ptgAreaNR : "ptgAreaNR",
ptgMemAreaNR : "ptgMemAreaNR",
ptgMemNoMemNR : "ptgMemNoMemNR",
ptgNameXR : "ptgNameXR",
ptgRef3dR : "ptgRef3dR",
ptgArea3dR : "ptgArea3dR",
ptgRefErr3dR : "ptgRefErr3dR",
ptgAreaErr3dR : "ptgAreaErr3dR",
ptgArrayV : "ptgArrayV",
ptgFuncV : "ptgFuncV",
ptgFuncVarV : "ptgFuncVarV",
ptgNameV : "ptgNameV",
ptgRefV : "ptgRefV",
ptgAreaV : "ptgAreaV",
ptgMemAreaV : "ptgMemAreaV",
ptgMemErrV : "ptgMemErrV",
ptgMemNoMemV : "ptgMemNoMemV",
ptgMemFuncV : "ptgMemFuncV",
ptgRefErrV : "ptgRefErrV",
ptgAreaErrV : "ptgAreaErrV",
ptgRefNV : "ptgRefNV",
ptgAreaNV : "ptgAreaNV",
ptgMemAreaNV : "ptgMemAreaNV",
ptgMemNoMemNV : "ptgMemNoMemNV",
ptgFuncCEV : "ptgFuncCEV",
ptgNameXV : "ptgNameXV",
ptgRef3dV : "ptgRef3dV",
ptgArea3dV : "ptgArea3dV",
ptgRefErr3dV : "ptgRefErr3dV",
ptgAreaErr3dV : "ptgAreaErr3dV",
ptgArrayA : "ptgArrayA",
ptgFuncA : "ptgFuncA",
ptgFuncVarA : "ptgFuncVarA",
ptgNameA : "ptgNameA",
ptgRefA : "ptgRefA",
ptgAreaA : "ptgAreaA",
ptgMemAreaA : "ptgMemAreaA",
ptgMemErrA : "ptgMemErrA",
ptgMemNoMemA : "ptgMemNoMemA",
ptgMemFuncA : "ptgMemFuncA",
ptgRefErrA : "ptgRefErrA",
ptgAreaErrA : "ptgAreaErrA",
ptgRefNA : "ptgRefNA",
ptgAreaNA : "ptgAreaNA",
ptgMemAreaNA : "ptgMemAreaNA",
ptgMemNoMemNA : "ptgMemNoMemNA",
ptgFuncCEA : "ptgFuncCEA",
ptgNameXA : "ptgNameXA",
ptgRef3dA : "ptgRef3dA",
ptgArea3dA : "ptgArea3dA",
ptgRefErr3dA : "ptgRefErr3dA",
ptgAreaErr3dA : "ptgAreaErr3dA"
}
error_msg_by_code = {
0x00: u"#NULL!", # intersection of two cell ranges is empty
0x07: u"#DIV/0!", # division by zero
0x0F: u"#VALUE!", # wrong type of operand
0x17: u"#REF!", # illegal or deleted cell reference
0x1D: u"#NAME?", # wrong function or range name
0x24: u"#NUM!", # value range overflow
0x2A: u"#N/A!" # argument or function not available
}
-261
View File
@@ -1,261 +0,0 @@
#!/usr/bin/env python
'''
The XF record is able to store explicit cell formatting attributes or the
attributes of a cell style. Explicit formatting includes the reference to
a cell style XF record. This allows to extend a defined cell style with
some explicit attributes. The formatting attributes are divided into
6 groups:
Group Attributes
-------------------------------------
Number format Number format index (index to FORMAT record)
Font Font index (index to FONT record)
Alignment Horizontal and vertical alignment, text wrap, indentation,
orientation/rotation, text direction
Border Border line styles and colours
Background Background area style and colours
Protection Cell locked, formula hidden
For each group a flag in the cell XF record specifies whether to use the
attributes contained in that XF record or in the referenced style
XF record. In style XF records, these flags specify whether the attributes
will overwrite explicit cell formatting when the style is applied to
a cell. Changing a cell style (without applying this style to a cell) will
change all cells which already use that style and do not contain explicit
cell attributes for the changed style attributes. If a cell XF record does
not contain explicit attributes in a group (if the attribute group flag
is not set), it repeats the attributes of its style XF record.
'''
import BIFFRecords
class Font(object):
ESCAPEMENT_NONE = 0x00
ESCAPEMENT_SUPERSCRIPT = 0x01
ESCAPEMENT_SUBSCRIPT = 0x02
UNDERLINE_NONE = 0x00
UNDERLINE_SINGLE = 0x01
UNDERLINE_SINGLE_ACC = 0x21
UNDERLINE_DOUBLE = 0x02
UNDERLINE_DOUBLE_ACC = 0x22
FAMILY_NONE = 0x00
FAMILY_ROMAN = 0x01
FAMILY_SWISS = 0x02
FAMILY_MODERN = 0x03
FAMILY_SCRIPT = 0x04
FAMILY_DECORATIVE = 0x05
CHARSET_ANSI_LATIN = 0x00
CHARSET_SYS_DEFAULT = 0x01
CHARSET_SYMBOL = 0x02
CHARSET_APPLE_ROMAN = 0x4D
CHARSET_ANSI_JAP_SHIFT_JIS = 0x80
CHARSET_ANSI_KOR_HANGUL = 0x81
CHARSET_ANSI_KOR_JOHAB = 0x82
CHARSET_ANSI_CHINESE_GBK = 0x86
CHARSET_ANSI_CHINESE_BIG5 = 0x88
CHARSET_ANSI_GREEK = 0xA1
CHARSET_ANSI_TURKISH = 0xA2
CHARSET_ANSI_VIETNAMESE = 0xA3
CHARSET_ANSI_HEBREW = 0xB1
CHARSET_ANSI_ARABIC = 0xB2
CHARSET_ANSI_BALTIC = 0xBA
CHARSET_ANSI_CYRILLIC = 0xCC
CHARSET_ANSI_THAI = 0xDE
CHARSET_ANSI_LATIN_II = 0xEE
CHARSET_OEM_LATIN_I = 0xFF
def __init__(self):
# twip = 1/20 of a point = 1/1440 of a inch
# usually resolution == 96 pixels per 1 inch
# (rarely 120 pixels per 1 inch or another one)
self.height = 0x00C8 # 200: this is font with height 10 points
self.italic = False
self.struck_out = False
self.outline = False
self.shadow = False
self.colour_index = 0x7FFF
self.bold = False
self._weight = 0x0190 # 0x02BC gives bold font
self.escapement = self.ESCAPEMENT_NONE
self.underline = self.UNDERLINE_NONE
self.family = self.FAMILY_NONE
self.charset = self.CHARSET_SYS_DEFAULT
self.name = 'Arial'
def get_biff_record(self):
height = self.height
options = 0x00
if self.bold:
options |= 0x01
self._weight = 0x02BC
if self.italic:
options |= 0x02
if self.underline != self.UNDERLINE_NONE:
options |= 0x04
if self.struck_out:
options |= 0x08
if self.outline:
options |= 0x010
if self.shadow:
options |= 0x020
colour_index = self.colour_index
weight = self._weight
escapement = self.escapement
underline = self.underline
family = self.family
charset = self.charset
name = self.name
return BIFFRecords.FontRecord(height, options, colour_index, weight, escapement,
underline, family, charset,
name)
def _search_key(self):
return (
self.height,
self.italic,
self.struck_out,
self.outline,
self.shadow,
self.colour_index,
self.bold,
self._weight,
self.escapement,
self.underline,
self.family,
self.charset,
self.name,
)
class Alignment(object):
HORZ_GENERAL = 0x00
HORZ_LEFT = 0x01
HORZ_CENTER = 0x02
HORZ_RIGHT = 0x03
HORZ_FILLED = 0x04
HORZ_JUSTIFIED = 0x05 # BIFF4-BIFF8X
HORZ_CENTER_ACROSS_SEL = 0x06 # Centred across selection (BIFF4-BIFF8X)
HORZ_DISTRIBUTED = 0x07 # Distributed (BIFF8X)
VERT_TOP = 0x00
VERT_CENTER = 0x01
VERT_BOTTOM = 0x02
VERT_JUSTIFIED = 0x03 # Justified (BIFF5-BIFF8X)
VERT_DISTRIBUTED = 0x04 # Distributed (BIFF8X)
DIRECTION_GENERAL = 0x00 # BIFF8X
DIRECTION_LR = 0x01
DIRECTION_RL = 0x02
ORIENTATION_NOT_ROTATED = 0x00
ORIENTATION_STACKED = 0x01
ORIENTATION_90_CC = 0x02
ORIENTATION_90_CW = 0x03
ROTATION_0_ANGLE = 0x00
ROTATION_STACKED = 0xFF
WRAP_AT_RIGHT = 0x01
NOT_WRAP_AT_RIGHT = 0x00
SHRINK_TO_FIT = 0x01
NOT_SHRINK_TO_FIT = 0x00
def __init__(self):
self.horz = self.HORZ_GENERAL
self.vert = self.VERT_BOTTOM
self.dire = self.DIRECTION_GENERAL
self.orie = self.ORIENTATION_NOT_ROTATED
self.rota = self.ROTATION_0_ANGLE
self.wrap = self.NOT_WRAP_AT_RIGHT
self.shri = self.NOT_SHRINK_TO_FIT
self.inde = 0
self.merg = 0
def _search_key(self):
return (
self.horz, self.vert, self.dire, self.orie, self.rota,
self.wrap, self.shri, self.inde, self.merg,
)
class Borders(object):
NO_LINE = 0x00
THIN = 0x01
MEDIUM = 0x02
DASHED = 0x03
DOTTED = 0x04
THICK = 0x05
DOUBLE = 0x06
HAIR = 0x07
#The following for BIFF8
MEDIUM_DASHED = 0x08
THIN_DASH_DOTTED = 0x09
MEDIUM_DASH_DOTTED = 0x0A
THIN_DASH_DOT_DOTTED = 0x0B
MEDIUM_DASH_DOT_DOTTED = 0x0C
SLANTED_MEDIUM_DASH_DOTTED = 0x0D
NEED_DIAG1 = 0x01
NEED_DIAG2 = 0x01
NO_NEED_DIAG1 = 0x00
NO_NEED_DIAG2 = 0x00
def __init__(self):
self.left = self.NO_LINE
self.right = self.NO_LINE
self.top = self.NO_LINE
self.bottom = self.NO_LINE
self.diag = self.NO_LINE
self.left_colour = 0x40
self.right_colour = 0x40
self.top_colour = 0x40
self.bottom_colour = 0x40
self.diag_colour = 0x40
self.need_diag1 = self.NO_NEED_DIAG1
self.need_diag2 = self.NO_NEED_DIAG2
def _search_key(self):
return (
self.left, self.right, self.top, self.bottom, self.diag,
self.left_colour, self.right_colour, self.top_colour,
self.bottom_colour, self.diag_colour,
self.need_diag1, self.need_diag2,
)
class Pattern(object):
# patterns 0x00 - 0x12
NO_PATTERN = 0x00
SOLID_PATTERN = 0x01
def __init__(self):
self.pattern = self.NO_PATTERN
self.pattern_fore_colour = 0x40
self.pattern_back_colour = 0x41
def _search_key(self):
return (
self.pattern,
self.pattern_fore_colour,
self.pattern_back_colour,
)
class Protection(object):
def __init__(self):
self.cell_locked = 1
self.formula_hidden = 0
def _search_key(self):
return (
self.cell_locked,
self.formula_hidden,
)
-253
View File
@@ -1,253 +0,0 @@
# -*- coding: windows-1252 -*-
import BIFFRecords
import Style
from Cell import StrCell, BlankCell, NumberCell, FormulaCell, MulBlankCell, BooleanCell, ErrorCell, \
_get_cells_biff_data_mul
import ExcelFormula
import datetime as dt
try:
from decimal import Decimal
except ImportError:
# Python 2.3: decimal not supported; create dummy Decimal class
class Decimal(object):
pass
class Row(object):
__slots__ = [# private variables
"__idx",
"__parent",
"__parent_wb",
"__cells",
"__min_col_idx",
"__max_col_idx",
"__xf_index",
"__has_default_xf_index",
"__height_in_pixels",
# public variables
"height",
"has_default_height",
"height_mismatch",
"level",
"collapse",
"hidden",
"space_above",
"space_below"]
def __init__(self, rowx, parent_sheet):
if not (isinstance(rowx, int) and 0 <= rowx <= 65535):
raise ValueError("row index (%r) not an int in range(65536)" % rowx)
self.__idx = rowx
self.__parent = parent_sheet
self.__parent_wb = parent_sheet.get_parent()
self.__cells = {}
self.__min_col_idx = 0
self.__max_col_idx = 0
self.__xf_index = 0x0F
self.__has_default_xf_index = 0
self.__height_in_pixels = 0x11
self.height = 0x00FF
self.has_default_height = 0x00
self.height_mismatch = 0
self.level = 0
self.collapse = 0
self.hidden = 0
self.space_above = 0
self.space_below = 0
def __adjust_height(self, style):
twips = style.font.height
points = float(twips)/20.0
# Cell height in pixels can be calcuted by following approx. formula:
# cell height in pixels = font height in points * 83/50 + 2/5
# It works when screen resolution is 96 dpi
pix = int(round(points*83.0/50.0 + 2.0/5.0))
if pix > self.__height_in_pixels:
self.__height_in_pixels = pix
def __adjust_bound_col_idx(self, *args):
for arg in args:
iarg = int(arg)
if not ((0 <= iarg <= 255) and arg == iarg):
raise ValueError("column index (%r) not an int in range(256)" % arg)
sheet = self.__parent
if iarg < self.__min_col_idx:
self.__min_col_idx = iarg
if iarg > self.__max_col_idx:
self.__max_col_idx = iarg
if iarg < sheet.first_used_col:
sheet.first_used_col = iarg
if iarg > sheet.last_used_col:
sheet.last_used_col = iarg
def __excel_date_dt(self, date):
if isinstance(date, dt.date) and (not isinstance(date, dt.datetime)):
epoch = dt.date(1899, 12, 31)
elif isinstance(date, dt.time):
date = dt.datetime.combine(dt.datetime(1900, 1, 1), date)
epoch = dt.datetime(1900, 1, 1, 0, 0, 0)
else:
epoch = dt.datetime(1899, 12, 31, 0, 0, 0)
delta = date - epoch
xldate = delta.days + float(delta.seconds) / (24*60*60)
# Add a day for Excel's missing leap day in 1900
if xldate > 59:
xldate += 1
return xldate
def get_height_in_pixels(self):
return self.__height_in_pixels
def set_style(self, style):
self.__adjust_height(style)
self.__xf_index = self.__parent_wb.add_style(style)
self.__has_default_xf_index = 1
def get_xf_index(self):
return self.__xf_index
def get_cells_count(self):
return len(self.__cells)
def get_min_col(self):
return self.__min_col_idx
def get_max_col(self):
return self.__max_col_idx
def get_row_biff_data(self):
height_options = (self.height & 0x07FFF)
height_options |= (self.has_default_height & 0x01) << 15
options = (self.level & 0x07) << 0
options |= (self.collapse & 0x01) << 4
options |= (self.hidden & 0x01) << 5
options |= (self.height_mismatch & 0x01) << 6
options |= (self.__has_default_xf_index & 0x01) << 7
options |= (0x01 & 0x01) << 8
options |= (self.__xf_index & 0x0FFF) << 16
options |= (self.space_above & 1) << 28
options |= (self.space_below & 1) << 29
return BIFFRecords.RowRecord(self.__idx, self.__min_col_idx,
self.__max_col_idx, height_options, options).get()
def insert_cell(self, col_index, cell_obj):
if col_index in self.__cells:
if not self.__parent._cell_overwrite_ok:
msg = "Attempt to overwrite cell: sheetname=%r rowx=%d colx=%d" \
% (self.__parent.name, self.__idx, col_index)
raise Exception(msg)
prev_cell_obj = self.__cells[col_index]
sst_idx = getattr(prev_cell_obj, 'sst_idx', None)
if sst_idx is not None:
self.__parent_wb.del_str(sst_idx)
self.__cells[col_index] = cell_obj
def insert_mulcells(self, colx1, colx2, cell_obj):
self.insert_cell(colx1, cell_obj)
for col_index in xrange(colx1+1, colx2+1):
self.insert_cell(col_index, None)
def get_cells_biff_data(self):
cell_items = [item for item in self.__cells.iteritems() if item[1] is not None]
cell_items.sort() # in column order
return _get_cells_biff_data_mul(self.__idx, cell_items)
# previously:
# return ''.join([cell.get_biff_data() for colx, cell in cell_items])
def get_index(self):
return self.__idx
def set_cell_text(self, colx, value, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx, StrCell(self.__idx, colx, xf_index, self.__parent_wb.add_str(value)))
def set_cell_blank(self, colx, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx, BlankCell(self.__idx, colx, xf_index))
def set_cell_mulblanks(self, first_colx, last_colx, style=Style.default_style):
assert 0 <= first_colx <= last_colx <= 255
self.__adjust_height(style)
self.__adjust_bound_col_idx(first_colx, last_colx)
xf_index = self.__parent_wb.add_style(style)
# ncols = last_colx - first_colx + 1
self.insert_mulcells(first_colx, last_colx, MulBlankCell(self.__idx, first_colx, last_colx, xf_index))
def set_cell_number(self, colx, number, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx, NumberCell(self.__idx, colx, xf_index, number))
def set_cell_date(self, colx, datetime_obj, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx,
NumberCell(self.__idx, colx, xf_index, self.__excel_date_dt(datetime_obj)))
def set_cell_formula(self, colx, formula, style=Style.default_style, calc_flags=0):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.__parent_wb.add_sheet_reference(formula)
self.insert_cell(colx, FormulaCell(self.__idx, colx, xf_index, formula, calc_flags=0))
def set_cell_boolean(self, colx, value, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx, BooleanCell(self.__idx, colx, xf_index, bool(value)))
def set_cell_error(self, colx, error_string_or_code, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(colx)
xf_index = self.__parent_wb.add_style(style)
self.insert_cell(colx, ErrorCell(self.__idx, colx, xf_index, error_string_or_code))
def write(self, col, label, style=Style.default_style):
self.__adjust_height(style)
self.__adjust_bound_col_idx(col)
style_index = self.__parent_wb.add_style(style)
if isinstance(label, basestring):
if len(label) > 0:
self.insert_cell(col,
StrCell(self.__idx, col, style_index, self.__parent_wb.add_str(label))
)
else:
self.insert_cell(col, BlankCell(self.__idx, col, style_index))
elif isinstance(label, bool): # bool is subclass of int; test bool first
self.insert_cell(col, BooleanCell(self.__idx, col, style_index, label))
elif isinstance(label, (float, int, long, Decimal)):
self.insert_cell(col, NumberCell(self.__idx, col, style_index, label))
elif isinstance(label, (dt.datetime, dt.date, dt.time)):
date_number = self.__excel_date_dt(label)
self.insert_cell(col, NumberCell(self.__idx, col, style_index, date_number))
elif label is None:
self.insert_cell(col, BlankCell(self.__idx, col, style_index))
elif isinstance(label, ExcelFormula.Formula):
self.__parent_wb.add_sheet_reference(label)
self.insert_cell(col, FormulaCell(self.__idx, col, style_index, label))
else:
raise Exception("Unexpected data type %r" % type(label))
write_blanks = set_cell_mulblanks
-592
View File
@@ -1,592 +0,0 @@
# -*- coding: windows-1252 -*-
import Formatting
from BIFFRecords import *
FIRST_USER_DEFINED_NUM_FORMAT_IDX = 164
class XFStyle(object):
def __init__(self):
self.num_format_str = 'General'
self.font = Formatting.Font()
self.alignment = Formatting.Alignment()
self.borders = Formatting.Borders()
self.pattern = Formatting.Pattern()
self.protection = Formatting.Protection()
default_style = XFStyle()
class StyleCollection(object):
_std_num_fmt_list = [
'general',
'0',
'0.00',
'#,##0',
'#,##0.00',
'"$"#,##0_);("$"#,##',
'"$"#,##0_);[Red]("$"#,##',
'"$"#,##0.00_);("$"#,##',
'"$"#,##0.00_);[Red]("$"#,##',
'0%',
'0.00%',
'0.00E+00',
'# ?/?',
'# ??/??',
'M/D/YY',
'D-MMM-YY',
'D-MMM',
'MMM-YY',
'h:mm AM/PM',
'h:mm:ss AM/PM',
'h:mm',
'h:mm:ss',
'M/D/YY h:mm',
'_(#,##0_);(#,##0)',
'_(#,##0_);[Red](#,##0)',
'_(#,##0.00_);(#,##0.00)',
'_(#,##0.00_);[Red](#,##0.00)',
'_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
'_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
'_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
'_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
'mm:ss',
'[h]:mm:ss',
'mm:ss.0',
'##0.0E+0',
'@'
]
def __init__(self, style_compression=0):
self.style_compression = style_compression
self.stats = [0, 0, 0, 0, 0, 0]
self._font_id2x = {}
self._font_x2id = {}
self._font_val2x = {}
for x in (0, 1, 2, 3, 5): # The font with index 4 is omitted in all BIFF versions
font = Formatting.Font()
search_key = font._search_key()
self._font_id2x[font] = x
self._font_x2id[x] = font
self._font_val2x[search_key] = x
self._xf_id2x = {}
self._xf_x2id = {}
self._xf_val2x = {}
self._num_formats = {}
for fmtidx, fmtstr in zip(range(0, 23), StyleCollection._std_num_fmt_list[0:23]):
self._num_formats[fmtstr] = fmtidx
for fmtidx, fmtstr in zip(range(37, 50), StyleCollection._std_num_fmt_list[23:]):
self._num_formats[fmtstr] = fmtidx
self.default_style = XFStyle()
self._default_xf = self._add_style(self.default_style)[0]
def add(self, style):
if style == None:
return 0x10
return self._add_style(style)[1]
def _add_style(self, style):
num_format_str = style.num_format_str
if num_format_str in self._num_formats:
num_format_idx = self._num_formats[num_format_str]
else:
num_format_idx = (
FIRST_USER_DEFINED_NUM_FORMAT_IDX
+ len(self._num_formats)
- len(StyleCollection._std_num_fmt_list)
)
self._num_formats[num_format_str] = num_format_idx
font = style.font
if font in self._font_id2x:
font_idx = self._font_id2x[font]
self.stats[0] += 1
elif self.style_compression:
search_key = font._search_key()
font_idx = self._font_val2x.get(search_key)
if font_idx is not None:
self._font_id2x[font] = font_idx
self.stats[1] += 1
else:
font_idx = len(self._font_x2id) + 1 # Why plus 1? Font 4 is missing
self._font_id2x[font] = font_idx
self._font_val2x[search_key] = font_idx
self._font_x2id[font_idx] = font
self.stats[2] += 1
else:
font_idx = len(self._font_id2x) + 1
self._font_id2x[font] = font_idx
self.stats[2] += 1
gof = (style.alignment, style.borders, style.pattern, style.protection)
xf = (font_idx, num_format_idx) + gof
if xf in self._xf_id2x:
xf_index = self._xf_id2x[xf]
self.stats[3] += 1
elif self.style_compression == 2:
xf_key = (font_idx, num_format_idx) + tuple([obj._search_key() for obj in gof])
xf_index = self._xf_val2x.get(xf_key)
if xf_index is not None:
self._xf_id2x[xf] = xf_index
self.stats[4] += 1
else:
xf_index = 0x10 + len(self._xf_x2id)
self._xf_id2x[xf] = xf_index
self._xf_val2x[xf_key] = xf_index
self._xf_x2id[xf_index] = xf
self.stats[5] += 1
else:
xf_index = 0x10 + len(self._xf_id2x)
self._xf_id2x[xf] = xf_index
self.stats[5] += 1
if xf_index >= 0xFFF:
# 12 bits allowed, 0xFFF is a sentinel value
raise ValueError("More than 4094 XFs (styles)")
return xf, xf_index
def get_biff_data(self):
result = ''
result += self._all_fonts()
result += self._all_num_formats()
result += self._all_cell_styles()
result += self._all_styles()
return result
def _all_fonts(self):
result = ''
if self.style_compression:
alist = self._font_x2id.items()
else:
alist = [(x, o) for o, x in self._font_id2x.items()]
alist.sort()
for font_idx, font in alist:
result += font.get_biff_record().get()
return result
def _all_num_formats(self):
result = ''
alist = [
(v, k)
for k, v in self._num_formats.items()
if v >= FIRST_USER_DEFINED_NUM_FORMAT_IDX
]
alist.sort()
for fmtidx, fmtstr in alist:
result += NumberFormatRecord(fmtidx, fmtstr).get()
return result
def _all_cell_styles(self):
result = ''
for i in range(0, 16):
result += XFRecord(self._default_xf, 'style').get()
if self.style_compression == 2:
alist = self._xf_x2id.items()
else:
alist = [(x, o) for o, x in self._xf_id2x.items()]
alist.sort()
for xf_idx, xf in alist:
result += XFRecord(xf).get()
return result
def _all_styles(self):
return StyleRecord().get()
# easyxf and its supporting objects ###################################
class EasyXFException(Exception):
pass
class EasyXFCallerError(EasyXFException):
pass
class EasyXFAuthorError(EasyXFException):
pass
class IntULim(object):
# If astring represents a valid unsigned integer ('123', '0xabcd', etc)
# and it is <= limit, return the int value; otherwise return None.
def __init__(self, limit):
self.limit = limit
def __call__(self, astring):
try:
value = int(astring, 0)
except ValueError:
return None
if not 0 <= value <= self.limit:
return None
return value
bool_map = {
# Text values for all Boolean attributes
'1': 1, 'yes': 1, 'true': 1, 'on': 1,
'0': 0, 'no': 0, 'false': 0, 'off': 0,
}
border_line_map = {
# Text values for these borders attributes:
# left, right, top, bottom and diag
'no_line': 0x00,
'thin': 0x01,
'medium': 0x02,
'dashed': 0x03,
'dotted': 0x04,
'thick': 0x05,
'double': 0x06,
'hair': 0x07,
'medium_dashed': 0x08,
'thin_dash_dotted': 0x09,
'medium_dash_dotted': 0x0a,
'thin_dash_dot_dotted': 0x0b,
'medium_dash_dot_dotted': 0x0c,
'slanted_medium_dash_dotted': 0x0d,
}
charset_map = {
# Text values for font.charset
'ansi_latin': 0x00,
'sys_default': 0x01,
'symbol': 0x02,
'apple_roman': 0x4d,
'ansi_jap_shift_jis': 0x80,
'ansi_kor_hangul': 0x81,
'ansi_kor_johab': 0x82,
'ansi_chinese_gbk': 0x86,
'ansi_chinese_big5': 0x88,
'ansi_greek': 0xa1,
'ansi_turkish': 0xa2,
'ansi_vietnamese': 0xa3,
'ansi_hebrew': 0xb1,
'ansi_arabic': 0xb2,
'ansi_baltic': 0xba,
'ansi_cyrillic': 0xcc,
'ansi_thai': 0xde,
'ansi_latin_ii': 0xee,
'oem_latin_i': 0xff,
}
# Text values for colour indices. "grey" is a synonym of "gray".
# The names are those given by Microsoft Excel 2003 to the colours
# in the default palette. There is no great correspondence with
# any W3C name-to-RGB mapping.
_colour_map_text = """\
aqua 0x31
black 0x08
blue 0x0C
blue_gray 0x36
bright_green 0x0B
brown 0x3C
coral 0x1D
cyan_ega 0x0F
dark_blue 0x12
dark_blue_ega 0x12
dark_green 0x3A
dark_green_ega 0x11
dark_purple 0x1C
dark_red 0x10
dark_red_ega 0x10
dark_teal 0x38
dark_yellow 0x13
gold 0x33
gray_ega 0x17
gray25 0x16
gray40 0x37
gray50 0x17
gray80 0x3F
green 0x11
ice_blue 0x1F
indigo 0x3E
ivory 0x1A
lavender 0x2E
light_blue 0x30
light_green 0x2A
light_orange 0x34
light_turquoise 0x29
light_yellow 0x2B
lime 0x32
magenta_ega 0x0E
ocean_blue 0x1E
olive_ega 0x13
olive_green 0x3B
orange 0x35
pale_blue 0x2C
periwinkle 0x18
pink 0x0E
plum 0x3D
purple_ega 0x14
red 0x0A
rose 0x2D
sea_green 0x39
silver_ega 0x16
sky_blue 0x28
tan 0x2F
teal 0x15
teal_ega 0x15
turquoise 0x0F
violet 0x14
white 0x09
yellow 0x0D"""
colour_map = {}
for _line in _colour_map_text.splitlines():
_name, _num = _line.split()
_num = int(_num, 0)
colour_map[_name] = _num
if 'gray' in _name:
colour_map[_name.replace('gray', 'grey')] = _num
del _colour_map_text, _line, _name, _num
pattern_map = {
# Text values for pattern.pattern
# xlwt/doc/pattern_examples.xls showcases all of these patterns.
'no_fill': 0,
'none': 0,
'solid': 1,
'solid_fill': 1,
'solid_pattern': 1,
'fine_dots': 2,
'alt_bars': 3,
'sparse_dots': 4,
'thick_horz_bands': 5,
'thick_vert_bands': 6,
'thick_backward_diag': 7,
'thick_forward_diag': 8,
'big_spots': 9,
'bricks': 10,
'thin_horz_bands': 11,
'thin_vert_bands': 12,
'thin_backward_diag': 13,
'thin_forward_diag': 14,
'squares': 15,
'diamonds': 16,
}
def any_str_func(s):
return s.strip()
def colour_index_func(s, maxval=0x7F):
try:
value = int(s, 0)
except ValueError:
return None
if not (0 <= value <= maxval):
return None
return value
colour_index_func_7 = colour_index_func
def colour_index_func_15(s):
return colour_index_func(s, maxval=0x7FFF)
def rotation_func(s):
try:
value = int(s, 0)
except ValueError:
return None
if not (-90 <= value <= 90):
raise EasyXFCallerError("rotation %d: should be -90 to +90 degrees" % value)
if value < 0:
value = 90 - value # encode as 91 to 180 (clockwise)
return value
xf_dict = {
'align': 'alignment', # synonym
'alignment': {
'dire': {
'general': 0,
'lr': 1,
'rl': 2,
},
'direction': 'dire',
'horiz': 'horz',
'horizontal': 'horz',
'horz': {
'general': 0,
'left': 1,
'center': 2,
'centre': 2, # "align: horiz centre" means xf.alignment.horz is set to 2
'right': 3,
'filled': 4,
'justified': 5,
'center_across_selection': 6,
'centre_across_selection': 6,
'distributed': 7,
},
'inde': IntULim(15), # restriction: 0 <= value <= 15
'indent': 'inde',
'rota': [{'stacked': 255, 'none': 0, }, rotation_func],
'rotation': 'rota',
'shri': bool_map,
'shrink': 'shri',
'shrink_to_fit': 'shri',
'vert': {
'top': 0,
'center': 1,
'centre': 1,
'bottom': 2,
'justified': 3,
'distributed': 4,
},
'vertical': 'vert',
'wrap': bool_map,
},
'border': 'borders',
'borders': {
'left': [border_line_map, IntULim(0x0d)],
'right': [border_line_map, IntULim(0x0d)],
'top': [border_line_map, IntULim(0x0d)],
'bottom': [border_line_map, IntULim(0x0d)],
'diag': [border_line_map, IntULim(0x0d)],
'top_colour': [colour_map, colour_index_func_7],
'bottom_colour': [colour_map, colour_index_func_7],
'left_colour': [colour_map, colour_index_func_7],
'right_colour': [colour_map, colour_index_func_7],
'diag_colour': [colour_map, colour_index_func_7],
'top_color': 'top_colour',
'bottom_color': 'bottom_colour',
'left_color': 'left_colour',
'right_color': 'right_colour',
'diag_color': 'diag-colour',
'need_diag_1': bool_map,
'need_diag_2': bool_map,
},
'font': {
'bold': bool_map,
'charset': charset_map,
'color': 'colour_index',
'color_index': 'colour_index',
'colour': 'colour_index',
'colour_index': [colour_map, colour_index_func_15],
'escapement': {'none': 0, 'superscript': 1, 'subscript': 2},
'family': {'none': 0, 'roman': 1, 'swiss': 2, 'modern': 3, 'script': 4, 'decorative': 5, },
'height': IntULim(0xFFFF), # practical limits are much narrower e.g. 160 to 1440 (8pt to 72pt)
'italic': bool_map,
'name': any_str_func,
'outline': bool_map,
'shadow': bool_map,
'struck_out': bool_map,
'underline': [bool_map, {'none': 0, 'single': 1, 'single_acc': 0x21, 'double': 2, 'double_acc': 0x22, }],
},
'pattern': {
'back_color': 'pattern_back_colour',
'back_colour': 'pattern_back_colour',
'fore_color': 'pattern_fore_colour',
'fore_colour': 'pattern_fore_colour',
'pattern': [pattern_map, IntULim(16)],
'pattern_back_color': 'pattern_back_colour',
'pattern_back_colour': [colour_map, colour_index_func_7],
'pattern_fore_color': 'pattern_fore_colour',
'pattern_fore_colour': [colour_map, colour_index_func_7],
},
'protection': {
'cell_locked' : bool_map,
'formula_hidden': bool_map,
},
}
def _esplit(s, split_char, esc_char="\\"):
escaped = False
olist = ['']
for c in s:
if escaped:
olist[-1] += c
escaped = False
elif c == esc_char:
escaped = True
elif c == split_char:
olist.append('')
else:
olist[-1] += c
return olist
def _parse_strg_to_obj(strg, obj, parse_dict,
field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False):
for line in _esplit(strg, line_sep, esc_char):
line = line.strip()
if not line:
break
split_line = _esplit(line, intro_sep, esc_char)
if len(split_line) != 2:
raise EasyXFCallerError('line %r should have exactly 1 "%c"' % (line, intro_sep))
section, item_str = split_line
section = section.strip().lower()
for counter in range(2):
result = parse_dict.get(section)
if result is None:
raise EasyXFCallerError('section %r is unknown' % section)
if isinstance(result, dict):
break
if not isinstance(result, str):
raise EasyXFAuthorError(
'section %r should map to dict or str object; found %r' % (section, type(result)))
# synonym
old_section = section
section = result
else:
raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_section, result))
section_dict = result
section_obj = getattr(obj, section, None)
if section_obj is None:
raise EasyXFAuthorError('instance of %s class has no attribute named %s' % (obj.__class__.__name__, section))
for kv_str in _esplit(item_str, field_sep, esc_char):
guff = kv_str.split()
if not guff:
continue
k = guff[0].lower().replace('-', '_')
v = ' '.join(guff[1:])
if not v:
raise EasyXFCallerError("no value supplied for %s.%s" % (section, k))
for counter in xrange(2):
result = section_dict.get(k)
if result is None:
raise EasyXFCallerError('%s.%s is not a known attribute' % (section, k))
if not isinstance(result, basestring):
break
# synonym
old_k = k
k = result
else:
raise EasyXFAuthorError('Attempt to define synonym of synonym (%r: %r)' % (old_k, result))
value_info = result
if not isinstance(value_info, list):
value_info = [value_info]
for value_rule in value_info:
if isinstance(value_rule, dict):
# dict maps strings to integer field values
vl = v.lower().replace('-', '_')
if vl in value_rule:
value = value_rule[vl]
break
elif callable(value_rule):
value = value_rule(v)
if value is not None:
break
else:
raise EasyXFAuthorError("unknown value rule for attribute %r: %r" % (k, value_rule))
else:
raise EasyXFCallerError("unexpected value %r for %s.%s" % (v, section, k))
try:
orig = getattr(section_obj, k)
except AttributeError:
raise EasyXFAuthorError('%s.%s in dictionary but not in supplied object' % (section, k))
if debug: print "+++ %s.%s = %r # %s; was %r" % (section, k, value, v, orig)
setattr(section_obj, k, value)
def easyxf(strg_to_parse="", num_format_str=None,
field_sep=",", line_sep=";", intro_sep=":", esc_char="\\", debug=False):
xfobj = XFStyle()
if num_format_str is not None:
xfobj.num_format_str = num_format_str
if strg_to_parse:
_parse_strg_to_obj(strg_to_parse, xfobj, xf_dict,
field_sep=field_sep, line_sep=line_sep, intro_sep=intro_sep, esc_char=esc_char, debug=debug)
return xfobj
-81
View File
@@ -1,81 +0,0 @@
# -*- coding: windows-1252 -*-
'''
From BIFF8 on, strings are always stored using UTF-16LE text encoding. The
character array is a sequence of 16-bit values4. Additionally it is
possible to use a compressed format, which omits the high bytes of all
characters, if they are all zero.
The following tables describe the standard format of the entire string, but
in many records the strings differ from this format. This will be mentioned
separately. It is possible (but not required) to store Rich-Text formatting
information and Asian phonetic information inside a Unicode string. This
results in four different ways to store a string. The character array
is not zero-terminated.
The string consists of the character count (as usual an 8-bit value or
a 16-bit value), option flags, the character array and optional formatting
information. If the string is empty, sometimes the option flags field will
not occur. This is mentioned at the respective place.
Offset Size Contents
0 1 or 2 Length of the string (character count, ln)
1 or 2 1 Option flags:
Bit Mask Contents
0 01H Character compression (ccompr):
0 = Compressed (8-bit characters)
1 = Uncompressed (16-bit characters)
2 04H Asian phonetic settings (phonetic):
0 = Does not contain Asian phonetic settings
1 = Contains Asian phonetic settings
3 08H Rich-Text settings (richtext):
0 = Does not contain Rich-Text settings
1 = Contains Rich-Text settings
[2 or 3] 2 (optional, only if richtext=1) Number of Rich-Text formatting runs (rt)
[var.] 4 (optional, only if phonetic=1) Size of Asian phonetic settings block (in bytes, sz)
var. ln or
2·ln Character array (8-bit characters or 16-bit characters, dependent on ccompr)
[var.] 4·rt (optional, only if richtext=1) List of rt formatting runs
[var.] sz (optional, only if phonetic=1) Asian Phonetic Settings Block
'''
from struct import pack
def upack2(s, encoding='ascii'):
# If not unicode, make it so.
if isinstance(s, unicode):
us = s
else:
us = unicode(s, encoding)
# Limit is based on number of content characters
# (not on number of bytes in packed result)
len_us = len(us)
if len_us > 65535:
raise Exception('String longer than 65535 characters')
try:
encs = us.encode('latin1')
# Success here means all chars are in U+0000 to U+00FF
# inclusive, meaning that we can use "compressed format".
flag = 0
except UnicodeEncodeError:
encs = us.encode('utf_16_le')
flag = 1
return pack('<HB', len_us, flag) + encs
def upack1(s, encoding='ascii'):
# Same as upack2(), but with a one-byte length field.
if isinstance(s, unicode):
us = s
else:
us = unicode(s, encoding)
len_us = len(us)
if len_us > 255:
raise Exception('String longer than 255 characters')
try:
encs = us.encode('latin1')
flag = 0
except UnicodeEncodeError:
encs = us.encode('utf_16_le')
flag = 1
return pack('<BB', len_us, flag) + encs
-196
View File
@@ -1,196 +0,0 @@
# pyXLWriter: A library for generating Excel Spreadsheets
# Copyright (c) 2004 Evgeny Filatov <fufff@users.sourceforge.net>
# Copyright (c) 2002-2004 John McNamara (Perl Spreadsheet::WriteExcel)
#
# This library 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 2.1 of the License, or
# (at your option) any later version.
#
# This library 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 Lesser
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#----------------------------------------------------------------------------
# This module was written/ported from PERL Spreadsheet::WriteExcel module
# The author of the PERL Spreadsheet::WriteExcel module is John McNamara
# <jmcnamara@cpan.org>
#----------------------------------------------------------------------------
# See the README.txt distributed with pyXLWriter for more details.
# Portions are (C) Roman V. Kiseliov, 2005
# Utilities for work with reference to cells and with sheetnames
__rev_id__ = """$Id: Utils.py 3844 2009-05-20 01:02:54Z sjmachin $"""
import re
from struct import pack
from ExcelMagic import MAX_ROW, MAX_COL
_re_cell_ex = re.compile(r"(\$?)([A-I]?[A-Z])(\$?)(\d+)", re.IGNORECASE)
_re_row_range = re.compile(r"\$?(\d+):\$?(\d+)")
_re_col_range = re.compile(r"\$?([A-I]?[A-Z]):\$?([A-I]?[A-Z])", re.IGNORECASE)
_re_cell_range = re.compile(r"\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE)
_re_cell_ref = re.compile(r"\$?([A-I]?[A-Z]\$?\d+)", re.IGNORECASE)
def col_by_name(colname):
"""
"""
col = 0
pow = 1
for i in xrange(len(colname)-1, -1, -1):
ch = colname[i]
col += (ord(ch) - ord('A') + 1) * pow
pow *= 26
return col - 1
def cell_to_rowcol(cell):
"""Convert an Excel cell reference string in A1 notation
to numeric row/col notation.
Returns: row, col, row_abs, col_abs
"""
m = _re_cell_ex.match(cell)
if not m:
raise Exception("Ill-formed single_cell reference: %s" % cell)
col_abs, col, row_abs, row = m.groups()
row_abs = bool(row_abs)
col_abs = bool(col_abs)
row = int(row) - 1
col = col_by_name(col.upper())
return row, col, row_abs, col_abs
def cell_to_rowcol2(cell):
"""Convert an Excel cell reference string in A1 notation
to numeric row/col notation.
Returns: row, col
"""
m = _re_cell_ex.match(cell)
if not m:
raise Exception("Error in cell format")
col_abs, col, row_abs, row = m.groups()
# Convert base26 column string to number
# All your Base are belong to us.
row = int(row) - 1
col = col_by_name(col.upper())
return row, col
def rowcol_to_cell(row, col, row_abs=False, col_abs=False):
"""Convert numeric row/col notation to an Excel cell reference string in
A1 notation.
"""
assert 0 <= row < MAX_ROW # MAX_ROW counts from 1
assert 0 <= col < MAX_COL # MAX_COL counts from 1
d = col // 26
m = col % 26
chr1 = "" # Most significant character in AA1
if row_abs:
row_abs = '$'
else:
row_abs = ''
if col_abs:
col_abs = '$'
else:
col_abs = ''
if d > 0:
chr1 = chr(ord('A') + d - 1)
chr2 = chr(ord('A') + m)
# Zero index to 1-index
return col_abs + chr1 + chr2 + row_abs + str(row + 1)
def rowcol_pair_to_cellrange(row1, col1, row2, col2,
row1_abs=False, col1_abs=False, row2_abs=False, col2_abs=False):
"""Convert two (row,column) pairs
into a cell range string in A1:B2 notation.
Returns: cell range string
"""
assert row1 <= row2
assert col1 <= col2
return (
rowcol_to_cell(row1, col1, row1_abs, col1_abs)
+ ":"
+ rowcol_to_cell(row2, col2, row2_abs, col2_abs)
)
def cellrange_to_rowcol_pair(cellrange):
"""Convert cell range string in A1 notation to numeric row/col
pair.
Returns: row1, col1, row2, col2
"""
cellrange = cellrange.upper()
# Convert a row range: '1:3'
res = _re_row_range.match(cellrange)
if res:
row1 = int(res.group(1)) - 1
col1 = 0
row2 = int(res.group(2)) - 1
col2 = -1
return row1, col1, row2, col2
# Convert a column range: 'A:A' or 'B:G'.
# A range such as A:A is equivalent to A1:A16384, so add rows as required
res = _re_col_range.match(cellrange)
if res:
col1 = col_by_name(res.group(1).upper())
row1 = 0
col2 = col_by_name(res.group(2).upper())
row2 = -1
return row1, col1, row2, col2
# Convert a cell range: 'A1:B7'
res = _re_cell_range.match(cellrange)
if res:
row1, col1 = cell_to_rowcol2(res.group(1))
row2, col2 = cell_to_rowcol2(res.group(2))
return row1, col1, row2, col2
# Convert a cell reference: 'A1' or 'AD2000'
res = _re_cell_ref.match(cellrange)
if res:
row1, col1 = cell_to_rowcol2(res.group(1))
return row1, col1, row1, col1
raise Exception("Unknown cell reference %s" % (cell))
def cell_to_packed_rowcol(cell):
""" pack row and column into the required 4 byte format """
row, col, row_abs, col_abs = cell_to_rowcol(cell)
if col >= MAX_COL:
raise Exception("Column %s greater than IV in formula" % cell)
if row >= MAX_ROW: # this for BIFF8. for BIFF7 available 2^14
raise Exception("Row %s greater than %d in formula" % (cell, MAX_ROW))
col |= int(not row_abs) << 15
col |= int(not col_abs) << 14
return row, col
# === sheetname functions ===
def valid_sheet_name(sheet_name):
if sheet_name == u"" or sheet_name[0] == u"'" or len(sheet_name) > 31:
return False
for c in sheet_name:
if c in u"[]:\\?/*\x00":
return False
return True
def quote_sheet_name(unquoted_sheet_name):
if not valid_sheet_name(unquoted_sheet_name):
raise Exception(
'attempt to quote an invalid worksheet name %r' % unquoted_sheet_name)
return u"'" + unquoted_sheet_name.replace(u"'", u"''") + u"'"
-636
View File
@@ -1,636 +0,0 @@
# -*- coding: windows-1252 -*-
'''
Record Order in BIFF8
Workbook Globals Substream
BOF Type = workbook globals
Interface Header
MMS
Interface End
WRITEACCESS
CODEPAGE
DSF
TABID
FNGROUPCOUNT
Workbook Protection Block
WINDOWPROTECT
PROTECT
PASSWORD
PROT4REV
PROT4REVPASS
BACKUP
HIDEOBJ
WINDOW1
DATEMODE
PRECISION
REFRESHALL
BOOKBOOL
FONT +
FORMAT *
XF +
STYLE +
? PALETTE
USESELFS
BOUNDSHEET +
COUNTRY
? Link Table
SST
ExtSST
EOF
'''
import BIFFRecords
import Style
class Workbook(object):
#################################################################
## Constructor
#################################################################
def __init__(self, encoding='ascii', style_compression=0):
self.encoding = encoding
self.__owner = 'None'
self.__country_code = None # 0x07 is Russia :-)
self.__wnd_protect = 0
self.__obj_protect = 0
self.__protect = 0
self.__backup_on_save = 0
# for WINDOW1 record
self.__hpos_twips = 0x01E0
self.__vpos_twips = 0x005A
self.__width_twips = 0x3FCF
self.__height_twips = 0x2A4E
self.__active_sheet = 0
self.__first_tab_index = 0
self.__selected_tabs = 0x01
self.__tab_width_twips = 0x0258
self.__wnd_hidden = 0
self.__wnd_mini = 0
self.__hscroll_visible = 1
self.__vscroll_visible = 1
self.__tabs_visible = 1
self.__styles = Style.StyleCollection(style_compression)
self.__dates_1904 = 0
self.__use_cell_values = 1
self.__sst = BIFFRecords.SharedStringTable(self.encoding)
self.__worksheets = []
self.__worksheet_idx_from_name = {}
self.__sheet_refs = {}
self._supbook_xref = {}
self._xcall_xref = {}
self._ownbook_supbookx = None
self._ownbook_supbook_ref = None
self._xcall_supbookx = None
self._xcall_supbook_ref = None
#################################################################
## Properties, "getters", "setters"
#################################################################
def get_style_stats(self):
return self.__styles.stats[:]
def set_owner(self, value):
self.__owner = value
def get_owner(self):
return self.__owner
owner = property(get_owner, set_owner)
#################################################################
def set_country_code(self, value):
self.__country_code = value
def get_country_code(self):
return self.__country_code
country_code = property(get_country_code, set_country_code)
#################################################################
def set_wnd_protect(self, value):
self.__wnd_protect = int(value)
def get_wnd_protect(self):
return bool(self.__wnd_protect)
wnd_protect = property(get_wnd_protect, set_wnd_protect)
#################################################################
def set_obj_protect(self, value):
self.__obj_protect = int(value)
def get_obj_protect(self):
return bool(self.__obj_protect)
obj_protect = property(get_obj_protect, set_obj_protect)
#################################################################
def set_protect(self, value):
self.__protect = int(value)
def get_protect(self):
return bool(self.__protect)
protect = property(get_protect, set_protect)
#################################################################
def set_backup_on_save(self, value):
self.__backup_on_save = int(value)
def get_backup_on_save(self):
return bool(self.__backup_on_save)
backup_on_save = property(get_backup_on_save, set_backup_on_save)
#################################################################
def set_hpos(self, value):
self.__hpos_twips = value & 0xFFFF
def get_hpos(self):
return self.__hpos_twips
hpos = property(get_hpos, set_hpos)
#################################################################
def set_vpos(self, value):
self.__vpos_twips = value & 0xFFFF
def get_vpos(self):
return self.__vpos_twips
vpos = property(get_vpos, set_vpos)
#################################################################
def set_width(self, value):
self.__width_twips = value & 0xFFFF
def get_width(self):
return self.__width_twips
width = property(get_width, set_width)
#################################################################
def set_height(self, value):
self.__height_twips = value & 0xFFFF
def get_height(self):
return self.__height_twips
height = property(get_height, set_height)
#################################################################
def set_active_sheet(self, value):
self.__active_sheet = value & 0xFFFF
self.__first_tab_index = self.__active_sheet
def get_active_sheet(self):
return self.__active_sheet
active_sheet = property(get_active_sheet, set_active_sheet)
#################################################################
def set_tab_width(self, value):
self.__tab_width_twips = value & 0xFFFF
def get_tab_width(self):
return self.__tab_width_twips
tab_width = property(get_tab_width, set_tab_width)
#################################################################
def set_wnd_visible(self, value):
self.__wnd_hidden = int(not value)
def get_wnd_visible(self):
return not bool(self.__wnd_hidden)
wnd_visible = property(get_wnd_visible, set_wnd_visible)
#################################################################
def set_wnd_mini(self, value):
self.__wnd_mini = int(value)
def get_wnd_mini(self):
return bool(self.__wnd_mini)
wnd_mini = property(get_wnd_mini, set_wnd_mini)
#################################################################
def set_hscroll_visible(self, value):
self.__hscroll_visible = int(value)
def get_hscroll_visible(self):
return bool(self.__hscroll_visible)
hscroll_visible = property(get_hscroll_visible, set_hscroll_visible)
#################################################################
def set_vscroll_visible(self, value):
self.__vscroll_visible = int(value)
def get_vscroll_visible(self):
return bool(self.__vscroll_visible)
vscroll_visible = property(get_vscroll_visible, set_vscroll_visible)
#################################################################
def set_tabs_visible(self, value):
self.__tabs_visible = int(value)
def get_tabs_visible(self):
return bool(self.__tabs_visible)
tabs_visible = property(get_tabs_visible, set_tabs_visible)
#################################################################
def set_dates_1904(self, value):
self.__dates_1904 = int(value)
def get_dates_1904(self):
return bool(self.__dates_1904)
dates_1904 = property(get_dates_1904, set_dates_1904)
#################################################################
def set_use_cell_values(self, value):
self.__use_cell_values = int(value)
def get_use_cell_values(self):
return bool(self.__use_cell_values)
use_cell_values = property(get_use_cell_values, set_use_cell_values)
#################################################################
def get_default_style(self):
return self.__styles.default_style
default_style = property(get_default_style)
##################################################################
## Methods
##################################################################
def add_style(self, style):
return self.__styles.add(style)
def add_str(self, s):
return self.__sst.add_str(s)
def del_str(self, sst_idx):
self.__sst.del_str(sst_idx)
def str_index(self, s):
return self.__sst.str_index(s)
def add_sheet(self, sheetname, cell_overwrite_ok=False):
import Worksheet, Utils
if not isinstance(sheetname, unicode):
sheetname = sheetname.decode(self.encoding)
if not Utils.valid_sheet_name(sheetname):
raise Exception("invalid worksheet name %r" % sheetname)
lower_name = sheetname.lower()
if lower_name in self.__worksheet_idx_from_name:
raise Exception("duplicate worksheet name %r" % sheetname)
self.__worksheet_idx_from_name[lower_name] = len(self.__worksheets)
self.__worksheets.append(Worksheet.Worksheet(sheetname, self, cell_overwrite_ok))
return self.__worksheets[-1]
def get_sheet(self, sheetnum):
return self.__worksheets[sheetnum]
def raise_bad_sheetname(self, sheetname):
raise Exception("Formula: unknown sheet name %s" % sheetname)
def convert_sheetindex(self, strg_ref, n_sheets):
idx = int(strg_ref)
if 0 <= idx < n_sheets:
return idx
msg = "Formula: sheet index (%s) >= number of sheets (%d)" % (strg_ref, n_sheets)
raise Exception(msg)
def _get_supbook_index(self, tag):
if tag in self._supbook_xref:
return self._supbook_xref[tag]
self._supbook_xref[tag] = idx = len(self._supbook_xref)
return idx
def setup_ownbook(self):
self._ownbook_supbookx = self._get_supbook_index(('ownbook', 0))
self._ownbook_supbook_ref = None
reference = (self._ownbook_supbookx, 0xFFFE, 0xFFFE)
if reference in self.__sheet_refs:
raise Exception("can't happen")
self.__sheet_refs[reference] = self._ownbook_supbook_ref = len(self.__sheet_refs)
def setup_xcall(self):
self._xcall_supbookx = self._get_supbook_index(('xcall', 0))
self._xcall_supbook_ref = None
reference = (self._xcall_supbookx, 0xFFFE, 0xFFFE)
if reference in self.__sheet_refs:
raise Exception("can't happen")
self.__sheet_refs[reference] = self._xcall_supbook_ref = len(self.__sheet_refs)
def add_sheet_reference(self, formula):
patches = []
n_sheets = len(self.__worksheets)
sheet_refs, xcall_refs = formula.get_references()
for ref0, ref1, offset in sheet_refs:
if not ref0.isdigit():
try:
ref0n = self.__worksheet_idx_from_name[ref0.lower()]
except KeyError:
self.raise_bad_sheetname(ref0)
else:
ref0n = self.convert_sheetindex(ref0, n_sheets)
if ref1 == ref0:
ref1n = ref0n
elif not ref1.isdigit():
try:
ref1n = self.__worksheet_idx_from_name[ref1.lower()]
except KeyError:
self.raise_bad_sheetname(ref1)
else:
ref1n = self.convert_sheetindex(ref1, n_sheets)
if ref1n < ref0n:
msg = "Formula: sheets out of order; %r:%r -> (%d, %d)" \
% (ref0, ref1, ref0n, ref1n)
raise Exception(msg)
if self._ownbook_supbookx is None:
self.setup_ownbook()
reference = (self._ownbook_supbookx, ref0n, ref1n)
if reference in self.__sheet_refs:
patches.append((offset, self.__sheet_refs[reference]))
else:
nrefs = len(self.__sheet_refs)
if nrefs > 65535:
raise Exception('More than 65536 inter-sheet references')
self.__sheet_refs[reference] = nrefs
patches.append((offset, nrefs))
for funcname, offset in xcall_refs:
if self._ownbook_supbookx is None:
self.setup_ownbook()
if self._xcall_supbookx is None:
self.setup_xcall()
# print funcname, self._supbook_xref
patches.append((offset, self._xcall_supbook_ref))
if not isinstance(funcname, unicode):
funcname = funcname.decode(self.encoding)
if funcname in self._xcall_xref:
idx = self._xcall_xref[funcname]
else:
self._xcall_xref[funcname] = idx = len(self._xcall_xref)
patches.append((offset + 2, idx + 1))
formula.patch_references(patches)
##################################################################
## BIFF records generation
##################################################################
def __bof_rec(self):
return BIFFRecords.Biff8BOFRecord(BIFFRecords.Biff8BOFRecord.BOOK_GLOBAL).get()
def __eof_rec(self):
return BIFFRecords.EOFRecord().get()
def __intf_hdr_rec(self):
return BIFFRecords.InteraceHdrRecord().get()
def __intf_end_rec(self):
return BIFFRecords.InteraceEndRecord().get()
def __intf_mms_rec(self):
return BIFFRecords.MMSRecord().get()
def __write_access_rec(self):
return BIFFRecords.WriteAccessRecord(self.__owner).get()
def __wnd_protect_rec(self):
return BIFFRecords.WindowProtectRecord(self.__wnd_protect).get()
def __obj_protect_rec(self):
return BIFFRecords.ObjectProtectRecord(self.__obj_protect).get()
def __protect_rec(self):
return BIFFRecords.ProtectRecord(self.__protect).get()
def __password_rec(self):
return BIFFRecords.PasswordRecord().get()
def __prot4rev_rec(self):
return BIFFRecords.Prot4RevRecord().get()
def __prot4rev_pass_rec(self):
return BIFFRecords.Prot4RevPassRecord().get()
def __backup_rec(self):
return BIFFRecords.BackupRecord(self.__backup_on_save).get()
def __hide_obj_rec(self):
return BIFFRecords.HideObjRecord().get()
def __window1_rec(self):
flags = 0
flags |= (self.__wnd_hidden) << 0
flags |= (self.__wnd_mini) << 1
flags |= (self.__hscroll_visible) << 3
flags |= (self.__vscroll_visible) << 4
flags |= (self.__tabs_visible) << 5
return BIFFRecords.Window1Record(self.__hpos_twips, self.__vpos_twips,
self.__width_twips, self.__height_twips,
flags,
self.__active_sheet, self.__first_tab_index,
self.__selected_tabs, self.__tab_width_twips).get()
def __codepage_rec(self):
return BIFFRecords.CodepageBiff8Record().get()
def __country_rec(self):
if not self.__country_code:
return ''
return BIFFRecords.CountryRecord(self.__country_code, self.__country_code).get()
def __dsf_rec(self):
return BIFFRecords.DSFRecord().get()
def __tabid_rec(self):
return BIFFRecords.TabIDRecord(len(self.__worksheets)).get()
def __fngroupcount_rec(self):
return BIFFRecords.FnGroupCountRecord().get()
def __datemode_rec(self):
return BIFFRecords.DateModeRecord(self.__dates_1904).get()
def __precision_rec(self):
return BIFFRecords.PrecisionRecord(self.__use_cell_values).get()
def __refresh_all_rec(self):
return BIFFRecords.RefreshAllRecord().get()
def __bookbool_rec(self):
return BIFFRecords.BookBoolRecord().get()
def __all_fonts_num_formats_xf_styles_rec(self):
return self.__styles.get_biff_data()
def __palette_rec(self):
result = ''
return result
def __useselfs_rec(self):
return BIFFRecords.UseSelfsRecord().get()
def __boundsheets_rec(self, data_len_before, data_len_after, sheet_biff_lens):
# .................................
# BOUNDSEHEET0
# BOUNDSEHEET1
# BOUNDSEHEET2
# ..................................
# WORKSHEET0
# WORKSHEET1
# WORKSHEET2
boundsheets_len = 0
for sheet in self.__worksheets:
boundsheets_len += len(BIFFRecords.BoundSheetRecord(
0x00L, sheet.visibility, sheet.name, self.encoding
).get())
start = data_len_before + boundsheets_len + data_len_after
result = ''
for sheet_biff_len, sheet in zip(sheet_biff_lens, self.__worksheets):
result += BIFFRecords.BoundSheetRecord(
start, sheet.visibility, sheet.name, self.encoding
).get()
start += sheet_biff_len
return result
def __all_links_rec(self):
pieces = []
temp = [(idx, tag) for tag, idx in self._supbook_xref.items()]
temp.sort()
for idx, tag in temp:
stype, snum = tag
if stype == 'ownbook':
rec = BIFFRecords.InternalReferenceSupBookRecord(len(self.__worksheets)).get()
pieces.append(rec)
elif stype == 'xcall':
rec = BIFFRecords.XcallSupBookRecord().get()
pieces.append(rec)
temp = [(idx, name) for name, idx in self._xcall_xref.items()]
temp.sort()
for idx, name in temp:
rec = BIFFRecords.ExternnameRecord(
options=0, index=0, name=name, fmla='\x02\x00\x1c\x17').get()
pieces.append(rec)
else:
raise Exception('unknown supbook stype %r' % stype)
if len(self.__sheet_refs) > 0:
# get references in index order
temp = [(idx, ref) for ref, idx in self.__sheet_refs.items()]
temp.sort()
temp = [ref for idx, ref in temp]
externsheet_record = BIFFRecords.ExternSheetRecord(temp).get()
pieces.append(externsheet_record)
return ''.join(pieces)
def __sst_rec(self):
return self.__sst.get_biff_record()
def __ext_sst_rec(self, abs_stream_pos):
return ''
#return BIFFRecords.ExtSSTRecord(abs_stream_pos, self.sst_record.str_placement,
#self.sst_record.portions_len).get()
def get_biff_data(self):
before = ''
before += self.__bof_rec()
before += self.__intf_hdr_rec()
before += self.__intf_mms_rec()
before += self.__intf_end_rec()
before += self.__write_access_rec()
before += self.__codepage_rec()
before += self.__dsf_rec()
before += self.__tabid_rec()
before += self.__fngroupcount_rec()
before += self.__wnd_protect_rec()
before += self.__protect_rec()
before += self.__obj_protect_rec()
before += self.__password_rec()
before += self.__prot4rev_rec()
before += self.__prot4rev_pass_rec()
before += self.__backup_rec()
before += self.__hide_obj_rec()
before += self.__window1_rec()
before += self.__datemode_rec()
before += self.__precision_rec()
before += self.__refresh_all_rec()
before += self.__bookbool_rec()
before += self.__all_fonts_num_formats_xf_styles_rec()
before += self.__palette_rec()
before += self.__useselfs_rec()
country = self.__country_rec()
all_links = self.__all_links_rec()
shared_str_table = self.__sst_rec()
after = country + all_links + shared_str_table
ext_sst = self.__ext_sst_rec(0) # need fake cause we need calc stream pos
eof = self.__eof_rec()
self.__worksheets[self.__active_sheet].selected = True
sheets = ''
sheet_biff_lens = []
for sheet in self.__worksheets:
data = sheet.get_biff_data()
sheets += data
sheet_biff_lens.append(len(data))
bundlesheets = self.__boundsheets_rec(len(before), len(after)+len(ext_sst)+len(eof), sheet_biff_lens)
sst_stream_pos = len(before) + len(bundlesheets) + len(country) + len(all_links)
ext_sst = self.__ext_sst_rec(sst_stream_pos)
return before + bundlesheets + after + ext_sst + eof + sheets
def save(self, filename):
import CompoundDoc
doc = CompoundDoc.XlsDoc()
doc.save(filename, self.get_biff_data())
File diff suppressed because it is too large Load Diff
-16
View File
@@ -1,16 +0,0 @@
# -*- coding: windows-1252 -*-
__VERSION__ = '0.7.2'
import sys
if sys.version_info[:2] < (2, 3):
print >> sys.stderr, "Sorry, xlwt requires Python 2.3 or later"
sys.exit(1)
from Workbook import Workbook
from Worksheet import Worksheet
from Row import Row
from Column import Column
from Formatting import Font, Alignment, Borders, Pattern, Protection
from Style import XFStyle, easyxf
from ExcelFormula import *
File diff suppressed because it is too large Load Diff
-199
View File
@@ -1,199 +0,0 @@
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=us-ascii' />
<title>The xlwt Module</title>
</head>
<body>
<h1>The xlwt Module</h1>
<p /><p><b>A Python package for generating Microsoft Excel &#8482; spreadsheet files.
</b></p>
<h2>General information</h2>
<h3>State of Documentation</h3>
<p>
This documentation is currently incomplete. There may be methods and
classes not included and any item marked with a <em
style="color:red;">[NC]</em> is not complete and may have further
parameters, methods, attributes and functionality that are not
documented. In these cases, you'll have to refer to the source if the
documentation provided is insufficient.
</p>
</p>
<h2>Module Contents <em style="color:red;">[NC]</em></h2>
<dl>
<dt><b>easyxf</b> (function)</dt>
<dd>
<p>
This function is used to create and configure XFStyle objects
for use with (for example) the Worksheet.write method.
</p>
<dl>
<dt><i>strg_to_parse</i></dt>
<dd>
<p>
A string to be parsed to obtain attribute values for Alignment, Borders, Font,
Pattern and Protection objects. Refer to the examples
in the file .../examples/xlwt_easyxf_simple_demo.py and to the xf_dict
dictionary in Style.py. Various synonyms including color/colour, center/centre and gray/grey
are allowed. Case is irrelevant (except maybe in font names). '-' may be used instead
of '_'.<br />
Example: "font: bold on; align: wrap on, vert centre, horiz center"
</p>
</dd>
<dt><i>num_format_str</i></dt>
<dd>
<p>
To get the "number format string" of an existing cell whose format you want to reproduce,
select the cell and click on Format/Cells/Number/Custom. Otherwise, refer to Excel help.<br />
Examples: "#,##0.00", "dd/mm/yyyy"
</p>
</dd>
<dt>Returns:</dt>
<dd>
An object of the XFstyle class
</dd>
</dl>
<br />
</dd>
<dt><b>Workbook</b> (class) [<a href='#xlwt.Workbook-class'>#</a>]</dt>
<dd>
<p>The class to instantiate to create a workbook</p>
<p>For more information about this class, see <a href='#xlwt.Workbook-class'><i>The Workbook Class</i></a>.</p>
</dd>
<dt><b>Worksheet</b> (class) [<a href='#xlwt.Worksheet-class'>#</a>]</dt>
<dd>
<p>A class to represent the contents of a sheet in a workbook.</p>
<p>For more information about this class, see <a href='#xlwt.Worksheet-class'><i>The Worksheet Class</i></a>.</p>
</dd>
</dl>
<h2><a id='xlwt.Workbook-class' name='xlwt.Workbook-class'>The Workbook Class</a><em style="color:red;">[NC]</em></h2>
<dl>
<dt><b>Workbook(encoding='ascii',style_compression=0)</b> (class) [<a href='#xlwt.Workbook-class'>#</a>]</dt>
<dd>
<p>
This is a class representing a workbook and all its contents.
When creating Excel files with xlwt, you will normally start by
instantiating an object of this class.
</p>
<dl>
<dt><i>encoding</i></dt>
<dd>
<em style="color:red;">[NC]</em>
</dd>
<dt><i>style_compression</i></dt>
<dd>
<em style="color:red;">[NC]</em>
</dd>
<dt>Returns:</dt>
<dd>
An object of the <a href="#xlwt.Workbook-class">Workbook</a> class
</dd>
</dl>
<br />
</dd>
<dt><a id='xlwt.Workbook.add_sheet-method' name='xlwt.Workbook.add_sheet-method'><b>add_sheet(sheetname)</b></a> [<a href='#xlwt.Workbook.add_sheet-method'>#</a>]</dt>
<dd>
<p>
This method is used to create Worksheets in a Workbook.
</p>
<dl>
<dt><i>sheetname</i></dt>
<dd>
The name to use for this sheet, as it will appear in the tabs at
the bottom of the Excel application.
</dd>
<dt>Returns:</dt>
<dd>
An object of the <a href="#xlwt.Worksheet-class">Worksheet</a> class
</dd>
</dl>
<br />
</dd>
<dt><a id='xlwt.Workbook.save-method' name='xlwt.Workbook.save-method'><b>save(filename_or_stream)</b></a> [<a href='#xlwt.Workbook.save-method'>#</a>]</dt>
<dd>
<p>
This method is used to save Workbook to a file in native Excel format.
</p>
<dl>
<dt><i>filename_or_stream</i></dt>
<dd>
<p>
This can be a string containing a filename of the file, in which case
the excel file is saved to disk using the name provided.
</p>
<p>
It can also be a stream object with a write method, such as a
StringIO, in which case the data for the excel file is written
to the stream.
</p>
</dd>
</dl>
<br />
</dd>
</dl>
<h2><a id='xlwt.Worksheet-class' name='xlwt.Worksheet-class'>The Worksheet Class</a><em style="color:red;">[NC]</em></h2>
<dl>
<dt><b>Worksheet(sheetname, parent_book)</b> (class) [<a href='#xlwt.Worksheet-class'>#</a>]</dt>
<dd>
<p>
This is a class representing the contents of a sheet in a workbook.
</p>
<p>
WARNING: You don't normally create instances of this class
yourself. They are returned from calls to <a href="#xlwt.Workbook.add_sheet-method">Workbook.add_sheet</a>
</p>
</dd>
<dt><a id='xlwt.Worksheet.write-method'
name='xlwt.Worksheet.write-method'><b>write(r, c, label="", style=Style.default_style)</b></a> [<a href='#xlwt.Worksheet.write-method'>#</a>]</dt>
<dd>
<p>
This method is used to write a cell to a Worksheet..
</p>
<dl>
<dt><i>r</i></dt>
<dd>
The zero-relative number of the row in the worksheet to which the cell should be written.
</dd>
<dt><i>c</i></dt>
<dd>
The zero-relative number of the column in the worksheet to which the cell should be written.
</dd>
<dt><i>label</i></dt>
<dd>
The data value to be written.
An int, long, or decimal.Decimal instance is converted to float.
A unicode instance is written as is.
A str instance is converted to unicode using the encoding (default: 'ascii') specified
when the Workbook instance was created.
A datetime.datetime, datetime.date, or datetime.time instance is converted into Excel date format
(a float representing the number of days since (typically) 1899-12-31T00:00:00,
under the pretence that 1900 was a leap year).
A bool instance will show up as TRUE or FALSE in Excel.
None causes the cell to be blank -- no data, only formatting.
An xlwt.Formula instance causes an Excel formula to be written.
<em style="color:red;">[NC]</em>
</dd>
<dt><i>style</i></dt>
<dd>
A style -- also known as an XF (extended format) -- is an XFStyle object, which encapsulates
the formatting applied to the cell and its contents. XFStyle objects are best set up using the
<i>easyxf</i> function. They may also be set up by setting attributes in
Alignment, Borders, Pattern, Font and Protection objects
then setting those objects and a format string as attributes of an XFStyle object.
<em style="color:red;">[NC]</em>
</dd>
</dl>
<br />
</dd>
</dl>
</body></html>
-35
View File
@@ -1,35 +0,0 @@
#!/usr/bin/env python
# tries stress SST, SAT and MSAT
from time import *
from xlwt.Workbook import *
from xlwt.Style import *
style = XFStyle()
wb = Workbook()
ws0 = wb.add_sheet('0')
colcount = 200 + 1
rowcount = 6000 + 1
t0 = time()
print "\nstart: %s" % ctime(t0)
print "Filling..."
for col in xrange(colcount):
print "[%d]" % col,
for row in xrange(rowcount):
#ws0.write(row, col, "BIG(%d, %d)" % (row, col))
ws0.write(row, col, "BIG")
t1 = time() - t0
print "\nsince starting elapsed %.2f s" % (t1)
print "Storing..."
wb.save('big-16Mb.xls')
t2 = time() - t0
print "since starting elapsed %.2f s" % (t2)
-34
View File
@@ -1,34 +0,0 @@
#!/usr/bin/env python
# tries stress SST, SAT and MSAT
from time import *
from xlwt import *
style = XFStyle()
wb = Workbook()
ws0 = wb.add_sheet('0')
colcount = 200 + 1
rowcount = 6000 + 1
t0 = time()
print "\nstart: %s" % ctime(t0)
print "Filling..."
for col in xrange(colcount):
print "[%d]" % col,
for row in xrange(rowcount):
ws0.write(row, col, "BIG(%d, %d)" % (row, col))
#ws0.write(row, col, "BIG")
t1 = time() - t0
print "\nsince starting elapsed %.2f s" % (t1)
print "Storing..."
wb.save('big-35Mb.xls')
t2 = time() - t0
print "since starting elapsed %.2f s" % (t2)
-36
View File
@@ -1,36 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
font0 = Font()
font0.name = 'Times New Roman'
font0.struck_out = True
font0.bold = True
style0 = XFStyle()
style0.font = font0
wb = Workbook()
ws0 = wb.add_sheet('0')
ws0.write(1, 1, 'Test', style0)
for i in range(0, 0x53):
borders = Borders()
borders.left = i
borders.right = i
borders.top = i
borders.bottom = i
style = XFStyle()
style.borders = borders
ws0.write(i, 2, '', style)
ws0.write(i, 3, hex(i), style0)
ws0.write_merge(5, 8, 6, 10, "")
wb.save('blanks.xls')
@@ -1,19 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
__rev_id__ = """$Id: col_width.py 3315 2008-03-14 14:44:52Z chris $"""
from xlwt import *
w = Workbook()
ws = w.add_sheet('Hey, Dude')
for i in range(6, 80):
fnt = Font()
fnt.height = i*20
style = XFStyle()
style.font = fnt
ws.write(1, i, 'Test')
ws.col(i).width = 0x0d00 + i
w.save('col_width.xls')
-10
View File
@@ -1,10 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1252 -*-
# Copyright (C) 2007 John Machin
from xlwt import *
w = Workbook()
w.country_code = 61
ws = w.add_sheet('AU')
w.save('country.xls')
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
from datetime import datetime
w = Workbook()
ws = w.add_sheet('Hey, Dude')
fmts = [
'M/D/YY',
'D-MMM-YY',
'D-MMM',
'MMM-YY',
'h:mm AM/PM',
'h:mm:ss AM/PM',
'h:mm',
'h:mm:ss',
'M/D/YY h:mm',
'mm:ss',
'[h]:mm:ss',
'mm:ss.0',
]
i = 0
for fmt in fmts:
ws.write(i, 0, fmt)
style = XFStyle()
style.num_format_str = fmt
ws.write(i, 4, datetime.now(), style)
i += 1
w.save('dates.xls')
-38
View File
@@ -1,38 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
font0 = Font()
font0.name = 'Times New Roman'
font0.struck_out = True
font0.bold = True
style0 = XFStyle()
style0.font = font0
wb = Workbook()
ws0 = wb.add_sheet('0')
ws0.write(1, 1, 'Test', style0)
for i in range(0, 0x53):
fnt = Font()
fnt.name = 'Arial'
fnt.colour_index = i
fnt.outline = True
borders = Borders()
borders.left = i
style = XFStyle()
style.font = fnt
style.borders = borders
ws0.write(i, 2, 'colour', style)
ws0.write(i, 3, hex(i), style0)
wb.save('format.xls')
@@ -1,34 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
from xlwt.ExcelFormulaParser import FormulaParseException
w = Workbook()
ws = w.add_sheet('F')
## This example is a little silly since the formula building is
## so simplistic that it often fails because the generated text
## has the wrong number of parameters for the function being
## tested.
i = 0
succeed_count = 0
fail_count = 0
for n in sorted(ExcelMagic.std_func_by_name):
ws.write(i, 0, n)
text = n + "($A$1)"
try:
formula = Formula(text)
except FormulaParseException,e:
print "Could not parse %r: %s" % (text,e.args[0])
fail_count += 1
else:
ws.write(i, 3, formula)
succeed_count += 1
i += 1
w.save('formula_names.xls')
print "succeeded with %i functions, failed with %i" % (succeed_count,fail_count)
-47
View File
@@ -1,47 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('F')
ws.write(0, 0, Formula("-(1+1)"))
ws.write(1, 0, Formula("-(1+1)/(-2-2)"))
ws.write(2, 0, Formula("-(134.8780789+1)"))
ws.write(3, 0, Formula("-(134.8780789e-10+1)"))
ws.write(4, 0, Formula("-1/(1+1)+9344"))
ws.write(0, 1, Formula("-(1+1)"))
ws.write(1, 1, Formula("-(1+1)/(-2-2)"))
ws.write(2, 1, Formula("-(134.8780789+1)"))
ws.write(3, 1, Formula("-(134.8780789e-10+1)"))
ws.write(4, 1, Formula("-1/(1+1)+9344"))
ws.write(0, 2, Formula("A1*B1"))
ws.write(1, 2, Formula("A2*B2"))
ws.write(2, 2, Formula("A3*B3"))
ws.write(3, 2, Formula("A4*B4*sin(pi()/4)"))
ws.write(4, 2, Formula("A5%*B5*pi()/1000"))
##############
## NOTE: parameters are separated by semicolon!!!
##############
ws.write(5, 2, Formula("C1+C2+C3+C4+C5/(C1+C2+C3+C4/(C1+C2+C3+C4/(C1+C2+C3+C4)+C5)+C5)-20.3e-2"))
ws.write(5, 3, Formula("C1^2"))
ws.write(6, 2, Formula("SUM(C1;C2;;;;;C3;;;C4)"))
ws.write(6, 3, Formula("SUM($A$1:$C$5)"))
ws.write(7, 0, Formula('"lkjljllkllkl"'))
ws.write(7, 1, Formula('"yuyiyiyiyi"'))
ws.write(7, 2, Formula('A8 & B8 & A8'))
ws.write(8, 2, Formula('now()'))
ws.write(10, 2, Formula('TRUE'))
ws.write(11, 2, Formula('FALSE'))
ws.write(12, 3, Formula('IF(A1>A2;3;"hkjhjkhk")'))
w.save('formulas.xls')
@@ -1,28 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
f = Font()
f.height = 20*72
f.name = 'Verdana'
f.bold = True
f.underline = Font.UNDERLINE_DOUBLE
f.colour_index = 4
h_style = XFStyle()
h_style.font = f
w = Workbook()
ws = w.add_sheet('F')
##############
## NOTE: parameters are separated by semicolon!!!
##############
n = "HYPERLINK"
ws.write_merge(1, 1, 1, 10, Formula(n + '("http://www.irs.gov/pub/irs-pdf/f1000.pdf";"f1000.pdf")'), h_style)
ws.write_merge(2, 2, 2, 25, Formula(n + '("mailto:roman.kiseliov@gmail.com?subject=pyExcelerator-feedback&Body=Hello,%20Roman!";"pyExcelerator-feedback")'), h_style)
w.save("hyperlinks.xls")
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('Image')
ws.insert_bitmap('python.bmp', 2, 2)
ws.insert_bitmap('python.bmp', 10, 2)
w.save('image.xls')
-39
View File
@@ -1,39 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
fnt = Font()
fnt.name = 'Arial'
fnt.colour_index = 4
fnt.bold = True
borders = Borders()
borders.left = 6
borders.right = 6
borders.top = 6
borders.bottom = 6
al = Alignment()
al.horz = Alignment.HORZ_CENTER
al.vert = Alignment.VERT_CENTER
style = XFStyle()
style.font = fnt
style.borders = borders
style.alignment = al
wb = Workbook()
ws0 = wb.add_sheet('sheet0')
ws1 = wb.add_sheet('sheet1')
ws2 = wb.add_sheet('sheet2')
for i in range(0, 0x200, 2):
ws0.write_merge(i, i+1, 1, 5, 'test %d' % i, style)
ws1.write_merge(i, i, 1, 7, 'test %d' % i, style)
ws2.write_merge(i, i+1, 1, 7 + (i%10), 'test %d' % i, style)
wb.save('merged.xls')
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
wb = Workbook()
ws0 = wb.add_sheet('sheet0')
fnt = Font()
fnt.name = 'Arial'
fnt.colour_index = 4
fnt.bold = True
borders = Borders()
borders.left = 6
borders.right = 6
borders.top = 6
borders.bottom = 6
style = XFStyle()
style.font = fnt
style.borders = borders
ws0.write_merge(3, 3, 1, 5, 'test1', style)
ws0.write_merge(4, 10, 1, 5, 'test2', style)
ws0.col(1).width = 0x0d00
wb.save('merged0.xls')
-102
View File
@@ -1,102 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
wb = Workbook()
ws0 = wb.add_sheet('sheet0')
fnt1 = Font()
fnt1.name = 'Verdana'
fnt1.bold = True
fnt1.height = 18*0x14
pat1 = Pattern()
pat1.pattern = Pattern.SOLID_PATTERN
pat1.pattern_fore_colour = 0x16
brd1 = Borders()
brd1.left = 0x06
brd1.right = 0x06
brd1.top = 0x06
brd1.bottom = 0x06
fnt2 = Font()
fnt2.name = 'Verdana'
fnt2.bold = True
fnt2.height = 14*0x14
brd2 = Borders()
brd2.left = 0x01
brd2.right = 0x01
brd2.top = 0x01
brd2.bottom = 0x01
pat2 = Pattern()
pat2.pattern = Pattern.SOLID_PATTERN
pat2.pattern_fore_colour = 0x01F
fnt3 = Font()
fnt3.name = 'Verdana'
fnt3.bold = True
fnt3.italic = True
fnt3.height = 12*0x14
brd3 = Borders()
brd3.left = 0x07
brd3.right = 0x07
brd3.top = 0x07
brd3.bottom = 0x07
fnt4 = Font()
al1 = Alignment()
al1.horz = Alignment.HORZ_CENTER
al1.vert = Alignment.VERT_CENTER
al2 = Alignment()
al2.horz = Alignment.HORZ_RIGHT
al2.vert = Alignment.VERT_CENTER
al3 = Alignment()
al3.horz = Alignment.HORZ_LEFT
al3.vert = Alignment.VERT_CENTER
style1 = XFStyle()
style1.font = fnt1
style1.alignment = al1
style1.pattern = pat1
style1.borders = brd1
style2 = XFStyle()
style2.font = fnt2
style2.alignment = al1
style2.pattern = pat2
style2.borders = brd2
style3 = XFStyle()
style3.font = fnt3
style3.alignment = al1
style3.pattern = pat2
style3.borders = brd3
price_style = XFStyle()
price_style.font = fnt4
price_style.alignment = al2
price_style.borders = brd3
price_style.num_format_str = '_(#,##0.00_) "money"'
ware_style = XFStyle()
ware_style.font = fnt4
ware_style.alignment = al3
ware_style.borders = brd3
ws0.merge(3, 3, 1, 5, style1)
ws0.merge(4, 10, 1, 6, style2)
ws0.merge(14, 16, 1, 7, style3)
ws0.col(1).width = 0x0d00
wb.save('merged1.xls')
-9
View File
@@ -1,9 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('xlwt was here')
w.save('mini.xls')
Binary file not shown.
@@ -1,60 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('Hey, Dude')
fmts = [
'general',
'0',
'0.00',
'#,##0',
'#,##0.00',
'"$"#,##0_);("$"#,##',
'"$"#,##0_);[Red]("$"#,##',
'"$"#,##0.00_);("$"#,##',
'"$"#,##0.00_);[Red]("$"#,##',
'0%',
'0.00%',
'0.00E+00',
'# ?/?',
'# ??/??',
'M/D/YY',
'D-MMM-YY',
'D-MMM',
'MMM-YY',
'h:mm AM/PM',
'h:mm:ss AM/PM',
'h:mm',
'h:mm:ss',
'M/D/YY h:mm',
'_(#,##0_);(#,##0)',
'_(#,##0_);[Red](#,##0)',
'_(#,##0.00_);(#,##0.00)',
'_(#,##0.00_);[Red](#,##0.00)',
'_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
'_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
'_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
'_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
'mm:ss',
'[h]:mm:ss',
'mm:ss.0',
'##0.0E+0',
'@'
]
i = 0
for fmt in fmts:
ws.write(i, 0, fmt)
style = XFStyle()
style.num_format_str = fmt
ws.write(i, 4, -1278.9078, style)
i += 1
w.save('num_formats.xls')
-25
View File
@@ -1,25 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('Hey, Dude')
ws.write(0, 0, 1)
ws.write(1, 0, 1.23)
ws.write(2, 0, 12345678)
ws.write(3, 0, 123456.78)
ws.write(0, 1, -1)
ws.write(1, 1, -1.23)
ws.write(2, 1, -12345678)
ws.write(3, 1, -123456.78)
ws.write(0, 2, -17867868678687.0)
ws.write(1, 2, -1.23e-5)
ws.write(2, 2, -12345678.90780980)
ws.write(3, 2, -123456.78)
w.save('numbers.xls')
-60
View File
@@ -1,60 +0,0 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
# Portions Copyright (C) 2005 Kiseliov Roman
import xlwt
style = xlwt.easyxf(
"font: name Arial, colour_index blue, bold on;"
"borders: top double, bottom double, left double, right double;"
)
def write_data_cells(ws):
ws.write_merge(1, 1, 1, 5, 'test 1', style)
ws.write_merge(2, 2, 1, 4, 'test 1', style)
ws.write_merge(3, 3, 1, 3, 'test 2', style)
ws.write_merge(4, 4, 1, 4, 'test 1', style)
ws.write_merge(5, 5, 1, 4, 'test 3', style)
ws.write_merge(6, 6, 1, 5, 'test 1', style)
ws.write_merge(7, 7, 1, 5, 'test 4', style)
ws.write_merge(8, 8, 1, 4, 'test 1', style)
ws.write_merge(9, 9, 1, 3, 'test 5', style)
def write_row_outline_levels(ws):
ws.row(1).level = 1
ws.row(2).level = 1
ws.row(3).level = 2
ws.row(4).level = 2
ws.row(5).level = 2
ws.row(6).level = 2
ws.row(7).level = 2
ws.row(8).level = 1
ws.row(9).level = 1
def write_column_outline_levels(ws):
ws.col(1).level = 1
ws.col(2).level = 1
ws.col(3).level = 2
ws.col(4).level = 2
ws.col(5).level = 2
ws.col(6).level = 2
ws.col(7).level = 2
ws.col(8).level = 1
ws.col(9).level = 1
wb = xlwt.Workbook()
ws0 = wb.add_sheet('Rows Outline')
write_data_cells(ws0)
write_row_outline_levels(ws0)
ws1 = wb.add_sheet('Columns Outline')
write_data_cells(ws1)
write_column_outline_levels(ws1)
ws2 = wb.add_sheet('Rows and Columns Outline')
write_data_cells(ws2)
write_row_outline_levels(ws2)
write_column_outline_levels(ws2)
wb.save('outline.xls')
-58
View File
@@ -1,58 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws1 = w.add_sheet('sheet 1')
ws2 = w.add_sheet('sheet 2')
ws3 = w.add_sheet('sheet 3')
ws4 = w.add_sheet('sheet 4')
ws5 = w.add_sheet('sheet 5')
ws6 = w.add_sheet('sheet 6')
for i in range(0x100):
ws1.write(i/0x10, i%0x10, i)
for i in range(0x100):
ws2.write(i/0x10, i%0x10, i)
for i in range(0x100):
ws3.write(i/0x10, i%0x10, i)
for i in range(0x100):
ws4.write(i/0x10, i%0x10, i)
for i in range(0x100):
ws5.write(i/0x10, i%0x10, i)
for i in range(0x100):
ws6.write(i/0x10, i%0x10, i)
ws1.panes_frozen = True
ws1.horz_split_pos = 2
ws2.panes_frozen = True
ws2.vert_split_pos = 2
ws3.panes_frozen = True
ws3.horz_split_pos = 1
ws3.vert_split_pos = 1
ws4.panes_frozen = False
ws4.horz_split_pos = 12
ws4.horz_split_first_visible = 2
ws5.panes_frozen = False
ws5.vert_split_pos = 40
ws4.vert_split_first_visible = 2
ws6.panes_frozen = False
ws6.horz_split_pos = 12
ws4.horz_split_first_visible = 2
ws6.vert_split_pos = 40
ws4.vert_split_first_visible = 2
w.save('panes.xls')
@@ -1,12 +0,0 @@
from xlwt import ExcelFormulaParser, ExcelFormula
import sys
f = ExcelFormula.Formula(
""" -((1.80 + 2.898 * 1)/(1.80 + 2.898))*
AVERAGE((1.80 + 2.898 * 1)/(1.80 + 2.898);
(1.80 + 2.898 * 1)/(1.80 + 2.898);
(1.80 + 2.898 * 1)/(1.80 + 2.898)) +
SIN(PI()/4)""")
#for t in f.rpn():
# print "%15s %15s" % (ExcelFormulaParser.PtgNames[t[0]], t[1])
-134
View File
@@ -1,134 +0,0 @@
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
fnt = Font()
fnt.name = 'Arial'
fnt.colour_index = 4
fnt.bold = True
borders = Borders()
borders.left = 6
borders.right = 6
borders.top = 6
borders.bottom = 6
style = XFStyle()
style.font = fnt
style.borders = borders
wb = Workbook()
ws0 = wb.add_sheet('Rows Outline')
ws0.write_merge(1, 1, 1, 5, 'test 1', style)
ws0.write_merge(2, 2, 1, 4, 'test 1', style)
ws0.write_merge(3, 3, 1, 3, 'test 2', style)
ws0.write_merge(4, 4, 1, 4, 'test 1', style)
ws0.write_merge(5, 5, 1, 4, 'test 3', style)
ws0.write_merge(6, 6, 1, 5, 'test 1', style)
ws0.write_merge(7, 7, 1, 5, 'test 4', style)
ws0.write_merge(8, 8, 1, 4, 'test 1', style)
ws0.write_merge(9, 9, 1, 3, 'test 5', style)
ws0.row(1).level = 1
ws0.row(2).level = 1
ws0.row(3).level = 2
ws0.row(4).level = 2
ws0.row(5).level = 2
ws0.row(6).level = 2
ws0.row(7).level = 2
ws0.row(8).level = 1
ws0.row(9).level = 1
ws1 = wb.add_sheet('Columns Outline')
ws1.write_merge(1, 1, 1, 5, 'test 1', style)
ws1.write_merge(2, 2, 1, 4, 'test 1', style)
ws1.write_merge(3, 3, 1, 3, 'test 2', style)
ws1.write_merge(4, 4, 1, 4, 'test 1', style)
ws1.write_merge(5, 5, 1, 4, 'test 3', style)
ws1.write_merge(6, 6, 1, 5, 'test 1', style)
ws1.write_merge(7, 7, 1, 5, 'test 4', style)
ws1.write_merge(8, 8, 1, 4, 'test 1', style)
ws1.write_merge(9, 9, 1, 3, 'test 5', style)
ws1.col(1).level = 1
ws1.col(2).level = 1
ws1.col(3).level = 2
ws1.col(4).level = 2
ws1.col(5).level = 2
ws1.col(6).level = 2
ws1.col(7).level = 2
ws1.col(8).level = 1
ws1.col(9).level = 1
ws2 = wb.add_sheet('Rows and Columns Outline')
ws2.write_merge(1, 1, 1, 5, 'test 1', style)
ws2.write_merge(2, 2, 1, 4, 'test 1', style)
ws2.write_merge(3, 3, 1, 3, 'test 2', style)
ws2.write_merge(4, 4, 1, 4, 'test 1', style)
ws2.write_merge(5, 5, 1, 4, 'test 3', style)
ws2.write_merge(6, 6, 1, 5, 'test 1', style)
ws2.write_merge(7, 7, 1, 5, 'test 4', style)
ws2.write_merge(8, 8, 1, 4, 'test 1', style)
ws2.write_merge(9, 9, 1, 3, 'test 5', style)
ws2.row(1).level = 1
ws2.row(2).level = 1
ws2.row(3).level = 2
ws2.row(4).level = 2
ws2.row(5).level = 2
ws2.row(6).level = 2
ws2.row(7).level = 2
ws2.row(8).level = 1
ws2.row(9).level = 1
ws2.write_merge(3, 3, 1, 3, 'test 2', style)
if 0:
ws2.write_merge(1, 1, 1, 5, 'test 1', style)
ws2.write_merge(2, 2, 1, 4, 'test 1', style)
ws2.write_merge(3, 3, 1, 3, 'test 2', style)
ws2.write_merge(4, 4, 1, 4, 'test 1', style)
ws2.write_merge(5, 5, 1, 4, 'test 3', style)
ws2.write_merge(6, 6, 1, 5, 'test 1', style)
ws2.write_merge(7, 7, 1, 5, 'test 4', style)
ws2.write_merge(8, 8, 1, 4, 'test 1', style)
ws2.write_merge(9, 9, 1, 3, 'test 5', style)
ws2.col(1).level = 1
ws2.col(2).level = 1
ws2.col(3).level = 2
ws2.col(4).level = 2
ws2.col(5).level = 2
ws2.col(6).level = 2
ws2.col(7).level = 2
ws2.col(8).level = 1
ws2.col(9).level = 1
if 0:
ws0.protect = True
ws0.wnd_protect = True
ws0.obj_protect = True
ws0.scen_protect = True
ws0.password = "123456"
ws1.protect = True
ws1.wnd_protect = True
ws1.obj_protect = True
ws1.scen_protect = True
ws1.password = "abcdefghij"
ws2.protect = True
ws2.wnd_protect = True
ws2.obj_protect = True
ws2.scen_protect = True
ws2.password = "ok"
wb.protect = True
wb.wnd_protect = True
wb.obj_protect = True
wb.save('protection.xls')
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

@@ -1,17 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws = w.add_sheet('Hey, Dude')
for i in range(6, 80):
fnt = Font()
fnt.height = i*20
style = XFStyle()
style.font = fnt
ws.write(i, 1, 'Test')
ws.row(i).set_style(style)
w.save('row_styles.xls')
@@ -1,18 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
__rev_id__ = """$Id: row_styles_empty.py 3309 2008-03-14 11:04:30Z chris $"""
from pyExcelerator import *
w = Workbook()
ws = w.add_sheet('Hey, Dude')
for i in range(6, 80):
fnt = Font()
fnt.height = i*20
style = XFStyle()
style.font = fnt
ws.row(i).set_style(style)
w.save('row_styles_empty.xls')
-24
View File
@@ -1,24 +0,0 @@
import xlwt
from datetime import datetime
font0 = xlwt.Font()
font0.name = 'Times New Roman'
font0.colour_index = 2
font0.bold = True
style0 = xlwt.XFStyle()
style0.font = font0
style1 = xlwt.XFStyle()
style1.num_format_str = 'D-MMM-YY'
wb = xlwt.Workbook()
ws = wb.add_sheet('A Test Sheet')
ws.write(0, 0, 'Test', style0)
ws.write(1, 0, datetime.now(), style1)
ws.write(2, 0, 1)
ws.write(2, 1, 1)
ws.write(2, 2, xlwt.Formula("A3+B3"))
wb.save('example.xls')
-52
View File
@@ -1,52 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
font0 = Formatting.Font()
font0.name = 'Arial'
font1 = Formatting.Font()
font1.name = 'Arial Cyr'
font2 = Formatting.Font()
font2.name = 'Times New Roman'
font3 = Formatting.Font()
font3.name = 'Courier New Cyr'
num_format0 = '0.00000'
num_format1 = '0.000000'
num_format2 = '0.0000000'
num_format3 = '0.00000000'
st0 = XFStyle()
st1 = XFStyle()
st2 = XFStyle()
st3 = XFStyle()
st4 = XFStyle()
st0.font = font0
st0.num_format = num_format0
st1.font = font1
st1.num_format = num_format1
st2.font = font2
st2.num_format = num_format2
st3.font = font3
st3.num_format = num_format3
wb = Workbook()
wb.add_style(st0)
wb.add_style(st1)
wb.add_style(st2)
wb.add_style(st3)
ws0 = wb.add_sheet('0')
ws0.write(0, 0, 'Olya'*0x4000, st0)
#for i in range(0, 0x10):
# ws0.write(i, 2, ('%d'%i)*0x4000, st1)
wb.save('sst.xls')
-12
View File
@@ -1,12 +0,0 @@
#!/usr/bin/env python
import xlwt
# Strings passed to (for example) Worksheet.write can be unicode objects,
# or str (8-bit) objects, which are then decoded into unicode.
# The encoding to be used defaults to 'ascii'. This can be overridden
# when the Workbook instance is created:
book = xlwt.Workbook(encoding='cp1251')
sheet = book.add_sheet('cp1251-demo')
sheet.write(0, 0, '\xce\xeb\xff')
book.save('unicode0.xls')
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws1 = w.add_sheet(u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}')
ws1.write(0, 0, u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}')
ws1.write(1, 1, u'\N{GREEK SMALL LETTER DELTA}x = 1 + \N{GREEK SMALL LETTER DELTA}')
ws1.write(2,0, u'A\u2262\u0391.') # RFC2152 example
ws1.write(3,0, u'Hi Mom -\u263a-!') # RFC2152 example
ws1.write(4,0, u'\u65E5\u672C\u8A9E') # RFC2152 example
ws1.write(5,0, u'Item 3 is \u00a31.') # RFC2152 example
ws1.write(8,0, u'\N{INTEGRAL}') # RFC2152 example
w.add_sheet(u'A\u2262\u0391.') # RFC2152 example
w.add_sheet(u'Hi Mom -\u263a-!') # RFC2152 example
one_more_ws = w.add_sheet(u'\u65E5\u672C\u8A9E') # RFC2152 example
w.add_sheet(u'Item 3 is \u00a31.') # RFC2152 example
one_more_ws.write(0, 0, u'\u2665\u2665')
w.add_sheet(u'\N{GREEK SMALL LETTER ETA WITH TONOS}')
w.save('unicode1.xls')
-19
View File
@@ -1,19 +0,0 @@
#!/usr/bin/env python
# -*- coding: windows-1251 -*-
# Copyright (C) 2005 Kiseliov Roman
from xlwt import *
w = Workbook()
ws1 = w.add_sheet(u'\N{GREEK SMALL LETTER ALPHA}\N{GREEK SMALL LETTER BETA}\N{GREEK SMALL LETTER GAMMA}\u2665\u041e\u041b\u042f\u2665')
fnt = Font()
fnt.height = 26*20
style = XFStyle()
style.font = fnt
for i in range(0x10000):
ws1.write(i/0x10, i%0x10, unichr(i), style)
w.save('unicode2.xls')
-155
View File
@@ -1,155 +0,0 @@
props = \
[
'name',
'parent',
'rows',
'cols',
'merged_ranges',
'bmp_rec',
'show_formulas',
'show_grid',
'show_headers',
'panes_frozen',
'show_empty_as_zero',
'auto_colour_grid',
'cols_right_to_left',
'show_outline',
'remove_splits',
'selected',
'hidden',
'page_preview',
'first_visible_row',
'first_visible_col',
'grid_colour',
'preview_magn',
'normal_magn',
'row_gut_width',
'col_gut_height',
'show_auto_page_breaks',
'dialogue_sheet',
'auto_style_outline',
'outline_below',
'outline_right',
'fit_num_pages',
'show_row_outline',
'show_col_outline',
'alt_expr_eval',
'alt_formula_entries',
'row_default_height',
'col_default_width',
'calc_mode',
'calc_count',
'RC_ref_mode',
'iterations_on',
'delta',
'save_recalc',
'print_headers',
'print_grid',
'grid_set',
'vert_page_breaks',
'horz_page_breaks',
'header_str',
'footer_str',
'print_centered_vert',
'print_centered_horz',
'left_margin',
'right_margin',
'top_margin',
'bottom_margin',
'paper_size_code',
'print_scaling',
'start_page_number',
'fit_width_to_pages',
'fit_height_to_pages',
'print_in_rows',
'portrait',
'print_not_colour',
'print_draft',
'print_notes',
'print_notes_at_end',
'print_omit_errors',
'print_hres',
'print_vres',
'header_margin',
'footer_margin',
'copies_num',
]
from xlwt import *
wb = Workbook()
ws = wb.add_sheet('sheet')
print ws.name
print ws.parent
print ws.rows
print ws.cols
print ws.merged_ranges
print ws.bmp_rec
print ws.show_formulas
print ws.show_grid
print ws.show_headers
print ws.panes_frozen
print ws.show_empty_as_zero
print ws.auto_colour_grid
print ws.cols_right_to_left
print ws.show_outline
print ws.remove_splits
print ws.selected
# print ws.hidden
print ws.page_preview
print ws.first_visible_row
print ws.first_visible_col
print ws.grid_colour
print ws.preview_magn
print ws.normal_magn
#print ws.row_gut_width
#print ws.col_gut_height
print ws.show_auto_page_breaks
print ws.dialogue_sheet
print ws.auto_style_outline
print ws.outline_below
print ws.outline_right
print ws.fit_num_pages
print ws.show_row_outline
print ws.show_col_outline
print ws.alt_expr_eval
print ws.alt_formula_entries
print ws.row_default_height
print ws.col_default_width
print ws.calc_mode
print ws.calc_count
print ws.RC_ref_mode
print ws.iterations_on
print ws.delta
print ws.save_recalc
print ws.print_headers
print ws.print_grid
#print ws.grid_set
print ws.vert_page_breaks
print ws.horz_page_breaks
print ws.header_str
print ws.footer_str
print ws.print_centered_vert
print ws.print_centered_horz
print ws.left_margin
print ws.right_margin
print ws.top_margin
print ws.bottom_margin
print ws.paper_size_code
print ws.print_scaling
print ws.start_page_number
print ws.fit_width_to_pages
print ws.fit_height_to_pages
print ws.print_in_rows
print ws.portrait
print ws.print_colour
print ws.print_draft
print ws.print_notes
print ws.print_notes_at_end
print ws.print_omit_errors
print ws.print_hres
print ws.print_vres
print ws.header_margin
print ws.footer_margin
print ws.copies_num

Some files were not shown because too many files have changed in this diff Show More