In [1]:
import itertools
import datetime
import calendar

def find_december_monday(currentYear):
    month = 12
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates
In [2]:
# Let's see what it outputs.
find_december_monday(datetime.date.today().year)
Out[2]:
['2016/12/5',
 '2015/12/7',
 '2014/12/8',
 '2013/12/9',
 '2012/12/3',
 '2011/12/5',
 '2010/12/6',
 '2009/12/7']

I see that it outputs 2016/12/5, which is in the future. I thought the challenge was for past meetings, so outputing future meetings would be an error. Maybe pruning future meetings is handled by whatever calls find_december_monday(). At least for now, I am not go to worry about it, but it should be discussed with the author.

Before we start refactoring it, we should check to see that it is correct. So we figure out what the correct output is. Partly for fun, partly for redundancy, we will explore several ways.

In [3]:
# First, some shell for a gut check.
# Let's see what the output of the cal command looks like.
!cal 12 2016 | tr ' ' '.'
...December.2016......
Su.Mo.Tu.We.Th.Fr.Sa..
.............1..2..3..
.4..5..6..7..8..9.10..
11.12.13.14.15.16.17..
18.19.20.21.22.23.24..
25.26.27.28.29.30.31..
......................
In [4]:
# In the above, I see that the Mondays are the second field,
# hence the following one line shell solutions.
!for year in `seq 2009 2016`;do cal 12 $year|awk "/^..  [3-9]/ {print $year, 12, \$2}";done
print()
# Two ways of reversing the order follow.
!for year in `seq 2009 2016`;do cal 12 $year|awk "/^..  [3-9]/ {print $year, 12, \$2}";done|tac
print()
!for year in `seq 2016 -1 2009`;do cal 12 $year|awk "/^..  [3-9]/ {print $year, 12, \$2}";done
2009 12 7
2010 12 6
2011 12 5
2012 12 3
2013 12 9
2014 12 8
2015 12 7
2016 12 5

2016 12 5
2015 12 7
2014 12 8
2013 12 9
2012 12 3
2011 12 5
2010 12 6
2009 12 7

2016 12 5
2015 12 7
2014 12 8
2013 12 9
2012 12 3
2011 12 5
2010 12 6
2009 12 7
In [5]:
# Now onto the Python gut check.
# Let's see what a Python calendar looks like.

import datetime

import calendar

DECEMBER = 12

c = calendar.TextCalendar().formatmonth(datetime.date.today().year, DECEMBER)
c = c.rstrip()
c = c.replace(' ', '.')
c.split('\n')
Out[5]:
['...December.2016',
 'Mo.Tu.We.Th.Fr.Sa.Su',
 '..........1..2..3..4',
 '.5..6..7..8..9.10.11',
 '12.13.14.15.16.17.18',
 '19.20.21.22.23.24.25',
 '26.27.28.29.30.31']
In [6]:
# From the above,
# we see that Monday is the first day of the week.
# Let's show just the interesting lines.

import datetime

import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

DECEMBER = 12

this_year = datetime.date.today().year

for year in reversed(range(FIRST_MEETING_DATE.year, this_year + 1)):
    for line in calendar.TextCalendar(
            ).formatmonth(year, DECEMBER).rstrip().split('\n'):
        if 'December' in line or 'Mo' in line:
            print(line)
        elif line[1].isdigit():
            date = int(line[:2])
            if 3 <= date <= 9:
                print(line)
   December 2016
Mo Tu We Th Fr Sa Su
 5  6  7  8  9 10 11
   December 2015
Mo Tu We Th Fr Sa Su
 7  8  9 10 11 12 13
   December 2014
Mo Tu We Th Fr Sa Su
 8  9 10 11 12 13 14
   December 2013
Mo Tu We Th Fr Sa Su
 9 10 11 12 13 14 15
   December 2012
Mo Tu We Th Fr Sa Su
 3  4  5  6  7  8  9
   December 2011
Mo Tu We Th Fr Sa Su
 5  6  7  8  9 10 11
   December 2010
Mo Tu We Th Fr Sa Su
 6  7  8  9 10 11 12
   December 2009
Mo Tu We Th Fr Sa Su
 7  8  9 10 11 12 13
In [7]:
# Try again, using regular expressions this time.
# This is more succinct.

import datetime
import re

import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

DECEMBER = 12

this_year = datetime.date.today().year

for year in reversed(range(FIRST_MEETING_DATE.year, this_year + 1)):
    for line in calendar.TextCalendar().formatmonth(year, DECEMBER).split('\n'):
        if re.search(r'^ [3-9]|December|Mo ', line):
            print(line)
   December 2016
Mo Tu We Th Fr Sa Su
 5  6  7  8  9 10 11
   December 2015
Mo Tu We Th Fr Sa Su
 7  8  9 10 11 12 13
   December 2014
Mo Tu We Th Fr Sa Su
 8  9 10 11 12 13 14
   December 2013
Mo Tu We Th Fr Sa Su
 9 10 11 12 13 14 15
   December 2012
Mo Tu We Th Fr Sa Su
 3  4  5  6  7  8  9
   December 2011
Mo Tu We Th Fr Sa Su
 5  6  7  8  9 10 11
   December 2010
Mo Tu We Th Fr Sa Su
 6  7  8  9 10 11 12
   December 2009
Mo Tu We Th Fr Sa Su
 7  8  9 10 11 12 13
In [8]:
# Get the known valid meetings dates
# and save them for later comparison.

import datetime
import re

import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

DECEMBER = 12

this_year = datetime.date.today().year

good_dates = []
for year in reversed(range(FIRST_MEETING_DATE.year, this_year + 1)):
    for line in calendar.TextCalendar().formatmonth(year, DECEMBER).split('\n'):
        m = re.search(r'^ (?P<date>[3-9])', line)
        if not m:
            continue
        date = int(m.group('date'))
        good_dates.append(datetime.date(year, DECEMBER, date))

good_dates
Out[8]:
[datetime.date(2016, 12, 5),
 datetime.date(2015, 12, 7),
 datetime.date(2014, 12, 8),
 datetime.date(2013, 12, 9),
 datetime.date(2012, 12, 3),
 datetime.date(2011, 12, 5),
 datetime.date(2010, 12, 6),
 datetime.date(2009, 12, 7)]
In [9]:
# From good_dates, create a list that has the same format
# as output from find_december_monday().

joe_style_good_output = [date.strftime('%Y/%-m/%-d') for date in good_dates]
joe_style_good_output
Out[9]:
['2016/12/5',
 '2015/12/7',
 '2014/12/8',
 '2013/12/9',
 '2012/12/3',
 '2011/12/5',
 '2010/12/6',
 '2009/12/7']
In [10]:
# Compare known good output to that from find_december_monday().
# We will do this each time the code is changed
# to make sure that the change does not change the output.
# This is almost test driven development (TDD).

this_year = datetime.date.today().year
assert find_december_monday(this_year) == joe_style_good_output

For giggles, one more way. This time in Haskell.

In [11]:
%%script ghci
let dw y m d = (d + (2 * m) + ((3 * (m + 1)) `div` 5) + y + (y `div` 4) - (y `div` 100) + (y `div` 400) + 2) `mod` 7
let decmtg y = [3,9,8,7,6,5,4] !! (dw y 12 1)
map decmtg [2009..2016]
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> Prelude> Prelude> [7,6,5,3,9,8,7,5]
Prelude> Leaving GHCi.

Now we start refactoring, one thing at a time.

In [12]:
# Give a name to 12.

import itertools
import datetime
import calendar

DECEMBER = 12

def find_december_monday(currentYear):
    month = DECEMBER
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert find_december_monday(this_year) == joe_style_good_output

That's nice. It worked. When creating new cells interactively with someone, they know exactly what the changes are because they just did them. But when one looks at the refactoring later, how does one know what all the little changes were? It would be nice the see the differences between one cell and another as we refactor. So I use some cell magic to show the difference between it and the previously executed cell, before showing the output of the cell. (There should not be any output when the assert is happy.)

One complication is that since my trickery executes cells outside Jupyter notebook, the cells do not have access to variables from Jupyter notebook and vice versa. In particular, joe_style_good_output, is not available for comparison in the assert statements. So we will write joe_style_good_output to a file. When cells are executed externally, they will read that file for the assert comparison.

One nice thing about running the cells outside Jupyter, is that we know each cell has all the stuff it needs and does not rely on some result from a previous cell.

In [13]:
with open('joe_style_good_output', 'w') as f:
    f.write(repr(joe_style_good_output))
In [14]:
# Change the assert to work with reading from file.

import itertools
import datetime
import calendar

DECEMBER = 12

def find_december_monday(currentYear):
    month = DECEMBER
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())

Create the script that be executed by %%script magic to show differences.

In [15]:
%%script bash

