Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Starting a repo with basic python code best practices #1

Merged
merged 11 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,36 @@
# py-template
Template for a new python project
This repository serves as a template for new python projects and a way to express best practices

## Best Practices

### User input
* Always use `argparse` for command-line arguments
* Assume the use of `yaml` for structured input files unless there are compelling reasons for something else
MicahGale marked this conversation as resolved.
Show resolved Hide resolved

### User output
* Always use `logger` for status output
* Carefully choose an output format for standard formats, considering the following in order of priority:
* CSV
* yaml
MicahGale marked this conversation as resolved.
Show resolved Hide resolved
* json
* HDF5
* SQL
MicahGale marked this conversation as resolved.
Show resolved Hide resolved

### Modularity
* All runnable scripts should include a block like:
MicahGale marked this conversation as resolved.
Show resolved Hide resolved

``` python
if __name__ == __main__():
do_main_task()
```

### Testing
* Always use `pytest` for testing
MicahGale marked this conversation as resolved.
Show resolved Hide resolved
* Introduce a simple continuous integration (CI) action ASAP

### Collaboration
* Generate pull requests (PRs) with as little code change as possible
* Include tests in all PRs

### Packaging and installation
* Introduce a `pyproject.toml` file ASAP
51 changes: 51 additions & 0 deletions do_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import argparse
import logging
import yaml

logger = logging.getLogger(__name__)
gonuke marked this conversation as resolved.
Show resolved Hide resolved

def perform_action(args, input_data):

return f"Some results based on args:\n{args}\n and input_data:\n{input_data}\n"

def report_results(args, input_data, results):

logger.info(f"Based on the values of args:\n{args}\n and input_data:\n{input_data}\n" +
"Here are the results:\n{results}\n")
MicahGale marked this conversation as resolved.
Show resolved Hide resolved

def task_args():

parser = argparse.ArgumentParser(
prog="do-task",
description="A program to perform a certain task.",
epilog="Some text at the bottom of the help message"
)

parser.add_argument('filename',
help="A filename to read for input")
parser.add_argument("--verbose", "-v",
type=int, default=0,
help="Level of verbosity for logging")

return parser.parse_args()

def read_input(input_filename):

with open(input_filename, 'r') as yaml_file:
input_data = yaml.safe_load(yaml_file)

return input_data

def do_task():

args = task_args()

logging.basicConfig(level=(logging.WARN-args.verbose))

input_data = read_input(args.filename)

results = perform_action(args, input_data)
report_results(results)

if __name__ == "__main__":
do_task()
13 changes: 13 additions & 0 deletions test_do_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import do_task

def test_perform_action():
args = foo
input_data = bar

exp = f"Some results based on args:\n{args}\n and input_data:\n{input_data}\n"

obs = do_task.perform_action(args, input_data)

assert exp == obs