Python powered spreadsheets

Overview

Marmir is powerful and fun

Marmir takes Python data structures and turns them into spreadsheets.

It is xlwt and google spreadsheets on steroids.

It also supports: input from Django models; taking Psycopg cursors; writing out ascii tables (like psql does); and will soon support HTML tables as output. The goal is to make it easy to generate many types of useful table files with the least amount of configuration.

Marmir melts in your mouth

Installing:

$ pip install Marmir

Talk about simple to use, wow. Marmir is just this:

import datetime
import mm

now = datetime.datetime.now().replace(microsecond=0)

my_data = [ 
    {
        'msg': "My first Row",
        'id': 1,
        'when': now,
    },
    {
        'msg': "My second Row",
        'id': 2,
        'when': now,
    },

]

mm_doc = mm.Document(my_data)
mm_doc.write("example.xls")

Same example above as lists (also node the 'order' argument works in the above as well:

my_headers = ('id', 'msg', 'when')
my_data = (
    (1, "My First Row", now),
    (2, "My Second Row", now)   
)

mm_doc = mm.Document(my_data, order=my_headers)
mm_doc.write("example.xls")

Or you can get fancier:

import datetime
import mm

my_data = [ 
    {
        'msg': "My first Row",
        'id': 1,
        'when': mm.Date(datetime.datetime.now(), "%Y-%m-%dT%H:%M:%S"),
        'homepage': mm.URL("https://github.com/brianray")
    },
    {
        'msg': "My second Row",
        'id': 2,
        'when': datetime.datetime.now(),
        'homepage': mm.URL("http://twitter.com/brianray", "Tweet Me")
    },

]

mm_doc = mm.Document(my_data)
mm_doc.write("example.xls")

# also you can publish to google spreadsheats
mm_doc.write_gdata("Example Spreadsheet", "Username", "Pass")

Now for a little Django (https://www.djangoproject.com/) example:

from yourproject.models import TestModel
from mm.contrib.django.data_model import DjangoDataModel
from mm.contrib.django.grid import DjangoGrid

django_query_set = TestModel.objects.all()
mm_doc = mm.Document(django_query_set, 
              data_model_class=DjangoDataModel, 
              grid_class=DjangoGrid)
mm_doc.write("django_example.xls")

There is a lot more. Check out the Examples.

... Not in your hand

So the primary goals are:

  • make XLS spreadsheets better than xlwt
  • Create Spreadsheets in Google Docs
  • convert python types automagically, date is a date, int is a int, string is a string, ...
  • do stuff you expect like make columns wider to fit, wrap in some cases
  • make stuff pretty colors and easier to read
  • generate directly from Django queries

Some other stuff:

  • do summaries and break out tables
  • add logic and math functions

Marmir is written with love

Brian Ray @brianray wrote Marmir. Brian: is the organizer of ChiPy (http://chipy.org); one of Chicago's Top Tech 25 (according to Crains Oct 2011); been professionally developing software for business for 15 years; and is sick of sub-par Python libraries for creating business spreadsheets.

The name Marmir name from parts of the names Maura and Miranda, the author's girls.

Copyright

Copyright (c) 2013 Brian Ray

Comments
  • object of type 'NoneType' has no len()

    object of type 'NoneType' has no len()

    I got that error when I'm trying to create xls. My code is something like this:

    from mymodel.models import MyList from mm.contrib.django.data_model import DjangoDataModel from mm.contrib.django.grid import DjangoGrid import mm

    thelist = MyList.objects.filter(create_time__range=(start,end)).extra(select={ 'newfield': 'select name from newtable where id=thistable.people_id'}).order_by('-create_time')

    mm_doc = mm.Document(thelist, data_model_class=DjangoDataModel, grid_class=DjangoGrid) mm_doc.write('example.xls')

    I'm using Django 1.4

    The same thing happen when I iterate the queryset and build the list of dict manually.

    opened by lantip 4
  • Doing more with less

    Doing more with less

    Brian; would really love to use this. I had been "rolling my own" Excel output for a Django project before coming across your project. I had been wondering how to incorporate decent formatting to the data and your project seems perfect for that.

    One small (?) issue though. The bulk of data I output from my views is in the form of (a) a list of headers and (b) a "list of lists" for data. This format is perfect for easy conversion to HTML tables, CSV data or Excel files. However your examples are dictionary-based and include header names encapsulated in each "row". Do you see a way to upgrade your project to handle the kind of input I would like to have? Thanks!

    opened by gamesbook 4
  • pip install error

    pip install error

    When I tried to install Marmir with pip it failed. Attached is a screenshot of the error log I received. Note, I haven't had any issues downloading anything else with pip. I also used pip to install another package right after I tried to install this one, and I didn't have any issues.

    error_log

    opened by tetter36 1
  • Proposal to generate files in tests/generated_files subdirectory

    Proposal to generate files in tests/generated_files subdirectory

    The generated XLS files are currently dumped into the project root directory. Can we output those files into tests/generated_files subdirectory instead?

    opened by pebreo 1
  • Proposal to change syntax of how files are opened in test suites

    Proposal to change syntax of how files are opened in test suites

    I propose to change the syntax of all unittests that currently open files like this:

    f = open("foo.xls", "wb")
    f.write(str)
    f.close()
    

    to the more idiomatic:

    with open("foo.xls", "wb") as f:
        f.write(str)
    
    opened by pebreo 1
  • Corrupt file generated using write() method in Windows

    Corrupt file generated using write() method in Windows

    The write() method generates a corrupt file that MS Excel (running in Windows environment) cannot read.

    When opening the file Excel gives the following error:

    "Excel found unreadable content in 'myfile.xls'. Do you want to recover the contents of this workbook?"

    Given the following code:

    my_data = [
                {
                    'msg': "My first Cell",
                    'id': 1,
                    'when': 'now',
                },
                {
                    'msg': "My second Cell",
                    'id': 2,
                    'when': 'now',
                },
    ]
    
    mm_doc = mm.Document(my_data)
    mm_doc.write("myfile.xls") # generates a corrupt file
    
    opened by pebreo 1
  • object of type 'NoneType' has no len()

    object of type 'NoneType' has no len()

    There was already a ticket regarding this issue... It only occurs if I export 2 or more rows at once...

    You can find the model here: https://gist.github.com/SachaMPS/e8448ffede30ed4f204c

    Heres the traceback:

    ERROR:django.request:Internal Server Error: /admin/contact/orderitem/ Traceback (most recent call last): File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/core/handlers/base.py", line 111, in get_response response = callback(request, _callback_args, *_callback_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/contrib/admin/options.py", line 366, in wrapper return self.admin_site.admin_view(view)(_args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view response = view_func(request, _args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/views/decorators/cache.py", line 89, in _wrapped_view_func response = view_func(request, _args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/contrib/admin/sites.py", line 196, in inner return view(request, _args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper return bound_func(_args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view response = view_func(request, _args, *_kwargs) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/utils/decorators.py", line 21, in bound_func return func(self, _args2, *_kwargs2) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/contrib/admin/options.py", line 1153, in changelist_view response = self.response_action(request, queryset=cl.get_query_set(request)) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/django/contrib/admin/options.py", line 908, in response_action response = func(self, request, queryset) File "/Users/sto/Sites/python.dev/python/stw_project/project/apps/contact/admin.py", line 63, in export_as_xls data = xlsDoc.writestr() File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/document_writers.py", line 21, in writestr return self.composer.run(child=child) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/composer_xls.py", line 220, in run self.iterate_grid() File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/composer_base.py", line 26, in iterate_grid self.write_cell(self.row_id, self.col_id, cell) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/composer_xls.py", line 165, in write_cell self.done_write_cell(row_id, col_id, cell, value, style) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/composer_xls.py", line 176, in done_write_cell new_width = get_string_width_from_style(value, style) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/composer_xls.py", line 19, in get_string_width_from_style return int(get_string_width(font_name, point_size, char_string) * 50) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/lib/font_data/decorators.py", line 21, in call value = self.func(*args) File "/Users/sto/Sites/python.dev/python/stw_project/env/lib/python2.7/site-packages/mm/lib/font_data/core.py", line 49, in get_string_width str_length = len(char_string) TypeError: object of type 'int' has no len()

    opened by SachaMPS 1
  • Extra Columns test fail

    Extra Columns test fail

    @hodgesds

    ERROR: test_extra_columns (test_extra_columns.TestColumns)

    Traceback (most recent call last): File "/Users/bray/mm/tests/test_extra_columns.py", line 36, in test_extra_columns self.check("test_extra_columns.xls", my_data) File "/Users/bray/mm/tests/test_extra_columns.py", line 45, in check cell_type = xls.get_type(row, col) return self.cell_types[str(worksheet.cell_type(row, colm))] File "/Users/bray/mm/mm_env/lib/python2.7/site-packages/xlrd/sheet.py", line 418, in cell_type return self._cell_types[rowx][colx] IndexError: array index out of range -------------------- >> begin captured logging << --------------------

    opened by brianray 1
  • Rename xlrd.py in test directory to xlrd_helper.py

    Rename xlrd.py in test directory to xlrd_helper.py

    Rename the xlrd.py to avoid the failing of tests

    C:\Users\Tathagata\Documents\GitHub\mm\tests>python gdata_tests.py
    Traceback (most recent call last):
     File "gdata_tests.py", line 6, in <module>
        from xlrd_helper import XLSReader
       ImportError: No module named xlrd_helper
    
    opened by tathagata 1
  • gdata_tests.py fails on Win 7, Python 2.7.2

    gdata_tests.py fails on Win 7, Python 2.7.2

    C:\Users\Tathagata\Documents\GitHub\mm\tests>python gdata_tests.py
    Google Username: C-3PO
    Google password:
    No handlers could be found for logger "mm.composer_xls"
    E
    ======================================================================
    ERROR: test_minimal (__main__.TestGdataSuite)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
     File "gdata_tests.py", line 45, in test_minimal
    password)
     File "C:\Python27\lib\site-packages\marmir-0.1.1-py2.7.egg\mm\document_writers.py", line 60, in write_gdata
    entry = gd_client.Upload(ms, name)
     File "C:\Python27\lib\site-packages\gdata\docs\service.py", line 306, in Upload
    folder_or_uri)
     File "C:\Python27\lib\site-packages\gdata\docs\service.py", line 161, in _UploadFile
    converter=gdata.docs.DocumentListEntryFromString)
     File "C:\Python27\lib\site-packages\gdata\service.py", line 1236, in Post
    media_source=media_source, converter=converter)
     File "C:\Python27\lib\site-packages\gdata\service.py", line 1358, in PostOrPut
    'reason': server_response.reason, 'body': result_body}
    RequestError: {'status': 400, 'body': 'The spreadsheet you are trying to upload is invalid.', 'reason': 'Bad Request'}
    
    ----------------------------------------------------------------------
    Ran 1 test in 11.664s
    
    FAILED (errors=1)
    

    Printing the values of the dict in the doc in line 36

        mm_doc = mm.Document(my_data)
        print mm_doc.__dict__.values()
    
     [<mm.grid_base.GridBase object at 0x0236BB50>, <mm.config_base.ConfigBase object at 0x0236BAD0>, <class 'mm.model_base.DataModel'>, [{'msg': 'My first Cell', 'when': datetime.datetime(2013, 2, 18, 19, 35, 11), 'id': 1}, {'msg': 'My second Cell', 'when': datetime.datetime(2013, 2, 18, 19, 35, 11), 'id': 2}], <mm.model_base.DataModel object at 0x0236BB10>]
    
    opened by tathagata 1
  • Fix Issues #24 and #25

    Fix Issues #24 and #25

    This is my pull request to fix issue #24 and #25.

    Issue #24 was about changing the syntax f = open(..) to with open(..) as f

    Issue #25 was about generating the *.xls files into their own subdirectory tests/generated_files

    A bunch of *_tests.py have been affected but the non-test files that have been affected are:

    document_writers.py
    textwidths.py
    

    All tests have passed as a result of these changes.

    opened by pebreo 0
  • Can it support python 3?

    Can it support python 3?

    It looks not support python3.

    $ pip install marmir
    Collecting marmir Using cached https://files.pythonhosted.org/packages/e4/7d/75d7c821c2a9439ccaad6f70d5cfb8ba3a7d5795b9632f3a9b89a3a40e2e/Marmir-0.1.3.tar.gz Complete output from command python setup.py egg_info: Traceback (most recent call last): File "", line 1, in File "/private/var/folders/n3/hnw9vdn51qzf29grjgmcyr800000gn/T/pip-install-8fun0y3l/marmir/setup.py", line 3, in import mm File "/private/var/folders/n3/hnw9vdn51qzf29grjgmcyr800000gn/T/pip-install-8fun0y3l/marmir/mm/init.py", line 10, in from document_base import * ModuleNotFoundError: No module named 'document_base'

    opened by hh-in-zhuzhou 10
  • catche and warn about more data than headers

    catche and warn about more data than headers

    https://github.com/brianray/mm/blob/master/mm/model_base.py#L125

    Catch the index error and raise a more specific exception. Add a setting to the config called 'INGORE_DATA_MISMATCH'--when True, log a warning instead of failing at this point.

    opened by brianray 0
Releases(mm3)
Owner
Brian Ray
Global Data Science Lead @brianray
Brian Ray
Python API wrapper library for Convex Value API

convex-value-python Python API wrapper library for Convex Value API. Further Links: Convex Value homepage @ConvexValue on Twitter JB on Twitter Authen

Aaron DeVera 2 May 11, 2022
Discord bot template.py

discord_bot_template.py A minimal and open-source discord.py boilerplate for kick-starting bot projects. I spend a lot of time developing bots for dif

Tarran Prior 1 Feb 24, 2022
Python Capfire API wrapper

General CampfireAPI based on Campfire web. Install pip install Campfire-API Quickstart Use it without login: from campfire_api import CampfireAPI cf

Ghost 0 Jan 03, 2022
Custom bot I've made to host events on my personal Discord server.

discord_events Custom bot I've made to host events on my personal Discord server. You can try the bot out in my personal server here: https://discord.

AlexFlipnote 5 Mar 16, 2022
Telegram chats reader with python

Telegram chat reader Программа полностью сливает чаты телеграм в базу данных PostgreSQL. Для использования нужен развернутый сервер постгрес и телегра

Anton 4 Dec 24, 2021
A python api to get info on covid-19

A python api to get info on covid-19

roof 2 Sep 18, 2022
Python bindings for ArrayFire: A general purpose GPU library.

ArrayFire Python Bindings ArrayFire is a high performance library for parallel computing with an easy-to-use API. It enables users to write scientific

ArrayFire 402 Dec 20, 2022
A Twitter bot developed in Python using the Tweepy library and hosted in AWS.

Twitter Cameroon: @atangana_aron A Twitter bot developed in Python using the Tweepy library and hosted in AWS. https://twitter.com/atangana_aron Cost

1 Jan 30, 2022
A program to convert YouTube channel registration information into Json files for ThirdTube.

ThirdTubeImporter A program to convert YouTube channel registration information into Json files for ThirdTube. Usage Japanese https://takeout.google.c

Hidegon 2 Dec 18, 2021
A Flask & Twilio Secret Santa app.

🎄 ✨ Secret Santa Twilio ✨ 📱 A contactless Secret Santa game built with Python, Flask and Twilio! Prerequisites 📝 A Twilio account. Sign up here ngr

Sangeeta Jadoonanan 5 Dec 23, 2021
Live Weather Updates using Flask and OpenWeather

AuraX Live Weather Updates using Flask and OpenWeather Installation To setup this project on your local machine, first clone this repository and insta

Ayush Gupta 3 Nov 02, 2021
Sunflower-farmers-automated-bot - Sunflower Farmers NFT Game automated bot.IT IS NOT a cheat or hack bot

Sunflower-farmers-auto-bot Sunflower Farmers NFT Game automated bot.IT IS NOT a

Arthur Alves 17 Nov 09, 2022
A python script to acquire multiple aws ec2 instances in a forensically sound-ish way

acquire_ec2.py The script acquire_ec2.py is used to automatically acquire AWS EC2 instances. The script needs to be run on an EC2 instance in the same

Deutsche Telekom Security GmbH 31 Sep 10, 2022
Stock Market Insights is a Dashboard that gives the 360 degree view of the particular company stock

fedora-easyfix A collection of self-contained and well-documented issues for newcomers to start contributing with How to setup the local development e

Ganesh N 3 Sep 10, 2021
Date Time Userbot With Python

DATE_TIME_USERBOT An Telegram Bot By @Pythone_3 Config Vars API_ID : Telegram API_ID, get it from my.telegram.org/apps API_HASH : Telegram API_ID, get

Sinzz-sinan-m 2 Oct 20, 2021
SystemSix is an e-Ink "desk accessory" running on a Raspberry Pi. It is a bit of nostalgia that can function as a calendar, display the weather

SystemSix is an e-Ink "desk accessory" running on a Raspberry Pi. It is a bit of nostalgia that can function as a calendar, display the weather, the c

John Calhoun 372 Jan 02, 2023
This project checks the weather in the next 12 hours and sends an SMS to your phone number if it's going to rain to remind you to take your umbrella.

RainAlert-Request-Twilio This project checks the weather in the next 12 hours and sends an SMS to your phone number if it's going to rain to remind yo

9 Apr 15, 2022
A python script to extract information from a Microsoft Remote Desktop Web Access (RDWA) application

This python script allow to extract various information from a Microsoft Remote Desktop Web Access (RDWA) application, such as the FQDN of the remote server, the internal AD domain name (from the FQD

Podalirius 60 Dec 09, 2022
Guildead - Guilded api wrapper written in python

Guildead Guilded api wrapper written in python. I have found "exploit" (guilded

0хVιcнy#1337 5 Sep 23, 2022
OpenEmu Discord Rich Presence provided with Python!

A simple application that provides your current OpenEmu game as an RPC state in Discord via PyPresence. How to use Unzip and open the latest x86_64 ve

Deltaion Lee 6 May 30, 2022