# As we refactor, it would be nice to see the difference between
# one cell and the previously executed cell.
# This script creates a shell script that
# does that when executed with the %%script diff_python
# at the beginning of a cell.
#
# To disable the diff command,
# Put a : and space in front of it. I.e.,
#     : diff old.py new.py
#
# meld yields a beautiful diff,
# but pops up a window for each cell executed.

program_name="${PATH%%:*}/diff_python"

cat >"$program_name" <<EOF
#!/usr/bin/env bash
cat >new.py
chmod +x new.py
if [ -a old.py ]; then
    diff old.py new.py
fi
python new.py
mv new.py old.py
EOF
rm old.py
chmod +x "$program_name"

From now on, each cell will start with the %%script diff_python magic. The original cell is repeated below with the addition of the %%script diff_python magic at the beginning, the assert at the end, and a change to deliberately cause a bug for the assert to catch. It also initializes the differences.

In [16]:
%%script diff_python

# Changed 12 to 11 to deliberately make assert fail for TDD.

import itertools
import datetime
import calendar

def find_december_monday(currentYear):
    month = 11
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
Traceback (most recent call last):
  File "new.py", line 31, in <module>
    open('joe_style_good_output').read())
AssertionError

The assert above blew up. That is good. That means that the assert is actually testing find_december_monday().

Next, we restore the original cell with boilerplate at top and bottom. For all following cells, the assert should succeed, there should be no output from the function, and the only output should be the difference in source code.

In [17]:
%%script diff_python

import itertools
import datetime
import calendar

def find_december_monday(currentYear):
    month = 12
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
2,3d1
< # Changed 12 to 11 to deliberately make assert fail for TDD.
< 
9c7
<     month = 11
---
>     month = 12
In [18]:
%%script diff_python
# Give a name to 12.

import itertools
import datetime
import calendar

DECEMBER = 12

def find_december_monday(currentYear):
    month = DECEMBER
    dates = []

    for year in range(currentYear, 2008, -1):
        day = 1
    
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
0a1
> # Give a name to 12.
5a7,8
> DECEMBER = 12
> 
7c10
<     month = 12
---
>     month = DECEMBER
In [19]:
%%script diff_python
# PEP8:
#     Delete trailing whitespace.
#     Rename currentYear to last_year.

import itertools
import datetime
import calendar

DECEMBER = 12

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, 2008, -1):
        day = 1

        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1c1,3
< # Give a name to 12.
---
> # PEP8:
> #     Delete trailing whitespace.
> #     Rename currentYear to last_year.
9c11
< def find_december_monday(currentYear):
---
> def find_december_monday(last_year):
13c15
<     for year in range(currentYear, 2008, -1):
---
>     for year in range(last_year, 2008, -1):
15c17
<     
---
> 
18c20
<             dates.append(str(year) + '/' + str(month) + '/' + str(day)) 
---
>             dates.append(str(year) + '/' + str(month) + '/' + str(day))
In [20]:
%%script diff_python
# Replace magic number 2008 with expression that has meaning.
# 2008 was a little sneaky.
# What one cares about is the year of the first meeting,
# which happens to be 2009, not 2008.
# The descending range needs a number that is one less than the last desired value.
# If one changed the year of the first meeting from 2009 to something else,
# how would one know to look for 2008?
# That is part of the perniciousness of magic numbers.
# We declare the first meeting date simply and directly,
# and calculate the preceding year from it.
# This way if first meeting date is changed,
# the loop automatically stops at the correct year.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

DECEMBER = 12

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        day = 1

        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += 7
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += 8
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,12
< # PEP8:
< #     Delete trailing whitespace.
< #     Rename currentYear to last_year.
---
> # Replace magic number 2008 with expression that has meaning.
> # 2008 was a little sneaky.
> # What one cares about is the year of the first meeting,
> # which happens to be 2009, not 2008.
> # The descending range needs a number that is one less than the last desired value.
> # If one changed the year of the first meeting from 2009 to something else,
> # how would one know to look for 2008?
> # That is part of the perniciousness of magic numbers.
> # We declare the first meeting date simply and directly,
> # and calculate the preceding year from it.
> # This way if first meeting date is changed,
> # the loop automatically stops at the correct year.
8a18,19
> FIRST_MEETING_DATE = datetime.date(2009, 9, 28)
> 
15c26
<     for year in range(last_year, 2008, -1):
---
>     for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
In [21]:
%%script diff_python
# Replace magic number 7 with DAYS_PER_WEEK.
# Also replace nastier magic number 8 with DAYS_PER_WEEK + 1.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        day = 1

        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += DAYS_PER_WEEK
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += DAYS_PER_WEEK + 1
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(3, 8):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,12c1,2
< # Replace magic number 2008 with expression that has meaning.
< # 2008 was a little sneaky.
< # What one cares about is the year of the first meeting,
< # which happens to be 2009, not 2008.
< # The descending range needs a number that is one less than the last desired value.
< # If one changed the year of the first meeting from 2009 to something else,
< # how would one know to look for 2008?
< # That is part of the perniciousness of magic numbers.
< # We declare the first meeting date simply and directly,
< # and calculate the preceding year from it.
< # This way if first meeting date is changed,
< # the loop automatically stops at the correct year.
---
> # Replace magic number 7 with DAYS_PER_WEEK.
> # Also replace nastier magic number 8 with DAYS_PER_WEEK + 1.
20a11
> DAYS_PER_WEEK = 7
30c21
<             day += 7
---
>             day += DAYS_PER_WEEK
33c24
<             day += 8
---
>             day += DAYS_PER_WEEK + 1
In [22]:
%%script diff_python
# Replace magic numbers in range(3, 8).
# Most of the work was in figuring out the expression
# to replace 8 with.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        day = 1

        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += DAYS_PER_WEEK
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
            day += DAYS_PER_WEEK + 1
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
        else:
            for day in range(
                    EARLIEST_VALID_DECEMBER_DATE,
                    EARLIEST_VALID_DECEMBER_DATE +
                    DAYS_PER_WEEK -
                    N_INVALID_DECEMBER_MEETING_DAYS):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,3
< # Replace magic number 7 with DAYS_PER_WEEK.
< # Also replace nastier magic number 8 with DAYS_PER_WEEK + 1.
---
> # Replace magic numbers in range(3, 8).
> # Most of the work was in figuring out the expression
> # to replace 8 with.
9a11,13
> N_INVALID_DECEMBER_MEETING_DAYS = 2
> EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1
> 
27c31,35
<             for day in range(3, 8):
---
>             for day in range(
>                     EARLIEST_VALID_DECEMBER_DATE,
>                     EARLIEST_VALID_DECEMBER_DATE +
>                     DAYS_PER_WEEK -
>                     N_INVALID_DECEMBER_MEETING_DAYS):
In [23]:
%%script diff_python
# Rework elif section to be more similar to if section.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        day = 1

        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += DAYS_PER_WEEK
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
            continue
        day += 1
        if calendar.weekday(year, month, day) == calendar.MONDAY:
            day += DAYS_PER_WEEK
            dates.append(str(year) + '/' + str(month) + '/' + str(day))
            continue

        for day in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE +
                DAYS_PER_WEEK -
                N_INVALID_DECEMBER_MEETING_DAYS):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,3c1
< # Replace magic numbers in range(3, 8).
< # Most of the work was in figuring out the expression
< # to replace 8 with.
---
> # Rework elif section to be more similar to if section.
27,28c25,28
<         elif calendar.weekday(year, month, day + 1) == calendar.MONDAY:
<             day += DAYS_PER_WEEK + 1
---
>             continue
>         day += 1
>         if calendar.weekday(year, month, day) == calendar.MONDAY:
>             day += DAYS_PER_WEEK
30,37c30,38
<         else:
<             for day in range(
<                     EARLIEST_VALID_DECEMBER_DATE,
<                     EARLIEST_VALID_DECEMBER_DATE +
<                     DAYS_PER_WEEK -
<                     N_INVALID_DECEMBER_MEETING_DAYS):
<                 if calendar.weekday(year, month, day) == calendar.MONDAY:
<                     dates.append(str(year) + '/' + str(month) + '/' + str(day))
---
>             continue
> 
>         for day in range(
>                 EARLIEST_VALID_DECEMBER_DATE,
>                 EARLIEST_VALID_DECEMBER_DATE +
>                 DAYS_PER_WEEK -
>                 N_INVALID_DECEMBER_MEETING_DAYS):
>             if calendar.weekday(year, month, day) == calendar.MONDAY:
>                 dates.append(str(year) + '/' + str(month) + '/' + str(day))
In [24]:
%%script diff_python
# The first two if sections above are identical,
# so combine them into a loop.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(1, N_INVALID_DECEMBER_MEETING_DAYS + 1):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                day += DAYS_PER_WEEK
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break
        else:
            for day in range(
                    EARLIEST_VALID_DECEMBER_DATE,
                    EARLIEST_VALID_DECEMBER_DATE +
                    DAYS_PER_WEEK -
                    N_INVALID_DECEMBER_MEETING_DAYS):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1c1,2
