Python Path the Easy Way. Add .pth Python Configuration Files

So python path is always a little daunting when coming to deployment. Especially since it’s typically done outside of your neatly wrapped software package.

The easiest way to do this so far is using python configuration files. Drop dead easy: put a .pth extension file in your site-packages directory, where each line corresponds to an entry you want put into sys.path.

http://docs.python.org/2/install/#modifying-python-s-search-path

Loading Shopify Posts via Flask on demand. Flask is Amazing.

Flask is really impressing me. It lets me write very clean obvious code.

We are launching a new site, and need a blog ASAP. I figure it would be a pain to migrate blog hosts so I was curious what I can do with Shopify’s blog API.

I was able to..

  • Loop through Shopify’s API until we get all of the blog posts. This takes a long time.
  • Strip the funky HTML
  • Parse HTML / find first image
  • Cache the results for 30 minutes
  • Split into pages of 25 / separate by pages

Some of the recommended caching plugins are just so useful right out of the box. cache.memoize will cache the results of a function for timeout building a cache key out of the function arguments.

cache.cached caches the result of a view. That means I can really easily and fluidly adjust caches as necessary to keep performance high, even though we’re making many requests to Shopify to get the posts themselves.

Check out the gist
https://gist.github.com/yuchant/312d42568192a2bf3acc

I’m impressed.

How to add ordering to a custom module list with LemonStand.

It took me a long time to figure out how to add sorting to a LemonStand list view.

Honestly, adding a simple M2M relationship in LS took me many many hours and modification of 4 partials. It takes me about 30 seconds with Django. The documentation is hard to read (but a part of the problem is just low volume / lack of search results) and mostly you just have to read the source.

Working with LS or Magento gives me a newfound appreciation for my frameworks of choice: Django or Flask + SQLAlchemy. It’s truly like magic in comparison. To be fair, those are tool for building web apps and nothing comes “in the box”. It’s just what I prefer.

Anyways, please forgive the quality of the post; I would have killed for somebody to write even half of the below. Hope it helps you guys!

Mostly we are going to copy functionality from the “manage top products”. I am not even going to bother with renaming things. Surprisingly, no new assets are required, and there is no hacking of core LS required.

Follow along.

Copy from the shop_categories.php controller

Copy the “top products” action code from the Category controller into your own controller, copying templates and modifying code as needed.

$implement

Make sure you are $implementing (subclassing)

public $implement = 'Db_ListBehavior, Db_FilterBehavior, Db_FormBehavior';

Take the relevant pieces from the __construct function in shop_categories.php

if (Phpr::$router->action == 'manage_top_products')
{
	$this->list_no_pagination = true;
	$this->list_render_as_tree = false;
	$this->list_render_as_sliding_list = false;
	$this->list_model_class = 'Shop_Product';

	$this->list_custom_body_cells = PATH_APP.'/modules/shop/controllers/shop_categories/_top_product_body_cells.htm';
	$this->list_custom_head_cells = PATH_APP.'/modules/shop/controllers/shop_categories/_top_product_head_cells.htm';
	$this->list_custom_prepare_func = 'prepare_top_product_list';
	$this->list_record_url = null;
	$this->list_search_enabled = false;
	$this->list_no_setup_link = false;
	$this->list_no_setup_link = false;
	$this->list_no_data_message = 'There are no top products in this category';
	$this->list_name = 'top_products_list';
	$this->list_no_sorting = true;
}

I ended up copying these, but it turns out you don’t need to modify anything so it’s not a strict requirement.

Remove list_record_url / add your own, to make sure edit links work.

– ‘/modules/shop/controllers/shop_categories/_top_product_body_cells.htm’;
– ‘/modules/shop/controllers/shop_categories/_top_product_head_cells.htm’;

Override sorting

The page has no default sorting, so nothing will appear to work without this sort override. Paste this function into your controller, and supply the appropriate sort field (sort_field)

	public function listOverrideSortingColumn($sorting_column)
	{
		if (Phpr::$router->action == 'reorder_categories')
		{
			$result = array('field'=>'front_end_sort_order', 'direction'=>'asc');
			return (object)$result;
		}

		return $sorting_column;
	}

The AJAX set order function

Modify the class Shop_Category with your class. Make sure your class $implements Db_Sortable to get access to the set_orders function.

	protected function reorder_categories_onSetOrders()
	{
		try
		{
			Shop_Category::set_orders(post('item_ids'), post('sort_orders'));
		}
		catch (Exception $ex)
		{
			Phpr::$response->ajaxReportException($ex, true, true);
		}
	}

The Sort field getter function

Copy the function that takes an ID and returns the sort field. This was done because the sort field is not even on the product model directly.

