Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
304b022
Move reports to directories by district, start work on threading / t…
krowvin Jul 20, 2024
94e75f3
Experimenting with forms
krowvin Jul 20, 2024
47e4d43
More deciding where to place the thread handlers
krowvin Jul 20, 2024
b18f271
Set version and thread count in repgen and pass to other locations.
krowvin Jul 21, 2024
5eee4bc
Migrate fetch code to a http worker for threading (not a working commit)
krowvin Jul 21, 2024
d0c7191
Working state. Tested to bring time down from 17s to 2s with parallel…
krowvin Jul 21, 2024
1c3aec5
It's thread safer...
krowvin Jul 21, 2024
e44f9d6
Fix requirement files - accidentally froze the wrong env. Going with …
krowvin Jul 21, 2024
35148b2
Investigating why deep copy is not working with value's _thread.lock.…
krowvin Jul 21, 2024
e066dfc
Fixed thread lock issue. Can't pass threads via parameters has to be …
krowvin Jul 21, 2024
733a577
Manually run spk converter tests to make sure those are still working…
krowvin Jul 21, 2024
5bd49fb
Update workflow to ensure shell script is executable. Add SWT test fo…
krowvin Jul 21, 2024
d8f04d7
Fix issue where queue was not properly being passed to thread workers…
krowvin Aug 8, 2024
84a0f34
120 seconds was too generous for an HTTP call in the thread
krowvin Aug 8, 2024
d6ab576
No need to lock since we don't try to access these threads from elsew…
krowvin Aug 8, 2024
f6cfbe1
Fixed - to _ in test form
krowvin Aug 8, 2024
cbc10ec
Rename tests, make the test files targetable, attempt to fix race con…
krowvin Aug 9, 2024
3089317
Update form to be dynamic again
krowvin Aug 9, 2024
7126e78
Fix spacing on sequential form
krowvin Aug 9, 2024
9ce2770
Convert the batch to a shell script for automation tests
krowvin Aug 9, 2024
b1ec50e
Fixed report name in pytest for ci/cd
krowvin Aug 9, 2024
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
14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ on:
pull_request:
branches: [ main ]