< # Rework elif section to be more similar to if section.
---
> # The first two if sections above are identical,
> # so combine them into a loop.
20,36c21
<         day = 1
< 
<         if calendar.weekday(year, month, day) == calendar.MONDAY:
<             day += DAYS_PER_WEEK
<             dates.append(str(year) + '/' + str(month) + '/' + str(day))
<             continue
<         day += 1
<         if calendar.weekday(year, month, day) == calendar.MONDAY:
<             day += DAYS_PER_WEEK
<             dates.append(str(year) + '/' + str(month) + '/' + str(day))
<             continue
< 
<         for day in range(
<                 EARLIEST_VALID_DECEMBER_DATE,
<                 EARLIEST_VALID_DECEMBER_DATE +
<                 DAYS_PER_WEEK -
<                 N_INVALID_DECEMBER_MEETING_DAYS):
---
>         for day in range(1, N_INVALID_DECEMBER_MEETING_DAYS + 1):
37a23
>                 day += DAYS_PER_WEEK
38a25,33
>                 break
>         else:
>             for day in range(
>                     EARLIEST_VALID_DECEMBER_DATE,
>                     EARLIEST_VALID_DECEMBER_DATE +
>                     DAYS_PER_WEEK -
>                     N_INVALID_DECEMBER_MEETING_DAYS):
>                 if calendar.weekday(year, month, day) == calendar.MONDAY:
>                     dates.append(str(year) + '/' + str(month) + '/' + str(day))
In [25]:
%%script diff_python
# Instead of iterating over invalid days, then jumping ahead a week,
# directly iterate over the valid days
# that happen a week later than the invalid days.
# Although this is an improvement by itself,
# even better are further improvements in later cells
# that this change enables.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(
                1 + DAYS_PER_WEEK,
                N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break
        else:
            for day in range(
                    EARLIEST_VALID_DECEMBER_DATE,
                    EARLIEST_VALID_DECEMBER_DATE +
                    DAYS_PER_WEEK -
                    N_INVALID_DECEMBER_MEETING_DAYS):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,6
< # The first two if sections above are identical,
< # so combine them into a loop.
---
> # Instead of iterating over invalid days, then jumping ahead a week,
> # directly iterate over the valid days
> # that happen a week later than the invalid days.
> # Although this is an improvement by itself,
> # even better are further improvements in later cells
> # that this change enables.
21c25,27
<         for day in range(1, N_INVALID_DECEMBER_MEETING_DAYS + 1):
---
>         for day in range(
>                 1 + DAYS_PER_WEEK,
>                 N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
23d28
<                 day += DAYS_PER_WEEK
In [26]:
%%script diff_python
# Now we add a minor optimization to the last loop
# to quit when it finds a match.
# Although this is a valid optimization all by itself,
# it was also done to make the bodies
# of the two inner for loops identical.
# That is a setup for another improvement a couple cells later.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(
                1 + DAYS_PER_WEEK,
                N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break
        else:
            for day in range(
                    EARLIEST_VALID_DECEMBER_DATE,
                    EARLIEST_VALID_DECEMBER_DATE +
                    DAYS_PER_WEEK -
                    N_INVALID_DECEMBER_MEETING_DAYS):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))
                    break

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,6c1,6
< # Instead of iterating over invalid days, then jumping ahead a week,
< # directly iterate over the valid days
< # that happen a week later than the invalid days.
< # Although this is an improvement by itself,
< # even better are further improvements in later cells
< # that this change enables.
---
> # Now we add a minor optimization to the last loop
> # to quit when it finds a match.
> # Although this is a valid optimization all by itself,
> # it was also done to make the bodies
> # of the two inner for loops identical.
> # That is a setup for another improvement a couple cells later.
38a39
>                     break
In [27]:
%%script diff_python
# The last argument to the last range() above is complicated.
#
#     EARLIEST_VALID_DECEMBER_DATE +
#     DAYS_PER_WEEK -
#     N_INVALID_DECEMBER_MEETING_DAYS
#
# Let's simplify it.
# First replace EARLIEST_VALID_DECEMBER_DATE with its definition.
#
#     (N_INVALID_DECEMBER_MEETING_DAYS + 1) +
#     DAYS_PER_WEEK -
#     N_INVALID_DECEMBER_MEETING_DAYS
#
# The N_INVALID_DECEMBER_MEETING_DAYS terms cancel each other out,
# leaving a much simpler expression.
#
#     DAYS_PER_WEEK + 1
#
# Why did I not think of that earlier?
# That's how refactoring goes.
# It is iterative.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(
                1 + DAYS_PER_WEEK,
                N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break
        else:
            for day in range(EARLIEST_VALID_DECEMBER_DATE, DAYS_PER_WEEK + 1):
                if calendar.weekday(year, month, day) == calendar.MONDAY:
                    dates.append(str(year) + '/' + str(month) + '/' + str(day))
                    break

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,6c1,21
< # Now we add a minor optimization to the last loop
< # to quit when it finds a match.
< # Although this is a valid optimization all by itself,
< # it was also done to make the bodies
< # of the two inner for loops identical.
< # That is a setup for another improvement a couple cells later.
---
> # The last argument to the last range() above is complicated.
> #
> #     EARLIEST_VALID_DECEMBER_DATE +
> #     DAYS_PER_WEEK -
> #     N_INVALID_DECEMBER_MEETING_DAYS
> #
> # Let's simplify it.
> # First replace EARLIEST_VALID_DECEMBER_DATE with its definition.
> #
> #     (N_INVALID_DECEMBER_MEETING_DAYS + 1) +
> #     DAYS_PER_WEEK -
> #     N_INVALID_DECEMBER_MEETING_DAYS
> #
> # The N_INVALID_DECEMBER_MEETING_DAYS terms cancel each other out,
> # leaving a much simpler expression.
> #
> #     DAYS_PER_WEEK + 1
> #
> # Why did I not think of that earlier?
> # That's how refactoring goes.
> # It is iterative.
32,36c47
<             for day in range(
<                     EARLIEST_VALID_DECEMBER_DATE,
<                     EARLIEST_VALID_DECEMBER_DATE +
<                     DAYS_PER_WEEK -
<                     N_INVALID_DECEMBER_MEETING_DAYS):
---
>             for day in range(EARLIEST_VALID_DECEMBER_DATE, DAYS_PER_WEEK + 1):
In [28]:
%%script diff_python
# The inner for loops have the same body,
# and their ranges are adjacent without overlapping,
# so combine the two inner loops into one loop.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(
                EARLIEST_VALID_DECEMBER_DATE,
                N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,21c1,3
< # The last argument to the last range() above is complicated.
< #
< #     EARLIEST_VALID_DECEMBER_DATE +
< #     DAYS_PER_WEEK -
< #     N_INVALID_DECEMBER_MEETING_DAYS
< #
< # Let's simplify it.
< # First replace EARLIEST_VALID_DECEMBER_DATE with its definition.
< #
< #     (N_INVALID_DECEMBER_MEETING_DAYS + 1) +
< #     DAYS_PER_WEEK -
< #     N_INVALID_DECEMBER_MEETING_DAYS
< #
< # The N_INVALID_DECEMBER_MEETING_DAYS terms cancel each other out,
< # leaving a much simpler expression.
< #
< #     DAYS_PER_WEEK + 1
< #
< # Why did I not think of that earlier?
< # That's how refactoring goes.
< # It is iterative.
---
> # The inner for loops have the same body,
> # and their ranges are adjacent without overlapping,
> # so combine the two inner loops into one loop.
41c23
<                 1 + DAYS_PER_WEEK,
---
>                 EARLIEST_VALID_DECEMBER_DATE,
46,50d27
<         else:
<             for day in range(EARLIEST_VALID_DECEMBER_DATE, DAYS_PER_WEEK + 1):
<                 if calendar.weekday(year, month, day) == calendar.MONDAY:
<                     dates.append(str(year) + '/' + str(month) + '/' + str(day))
<                     break
In [29]:
%%script diff_python
# We make the inner range slightly less ugly,
# replacing N_INVALID_DECEMBER_MEETING_DAYS + 1
# with EARLIEST_VALID_DECEMBER_DATE.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
        for day in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break

    return dates

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,3
< # The inner for loops have the same body,
< # and their ranges are adjacent without overlapping,
< # so combine the two inner loops into one loop.
---
> # We make the inner range slightly less ugly,
> # replacing N_INVALID_DECEMBER_MEETING_DAYS + 1
> # with EARLIEST_VALID_DECEMBER_DATE.
24c24
<                 N_INVALID_DECEMBER_MEETING_DAYS + 1 + DAYS_PER_WEEK):
---
>                 EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
In [30]:
%%script diff_python
# Backward ranges hurt my head,
# so go forward, then reverse result.

