Skip to content
Matt Turner edited this page Nov 10, 2015 · 3 revisions

WC-WAVE Adaptors

Welcome to the WC-WAVE Adaptors wiki! For now this is mainly a guide for contributing to the project. However, feel free to add new pages as you see fit.

Installation instructions

The very first step is to clone the vw-py repository

git clone https://github.com/VirtualWatershed/vw-py.git

Next, install some dependencies...

Non-python Prerequisites

First there are some non-python requirements to install: HDF5 and NetCDF.

On Debian/Ubuntu, you need libhdf5-serial-dev and libnetcdf-dev:

sudo apt-get install libhdf5-serial-dev libnetcdf-dev

Do not install libhdf5-dev!

On OSX, get Homebrew if you don't have it, then

brew install hdf5 netcdf

Python Requirements

For this you must have pip installed. To see if you have pip installed, type which pip at the command line. If it shows you where pip is located, then you have it. If not, use apt-get if you're using Debian/Ubuntu. If you're on OS X, use Homebrew to install a newer version of Python which comes with pip and you'll need anyway (brew install python).

Once you're sure you have pip installed, install the Python requirements by running

pip install -r requirements.txt

If you'd like to keep these requirements separate from the rest of the Python packages on your system, consider using a virtual environment.

Notes on Usage

CASiMiR and DFLOW coupling project

Please download and use the DFLOW/CASiMiR User Guide.

Contributing

A note on prerequisites

If you aren't familiar with Github and git version control, please work through some beginner guides from "Good Resources for Learning Git and Github". Our project is mainly written in Python.

For documentation, we use Sphinx. For a quick introduction, see First Steps with Sphinx. Sphinx uses ReStructured Text as its base markup language and extends this with powerful and flexible auto-documentation tools.

Unittests are required for all contributions. Not only do unittests help us "build quality in" at an early stage and focus our efforts, but unittests are a form of interactive documentation themselves. For unittesting in this project, we use nose, but it's also important to be familiar with the Python Standard Library's base unittest package, unittest, which nose is built on.

Finally, we follow PEP 8 standards. PEP stands for Python Enhancement Proposal. PEP 8 is the style proposal that is followed pretty stringently by the open source community, and so we need to follow it as well. I'll cover the important points from it below, but in order to implement PEP8 efficiently, you'll need to be using a text editor with options to, for example, set tabs to be four spaces. I use vim as a text editor. It has plugins that allow me to get instant feedback on both errors, syntax, and whether I'm following PEP8 standards. There are many editors that can do this, but another notable and popular one is Sublime Text.

Contribution guidelines

We require that code be documented intelligently. The code itself should say what its doing, so comments should say why the code is doing what it does and how it fits into the larger program structure. We need to generate web documentation via Sphinx so that others can dive in to using and developing our adaptors.

PEP 8: Highlights

PEP 8 is a long document. Please read it when you get a chance, because it will be enforced. However, here are the most important parts:

Maximum 79-character line length

Limit your lines to 79 characters or less. Granted this is not always feasible, but it should be a vast majority of the time. Maybe every one of 200 or 300 lines of code could exceed 79 characters. This may seem archaic since we have larger screens these days, but in fact it's very useful. It allows all users to have the same experience when editing the code. Also, printing out code can be useful, and this can add complexity when lines exceed 79 characters.

If you have a lengthy call in Python, you can break lines within parenthesis at any point, for example

new_variable = make_new_variable(a, b,
                                                          c, d)

or if, say you have a long function call and you need to add something after it, you can add \ to the end of the line, and the line will be continued to the next:

new_variable = long_function_call(long_argument_name1, long_argument_name2) + \
                                  25.0

Four spaces, no tabs

This is one of the most important of them all because of how fussy python can be about tabs. The entire language is based on tabbing, but PEP 8 tells us that we shouldn't actually use tabs, but four spaces for a tab. Currently we are working with Python 2.7, but Python 3 has many nice features. Python 2 will allow mixed tabs and spaces, but Python 3 will not. Plus, all our editors can be configured the same and stably if we agree to this standard.

Naming Conventions

Classes

Classes are CamelCase with an upper case first letter.

class NewClass:
    """
    This class is a new class. I like it. It will control data input for the .nc file type.
    """
    def __init__(self):
        pass

Variables

Local variables are written with snake_case, like so:

import numpy as np
two_times_pi = np.pi * 2.0

Global variables are all-caps snake_case:

PI_USE_ME_ANYWHERE = 3.14159265359

def two_times_py():
    return 2.0 * PI_USE_ME_ANYWHERE

Spaces in various places

Here are some examples from the PEP 8 specification on Whitespace in Expressions and Statements. Please read the entire specification. Below are some examples of what to do and what not to do.

#### Assignment Operator ####
## One space to either side of the assignment operator, "="
# yes
x = 1
y = 2
z = x + y
# no, no, no, and no
x     =1
y     = 2
zed = x + y
phi=1.61803398875

#### Parenthesis and brackets ####
## No space should come between a parenthesis, bracket, or brace, 
## and the symbols immediate inside it
# Yes
def complex(x, y):
    z = x + I*y

z0 = complex(x0, y0)
z1 = complex(x1, y1)

complex_list = [z0, z1]

pointless_complex_dict = {"hey": complex_list[0], "yo": complex_list[1]}
# No
def complex( x, y )

complex_list_of_dicts = [ { "hey": complex_list[0], "don't do this": complex_list[1]  }]

#### Commas, semicolons, and colons
## These are used differently for different situations.
## When slicing an array or list, there should be no space to either side of the colon
# Yes
slice_of_eight = my_list[:8]
smaller_inner_slice = my_list[4:6]

## No whitespace ever comes immediately before a comma or colon
# Yes
if x == 4:
    print "x is four!!!"
    z = complex(x, x)
# No
if x == 4 : 
    print "x is four!!!"
    z = complex(x , x)

Doc Strings

Functions and classes must have an associated doc string, even if it's only a few words.

def foo(arg1, arg2, **kwargs)
    """
    foo will return some foo for you. 
    Inputs: 
        (str) arg1
        (int) arg2
    Returns: (str) a foo string
    """

The details of what actually goes in there are not too important in this project. So far we don't have a strongly-established standard for that. The important thing is that they are there, starting with three quotes tabbed in once, and comments aligned with the quotation marks. Types and descriptions of input arguments and return values do need to be included somehow.

Conclusion

Standards exist so that we may collaborate more efficiently and so that anyone at any later time may most easily get involved with or use our product. Indeed, collaboration can truly be a joy if everyone does their part in holding to standards. Otherwise, that burden falls on the folks who care about standards.

If there is ever any question, my first bit of advice would be to google it or search the PEP 8 standards. If that still doesn't work, email me.