Index
- 1.0 In General
- 2.0 Revision Control
- 2.1 Branch naming & commit comments
- 2.2 Branching Model
- 2.3 Tagging & Releases
- 2.4 Versioning
- 2.5 Code Review
- 3.0 Languages
- 3.1 Python
- 3.1.1 Style
- 3.1.2 Type Hints
- 3.1.3 Doc String & Comments
- 3.1.4 Testing
- 3.1.5 Dependencies
- 3.1.6 Packaging
- 3.1.6.1 Pure Python
- 3.1.6.2 For C Extensions
- 3.1.6.3 Conda
- 3.1.6.4 Building
- 3.1 Python
1.0 In general
Most projects should compile, test, and run on MacOS X and Linux.
Some projects only need to run on a single platform or computer. Most need to be distributed for both of the above.
We do not support Windows with certain exceptions i.e. POCUS rt125 Texan software. If the software runs under Windows, that is fine, but we do not explicitly target it as a platform.
Code should be written to be easy to read and understand.
Fortunately, most of our code is written in Python which lends itself well to this. The Zen of python and many of the PEP's outline not just hard rules for style, versioning, etc, but also principles and philosophies. Read them and try to follow in their spirit.
Code should be written in a modular way that lends itself to reuse.
2.0 Revision control
Use git!!!
Most projects should be hosted here at PASSCAL's GitLab
Some projects collaborating with outside groups are on GitHub (i.e. ph5)
Repositories stored in GitLab are backed-up off-site nightly.
2.1 Branch naming and commit comments
2.1.1 Branch Naming
2.1.2 Commit Comments
In order to create a useful revision history, all developers should follow a set of rules for commit comments. These rules will define:
- Style: Markup syntax, wrap margins, grammar, capitalization, and punctuation.
- Content: The information that should or should not be in the commit message's body.
- Metadata: The reference to issue tracking IDs, pull request numbers, etc. Split the commit messages into subject and body. Use the following 7 rules to create a proper commit message for different projects. A diff will tell you what changed, but only the commit message can properly tell you why.
- Separate subject from body with a blank line
- Limit the subject line to 50 characters
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how
2.2 Branching Model:
Master should be stable, trusted and field worthy. And releases should be tagged on master.
All development, features and bug fixes, are done in separate branches.
In general, keep commits and branches as small as logically possible. A branch should encompass a single bug fix, or feature. If the feature is large it can be broken up into several branches that build on each other. Rebasing is preferred when upstream changes. If you are working on a branch and want to make unrelated changes(another bug, pep8, refactor) avoid the urge to add it to the current branch, create another small branch and MR. It's an extra effort, but becomes fast and second nature. Small branches can be merged quickly.
Commits should be small and frequent, representing a single logical change. Writing tests and committing in a failing state before implementing the code is often a good way to develop.
We can implement a dev
or release candidate
branch model for in-house/alpha releases for testing before field distribution...
Branch commit naming is important.
- Use present tense
- Commits should be small enough that you can describe what is changed in a sentence or 2.
- Semantic, they should describe what is being done to the code There are plenty of articles on good and bad examples
This stuff is standard git best practice. There are tons of articles and references, here are some, particularly poignant on commits and messages:
https://blog.hartleybrody.com/git-small-teams/
2.3 Tagging / releases:
For tagging and versioning, we will be using the PEP 440 standard.
2.4 Versioning:
Our version numbers must start with the year and the Julian day (YYYY.JJJ). For example: 2019.133.
An additional value can be added to denote point releases, like:
Example | Description |
---|---|
2019.123 | Release on day JJJ of year YYYY |
2019.123.1 | Another release on day JJJ of year YYYY |
2019.123a1 | Alpha release 1 |
2019.123a2 | Alpha release 2 |
2019.123b1 | Beta release 1 |
2019.123b3 | Beta release 2 |
2019.123rc2 | Release candidate 2 |
2019.123.3rc2 | 4th release on 2019-123, Release candidate 2 |
Conda build numbers
If a package is rebuilt it must have a unique version and build number combination. A package can not be rebuilt and published without 1 or both of these changing.
The rule is:
If software is changed (bug fix, feature, refactor... any source code changes):
- A new version number should be update as the section above, and build version reset to 0.
If any packaging or meta data is changed, or if the package is simply rebuilt:
- The software version remains the same, but the conda build number should be incremented
2.5 Code review:
All code is subject to a review of peers and acceptance by the project lead. All merge requests will be reviewed and accepted before merging.
Code reviews take a considerable amount of time, and for good reason, the reviewer has to understand the code you're changing, what you're trying to change, and how you're changing it.
Be courteous and mindful of reviewers' time by giving your own code a thorough review FIRST!!! Follow the guidelines on branching, committing, and style in this document.
The first reviewer is the author. That is, before you request a review, review your code yourself. It should be something you're proud of and consider worthy of publishing, pass PEP and follow the guidelines here on style.
Readability is key here.
3.0 Languages
3.1 Python:
Use Python >= 3.7 for all new projects.
3.1.1 Style:
Working, functioning code is not sufficient.
Coding style; Pythonic and idiomatic may seem like subjective terms that are a matter of taste and personal preference and can vary from author to author. To a very large degree, this is not the case! It is required for our software. The biggest reason is maintainability.
There a tons of resources out there. Reitz & Schlusser summarized it well:
If you ask Python programmers what they like most about Python, they will often cite its high readability. Indeed, a high level of readability is at the heart of the design of the Python language, following the recognized fact that code is read much more often than it is written. One reason for the high readability of Python code is its relatively complete set of Code Style guidelines and “Pythonic” idioms. When a veteran Python developer (a Pythonista) calls portions of code not “Pythonic”, they usually mean that these lines of code do not follow the common guidelines and fail to express its intent in what is considered the best (hear: most readable) way. On some border cases, no best way has been agreed upon on how to express an intent in Python code, but these cases are rare.
-https://docs.python-guide.org/writing/style/
also https://www.codementor.io/blog/pythonic-code-6yxqdoktzt
https://realpython.com/learning-paths/writing-pythonic-code/
and the several PEPs https://www.python.org/dev/peps/ related to code style and guidelines
These change with time, especially as features/syntax are added to the language. Stay current.
PEP 8 outlines the standard python style. Use this and more importantly follow its spirit.
All code should pass flake8, feel free to exclude a line or 2 that you think is more readable logical with # NOQA
3.1.2 Type hints:
Variables and function return values should be type-hinted according to PEP 484. For example:
def greeting(name: str) -> str:
return 'Hello ' + name
This specifies that the name
parameter of greeting()
accepts a string, and that the function itself is expected to return a string.
3.1.3 Doc string & comments:
The PEP 257 standard should be used for single and multi-line comments.
Each function and parameter should be documented in this way, too. For example:
def complex(real=0.0, imag=0.0):
"""Form a complex number.
Keyword arguments:
real -- the real part (default 0.0)
imag -- the imaginary part (default 0.0)
"""
if imag == 0.0 and real == 0.0:
return complex_zero
3.1.4 Testing:
All packages should have a core set of automated tests unit and optionally integration tests. Unittest is included with python, PyTest can also be used. Tests should be automatically run, and pass before merge.
3.1.5 Dependencies:
There are many great, well tested, dependable libraries that can be installed and used. While keeping our dependencies constrained is a good goal, we don't want to spend our hours re-inventing the wheel. Use your better judgment. If a package is already a dependency of another package, use it before a similar, or suggest we switch. Before depending on a large package, create a justification and discuss it.
3.1.5.1 Obspy
This is a large package that we are including, and are encouraged to use. If it is missing a feature ask about contributing.
3.1.5.2 PySide2
Projects that require a GUI should use PySide2.
3.1.6 Packaging:
3.1.6.1 Pure Python
All should be pip-installable with a minimum setup.py.
Conda packages can be built automatically from these
3.1.6.2 For C extensions:
DBD: distutils or setuptools Whichever of the above is used, builds should be automated, place compiled code in a logical place, and
3.1.6.3 Conda
All Software should build as a conda package
3.1.6.4 Building:
All packages and code should have automated builds with the de facto frameworks are chosen ( setup.py, conda, etc)
Handmade builds are forgotten and cause problems later. It's best to start and empty project with setup.py and start testing from the beginning.