# Why are reverse order dates desired anyway?
# I don't know the answer to that,
# so I maintain returning result in reverse order.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for day in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append(str(year) + '/' + str(month) + '/' + str(day))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,6
< # We make the inner range slightly less ugly,
< # replacing N_INVALID_DECEMBER_MEETING_DAYS + 1
< # with EARLIEST_VALID_DECEMBER_DATE.
---
> # Backward ranges hurt my head,
> # so go forward, then reverse result.
> 
> # Why are reverse order dates desired anyway?
> # I don't know the answer to that,
> # so I maintain returning result in reverse order.
21c24
<     for year in range(last_year, FIRST_MEETING_DATE.year - 1, -1):
---
>     for year in range(FIRST_MEETING_DATE.year, last_year + 1):
29c32
<     return dates
---
>     return list(reversed(dates))
In [31]:
%%script diff_python
# Refactor date formatting.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for day in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, day) == calendar.MONDAY:
                dates.append('%s/%s/%s' % (year, month, day))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,6c1
< # Backward ranges hurt my head,
< # so go forward, then reverse result.
< 
< # Why are reverse order dates desired anyway?
< # I don't know the answer to that,
< # so I maintain returning result in reverse order.
---
> # Refactor date formatting.
29c24
<                 dates.append(str(year) + '/' + str(month) + '/' + str(day))
---
>                 dates.append('%s/%s/%s' % (year, month, day))
In [32]:
%%script diff_python
# Make names more consisdent: day -> date.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for date in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, date) == calendar.MONDAY:
                dates.append('%s/%s/%s' % (year, month, date))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1c1
