monkinetic

Steve Ivy's weblog, XI Ed.

Another View of Privilege

(See the disclaimer)

Leslie Hawthorn's recent keynote at OSCON on privilege is unassuming and powerful.

Please watch it and pay attention to this tidbit: privilege can be viewed as operating in a system where all the default settings work for you. This stuck with me, even more than John Scalzi's (also excellent) gaming metaphor (I'm not a huge gamer).

Watch and think:

A gender/privilege topic disclaimer

For future reference:

Disclaimer: I've never written about gender and privilege topics - I'm a hetero white male who grew up in a suburban, anglo, Christan, two-parent family in the 70s and 80s when such things were (to me) normal. I didn't go through much of a rebellious stage (barring a couple of years of slightly-over-drinking, hair-coloring and ear-piercings that didn't offend, literally, anyone).

As John Scalzi would put it, my life has been basically lived on the lowest difficuly setting and I've been fortunate due to no particular effort on my own part. Please forgive statements made as fact that are obvious to you to be side-effects of this phenomenon, and please feel free to get in touch with any feedback.

Day One, Again

I'm really liking Day One. Picked it up for free yesterday and finding it fun and useful.

Neat trick: select a passage in the book I'm reading in iBooks, select "Share" > "Copy" and paste into Day One, complete with link to the book in the iBookstore.

Easy way to temporarily kill logging in Python

Ever want to just turn off that logger for a while in Python? Maybe while running tests or debugging? Even the CRITICAL messages?

Notice that the logging level contants (logging.DEBUG etc) actually represent numeric values:

Level       Numeric value
CRITICAL    50
ERROR       40
WARNING     30
INFO        20
DEBUG       10
NOTSET      0

On a whim I tried:

logging.getLogger('logger_to_turn_off').setLevel(100)

And bam, no logging, even the CRITICAL messages. Yes, most of you python nerds knew this, but I didn't, so I learned something at least!

Idea: LinkedIn Disclaimers

Fun little idea: a blog disclaimer generator based on your current LinkedIn profile.

"My opinions on [current industry] are my own and not those of [current employer]"

Markbox Public Beta, No Invite Required

Markbox is now in public beta, which means that no invite code is required to sign up!. (Do eet noowww!) In addition, after some thought we've removed the requirement that a credit card be provided to join the service. Just as before, there is a 30-day free trial, after which a valid card will be required to continue using it.

Have fun! Sign up for a free trial!

New Markbox invites have gone out

It's been a crazy road with more hair-pulling and teeth-gnashing than I had hoped, but I've scheduled the final set of invites for Markbox. Anyone who had signed up as of tonight to be notified will be sent an invite in the morning.

The hardest part of this for me is turning on Billing. Markbox has operating expenses that I need to recouop a little bit of so it can keep going, so Markbox is now $6/mo. through the end of the Beta. How much it will be thereafter remains to be seen. I have some ideas but I'm not going to commit to anything right now.

It's nearly midnight. I'm excited and exhausted. Those who say you can build and launch as web product on the side these days is technically, but not practically, correct. It's amazingly hard and after months and months working on this I'm still embarassed at some parts of it.

But I'm not going to let this stop me.

When in doubt...

...put it in a transaction.

This nerd advice brought to you by flask and MySQL.

p.s. Anyone remember the msql/mysql wars of the mid 90s?

SqlAlchemy Relationship Error: 'property of that name exists on mapper'

The Setup

I'm writing a web app in python with Flask and SqlAlchemy with MySQL.

the solution...

The Code

Starting with the following (slightly snipped for brevity) python/SqlAlchemy code in <project>/markbox/models.py:

class UserBlog(ModelBase):
    __tablename__ = 'user_blog'

    id = sa.Column(sa.Integer, primary_key=True)
    uid = sa.Column(strcol)
    # blog title
    name = sa.Column(strcol)

    # returns a query => blog.sync_stats.all()
    sync_stats = relationship(
        'models.SyncStats', backref='blog',
        lazy='dynamic')


class SyncStats(ModelBase):
    """
    Store various statistics about sync operations
    """
    __tablename__ = 'system_syncstats'

    id = sa.Column(sa.Integer, primary_key=True)
    uid = sa.Column(strcol, sa.ForeignKey('user_blogsettings.uid'))

And this code in <project>/markbox/tools/test.py:

