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
Powerful Url uploader bot With Mongodb support ๐Ÿ”ฅ

Uploader X Bot Telegram RoBot to Upload Links. Features: ๐Ÿ‘‰ Upload YouTube-dl Supported Links to Telegram. ๐Ÿ‘‰ Upload HTTP/HTTPS as File/Video to Teleg

Cอกlinton Abra๊ซam 250 Jan 06, 2023
AWS Lambda - Parsing Cloudwatch Data and sending the response via email.

AWS Lambda - Parsing Cloudwatch Data and sending the response via email. Author: Evan Erickson Language: Python Backend: AWS / Serverless / AWS Lambda

Evan Scott Erickson 1 Nov 14, 2021
a discord libary that use to make discord bot with low efficiency and bad performance because I don't know how to manage the project

Aircord ๐Ÿ›ฉ๏ธ a discord libary that use to make discord bot with low efficiency and bad performance because I don't know how to manage the project Examp

Aircord 2 Oct 24, 2021
Telegram Reporter

[Telegram Reporter v.3 ] ๐Ÿ‡ฎ๐Ÿ‡ท AliCybeRR ๐Ÿ‡ฎ๐Ÿ‡ท [ AliCybeRR.Reporter feature ] Login Your Telegram account ๐Ÿ‘ฝ support Termux โ• No Limits โšก Secure ๐Ÿ” Free

AliCybeRR 1 Jun 08, 2022
Change the discord status throught websocket every 5 seconds with an insult

Discord status insult changer Change the discord status throught websocket every 5 seconds with an insult! - pip install httpx - put your tokens in "t

ัดฮนcะฝั‡ 10 Oct 27, 2022
A hyper-user friendly bot framework built on hikari

Framework A hyper-user friendly bot framework built on hikari. Framework is based off the blocking discord library disco, In both modularity and struc

Vincent 1 Jan 10, 2022
Queen Zellie is a chat bot for Telegram.

๐Ÿงโ€โ™€๏ธ ๐Ÿ’™ Queen Zellei ๐Ÿ’™ ๐Ÿงโ€โ™€๏ธ Queen Zellie is a chat bot for Telegram. Make it easy and fun to use Telegram. Telegram | Telegram Channel | Whatsapp H

Sinhalaya Official 4 Dec 18, 2021
One destination for all the developer's learning resources.

DevResources One destination for all the developer's learning resources. Find all of your learning resources under one roof and add your own. Live โœจ Y

Gaurav Sharma 33 Oct 21, 2022
Secret messaging app which you can use to communicate with your friends by encrypting / decrypting secret messages or sending secret message through mail.

Secret-Whisper A Secret messaging app which you can use to communicate with your friends by encrypting / decrypting secret messages ๐Ÿคซ or sending secr

3 Jan 01, 2022
A module to complement discord.py that has Music, Paginator and Levelling.

discord-super-utils A modern python module including many useful features that make discord bot programming extremely easy. Features Modern leveling m

Yash 106 Dec 19, 2022
Social Framework

Social Int Framework Social Int Framework its a Selenium script that scrape the IG photos and do a Reverse search on google and yandex for finding ano

29 Dec 06, 2022
Discondelete, is a Discord self-bot to delete dm's or purge all messages from a guild.

Discondelete Discondelete, is a Discord self-bot to delete dm's or purge all messages from a guild. Report Bug ยท Request Feature Table of Contents Abo

core 4 Feb 28, 2022
A discord nuking tool made by python, this also has nuke accounts, inbuilt Selfbot, Massreport, Token Grabber, Nitro Sniper and ALOT more!

Disclaimer: Rage Multi Tool was made for Educational Purposes This project was created only for good purposes and personal use. By using Rage, you agr

โ€ โ€  50 Jul 19, 2022
Maintained wavelink fork for pycord

Pycord.Wavelink Wavelink is robust and powerful Lavalink wrapper for Pycord! Wavelink features a fully asynchronous API that's intuitive and easy to u

Pycord Development 23 Dec 11, 2022
The most versatile torrent leecher and youtube-dl bot for telegram

TorToolkit Telegram So basically Tortoolkit is aimed to be the most versatile torrent leecher and youtube-dl bot for telegram. This bot is highly cust

ฮฑะฒฮนื ั‚ะฝ 1 Nov 11, 2021
Free and Open Source Group Voice chat music player for telegram โค๏ธ with button support youtube playback support

Free and Open Source Group Voice chat music player for telegram โค๏ธ with button support youtube playback support

Sehath Perera 1 Jan 08, 2022
A Discord API Wrapper for Userbots/Selfbots written in Python.

DisCum A simple, easy to use, non-restrictive, synchronous Discord API Wrapper for Selfbots/Userbots written in Python. -using requests and websockets

Liam 450 Dec 27, 2022
A plugin for modmail-bot for stealing,making ,etc emojis

EmojiPlugin for the Modmail-bot My first plugin .. its very Basic I will make more and better too Only 3 commands for now emojiadd-supports .jpg, .png

1 Dec 28, 2021
A Python Library to interface with LinkedIn API, OAuth and JSON responses

#Overview Here's another library based on the LinkedIn API, OAuth and JSON responses. Hope this documentation explains everything you need to get star

Mike Helmick 69 Dec 11, 2022