< # Refactor date formatting.
---
> # Make names more consisdent: day -> date.
20c20
<         for day in range(
---
>         for date in range(
23,24c23,24
<             if calendar.weekday(year, month, day) == calendar.MONDAY:
<                 dates.append('%s/%s/%s' % (year, month, day))
---
>             if calendar.weekday(year, month, date) == calendar.MONDAY:
>                 dates.append('%s/%s/%s' % (year, month, date))
In [33]:
%%script diff_python
# Factor out date formatting to another function.
#
# That way, the formatting for all find_*_monday() functions
# can be in one place.

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '%s/%s/%s' % (year, month, date)

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for date in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, date) == calendar.MONDAY:
                dates.append(year_month_date(year, month, date))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1c1,4
< # Make names more consisdent: day -> date.
---
> # Factor out date formatting to another function.
> #
> # That way, the formatting for all find_*_monday() functions
> # can be in one place.
14a18,20
> def year_month_date(year, month, date):
>     return '%s/%s/%s' % (year, month, date)
> 
24c30
<                 dates.append('%s/%s/%s' % (year, month, date))
---
>                 dates.append(year_month_date(year, month, date))
In [34]:
%%script diff_python
# Try another way of formatting year/month/date string for better readability.
# The repetition in the argument list to .format() is ugly:
#     year=year, month=month, date=date

import itertools
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '{year}/{month}/{date}'.format(
        year=year, month=month, date=date)

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for date in range(
                EARLIEST_VALID_DECEMBER_DATE,
                EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
            if calendar.weekday(year, month, date) == calendar.MONDAY:
                dates.append(year_month_date(year, month, date))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,4c1,3
< # Factor out date formatting to another function.
< #
< # That way, the formatting for all find_*_monday() functions
< # can be in one place.
---
> # Try another way of formatting year/month/date string for better readability.
> # The repetition in the argument list to .format() is ugly:
> #     year=year, month=month, date=date
19c18,19
<     return '%s/%s/%s' % (year, month, date)
---
>     return '{year}/{month}/{date}'.format(
>         year=year, month=month, date=date)
In [35]:
%%script diff_python
# The inner range() above is correct and a little bit ugly.
# Let's try replacing it with itertools.count(EARLIEST_VALID_DECEMBER_DATE).
# The break statement which earlier was an optimization,
# is now required.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '{year}/{month}/{date}'.format(
        year=year, month=month, date=date)

def find_december_monday(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for date in count(EARLIEST_VALID_DECEMBER_DATE):
            if calendar.weekday(year, month, date) == calendar.MONDAY:
                dates.append(year_month_date(year, month, date))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(find_december_monday(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,4
< # Try another way of formatting year/month/date string for better readability.
< # The repetition in the argument list to .format() is ugly:
< #     year=year, month=month, date=date
---
> # The inner range() above is correct and a little bit ugly.
> # Let's try replacing it with itertools.count(EARLIEST_VALID_DECEMBER_DATE).
> # The break statement which earlier was an optimization,
> # is now required.
5c6
< import itertools
---
> from itertools import count
26,28c27
<         for date in range(
<                 EARLIEST_VALID_DECEMBER_DATE,
<                 EARLIEST_VALID_DECEMBER_DATE + DAYS_PER_WEEK):
---
>         for date in count(EARLIEST_VALID_DECEMBER_DATE):
In [36]:
%%script diff_python
# If December meetings were changed to be on some other weekday,
# the name of the function find_december_monday() would have to
# be changed. For example, if meetings were changed to be Tuesdays,
# the name would be changed to find_december_tuesday().
#
# If the meeting was not a on a particular weekday,
# such as two days after Christmas,
# the naming scheme of including the weekday in the function name
# would not make sense.
#
# Let's choose a name that works regardless of how the meeting dates
# are chosen. The name is the wrong place to indicate how the dates 
# are chosen.
#
# I choose get_december_meeting_dates().
#
# That name incorporates several changes.
#
#     find -> get
#
#         We don't just want to find the meeting dates,
#         we want to get them.
#         This is a small subtle improvement.
#
#     monday -> meeting_dates
#
#         avoids mentioning how meeting date is determined
#
#             Name is valid regardless of how date is determined.
#             This was the impetus for changing the name.
#
#         singular to plural
#
#             Multiple dates are returned,
#             so the plural name makes more sense
#             than the singular monday.
#
# Why did I not realize earlier that find_december_monday(),
# (especially the monday part) was a poor name?
#
# I have done this kind of stuff many times,
# and yet chosing names is hard.
#
# Part of the reason is that having monday in the name was accurate;
# December meetings _are_ on mondays.
# But having monday in the name missed the point
# of what the function is really about.
#
# One oftens paints oneself into a corner
# without even knowing it
# by the names one choses.
#
# It is so simple.
# Yet it is subtle.
#
# This also applies broadly in life.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '{year}/{month}/{date}'.format(
        year=year, month=month, date=date)

def get_december_meeting_dates(last_year):
    month = DECEMBER
    dates = []

    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        for date in count(EARLIEST_VALID_DECEMBER_DATE):
            if calendar.weekday(year, month, date) == calendar.MONDAY:
                dates.append(year_month_date(year, month, date))
                break

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,4c1,56
< # The inner range() above is correct and a little bit ugly.
< # Let's try replacing it with itertools.count(EARLIEST_VALID_DECEMBER_DATE).
< # The break statement which earlier was an optimization,
< # is now required.
---
> # If December meetings were changed to be on some other weekday,
> # the name of the function find_december_monday() would have to
> # be changed. For example, if meetings were changed to be Tuesdays,
> # the name would be changed to find_december_tuesday().
> #
> # If the meeting was not a on a particular weekday,
> # such as two days after Christmas,
> # the naming scheme of including the weekday in the function name
> # would not make sense.
> #
> # Let's choose a name that works regardless of how the meeting dates
> # are chosen. The name is the wrong place to indicate how the dates 
> # are chosen.
> #
> # I choose get_december_meeting_dates().
> #
> # That name incorporates several changes.
> #
> #     find -> get
> #
> #         We don't just want to find the meeting dates,
> #         we want to get them.
> #         This is a small subtle improvement.
> #
> #     monday -> meeting_dates
> #
> #         avoids mentioning how meeting date is determined
> #
> #             Name is valid regardless of how date is determined.
> #             This was the impetus for changing the name.
> #
> #         singular to plural
> #
> #             Multiple dates are returned,
> #             so the plural name makes more sense
> #             than the singular monday.
> #
> # Why did I not realize earlier that find_december_monday(),
> # (especially the monday part) was a poor name?
> #
> # I have done this kind of stuff many times,
> # and yet chosing names is hard.
> #
> # Part of the reason is that having monday in the name was accurate;
> # December meetings _are_ on mondays.
> # But having monday in the name missed the point
> # of what the function is really about.
> #
> # One oftens paints oneself into a corner
> # without even knowing it
> # by the names one choses.
> #
> # It is so simple.
> # Yet it is subtle.
> #
> # This also applies broadly in life.
22c74
< def find_december_monday(last_year):
---
> def get_december_meeting_dates(last_year):
36c88
<     repr(find_december_monday(this_year)) ==
---
>     repr(get_december_meeting_dates(this_year)) ==
In [37]:
%%script diff_python
# Let's separate getting one particular december meeting date
# into another function.
#
# get_december_meeting_date() and get_december_meeting_dates()
# each do one thing. This makes each easier to undertstand.
#
# break statements are a little ugly.
# A nice side effect of separating the functions,
# is that the break statement disappeared,
# becoming a return statement.
#
# get_december_meeting_date() is pretty simple now.
#
# get_december_meeting_dates() is also simple now.
#
# I don't like the similarity in the names.
# That makes it easy to confuse them.
# But I have a feeling that get_december_meeting_dates
# will be combined with other similar functions
# eliminating the problem.
# If that does not happen, maybe we revisit name choices.
#
# By the way, there is a school of thought that requires
# that each function must have only a single return statement,
# that it be at the bottom of the function,
# and that it be at the top level of the function.
# That can make the code awkward and ugly,
# so I do not follow that school.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '{year}/{month}/{date}'.format(
        year=year, month=month, date=date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return year_month_date(year, month, date)

def get_december_meeting_dates(last_year):
    dates = []
    for year in range(FIRST_MEETING_DATE.year, last_year + 1):
        dates.append(get_december_meeting_date(year))

    return list(reversed(dates))

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,4c1,2
< # If December meetings were changed to be on some other weekday,
< # the name of the function find_december_monday() would have to
< # be changed. For example, if meetings were changed to be Tuesdays,
< # the name would be changed to find_december_tuesday().
---
> # Let's separate getting one particular december meeting date
> # into another function.
6,9c4,5
< # If the meeting was not a on a particular weekday,
< # such as two days after Christmas,
< # the naming scheme of including the weekday in the function name
< # would not make sense.
---
> # get_december_meeting_date() and get_december_meeting_dates()
> # each do one thing. This makes each easier to undertstand.
11,56c7,28
< # Let's choose a name that works regardless of how the meeting dates
< # are chosen. The name is the wrong place to indicate how the dates 
< # are chosen.
< #
< # I choose get_december_meeting_dates().
< #
< # That name incorporates several changes.
< #
< #     find -> get
< #
< #         We don't just want to find the meeting dates,
< #         we want to get them.
< #         This is a small subtle improvement.
< #
< #     monday -> meeting_dates
< #
< #         avoids mentioning how meeting date is determined
< #
< #             Name is valid regardless of how date is determined.
< #             This was the impetus for changing the name.
< #
< #         singular to plural
< #
< #             Multiple dates are returned,
< #             so the plural name makes more sense
< #             than the singular monday.
< #
< # Why did I not realize earlier that find_december_monday(),
< # (especially the monday part) was a poor name?
< #
< # I have done this kind of stuff many times,
< # and yet chosing names is hard.
< #
< # Part of the reason is that having monday in the name was accurate;
< # December meetings _are_ on mondays.
< # But having monday in the name missed the point
< # of what the function is really about.
< #
< # One oftens paints oneself into a corner
< # without even knowing it
< # by the names one choses.
< #
< # It is so simple.
< # Yet it is subtle.
< #
< # This also applies broadly in life.
---
> # break statements are a little ugly.
> # A nice side effect of separating the functions,
> # is that the break statement disappeared,
> # becoming a return statement.
> #
> # get_december_meeting_date() is pretty simple now.
> #
> # get_december_meeting_dates() is also simple now.
> #
> # I don't like the similarity in the names.
> # That makes it easy to confuse them.
> # But I have a feeling that get_december_meeting_dates
> # will be combined with other similar functions
> # eliminating the problem.
> # If that does not happen, maybe we revisit name choices.
> #
> # By the way, there is a school of thought that requires
> # that each function must have only a single return statement,
> # that it be at the bottom of the function,
> # and that it be at the top level of the function.
> # That can make the code awkward and ugly,
> # so I do not follow that school.
74c46
< def get_december_meeting_dates(last_year):
---
> def get_december_meeting_date(year):
76c48,50
<     dates = []
---
>     for date in count(EARLIEST_VALID_DECEMBER_DATE):
>         if calendar.weekday(year, month, date) == calendar.MONDAY:
>             return year_month_date(year, month, date)
77a52,53
> def get_december_meeting_dates(last_year):
>     dates = []
79,82c55
<         for date in count(EARLIEST_VALID_DECEMBER_DATE):
<             if calendar.weekday(year, month, date) == calendar.MONDAY:
<                 dates.append(year_month_date(year, month, date))
<                 break
---
>         dates.append(get_december_meeting_date(year))
In [38]:
%%script diff_python
# get_december_meeting_dates() is simple enough,
# that I consider refactoring it to use a comprehension.
# 
# This got rid of the dates variable,
# its initialization, and slightly ugly .append()s.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(year, month, date):
    return '{year}/{month}/{date}'.format(
        year=year, month=month, date=date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return year_month_date(year, month, date)

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,28c1,5
< # Let's separate getting one particular december meeting date
< # into another function.
< #
< # get_december_meeting_date() and get_december_meeting_dates()
< # each do one thing. This makes each easier to undertstand.
< #
< # break statements are a little ugly.
< # A nice side effect of separating the functions,
< # is that the break statement disappeared,
< # becoming a return statement.
< #
< # get_december_meeting_date() is pretty simple now.
< #
< # get_december_meeting_dates() is also simple now.
< #
< # I don't like the similarity in the names.
< # That makes it easy to confuse them.
< # But I have a feeling that get_december_meeting_dates
< # will be combined with other similar functions
< # eliminating the problem.
< # If that does not happen, maybe we revisit name choices.
< #
< # By the way, there is a school of thought that requires
< # that each function must have only a single return statement,
< # that it be at the bottom of the function,
< # and that it be at the top level of the function.
< # That can make the code awkward and ugly,
< # so I do not follow that school.
---
> # get_december_meeting_dates() is simple enough,
> # that I consider refactoring it to use a comprehension.
> # 
> # This got rid of the dates variable,
> # its initialization, and slightly ugly .append()s.
53,57c30,32
<     dates = []
<     for year in range(FIRST_MEETING_DATE.year, last_year + 1):
<         dates.append(get_december_meeting_date(year))
< 
<     return list(reversed(dates))
---
>     return list(reversed([
>         get_december_meeting_date(year)
>         for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))
In [39]:
%%script diff_python
# Something that bugs me, is returning strings.
# So I will work in datetime.date objects as long as I can,
# then convert to strings at the last moment.
#
# The new function name, get_december_meeting_date_strings,
# is getting long and unwieldy,
# but each function does just one thing
# and sure are easy to understand.
#
# Something I did not realize until after I did it,
# is that if I just want datetime.date objects
# I can use get_december_meeting_dates(),
# ignoring get_december_meeting_date_strings().
#
# I like how year_month_date() now has just a single argument.
# Unfortunately, The format arguments got even uglier.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(date):
    return '{year}/{month}/{date}'.format(
        year=date.year, month=date.month, date=date.day)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return datetime.date(year, month, date)

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        year_month_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1,5c1,16
< # get_december_meeting_dates() is simple enough,
< # that I consider refactoring it to use a comprehension.
< # 
< # This got rid of the dates variable,
< # its initialization, and slightly ugly .append()s.
---
> # Something that bugs me, is returning strings.
> # So I will work in datetime.date objects as long as I can,
> # then convert to strings at the last moment.
> #
> # The new function name, get_december_meeting_date_strings,
> # is getting long and unwieldy,
> # but each function does just one thing
> # and sure are easy to understand.
> #
> # Something I did not realize until after I did it,
> # is that if I just want datetime.date objects
> # I can use get_december_meeting_dates(),
> # ignoring get_december_meeting_date_strings().
> #
> # I like how year_month_date() now has just a single argument.
> # Unfortunately, The format arguments got even uglier.
19c30
< def year_month_date(year, month, date):
---
> def year_month_date(date):
21c32
<         year=year, month=month, date=date)
---
>         year=date.year, month=date.month, date=date.day)
27c38
<             return year_month_date(year, month, date)
---
>             return datetime.date(year, month, date)
33a45,49
> def get_december_meeting_date_strings(last_year):
>     return [
>         year_month_date(date)
>         for date in get_december_meeting_dates(last_year)]
> 
36c52
<     repr(get_december_meeting_dates(this_year)) ==
---
>     repr(get_december_meeting_date_strings(this_year)) ==
In [40]:
%%script diff_python
# Let's refactor the formatting in year_month_date()
# by trying another style of .format() syntax.
#
# I like this way because there is no repetition.
#
# Ahhh, year_month_date() looks much better now.

from itertools import count
import datetime
import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return datetime.date(year, month, date)

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        year_month_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,2
< # Something that bugs me, is returning strings.
< # So I will work in datetime.date objects as long as I can,
< # then convert to strings at the last moment.
---
> # Let's refactor the formatting in year_month_date()
> # by trying another style of .format() syntax.
5,8c4
< # The new function name, get_december_meeting_date_strings,
< # is getting long and unwieldy,
< # but each function does just one thing
< # and sure are easy to understand.
---
> # I like this way because there is no repetition.
10,16c6
< # Something I did not realize until after I did it,
< # is that if I just want datetime.date objects
< # I can use get_december_meeting_dates(),
< # ignoring get_december_meeting_date_strings().
< #
< # I like how year_month_date() now has just a single argument.
< # Unfortunately, The format arguments got even uglier.
---
> # Ahhh, year_month_date() looks much better now.
31,32c21
<     return '{year}/{month}/{date}'.format(
<         year=date.year, month=date.month, date=date.day)
---
>     return '{0.year}/{0.month}/{0.day}'.format(date)
In [41]:
%%script diff_python
# PEP8: import order and spacing

import datetime
from itertools import count

import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def year_month_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return datetime.date(year, month, date)

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        year_month_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1,6c1
< # Let's refactor the formatting in year_month_date()
< # by trying another style of .format() syntax.
< #
< # I like this way because there is no repetition.
< #
< # Ahhh, year_month_date() looks much better now.
---
> # PEP8: import order and spacing
8d2
< from itertools import count
9a4,5
> from itertools import count
> 
In [42]:
%%script diff_python
# Just like monday in a function name was accurate,
# but was not a good choice,
# year_month_date is a poor function name.
#
# So I changed it to format_date,
# leaving the details of what that format is
# to the innards of the function.
#
# Function names should begin with a verb.
# 
# So another bad thing about year_month_date
# as a function name is that it has no verb.
# format_date begins with a verb.
#
# If I had several date formatting functions,
# I might revert to names like year_month_date.
# I might also have a variable format_date
# to select the desired format function.

import datetime
from itertools import count

import calendar

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        if calendar.weekday(year, month, date) == calendar.MONDAY:
            return datetime.date(year, month, date)

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        format_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1c1,18
< # PEP8: import order and spacing
---
> # Just like monday in a function name was accurate,
> # but was not a good choice,
> # year_month_date is a poor function name.
> #
> # So I changed it to format_date,
> # leaving the details of what that format is
> # to the innards of the function.
> #
> # Function names should begin with a verb.
> # 
> # So another bad thing about year_month_date
> # as a function name is that it has no verb.
> # format_date begins with a verb.
> #
> # If I had several date formatting functions,
> # I might revert to names like year_month_date.
> # I might also have a variable format_date
> # to select the desired format function.
16c33
< def year_month_date(date):
---
> def format_date(date):
32c49
<         year_month_date(date)
---
>         format_date(date)
In [43]:
%%script diff_python
# I refactored get_december_meeting_date().
#
# I got rid of the dependency on the calendar module,
# but had to declare MONDAY myself.
#
# get_december_meeting_date() is a wee bit easier to read.

import datetime
from itertools import count

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def get_december_meeting_date(year):
    month = DECEMBER
    for date in count(EARLIEST_VALID_DECEMBER_DATE):
        d = datetime.date(year, month, date)
        if d.weekday() == MONDAY:
            return d

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        format_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1,3c1
< # Just like monday in a function name was accurate,
< # but was not a good choice,
< # year_month_date is a poor function name.
---
> # I refactored get_december_meeting_date().
5,7c3,4
< # So I changed it to format_date,
< # leaving the details of what that format is
< # to the innards of the function.
---
> # I got rid of the dependency on the calendar module,
> # but had to declare MONDAY myself.
9,18c6
< # Function names should begin with a verb.
< # 
< # So another bad thing about year_month_date
< # as a function name is that it has no verb.
< # format_date begins with a verb.
< #
< # If I had several date formatting functions,
< # I might revert to names like year_month_date.
< # I might also have a variable format_date
< # to select the desired format function.
---
> # get_december_meeting_date() is a wee bit easier to read.
23,24d10
< import calendar
< 
30a17
> MONDAY = 0  # per date.weekday()
39,40c26,28
<         if calendar.weekday(year, month, date) == calendar.MONDAY:
<             return datetime.date(year, month, date)
---
>         d = datetime.date(year, month, date)
>         if d.weekday() == MONDAY:
>             return d
In [44]:
%%script diff_python
# In the cell above, count() in get_december_meeting_date()
# only groks integers,
# so I had to convert from integers to datetime.date objects.
#
# It would be nice to iterate directly with datetime.date objects,
# skipping the conversion from integers to datetime.date objects.
# So I make a generator that iterates through datetime objects
# like itertools.count() does for integers.
#
# I stumbled into getting rid of the itertools dependency.
#
# get_december_meeting_date() got simpler and easier to read yet,
# although the argument to iter_date got long.
# iter_date() is a nice little function that might find broad use.
#
# Why is itertools.count() limited to iterating over integers
# instead of iterating of anything that can handle .__add__()?
# I will add that to my list of things to explore later.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    for date in iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        format_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1c1,3
< # I refactored get_december_meeting_date().
---
> # In the cell above, count() in get_december_meeting_date()
> # only groks integers,
> # so I had to convert from integers to datetime.date objects.
3,4c5,8
< # I got rid of the dependency on the calendar module,
< # but had to declare MONDAY myself.
---
> # It would be nice to iterate directly with datetime.date objects,
> # skipping the conversion from integers to datetime.date objects.
> # So I make a generator that iterates through datetime objects
> # like itertools.count() does for integers.
6c10,18
< # get_december_meeting_date() is a wee bit easier to read.
---
> # I stumbled into getting rid of the itertools dependency.
> #
> # get_december_meeting_date() got simpler and easier to read yet,
> # although the argument to iter_date got long.
> # iter_date() is a nice little function that might find broad use.
> #
> # Why is itertools.count() limited to iterating over integers
> # instead of iterating of anything that can handle .__add__()?
> # I will add that to my list of things to explore later.
9d20
< from itertools import count
22a34,38
> def iter_date(date, increment=datetime.timedelta(days=1)):
>     while True:
>         yield date;
>         date += increment
> 
25,28c41,43
<     for date in count(EARLIEST_VALID_DECEMBER_DATE):
<         d = datetime.date(year, month, date)
<         if d.weekday() == MONDAY:
<             return d
---
>     for date in iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)):
>         if date.weekday() == MONDAY:
>             return date
In [45]:
%%script diff_python
# In get_december_meeting_date() in the cell above,
# the argument to iter_date() got long,
# so I name it on a separate line.
#
# That made get_december_meeting_date() a little easier to read.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_december_meeting_date_strings(last_year):
    return [
        format_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_december_meeting_date_strings(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,3
< # In the cell above, count() in get_december_meeting_date()
< # only groks integers,
< # so I had to convert from integers to datetime.date objects.
---
> # In get_december_meeting_date() in the cell above,
> # the argument to iter_date() got long,
> # so I name it on a separate line.
5,18c5
< # It would be nice to iterate directly with datetime.date objects,
< # skipping the conversion from integers to datetime.date objects.
< # So I make a generator that iterates through datetime objects
< # like itertools.count() does for integers.
< #
< # I stumbled into getting rid of the itertools dependency.
< #
< # get_december_meeting_date() got simpler and easier to read yet,
< # although the argument to iter_date got long.
< # iter_date() is a nice little function that might find broad use.
< #
< # Why is itertools.count() limited to iterating over integers
< # instead of iterating of anything that can handle .__add__()?
< # I will add that to my list of things to explore later.
---
> # That made get_december_meeting_date() a little easier to read.
41c28,29
<     for date in iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)):
---
>     start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
>     for date in iter_date(start_date):
In [46]:
%%script diff_python
# Change get_december_meeting_date_strings
# to get_formatted_december_meeting_dates.
#
# That's a little bit more readable.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(last_year):
    return list(reversed([
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))

def get_formatted_december_meeting_dates(last_year):
    return [
        format_date(date)
        for date in get_december_meeting_dates(last_year)]

this_year = datetime.date.today().year
assert (
    repr(get_formatted_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,2
< # In get_december_meeting_date() in the cell above,
< # the argument to iter_date() got long,
< # so I name it on a separate line.
---
> # Change get_december_meeting_date_strings
> # to get_formatted_december_meeting_dates.
5c4
< # That made get_december_meeting_date() a little easier to read.
---
> # That's a little bit more readable.
38c37
< def get_december_meeting_date_strings(last_year):
---
> def get_formatted_december_meeting_dates(last_year):
45c44
<     repr(get_december_meeting_date_strings(this_year)) ==
---
>     repr(get_formatted_december_meeting_dates(this_year)) ==
In [47]:
%%script diff_python
# I don't like the reverse year stuff.
# I also don't like the list(reversed([ stuff in
# get_december_meeting_dates,
# so I am going to move that ugliness to a different function.
#
# get_december_meeting_dates() got prettier.
# Now it has a generator expression.
#
# get_formatted_december_meeting_dates() got uglier.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(last_year):
    return (
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)
    )

def get_formatted_december_meeting_dates(last_year):
    return [
        format_date(date)
        for date in list(reversed(list(get_december_meeting_dates(last_year))))
    ]

this_year = datetime.date.today().year
assert (
    repr(get_formatted_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,4
< # Change get_december_meeting_date_strings
< # to get_formatted_december_meeting_dates.
---
> # I don't like the reverse year stuff.
> # I also don't like the list(reversed([ stuff in
> # get_december_meeting_dates,
> # so I am going to move that ugliness to a different function.
4c6,9
< # That's a little bit more readable.
---
> # get_december_meeting_dates() got prettier.
> # Now it has a generator expression.
> #
> # get_formatted_december_meeting_dates() got uglier.
33c38
<     return list(reversed([
---
>     return (
35c40,41
<         for year in range(FIRST_MEETING_DATE.year, last_year + 1)]))
---
>         for year in range(FIRST_MEETING_DATE.year, last_year + 1)
>     )
40c46,47
<         for date in get_december_meeting_dates(last_year)]
---
>         for date in list(reversed(list(get_december_meeting_dates(last_year))))
>     ]
In [48]:
%%script diff_python
# Let's move the list(reversed(list( ugliness
# out of get_formatted_december_meeting_dates(),
# to a function that deals with just that ugliness.
#
# get_formatted_december_meeting_dates() got prettier.
# Now it has a generator expression.
#
# get_formatted_reversed_december_meeting_dates()
# has a name that is long and a bit awkward,
# but I like isolating the ugly reverse order stuff to it.
# With it doing that one thing, it is simple.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(last_year):
    return (
        get_december_meeting_date(year)
        for year in range(FIRST_MEETING_DATE.year, last_year + 1)
    )

def get_formatted_december_meeting_dates(last_year):
    return (
        format_date(date)
        for date in get_december_meeting_dates(last_year)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(reversed(list(get_formatted_december_meeting_dates(last_year))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,4c1,3
< # I don't like the reverse year stuff.
< # I also don't like the list(reversed([ stuff in
< # get_december_meeting_dates,
< # so I am going to move that ugliness to a different function.
---
> # Let's move the list(reversed(list( ugliness
> # out of get_formatted_december_meeting_dates(),
> # to a function that deals with just that ugliness.
6c5
< # get_december_meeting_dates() got prettier.
---
> # get_formatted_december_meeting_dates() got prettier.
9c8,11
< # get_formatted_december_meeting_dates() got uglier.
---
> # get_formatted_reversed_december_meeting_dates()
> # has a name that is long and a bit awkward,
> # but I like isolating the ugly reverse order stuff to it.
> # With it doing that one thing, it is simple.
44c46
<     return [
---
>     return (
46,47c48,52
<         for date in list(reversed(list(get_december_meeting_dates(last_year))))
<     ]
---
>         for date in get_december_meeting_dates(last_year)
>     )
> 
> def get_formatted_reversed_december_meeting_dates(last_year):
>     return list(reversed(list(get_formatted_december_meeting_dates(last_year))))
51c56
<     repr(get_formatted_december_meeting_dates(this_year)) ==
---
>     repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
In [49]:
%%script diff_python
# I dislike the whole approach to iterating over years,
# so I am going to move the details of that out of
# get_december_meeting_dates().
#
# Golly, get_december_meeting_dates() is very very simple now.
#
# get_formatted_december_meeting_dates() got a wee bit simpler.
#
# All the stuff I don't like is isolated to
# get_formatted_reversed_december_meeting_dates().

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = range(FIRST_MEETING_DATE.year, last_year + 1)
    return list(reversed(list(get_formatted_december_meeting_dates(years))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,3
< # Let's move the list(reversed(list( ugliness
< # out of get_formatted_december_meeting_dates(),
< # to a function that deals with just that ugliness.
---
> # I dislike the whole approach to iterating over years,
> # so I am going to move the details of that out of
> # get_december_meeting_dates().
5,6c5
< # get_formatted_december_meeting_dates() got prettier.
< # Now it has a generator expression.
---
> # Golly, get_december_meeting_dates() is very very simple now.
8,11c7,10
< # get_formatted_reversed_december_meeting_dates()
< # has a name that is long and a bit awkward,
< # but I like isolating the ugly reverse order stuff to it.
< # With it doing that one thing, it is simple.
---
> # get_formatted_december_meeting_dates() got a wee bit simpler.
> #
> # All the stuff I don't like is isolated to
> # get_formatted_reversed_december_meeting_dates().
39c38
< def get_december_meeting_dates(last_year):
---
> def get_december_meeting_dates(years):
42c41
<         for year in range(FIRST_MEETING_DATE.year, last_year + 1)
---
>         for year in years
45c44
< def get_formatted_december_meeting_dates(last_year):
---
> def get_formatted_december_meeting_dates(years):
48c47
<         for date in get_december_meeting_dates(last_year)
---
>         for date in get_december_meeting_dates(years)
52c51,52
<     return list(reversed(list(get_formatted_december_meeting_dates(last_year))))
---
>     years = range(FIRST_MEETING_DATE.year, last_year + 1)
>     return list(reversed(list(get_formatted_december_meeting_dates(years))))
In [50]:
%%script diff_python
# I think I can improve
# get_formatted_reversed_december_meeting_dates()
# a little bit.
#
# I moved the reversed() call to the expression for years.
# This also eliminated one of the list() calls. Nice.
#
# Now even the function that has all the things I don't like
# is easy to read and understand. Sweet!

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    month = DECEMBER
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,3
< # I dislike the whole approach to iterating over years,
< # so I am going to move the details of that out of
< # get_december_meeting_dates().
---
> # I think I can improve
> # get_formatted_reversed_december_meeting_dates()
> # a little bit.
5c5,6
< # Golly, get_december_meeting_dates() is very very simple now.
---
> # I moved the reversed() call to the expression for years.
> # This also eliminated one of the list() calls. Nice.
7,10c8,9
< # get_formatted_december_meeting_dates() got a wee bit simpler.
< #
< # All the stuff I don't like is isolated to
< # get_formatted_reversed_december_meeting_dates().
---
> # Now even the function that has all the things I don't like
> # is easy to read and understand. Sweet!
51,52c50,51
<     years = range(FIRST_MEETING_DATE.year, last_year + 1)
<     return list(reversed(list(get_formatted_december_meeting_dates(years))))
---
>     years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
>     return list(get_formatted_december_meeting_dates(years))
In [51]:
%%script diff_python
# Oops, the month variable in get_december_meeting_date()
# is not used, so get rid of it.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()
DAYS_PER_WEEK = 7

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,9c1,2
< # I think I can improve
< # get_formatted_reversed_december_meeting_dates()
< # a little bit.
< #
< # I moved the reversed() call to the expression for years.
< # This also eliminated one of the list() calls. Nice.
< #
< # Now even the function that has all the things I don't like
< # is easy to read and understand. Sweet!
---
> # Oops, the month variable in get_december_meeting_date()
> # is not used, so get rid of it.
31d23
<     month = DECEMBER
In [52]:
%%script diff_python
# DAYS_PER_WEEK is not used, so get rid of it.
# (Don't stop at the one bug.)

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    for date in iter_date(start_date):
        if date.weekday() == MONDAY:
            return date

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # Oops, the month variable in get_december_meeting_date()
< # is not used, so get rid of it.
---
> # DAYS_PER_WEEK is not used, so get rid of it.
> # (Don't stop at the one bug.)
13d12
< DAYS_PER_WEEK = 7

Compare what we have now to what we started with.

We started with one ugly complicated function that was hard to read and hard to understand. It was also frail because of magic numbers, especially the ones derived from other numbers.

Now we have several functions. Each one is simple, easy to read, and easy to understand. One function, iter_date(), is a generator. Two other functions, get_december_meeting_dates() and get_formatted_december_meeting_dates(), return simple generator expressions.

Study generators.


Now to reduce to the absurd, just for giggles.

In [53]:
%%script diff_python
# Eliminate the only if statement above.
# Replace it with functional programming.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
    return list(zip(filter(
        lambda date: date.weekday() == MONDAY, iter_date(start_date)),
        range(1)))[0][0]

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # DAYS_PER_WEEK is not used, so get rid of it.
< # (Don't stop at the one bug.)
---
> # Eliminate the only if statement above.
> # Replace it with functional programming.
24,26c24,26
<     for date in iter_date(start_date):
<         if date.weekday() == MONDAY:
<             return date
---
>     return list(zip(filter(
>         lambda date: date.weekday() == MONDAY, iter_date(start_date)),
>         range(1)))[0][0]
In [54]:
%%script diff_python
# Combine the two statements of
# get_december_meeting_date() to one statement.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_date(year):
    return list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]

def get_december_meeting_dates(years):
    return (
        get_december_meeting_date(year)
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # Eliminate the only if statement above.
< # Replace it with functional programming.
---
> # Combine the two statements of
> # get_december_meeting_date() to one statement.
23d22
<     start_date = datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE)
25c24,25
<         lambda date: date.weekday() == MONDAY, iter_date(start_date)),
---
>         lambda date: date.weekday() == MONDAY,
>         iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
In [55]:
%%script diff_python
# Combine get_december_meeting_date()
# into get_december_meeting_dates().

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_december_meeting_dates(years):
    return (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in years
    )

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in get_december_meeting_dates(years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # Combine the two statements of
< # get_december_meeting_date() to one statement.
---
> # Combine get_december_meeting_date()
> # into get_december_meeting_dates().
22,23c22,24
< def get_december_meeting_date(year):
<     return list(zip(filter(
---
> def get_december_meeting_dates(years):
>     return (
>         list(zip(filter(
27,30d27
< 
< def get_december_meeting_dates(years):
<     return (
<         get_december_meeting_date(year)
In [56]:
%%script diff_python
# Combine get_december_meeting_dates()
# into get_formatted_december_meeting_dates().

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def format_date(date):
    return '{0.year}/{0.month}/{0.day}'.format(date)

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_formatted_december_meeting_dates(years):
    return (
        format_date(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # Combine get_december_meeting_date()
< # into get_december_meeting_dates().
---
> # Combine get_december_meeting_dates()
> # into get_formatted_december_meeting_dates().
22c22
< def get_december_meeting_dates(years):
---
> def get_formatted_december_meeting_dates(years):
23a24,25
>         format_date(date)
>         for date in (
28,34c30
<         for year in years
<     )
< 
< def get_formatted_december_meeting_dates(years):
<     return (
<         format_date(date)
<         for date in get_december_meeting_dates(years)
---
>         for year in years)
In [57]:
%%script diff_python
# Combine format_date()
# into get_formatted_december_meeting_dates().

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_formatted_december_meeting_dates(years):
    return (
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in years)
    )

def get_formatted_reversed_december_meeting_dates(last_year):
    years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
    return list(get_formatted_december_meeting_dates(years))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1c1
< # Combine get_december_meeting_dates()
---
> # Combine format_date()
14,16d13
< def format_date(date):
<     return '{0.year}/{0.month}/{0.day}'.format(date)
< 
24c21
<         format_date(date)
---
>         '{0.year}/{0.month}/{0.day}'.format(date)
In [58]:
%%script diff_python
# Combine the two statements of
# get_formatted_reversed_december_meeting_dates()
# into one statement.

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_formatted_december_meeting_dates(years):
    return (
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in years))

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(get_formatted_december_meeting_dates(
        reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,3
< # Combine format_date()
< # into get_formatted_december_meeting_dates().
---
> # Combine the two statements of
> # get_formatted_reversed_december_meeting_dates()
> # into one statement.
27,28c28
<         for year in years)
<     )
---
>         for year in years))
31,32c31,32
<     years = reversed(range(FIRST_MEETING_DATE.year, last_year + 1))
<     return list(get_formatted_december_meeting_dates(years))
---
>     return list(get_formatted_december_meeting_dates(
>         reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))
In [59]:
%%script diff_python
# Combine get_formatted_december_meeting_dates()
# into get_formatted_reversed_december_meeting_dates().

import datetime

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def iter_date(date, increment=datetime.timedelta(days=1)):
    while True:
        yield date;
        date += increment

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,3c1,2
< # Combine the two statements of
< # get_formatted_reversed_december_meeting_dates()
< # into one statement.
---
> # Combine get_formatted_december_meeting_dates()
> # into get_formatted_reversed_december_meeting_dates().
20,21c19,20
< def get_formatted_december_meeting_dates(years):
<     return (
---
> def get_formatted_reversed_december_meeting_dates(last_year):
>     return list(
28,32c27
<         for year in years))
< 
< def get_formatted_reversed_december_meeting_dates(last_year):
<     return list(get_formatted_december_meeting_dates(
<         reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))
---
>         for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))
In [60]:
%%script diff_python
# Get rid of the loop in iter_date.
# To do that I reembraced count() from itertools.

import datetime

from itertools import count

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def iter_date(date, increment=datetime.timedelta(days=1)):
    return (date + i*increment for i in count())

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
        range(1)))[0][0]
        for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,2
< # Combine get_formatted_december_meeting_dates()
< # into get_formatted_reversed_december_meeting_dates().
---
> # Get rid of the loop in iter_date.
> # To do that I reembraced count() from itertools.
5a6,7
> from itertools import count
> 
15,17c17
<     while True:
<         yield date;
<         date += increment
---
>     return (date + i*increment for i in count())
In [61]:
%%script diff_python
# Combine iter_date() into
# get_formatted_reversed_december_meeting_dates().
#
# This reduces the task to one function with one statement.

import datetime

from itertools import count

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE) +
        i*datetime.timedelta(days=1)
        for i in count())),
        range(1)))[0][0]
        for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,2c1,4
< # Get rid of the loop in iter_date.
< # To do that I reembraced count() from itertools.
---
> # Combine iter_date() into
> # get_formatted_reversed_december_meeting_dates().
> #
> # This reduces the task to one function with one statement.
16,18d17
< def iter_date(date, increment=datetime.timedelta(days=1)):
<     return (date + i*increment for i in count())
< 
25c24,26
<         iter_date(datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE))),
---
>         (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE) +
>         i*datetime.timedelta(days=1)
>         for i in count())),
In [62]:
%%script diff_python
# Simplify the date increment.

