Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
43 changes: 43 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Run Unit and Function Tests

on:
push:
branches:
- '*'
pull_request:
branches: [ master ]

jobs:
run_styleCheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: mamba-org/setup-micromamba@v3
with:
environment-file: environment.yml
init-shell: bash
- run: pycodestyle $(git ls-files "*.py")
shell: bash -l {0}
run_unit_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: mamba-org/setup-micromamba@v3
with:
environment-file: environment.yml
init-shell: bash
- run: |
python -m unittest tests/test_my_utils.py
shell: bash -l {0}
run_function_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: mamba-org/setup-micromamba@v3
with:
environment-file: environment.yml
init-shell: bash
- run: |
bash tests/test_print_fires.sh
shell: bash -l {0}

8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This file contains utilities and functions to enable the easy reading and searching inside of csv files. While tested and confirmed to run with the Agrofood_co2_emission file, it can easily be applied to csv files of any shape or size. It currently does not ship with any relevant data. Data for analysis should be moved into the same folder as the python scripts.

UPDATE: The newest version of this package includes new functionality to perform basic rudimentary statistical analysis on output lists. See "Usage" for more information
The newest version of this package includes new functionality to perform basic rudimentary statistical analysis on output lists. See "Usage" for more information

## Installation

Expand All @@ -24,7 +24,7 @@ python print_fires.py -file "path/to/my/file" -q_col int_column_to_search \
-q_val "str_value_to_search" -res_col int_column_to_find(optional)
'''

UPDATE: The newest version of this package includes new functionality to perform basic rudimentary statistical analysis on output lists. To ignore, simply use the package as previously designed. To get the mean, median, or standard deviation of the output list, use the '-stat' flag:
The newest version of this package includes new functionality to perform basic rudimentary statistical analysis on output lists. To ignore, simply use the package as previously designed. To get the mean, median, or standard deviation of the output list, use the '-stat' flag:

'''bash
python print_fires.py -file "path/to/my/file" -q_col int_column_to_search \
Expand Down Expand Up @@ -52,6 +52,10 @@ python3 print_fires.py -file "environment.yml" -q_col 0 \
'''
returns "Expected a .csv file, got .yml"

## Contributing

New to version 4.0, automatic test architecture is now implemented. Ensure that tests are written appropriately in the "tests" folder, and add the appropriate text in the test.yml file. This ensures the tests will be automatically run upon pushing and pulling.

## Summary of Changes:

Updated get_col to correctly handle errors and return only integer output.
Expand Down
23 changes: 2 additions & 21 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,7 @@ name: swe4s
channels:
- conda-forge
dependencies:
- bzip2=1.0.8=h4e30115_10
- ca-certificates=2026.7.22=hbd8a1cb_0
- icu=78.3=py310h579977c_2
- libcxx=23.1.0=h55c6f16_0
- libexpat=2.8.1=hf6b4638_1
- libffi=3.7.0=h47dc5ef_1
- liblzma=5.8.3=h8088a28_1
- libmpdec=4.0.0=h84a0fba_2
- libpython=3.14.7=h4311e70_106_cp314
- libsqlite=3.53.4=hca69786_1
- libzlib=1.3.2=h8088a28_3
- ncurses=6.6=he64c551_1
- openssl=3.6.4=h55eecbc_0
- pip=26.2.1=pyh145f28c_0
- pycodestyle=2.14.0=pyhd8ed1ab_0
- python=3.14.7=h0ae1c2c_106_cp314
- python_abi=3.14=9_cp314
- readline=8.3=h8b90a29_1
- tk=8.6.13=hbeba79b_4
- tzdata=2026c=h151e31d_0
- zstd=1.5.7=hf451053_7
- pycodestyle
- python

prefix: "/Users/theurdragon/miniforge3/envs/swe4s"
3 changes: 2 additions & 1 deletion print_fires.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
query_column = args.q_col
result_column = args.res_col
file_name = args.file
fires = my_utils.get_column(file_name, query_column, query_value, result_column)
fires = my_utils.get_column(file_name, query_column,
query_value, result_column)

if args.stat:
if args.stat == "mean":
Expand Down
Binary file added tests/__pycache__/test_my_utils.cpython-314.pyc
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/test_file.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Area,Year,Savanna fires,Forest fires,Crop Residues,Rice Cultivation,Drained organic soils (CO2),Pesticides Manufacturing,Food Transport,Forestland,Net Forest conversion,Food Household Consumption,Food Retail,On-farm Electricity Use,Food Packaging,Agrifood Systems Waste Disposal,Food Processing,Fertilizers Manufacturing,IPPU,Manure applied to Soils,Manure left on Pasture,Manure Management,Fires in organic soils,Fires in humid tropical forests,On-farm energy use,Rural population,Urban population,Total Population - Male,Total Population - Female,total_emission,Average Temperature °C
Afghanistan,1990,14.7237,0.0557,205.6077,686.0,0.0,11.807482956246297,63.1152,-2388.803,0.0,79.0851,109.6446,14.2666,67.63136607385836,691.7888,252.2141899664796,11.997,209.9778,260.1431,1590.5319,319.1763,0.0,0.0,,9655167.0,2593947.0,5348387.0,5346409.0,2198.9635389965842,0.5361666666666667
Afghanistan,1991,14.7237,0.0557,209.4971,678.16,0.0,11.712073091310696,61.2125,-2388.803,0.0,80.4885,116.6789,11.4182,67.63136607385836,710.8212,252.2141899664796,12.8539,217.0388,268.6292,1657.2364,342.3079,0.0,0.0,,10230490.0,2763167.0,5372959.0,5372208.0,2323.8766291316488,0.02066666666666665
Afghanistan,1992,14.7237,0.0557,196.5341,686.0,0.0,11.712073091310696,53.317,-2388.803,0.0,80.7692,126.1721,9.2752,67.63136607385836,743.6751,252.2141899664796,13.4929,222.1156,264.7898,1653.5068,349.1224,0.0,0.0,,10995568.0,2985663.0,6028494.0,6028939.0,2356.3042291316488,-0.25958333333333333
Afghanistan,1993,14.7237,0.0557,230.8175,686.0,0.0,11.712073091310696,54.3617,-2388.803,0.0,85.0678,81.4607,9.0635,67.63136607385836,791.9246,252.2141899664796,14.0559,201.2057,261.7221,1642.9623,352.2947,0.0,0.0,,11858090.0,3237009.0,7003641.0,7000119.0,2368.470529131649,0.10191666666666666
Afghanistan,1994,14.7237,0.0557,242.0494,705.6,0.0,11.712073091310696,53.9874,-2388.803,0.0,88.8058,90.4008,8.3962,67.63136607385836,831.9181,252.2141899664796,15.1269,182.2905,267.6219,1689.3593,367.6784,0.0,0.0,,12690115.0,3482604.0,7733458.0,7722096.0,2500.768729131649,0.37224999999999997
American Samoa,1990,0.0,0.0,,926.3422784724489,0.0,11.481084565896976,16.9802,-58.8991,7.9612,0.5104,8.4872,17.00466278502689,77.39365076150476,1.6937,94.6238,2005.7921290780253,,,2148.251692850715,,0.0,0.0,41.4996,8962.0,38076.0,24538.0,23281.0,5299.122498513618,0.5665
American Samoa,1991,0.0,0.0,,926.3422784724489,0.0,11.481084565896976,16.7829,-58.8991,7.9612,0.5104,8.3916,17.00466278502689,77.39365076150476,1.7413,92.7057,2005.7921290780253,,,2148.251692850715,,0.0,0.0,40.8094,8763.0,39612.0,25117.0,23874.0,5296.268898513617,0.599
American Samoa,1992,0.0,0.0,,926.3422784724489,0.0,11.481084565896976,17.339,-58.8991,7.9612,0.5104,8.7751,17.00466278502689,77.39365076150476,1.7848,97.5009,2005.7921290780253,,,2148.251692850715,,0.0,0.0,42.9095,8535.0,41058.0,25656.0,24422.0,5304.147298513618,0.3661666666666667
American Samoa,1993,0.0,0.0,,926.3422784724489,0.0,11.481084565896976,16.9225,-58.8991,7.9612,0.5104,8.4394,17.00466278502689,77.39365076150476,1.8251,94.3041,2005.7921290780253,,,2148.251692850715,,0.0,0.0,41.4996,8291.0,42429.0,26198.0,24976.0,5298.828698513617,-0.03266666666666668
test_val,STRING,a,a,,926.3422784724489,0.0,11.481084565896976,16.9225,-58.8991,7.9612,0.5104,8.4394,17.00466278502689,77.39365076150476,1.8251,94.3041,2005.7921290780253,,,2148.251692850715,,0.0,0.0,41.4996,8291.0,42429.0,26198.0,24976.0,5298.828698513617,-0.03266666666666668
184 changes: 184 additions & 0 deletions tests/test_my_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import unittest
from random import uniform
from random import gauss
import os
import sys

# Allows running from main directory, my_utils is there.
module_path = os.path.abspath(".")

sys.path.append(module_path)

sys.path.append("orig/unit_testing")

import my_utils # noqa


class TestUtils(unittest.TestCase):

"""get_mean() Tests"""
# Test mean function even
def test_mean_pos4(self):
lst = [1, 2, 4, 5]
m = my_utils.get_mean(lst)
self.assertEqual(m, 3)

def test_mean_neg4(self):
lst = [-1, -2, -4, -5]
m = my_utils.get_mean(lst)
self.assertEqual(m, -3)

# Test mean function odd
def test_mean_pos5(self):
lst = [2, 3, 4, 5, 6]
m = my_utils.get_mean(lst)
self.assertEqual(m, 4)

def test_mean_neg5(self):
lst = [-2, -3, -4, -5, -6]
m = my_utils.get_mean(lst)
self.assertEqual(m, -4)

# Test mean function float
def test_mean_posFloat(self):
lst = [1.5, 2.5, 4.5, 5.5]
m = my_utils.get_mean(lst)
self.assertEqual(m, 3.5)

def test_mean_negFloat(self):
lst = [-1.5, -2.5, -4.5, -5.5]
m = my_utils.get_mean(lst)
self.assertEqual(m, -3.5)

# Assorted mean error handling
def test_mean_str(self):
lst = ["a", 1, 2]
self.assertRaises(SystemExit, my_utils.get_mean, lst)

def test_mean_empty(self):
lst = []
self.assertRaises(SystemExit, my_utils.get_mean, lst)

def test_mean_none(self):
lst = None
self.assertRaises(SystemExit, my_utils.get_mean, lst)

# Test mean large numbers
def test_mean_rand(self):
lst = [uniform(-10, 10) for _ in range(100000)]
m = my_utils.get_mean(lst)
self.assertAlmostEqual(m, 0, 1)

"""get_median() Tests"""
# Test median function even
def test_median_pos4(self):
lst = [1, 2, 4, 10]
m = my_utils.get_median(lst)
self.assertEqual(m, 3)

def test_median_neg4(self):
lst = [-1, -2, -4, -10]
m = my_utils.get_median(lst)
self.assertEqual(m, -3)

# Test median function odd
def test_median_pos5(self):
lst = [1, 3, 4, 6, 20]
m = my_utils.get_median(lst)
self.assertEqual(m, 4)

def test_median_neg5(self):
lst = [-1, -3, -4, -6, -20]
m = my_utils.get_median(lst)
self.assertEqual(m, -4)

# Test median float
def test_median_posFloat(self):
lst = [0.1, 3.5, 4.5, 800.2]
m = my_utils.get_median(lst)
self.assertEqual(m, 4)

def test_median_negFloat(self):
lst = [-0.1, -3.5, -4.5, -800.2]
m = my_utils.get_median(lst)
self.assertEqual(m, -4)

# Assorted median error handling
def test_median_str(self):
lst = ["a", 1, "2"]
self.assertRaises(SystemExit, my_utils.get_median, lst)

def test_median_empty(self):
lst = []
self.assertRaises(SystemExit, my_utils.get_median, lst)

def test_median_none(self):
lst = None
self.assertRaises(SystemExit, my_utils.get_median, lst)

def test_median_order(self):
lower = [uniform(-10, 0) for _ in range(10)]
upper = [uniform(0, 10) for _ in range(10)]
lst = upper + lower + [0] # Keep bad order for testing, keep 0 too
m = my_utils.get_median(lst)
self.assertEqual(m, 0)

# Test median large numbers
def test_median_large(self):
lst = [uniform(10, 20) for _ in range(1000000)]
m = my_utils.get_median(lst)
self.assertAlmostEqual(m, 15, 1)

"""get_sd() Tests"""
# Test sd function even
def test_sd_pos4(self):
lst = [0, 0, 2, 2]
sd = my_utils.get_sd(lst)
self.assertAlmostEqual(sd, 1)

def test_sd_neg4(self):
lst = [0, 0, -2, -2]
sd = my_utils.get_sd(lst)
self.assertAlmostEqual(sd, 1)

# Test sd function float
def test_sd_Float(self):
lst = [-2.45, 0, 2.449]
sd = my_utils.get_sd(lst)
self.assertAlmostEqual(sd, 2, 4)

# Assorted sd error handling
def test_sd_str(self):
lst = ["a", 1, 2]
self.assertRaises(SystemExit, my_utils.get_sd, lst)

def test_sd_empty(self):
lst = []
self.assertRaises(SystemExit, my_utils.get_sd, lst)

def test_sd_none(self):
lst = None
self.assertRaises(SystemExit, my_utils.get_sd, lst)

# Test sd function large numbers
def test_sd_large(self):
lst = [gauss(0, 1) for _ in range(100000)]
sd = my_utils.get_sd(lst)
self.assertAlmostEqual(sd, 1, 2)

"""get_column() Tests"""
def test_col_noFile(self):
self.assertRaises(SystemExit, my_utils.get_column,
"nonexistent.csv", 0, "Afghanistan")

def test_col_noCSV(self):
self.assertRaises(SystemExit, my_utils.get_column,
"test_my_utils.py", 0, "Afghanistan")

def test_col_noInt(self):
self.assertRaises(SystemExit, my_utils.get_column,
"test/test_file.csv", "a", "Afghanistan")


if __name__ == '__main__':
unittest.main()
78 changes: 78 additions & 0 deletions tests/test_print_fires.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
test -e ssshtest || wget -q https://raw.githubusercontent.com/ryanlayer/ssshtest/master/ssshtest
. ssshtest

run basic_test python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan" -res_col 1
assert_in_stdout "[1990, 1991, 1992, 1993, 1994]"
assert_exit_code 0

run default_test python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan"
assert_in_stdout "[1990, 1991, 1992, 1993, 1994]"
assert_exit_code 0

run test_space python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "American Samoa" -res_col 1
assert_in_stdout "[1990, 1991, 1992, 1993]"
assert_exit_code 0

run test_noFile python3 print_fires.py -file "test_file.csv" -q_col 0 \
-q_val "American Samoa" -res_col 1
assert_in_stdout "Error: File 'test_file.csv' not found in current directory."
assert_exit_code 1

run test_noCSV python3 print_fires.py -file "test/test_my_utils.py" -q_col 0 \
-q_val "American Samoa" -res_col 1
assert_in_stdout "Expected a .csv file, got .py"
assert_exit_code 1

run test_noQInt python3 print_fires.py -file "test/test_file.csv" -q_col 'a' \
-q_val "American Samoa" -res_col 1
assert_in_stdout "Error: Query column ('a') is not integer."
assert_exit_code 1

run test_QLong python3 print_fires.py -file "test/test_file.csv" -q_col 105 \
-q_val "American Samoa" -res_col 1
assert_in_stdout "Error: Query column ('105') out of bounds."
assert_exit_code 1

run test_noRInt python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "American Samoa" -res_col 'a'
assert_in_stdout "Error: Result column ('a') is not integer."
assert_exit_code 1

run test_RLong python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "American Samoa" -res_col 105
assert_in_stdout "Error: Result column ('105') out of bounds."

run test_Null python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Soviet Union" -res_col 1
assert_in_stdout "No results found."
assert_in_stdout '[]'
assert_exit_code 0

run test_NoInt python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "test_val" -res_col 1
assert_in_stdout "Data must be numberic. Found "STRING"."
assert_exit_code 1

run test_mean python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan" -res_col 1 -stat 'mean'
assert_in_stdout "1992"
assert_exit_code 0

run test_median python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan" -res_col 7 -stat 'median'
assert_in_stdout "11"
assert_exit_code 0

run test_sd python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan" -res_col 3 -stat 'sd'
assert_in_stdout "0"
assert_exit_code 0

run test_sd python3 print_fires.py -file "test/test_file.csv" -q_col 0 \
-q_val "Afghanistan" -res_col 3 -stat 'PERFECT MODEL'
assert_in_stdout "Error: Invalid statistic requested 'PERFECT MODEL'."
assert_exit_code 1

Loading