Sharepoint Cache Primer

Sorry, this has sharepoint in the title.

Last week, I published, for the first time, a proper python package to PyPI. The actual application is of fairly narrow scope - it's only interesting if you're a sharepoint administrator with a certain type of configuration. I'm not even interested in it. That's ok, though, as it was a great chance to learn how to package something. I'll avoid giving a rundown of the process here, as there are already good walkthroughs.

From the docs:

The first time a browser hits a sharepoint site after a restart, the caches are empty, so the page can take a while to load. One can script something to silently hit a sharepoint web-frontend, causing it to build caches and preventing any real people from experiencing that.

This tool does this for a specific circumstance where it's kind of hard to script it without better tools - where normal NTML authentication doesn't work, because there is ADFSv3 authentication configured, and where there may be a number of web-frontends behind a load balancer.

I'm pretty pleased with the outcome. I had to touch/refine a number of things that I'd never spent enough time on: argparser, configparser, PEP440, setuptools.. things you don't often use when you're making throw-away scripts or things that only you use yourself.

https://pypi.python.org/pypi/sharepointcacheprimer/

Music Online

I signed up for the Apple Music trial, to see if it has a chance at replacing rdio/spotify (it does, but only because of my specific habits this year), and was pleased to stumble across my old music. It wasn't on the streaming service, but it was uploaded for private streaming because it was in iTunes, and became available in my car for the first time.

This inspired me to published it on soundcloud: https://soundcloud.com/s7ank/sets/hanky-panky-highway

It's pretty trash, and it's 15 years old, but I had a lot of fun playing with sound over the years.

Duplicate Keywords When Using Keyword Argument Unpacking in Python

Python has a feature often called "Argument List Unpacking," which can be found
in several other popular languages under the names "splat" (ruby), "Apply" (LISP,
Scheme, general use):

>>> def all_my_args(arg1, *args):
...     print arg1  # first arg
...     print args  # list containing the rest
>>> all_my_args("first", "second", "third")
first
('second', 'third')

And this same method can be applied to dictionaries by using the ** operator:

>>> def all_my_args(arg1, **keyword_args):
...     print arg1  # first arg
...     print keyword_args  # dict containing the rest
...
>>> all_my_args("first", second=2, third=3)
first
{'second': 2, 'third': 3}

You can then "pack" dictionaries and handle them to functions as arguments:

>>> my_args = {"second": 2, "third": 3}
>>> all_my_args("first", **my_args)
first
{'second': 2, 'third': 3}

Now, remember that all arguments can be keyword arguments, as the order of
argument parsing matters: regular arguments are first, then variable arguments
(*args), then any keyword arguments (whether named explicitly via keywordname= or implied as a packed dictionary with **keywordargs). Let's expand the
above function to emphasize the concern:

>>> def describe_blob(name, shape, **attributes):
...   print "Name:", name
...   print "Shape:", shape
...   for k,v in attributes.items():
...     print "{}: {}".format(k, v)
...
>>> describe_blob("Jack", "round", size="huge", weight="ugly")
Name: Jack
Shape: round
weight: ugly
size: huge

This seems really cool at first, because it lets the user of the function
provide any sort of keyword they want to use to describe the blob. Unfortunately,
it can cause some problems:

>>> describe_blob("Jack", "round", shape="lumpy", size="huge", weight="ugly")
Traceback (most recent call last):
File "", line 1, in 
TypeError: describe_blob() got multiple values for keyword argument 'shape'

Multiple values were found for 'shape', but I only specified one: "lumpy". Well,
it turns out that the second position argument was internally called "shape" as
well, which broke the function call. You can learn this through introspection,
but that's not something one wants to do before every function is called:

>>> import inspect
>>> inspect.getargspec(describe_blob)
ArgSpec(args=['name', 'shape'], varargs=None, keywords='attributes', defaults=None)

Even if the argument list that is acceptable is described in the function's docstring,
the arguments are often named in a way that's descriptively useful to developers of the
function, not consumers of the function.

Ultimately, it's safer to just pass this as a dictionary, even though it seems
cool to use the unpacking:

>>> def describe_blob(name, shape, attributes):
...   print "Name:", name
...   print "Shape:", shape
...   for k,v in attributes.items():
...     print "{}: {}".format(k, v)
...
>>> my_blob_attributes = { "brain": "mushy", "height": 3, "shape": "duplicative" }
>>> describe_blob("Jack", "round", my_blob_attributes)
Name: Jack
Shape: round
brain: mushy
shape: duplicative
height: 3