import datetime

from itertools import count

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE) +
        datetime.timedelta(days=i)
        for i in count())),
        range(1)))[0][0]
        for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1,4c1
< # Combine iter_date() into
< # get_formatted_reversed_december_meeting_dates().
< #
< # This reduces the task to one function with one statement.
---
> # Simplify the date increment.
25c22
<         i*datetime.timedelta(days=1)
---
>         datetime.timedelta(days=i)
In [63]:
%%script diff_python
# The time increment we want is so simple,
# and since we will be staying within a month,
# we can eliminate datetime.timedelta() altogether.

import datetime

from itertools import count

FIRST_MEETING_DATE = datetime.date(2009, 9, 28)

N_INVALID_DECEMBER_MEETING_DAYS = 2
EARLIEST_VALID_DECEMBER_DATE = N_INVALID_DECEMBER_MEETING_DAYS + 1

DECEMBER = 12
MONDAY = 0  # per date.weekday()

def get_formatted_reversed_december_meeting_dates(last_year):
    return list(
        '{0.year}/{0.month}/{0.day}'.format(date)
        for date in (
        list(zip(filter(
        lambda date: date.weekday() == MONDAY,
        (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE + i)
        for i in count())),
        range(1)))[0][0]
        for year in reversed(range(FIRST_MEETING_DATE.year, last_year + 1))))