jobs:
tests:
runs-on: ubuntu-20.04
Expand All @@ -16,9 +15,11 @@ jobs:
with:
python-version: ${{ matrix.python-version}}
architecture: x64
- name: install requirements
- name: Install requirements
run: pip3 install -r tests/requirements.txt
- name: run tests
- name: Make shell script executable
run: chmod +x tests/swt/scripts/run.sh
- name: Run tests
run: pytest -v
canpackage:
runs-on: ubuntu-20.04
Expand All @@ -31,10 +32,9 @@ jobs:
with:
python-version: ${{ matrix.python-version}}
architecture: x64
- name: install requirements
- name: Install requirements
run: pip3 install -r tests/requirements.txt
- name: package
- name: Package
run: ./package.sh
- name: run package
- name: Run package
run: python build/repgen.zip -i test.manual/test.if

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ test_priv/*
*~
.vscode
*.swp
*.log
99 changes: 61 additions & 38 deletions __main__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import sys,time,datetime,pytz,tempfile,shutil,os
import sys, pytz, datetime, tempfile, shutil, os, time

import repgen
from repgen.data.value import Value
from repgen.report import Report
from repgen.util import filterAddress
from repgen import __version__, THREAD_COUNT
from repgen.workers.http import processSiteWorker

import threading
from queue import Queue

version = "5.0.5"

# setup base time, ex
# default formats
Expand All @@ -25,6 +31,7 @@ def parseArgs():
parser.add_argument( '-a', '--address', dest='host', default='localhost', help="location for data connections; equivalent to `DB=hostname:port/path`", metavar='IP_or_hostname:port[/basepath]')
parser.add_argument( '-A', '--alternate', dest='alternate', default=None, help="alternate location for data connections, if the primary is unavailable (only for RADAR)", metavar='IP_or_hostname:port[/basepath]')
parser.add_argument( '-c', '--compatibility', dest='compat', action="store_true", default=False, help="repgen4 compatibility; case-insensitive labels")
parser.add_argument( '-p', '--parallel', dest="parallel", action="store_true", default=False, help=f"When this flag is setup Repgen5 will process requests in parallel with {THREAD_COUNT} threads." )
parser.add_argument( '--timeout', dest='timeout', type=float, default=None, help="Socket timeout, in seconds" )
# This provides repgen4 style KEY=VALUE argument passing on the command-line
parser.add_argument( 'set', default=[], help="Additional key=value pairs. e.g. `DBTZ=UTC DBOFC=HEC`", metavar="KEY=VALUE", nargs="*" )
Expand All @@ -37,38 +44,40 @@ def parseArgs():

# https://stackoverflow.com/a/52014520
def parse_var(s):
"""
Parse a key, value pair, separated by '='
That's the reverse of ShellArgs.

On the command line (argparse) a declaration will typically look like:
foo=hello
or
foo="hello world"
"""
items = s.split('=')
key = items[0].strip() # we remove blanks around keys, as is logical
if len(items) > 1:
# rejoin the rest:
value = '='.join(items[1:])
return (key, value)
"""
Parse a key, value pair, separated by '='
That's the reverse of ShellArgs.

On the command line (argparse) a declaration will typically look like:
foo=hello
or
foo="hello world"
"""
items = s.split('=')
key = items[0].strip() # we remove blanks around keys, as is logical
if len(items) > 1:
# rejoin the rest:
value = '='.join(items[1:])
return (key, value)

def parse_vars(items):
"""
Parse a series of key-value pairs and return a dictionary and
a success boolean for whether each item was successfully parsed.
"""
count = 0
d = {}
for item in items:
if "=" in item:
split_string = item.split("=")
d[split_string[0].strip().upper()] = split_string[1].strip()
count += 1
else:
print(f"Error: Invalid argument provided - {item}")

return d, count == len(items)
"""
Parse a series of key-value pairs and return a dictionary and
a success boolean for whether each item was successfully parsed.
"""
count = 0
d = {}
for item in items:
if "=" in item:
split_string = item.split("=")
d[split_string[0].strip().upper()] = split_string[1].strip()
count += 1
else:
print(f"Error: Invalid argument provided - {item}")

return d, count == len(items)



# Pytz doesn't know all the aliases and abbreviations
# This works for Pacific, but untested in other locations that don't use DST.
Expand All @@ -93,12 +102,13 @@ def parse_vars(items):
}

if __name__ == "__main__":
start_time = time.time()
config = parseArgs()
kwargs = parse_vars(config.set)[0]

if config.show_ver == True:
print(version)
print(__version__)
sys.exit(0)


report_file = kwargs.get("IN", config.in_file)
out_file = kwargs.get("REPORT", config.out_file)
Expand All @@ -123,16 +133,27 @@ def parse_vars(items):

# set some of the default values
Value(1, host=host, path=path, tz=tz, ucformat=config.compat, timeout=config.timeout, althost=althost, altpath=altpath, dbofc=config.office, **kwargs)


# Enable IO bound process multi-threading
print ("parallel", config.parallel)
# if the user has a need for speed
if config.parallel:
repgen.queue = Queue()
# Setup worker threads
for _ in range(THREAD_COUNT):
thread = threading.Thread(target=processSiteWorker, args=(repgen.queue, ))
thread.daemon = True
thread.start()
repgen.threads.append(thread)
# read the report file
if report_file == '-':
report_file = sys.stdin.name
f = sys.stdin
else:
# TODO: change this to a context manager/with
f = open(report_file, 'rt')
report_data = f.read()
f.close()

base_date = kwargs.get("DATE", config.base_date)
base_time = kwargs.get("TIME", config.base_time)
delta = datetime.timedelta()
Expand All @@ -151,6 +172,7 @@ def parse_vars(items):
# Read data file input
data_file = kwargs.get("FILE", config.data_file)
if data_file:
# TODO: context manager?
f_d = open(config.data_file)
key = None
prefix = ""
Expand Down Expand Up @@ -182,10 +204,10 @@ def parse_vars(items):
key = None

f_d.close()

# exec the definitions
report = Report(report_data, report_file, config.compat)
report = Report(report_data, report_file, config.compat, config.parallel, **kwargs)
report.run(basedate, local_vars)

output = None
tmpname = None

Expand All @@ -204,3 +226,4 @@ def parse_vars(items):
mask = os.umask(0)
os.chmod(out_file, 0o666 & (~mask))
os.umask(mask)
print(f"Report created after {round(time.time() - start_time, 3)}s")
15 changes: 15 additions & 0 deletions repgen/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
__version__ = "5.1.0"
# =========================================== #
# THREADING VARS #
# =========================================== #
THREAD_COUNT = 15
THREAD_TIMEOUT = 30 # Seconds to consider thread is still alive
# =========================================== #
REPGEN_GITHUB_ISSUES_URL = "https://github.com/USACE-WaterManagement/repgen5/issues"
# CDA Constants
PARAM_DT_FMT = "%Y-%m-%dT%H:%M:%S"
# =========================================== #
# Global Variables Shared Between Classes #
# =========================================== #
threads = []
queue = None
Loading