Note that since I only have access to an ID, I am doing a very inefficient one query per sort field lookup. Oh well.

	protected function get_top_product_sort_order($id)
	{
		// return sort order for our model, given its ID.
		$ambassador = new Raen_Ambassador();
		$ambassador_sort_order = $ambassador->find_by_id($id)->sort_order;
		return $ambassador_sort_order;
	}

Copy sorting javascript

Copy the sorting javascript header block from manage_top_products.htm

In my case, I injected the followingn block into my module index.html file.

<? Phpr_View::beginBlock("head") ?>
	<script type="text/javascript" src="modules/shop/resources/javascript/top_category_products.js"></script>
	<link rel="stylesheet" href="modules/shop/resources/css/shop.css" type="text/css"/>
<? Phpr_View::endBlock() ?>

Modify your Models

Add sort field

Make sure your model has a sort_order field. It must be named sort_order, as the DB_Sortable has hard coded values.

Add Db_Sortable to your $implement.

Add after_create default sort order

Make sure a default sort order is applied to new elements, or sorting likes to blow up.

	public static function create()
	{
		return new self();
	}

	public function after_create()
	{
		Db_DbHelper::query("UPDATE {$this->table_name} set sort_order=:sort_order where id=:id", array(
			'sort_order'=>$this->id,
			'id'=>$this->id
		));
	}

Done!

Surprisingly, this works now w/o any modification to method names 🙂

Completed controller for reference: https://gist.github.com/yuchant/8683096
Completed model for reference: https://gist.github.com/yuchant/8683106 (sans fields)

Shopify Python API Undocumented

This was frustrating. Both pyactiveresource and Shopify Python API are undocumented, and looking at the source is frustrating as it’s all so dynamic. Had to go all the way to activeresource.
To query a record which relies on another one, pass the class constructor an argument called `prefix_options`. In it must be a dict which corresponds to arguments in the URL (look at source) denoted by source_prefix.

In my case, source_prefix contained $product_id, so my call looked like this:

image = shopify.Image(prefix_options={‘product_id’: product.id})

Use Viewport Relative Units

I just learned about viewport relative units, vh, vw, vmax, vmin.

Amazing. Finally an easy way to do full height elements via 100vh == 100% viewport height.

Only problem? It blows up explosively on IOS devices.

I love the concept though, so I just created a simple coffeescript class which can be invoked directly or via data tags to trigger widths and heights correctly by converting an inline data attribute to explicit calculations on resize.

Parsing CSS for these new units was too much overhead.

https://gist.github.com/yuchant/8610909

Usage:
<div data-viewport-styles="width: 100vh; height: 50vw;"></div>

class root.utils.ViewportHeight
‘The VH unit is not well supported. Use data-tags instead.
data-viewport-unit="line-height: 100vh; height: 100vh;’
constructor: ({@element, @styles}={}) ->
@$element = $ @element
@$window = $ window
@_bindHandlers()

_getStyles: ->
# get styles as array
if not @_styles
styles = {}
for style in _.filter(@styles.split(‘;’), Boolean)
[key, value] = style.split(‘:’)
styles[key.trim()] = @_getValue(value)
self._styles = styles
return self._styles

_bindHandlers: ->
$(window).resize _.debounce(@onResize, 50)

_getValue: (value) ->
# given a unit like 400vw or 400vh, set it to absolute pixel values
# map viewport units to viewport unit conversion functions
viewportUnitMap = {
‘vh’: @_vh,
‘vw’: @_vw,
‘vmax’: null,
‘vmin’: null,
}
value = value.replace(‘;’, ”).trim()
for unit, func of viewportUnitMap
if unit.substr(value)
return func(parseInt(value))

_vh: (value) =>
@$window.height() * value/100

_vw: (value) =>
@$window.width() * value/100

_vmax: (value) =>
return Math.max @_vh(value), @_vw(value)

_vmin: (value) =>
return Math.min @_vh(value), @_vw(value)

onResize: =>
# window has been resized. update CSS values of vh/vw equivalents
@$element.css @_getStyles()

$("[data-viewport-styles]").each (index, el) ->
new root.utils.ViewportHeight
element: el
styles: $(el).data(‘viewport-styles’)

Use native SQLAlchemy in Flask-DebugToolbar

Flask-DebugToolbar only works with Flask-SQLAlchemy.

If you’re using native sqlalchemy, it turns out it’s pretty simple to activate. Instantiate the class below with your sqlalchemy DB engine and flask app.

from flask.ext.sqlalchemy import _EngineDebuggingSignalEvents
_EngineDebuggingSignalEvents(engine, app.import_name).register()

Installing psycopg2 on OSX Mavericks

There are a ton of posts on this subject… with 100 different fixes.

You need Xcode / command line tools / GCC etc. of course.

Most importantly the piece that solved my issue was described here
http://stackoverflow.com/questions/18667916/installing-psycopg2-has-it-stuck-between-xcrun-and-lipo

 ln /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/lipo /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo 
 xcrun -k lipo