import sys
import os

sys.path.append(os.path.abspath('.'))
sys.path.append(os.path.abspath('markbox'))
print sys.path

from markbox.models import UserBlog, SyncStats

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DateTime
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URI = "mysql://markbox_user:markbox@localhost/markbox"

engine = create_engine(SQLALCHEMY_DATABASE_URI, echo='debug')
Session = sessionmaker(bind=engine)
session = Session()

if __name__ == '__main__':
    blog = UserBlog.query.limit(1)

The Error

When run from the command line in <project>:

% python markbox/tools/test.py

I get:

['/Users/sivy/Projects/personal/markbox/markbox/tools', ..., '/Users/sivy/Projects/personal/markbox', '/Users/sivy/Projects/personal/markbox/markbox']
Traceback (most recent call last):
  File "markbox/tools/test.py", line 25, in <module>
    blog = UserBlog.query.limit(1)
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/scoping.py", line 131, in __get__
    mapper = class_mapper(owner)
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/util.py", line 1112, in class_mapper
    mapper = _inspect_mapped_class(class_, configure=configure)
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/util.py", line 1045, in _inspect_mapped_class
    mapperlib.configure_mappers()
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2122, in configure_mappers
    mapper._post_configure_properties()
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1244, in _post_configure_properties
    prop.init()
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/interfaces.py", line 231, in init
    self.do_init()
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/properties.py", line 1031, in do_init
    self._generate_backref()
  File "/Users/sivy/.virtualenvs/markbox/lib/python2.7/site-packages/sqlalchemy/orm/properties.py", line 1220, in _generate_backref
    self, m))
sqlalchemy.exc.ArgumentError: Error creating backref 'blog' on relationship 'UserBlog.sync_stats': property of that name exists on mapper 'Mapper|SyncStats|system_syncstats'

What I've Done

I've already confirmed that:

  • the SyncStats model has no "blog" property (it used to have a method, decorated with @property).
  • I've deleted any existing *.pyc files to make sure that the interpreter is not picking up pre-compiled code.

The solution

So, the problem turned out to be that the models were being imported from two paths:

from models import UserBlog

and later:

from markbox.models import UserBlog

This caused the intilization code to be run twice, and the resulting error.

Crowning Moment of Heart Warming

My kids, wife, and Mom went to the movies today (Turbo, well-liked all around) and before they went they stopped by the drugstore and bought movies snacks. Apparently our 8yo daughter, remembering Daddy's favorite candy, convinced Mom to buy a box of Reese's Pieces.

After the movie and a couple more errands, they came home, at which time our youngest called out something akin to "No Peeeeeking" and disappeared into her room. 20 minutes later she appeared in my office with a note that said (she's somewhat developmentally delayed) "Daddy <her name> romm for You Lov <her name>". She excitedly communicated that this was a hint and I was to accompany her to her room, where I got to search her room for a present.

When I found and opened the small gift bag under her pillow containing a wrapped-with-a-bow box of candy, my heart simply melted. How did I deserve such love and adoration?

Reeses Pieces

If monkinetic Then app.net

I'm testing out a basic IFTTT recipe that reposts monkinetic posts to my app.net account.

Update: Sorry I didn't realize when I made the recipe that it was going to grab the last n existing posts and repost them as well. Whoops. Thankfully it only reposted the last 3 posts.

Why is Adobe Flash Installing Google Chrome?

So, like a sheep, I install the latest Adobe Flash (bleagh) this morning so I can watch the Superb Owl Iron Man 3 commercial, since Adobe's being a snot and pigging backing on the Superb Owl's popularity to get more Flash installs out there, and I see this:

Adobe Flash installing Google Chrome

Since when does Flash install Chrome? /me Googles

Apparently, since at least August of 2012 accordion to this Adobe Forum post:

For regularly scheduled Flash Player releases, such as our 11.4 release, users are notified of new features included in the release and may opt to download the latest player via http://get.adobe.com/flashplayer. This workflow allows users to optionally download software from select Adobe partners along with Flash Player. Adobe offsets the ongoing development costs of Flash Player, which is made available for free, by offering users these options. Bundling Google Chrome and Toolbar???

Hm.

A Modern Proverb

Three things you should be wary of,
A new kid in his prime,
A man with all the answers,
And code that runs first time.