this_year = datetime.date.today().year
assert (
    repr(get_formatted_reversed_december_meeting_dates(this_year)) ==
    open('joe_style_good_output').read())
1c1,3
< # Simplify the date increment.
---
> # The time increment we want is so simple,
> # and since we will be staying within a month,
> # we can eliminate datetime.timedelta() altogether.
21,22c23
<         (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE) +
<         datetime.timedelta(days=i)
---
>         (datetime.date(year, DECEMBER, EARLIEST_VALID_DECEMBER_DATE + i)

Wow, that is thoroughly nasty disgusting ugly code.

In [64]:
todo = '''
    show differences
        visual diff with old cell on left and new cell on right would be fantastic
            but Jupyter notebook does not scroll cells horizontally,
            so that ain't gonna happen
        easy toggling of differences
            (because often, the diffs are distracting clutter)
        colorization of differences
        show differences _between_ the cells
            (right now the diff is shown _after_ the second cell)
        make it Pythonic
            use python instead of bash/sh
            use python difflib instead of unix command line diff
                difflib.ndiff() or difflib.context_diff()
            .splitlines()?
    copy definition into a docstring
        get_december_meeting_dates_for_years(first_year, last_year)
            maybe return comprehension
    do docstrings
    pep8
    Add references to 
        The Elements of Programming Style
        The Practice of Programming
        Brandon Rhodes videos
        Raymond Hettinger videos
    Is it correct to output December 2016 meeting before then?
    Put on github.
'''