diff --git a/.cspell.json b/.cspell.json index 1bc0030c84..68858f1215 100644 --- a/.cspell.json +++ b/.cspell.json @@ -131,6 +131,7 @@ "filename", "filepath", "filesystem", + "filterset", "fineuploader", "firefox", "Firefox", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46336586a5..61fb3a04fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: - name: Install deps run: | pip install --upgrade pip - pip install tox==3.14.3 + pip install tox==4.20.0 sudo apt update sudo apt install gdal-bin - name: Setup config diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index a43dab4223..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,223 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# User-friendly check for sphinx-build -ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) -$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) -endif - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " applehelp to make an Apple Help Book" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " xml to make Docutils-native XML files" - @echo " pseudoxml to make pseudoxml-XML files for display purposes" - @echo " linkcheck to check all external links for integrity" - @echo " spelling to check files for spelling" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - @echo " coverage to run coverage check of the documentation (if enabled)" - -.PHONY: clean -clean: - rm -rf $(BUILDDIR)/* - -.PHONY: html -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -.PHONY: spelling -spelling: - $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling - @echo - @echo "Build finished. The spelling results are in $(BUILDDIR)/spelling." - -.PHONY: dirhtml -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -.PHONY: singlehtml -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -.PHONY: pickle -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -.PHONY: json -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -.PHONY: htmlhelp -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -.PHONY: qthelp -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SEEDPlatform.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SEEDPlatform.qhc" - -.PHONY: applehelp -applehelp: - $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp - @echo - @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." - @echo "N.B. You won't be able to view it unless you put it in" \ - "~/Library/Documentation/Help or install it in your application" \ - "bundle." - -.PHONY: devhelp -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/SEEDPlatform" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SEEDPlatform" - @echo "# devhelp" - -.PHONY: epub -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -.PHONY: latex -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -.PHONY: latexpdf -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: latexpdfja -latexpdfja: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through platex and dvipdfmx..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -.PHONY: text -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -.PHONY: man -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -.PHONY: texinfo -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -.PHONY: info -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -.PHONY: gettext -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -.PHONY: changes -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -.PHONY: linkcheck -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -.PHONY: doctest -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." - -.PHONY: coverage -coverage: - $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage - @echo "Testing of coverage in the sources finished, look at the " \ - "results in $(BUILDDIR)/coverage/python.txt." - -.PHONY: xml -xml: - $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml - @echo - @echo "Build finished. The XML files are in $(BUILDDIR)/xml." - -.PHONY: pseudoxml -pseudoxml: - $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml - @echo - @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 9a06e86fbc..0000000000 --- a/docs/make.bat +++ /dev/null @@ -1,271 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. xml to make Docutils-native XML files - echo. pseudoxml to make pseudoxml-XML files for display purposes - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - echo. coverage to run coverage check of the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - - -REM Check if sphinx-build is available and fallback to Python version if any -%SPHINXBUILD% 1>NUL 2>NUL -if errorlevel 9009 goto sphinx_python -goto sphinx_ok - -:sphinx_python - -set SPHINXBUILD=python -m sphinx.__init__ -%SPHINXBUILD% 2> nul -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -:sphinx_ok - - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "spelling" ( - %SPHINXBUILD% -b spelling %ALLSPHINXOPTS% %BUILDDIR%/spelling - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The spelling results are in %BUILDDIR%/spelling. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SEEDPlatform.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SEEDPlatform.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdf" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "latexpdfja" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - cd %BUILDDIR%/latex - make all-pdf-ja - cd %~dp0 - echo. - echo.Build finished; the PDF files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -if "%1" == "coverage" ( - %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage - if errorlevel 1 exit /b 1 - echo. - echo.Testing of coverage in the sources finished, look at the ^ -results in %BUILDDIR%/coverage/python.txt. - goto end -) - -if "%1" == "xml" ( - %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The XML files are in %BUILDDIR%/xml. - goto end -) - -if "%1" == "pseudoxml" ( - %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. - goto end -) - -:end diff --git a/docs/scripts/export_issues_to_csv.py b/docs/scripts/export_issues_to_csv.py deleted file mode 100644 index 713a1e0b51..0000000000 --- a/docs/scripts/export_issues_to_csv.py +++ /dev/null @@ -1,126 +0,0 @@ -# pip install github3.py - -import argparse -import contextlib -import csv -import locale -from typing import List - -import github3 - -parser = argparse.ArgumentParser() -parser.add_argument("-k", "--github-key", required=True, help="Github API Key") -parser.add_argument("--csv", action="store_true", help="Download CSV of Issues") -# parser.add_argument('--diff', action='store_true', help='Download CSV of Issues') -args = parser.parse_args() - -# Connect to github -gh = github3.login(token=args.github_key) -repo = gh.repository("SEED-platform", "seed") -print(repo) - -# Initialize some data -header = [ - "Github URL", - "Order", - "Title", - "Category", - "Priority", - "Impact", - "Estimate", - "Weighted Priority", - "Note", - "Github ID", - "Type/Labels", - "Pivotal URL", -] -lines: List[List] = [] -ids_added: List[int] = [] - - -def add_issue_to_csv(issue): - # import json - # print(json.dumps(issue.as_dict(), indent=2)) - print(f"Adding Issue {issue.number} : {issue.title}") - labels = [label.name for label in issue.labels()] - ids_added.append(issue.number) - line = [] - line.append(int(issue.number)) # Github ID - line.append(len(lines)) # Order - line.append(issue.title) # Title - line.append("") # category - # nrel priority - if "P-1" in labels: - line.append(1) - elif "P-2" in labels: - line.append(2) - elif "P-3" in labels: - line.append(3) - else: - line.append("") - - # nrel impact - if "Impact-1" in labels: - line.append(1) - elif "Impact-2" in labels: - line.append(2) - elif "Impact-3" in labels: - line.append(3) - else: - line.append("") - - # estimate - if "1 Point" in labels: - line.append(1) - elif "2 Points" in labels: - line.append(2) - elif "3 Points" in labels: - line.append(3) - elif "5 Points" in labels: - line.append(5) - elif "8 Points" in labels: - line.append(8) - else: - line.append("") - # line.append("") # lbnl priority - # line.append("") # lbnl impact - line.append("") # weighted impact - line.append("") # Notes - line.append(",".join(labels)) # Type / Labels - line.append(issue.html_url) # Github URL - line.append("") # Pivotal URL - - lines.append(line) - - -if args.csv: - print("There are %s open issues" % repo.open_issues_count) - - print("Finding P-1 Issues") - for issue in repo.issues(state="open", labels="P-1"): - add_issue_to_csv(issue) - - print("Finding P-2 Issues") - for issue in repo.issues(state="open", labels="P-2"): - add_issue_to_csv(issue) - - print("Finding P-3 Issues") - for issue in repo.issues(state="open", labels="P-3"): - add_issue_to_csv(issue) - - print("Finding All Other Issues") - for issue in repo.issues(state="open"): - with contextlib.suppress(BaseException): - if issue.number not in ids_added and not issue.pull_request(): - add_issue_to_csv(issue) - - # sort the items by the first column - lines = sorted(lines, key=lambda x: (x[0])) - - # write out the lines - with open("seed_issues.csv", "w", encoding=locale.getpreferredencoding(False)) as csv_file: - writer = csv.writer(csv_file, delimiter=",") - writer.writerow(header) - - for line in lines: - writer.writerow(line) diff --git a/docs/scripts/set_github_issue_priorities.py b/docs/scripts/set_github_issue_priorities.py deleted file mode 100644 index 125da769e1..0000000000 --- a/docs/scripts/set_github_issue_priorities.py +++ /dev/null @@ -1,57 +0,0 @@ -# pip install github3.py - -# Read in a CSV and have it update an issue's priority, impact, and estimate. -# Column order is important, 0 is ID, then 3-5 are the fields to update. -# -# e.g., python docs/scripts/set_github_issue_priorities.py -k -i in.csv - -import argparse -import csv -import locale -import os - -import github3 - -parser = argparse.ArgumentParser() -parser.add_argument("-k", "--github-key", required=True, help="Github API Key") -parser.add_argument("-i", "--infile", required=True, help="Input file to parse") -args = parser.parse_args() - -# Connect to github -gh = github3.login(token=args.github_key) -repo = gh.repository("SEED-platform", "seed") -print(repo) - -# Read in the CSV -if not os.path.exists(args.infile): - print(f"Could not find input file to parse {args.infile}") - -# column 3 is priority -# column 4 is user impact -# column 5 is estimate -priority_labels = ["P-1", "P-2", "P-3"] -impact_labels = ["Impact-1", "Impact-2", "Impact-3"] -estimate_impact = ["1 Point", "2 Points", "3 Points", "5 Points", "8 Points"] -points_map = {1: "1 Point", 2: "2 Points", 3: "3 Points", 5: "5 Points", 8: "8 Points"} - -with open(args.infile, encoding=locale.getpreferredencoding(False)) as csvfile: - reader = csv.reader(csvfile) - for index, row in enumerate(reader): - if index >= 1: # skip header row - print(row) - issue = repo.issue(row[0]) - labels = [label.name for label in issue.labels()] - - # remove any of the labels that we are setting that may - # already be on the issue - labels = list(set(labels) - set(priority_labels)) - labels = list(set(labels) - set(impact_labels)) - labels = list(set(labels) - set(estimate_impact)) - - # add the new labels to the list - labels.append(priority_labels[int(row[3]) - 1]) - labels.append(impact_labels[int(row[4]) - 1]) - labels.append(points_map[int(row[5])]) - - # save the labels to github - issue.edit(labels=labels) diff --git a/docs/source/conf.py b/docs/source/conf.py index b87c79b935..56c6ef0ae6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -56,9 +56,7 @@ # Location of word list. # convert the spelling list to a text file and save -with open("../../.cspell.txt", "w", encoding=locale.getpreferredencoding(False)) as cspell_txt, open( - "../../.cspell.json", encoding=locale.getpreferredencoding(False) -) as cspell_json: +with open("../../.cspell.txt", "w", encoding="utf-8") as cspell_txt, open("../../.cspell.json", encoding="utf-8") as cspell_json: cspell_txt.write("\n".join(json.load(cspell_json)["words"])) spelling_word_list_filename = "../../.cspell.txt" @@ -83,14 +81,12 @@ # built documents. # # Grab the version from the package.json file -with open( - os.path.join(os.path.dirname(os.path.realpath(__file__)), "../../package.json"), encoding=locale.getpreferredencoding(False) -) as f: - data = json.load(f) +with open("../../package.json", encoding=locale.getpreferredencoding(False)) as package_json: + package = json.load(package_json) -version = data["version"] +version = package["version"] # The full version, including alpha/beta/rc tags. -release = data["version"] +release = package["version"] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/migrations.rst b/docs/source/migrations.rst index 32f35b7f85..cc95efce1f 100644 --- a/docs/source/migrations.rst +++ b/docs/source/migrations.rst @@ -54,7 +54,7 @@ Version 2.22.0 -------------- - Run ``./manage.py migrate``. - There is a Redis dependency update in this release that requires users and deployments to modify their settings' ``CACHES`` config. - #. Update your dependencies with pip install -r requirements/base.txt + #. Update your dependencies with ``pip install -r requirements/base.txt`` #. Update the CACHES BACKEND property to ``django_redis.cache.RedisCache`` #. Update the CACHES LOCATION property to match the redis-py native URL notation for connection strings, including the redis protocol and database number. e.g. ``redis://localhost:6379/1`` diff --git a/mypy.ini b/mypy.ini index 43c4e0e15f..0f27946b3e 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,9 +1,10 @@ [mypy] ignore_missing_imports = True exclude = (?x)( - ^docs\/source\/conf.py$ | - ^seed\/tests\/test_search\.py$ | - ^src\/.*$ + ^docs\/source\/conf\.py$ + | ^seed\/tests\/test_search\.py$ + | ^src\/.*$ + | ^venv\/.*$ ) [mypy-seed.*.migrations.*] diff --git a/requirements/aws.txt b/requirements/aws.txt index 2fec7bddbf..c28395f25f 100644 --- a/requirements/aws.txt +++ b/requirements/aws.txt @@ -1,6 +1,4 @@ -r base.txt -boto3==1.34.42 -django-redis==5.2.0 -django-sslify==0.2.7 -django-ses==3.5.0 -uWSGI==2.0.22; sys_platform != "win32" +boto3==1.35.21 +django-ses==4.1.1 +uWSGI==2.0.26; sys_platform != "win32" diff --git a/requirements/base.txt b/requirements/base.txt index 8d3d08c641..633dc9ed53 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,61 +1,57 @@ # Django -django==3.2.25 +django==3.2.25 # TODO update -django-autoslug==1.9.8 # Used by django-filter. See here: https://github.com/carltongibson/django-filter/blob/fe90e3a5fdeaff0983d1325a3e9dcf3458ef078f/docs/guide/rest_framework.txt#L210 -django-crispy-forms==1.8.1 +django-crispy-forms==1.8.1 # Update to major version 2 # Persistence stores psycopg2-binary==2.9.9 - -# background process management -celery==5.2.2 -django-celery-beat==2.2.1 -django-redis==5.2.0 # Version is tied to compatibility with boto3 -hiredis==2.3.2 +# Background process management +celery==5.4.0 +django-celery-beat==2.7.0 +django-redis==5.4.0 +hiredis==3.0.0 brotli==1.1.0 -django-compressor==4.4 +django-compressor==4.4 # Update after Django 4.2 django-extensions==3.2.3 -django-model-utils==4.3.1 +django-model-utils==5.0.0 # Time zones support -pytz==2024.1 +pytz==2024.2 python-dateutil==2.9.0.post0 # Metric/imperial units support -django-pint==0.6 +django-pint==0.7.3 # API -djangorestframework==3.12.2 -# Django-post-office dependency needs to be installed via github b/c -# with pypi version Celery fails to auto discover post_office tasks -django-post_office @ git+https://github.com/ui/django-post_office@v3.6.0 -drf-yasg==1.20.0 # TODO bump this to 1.21.7 to add `get_paginated_response_schema` bug fix (once pytz is bumped) -django-filter==2.4.0 -drf-nested-routers==0.91 +djangorestframework==3.15.1 # Update after Django 4.2 +django-post_office==3.8.0 # Update after Django 4.2 +drf-yasg==1.21.7 +django-filter==22.1 # Update after Django 4.2 and drf-spectacular +drf-nested-routers==0.94.0 # Update after Django 4.2 # Server monitoring -sentry-sdk==2.11.0 +sentry-sdk==2.14.0 # Various packages -jellyfish==0.8.2 -Markdown==3.1.1 +jellyfish==1.1.0 +Markdown==3.7 polling==0.3.2 -pyyaml==6.0.1 +pyyaml==6.0.2 street-address==0.4.0 -xlrd==1.2.0 -xlsxwriter==1.2.7 -xmltodict==0.12.0 -requests==2.32.0 -probablepeople==0.5.4 -xmlschema==1.1.1 -lark==0.11.3 +xlrd<2.0.0 # Version 2 removes xlsx support +xlsxwriter==3.2.0 +xmltodict==0.13.0 +requests==2.32.3 +probablepeople==0.5.5 +xmlschema==3.4.2 +lark==1.2.2 pandas==2.2.2 # Parsing and managing geojson data (this is only used in managed tasks at the moment) -geojson==2.5.0 +geojson==3.1.0 # BuildingSync Asset Extractor # this also includes the lxml dependency required by SEED @@ -65,17 +61,12 @@ buildingsync-asset-extractor==v0.2.0 seed-salesforce==0.1.0 # geospatial and pnnl/buildingid-py -shapely==2.0.1 +shapely==2.0.6 usaddress==0.5.10 pnnl-buildingid @ git+https://github.com/SEED-platform/buildingid@bdb0a6e -future==0.18.3 - -django-treebeard==4.6.1 +django-treebeard==4.7.1 -django-two-factor-auth[phonenumbers]==1.16.0 -qrcode[pil]==6.1 +django-two-factor-auth[phonenumbers]==1.16.0 # Update after Django 4.2 +qrcode[pil]==7.4.2 pyotp==2.9.0 - -# This dependency can be removed once a version newer than 8.5.0 has been released that fixes Django autoreload -importlib_metadata==8.4.0 diff --git a/requirements/local.txt b/requirements/local.txt index 0553bfebd6..94d08c6c6f 100644 --- a/requirements/local.txt +++ b/requirements/local.txt @@ -1,5 +1,3 @@ # Local development dependencies go here -r test.txt -django-debug-toolbar==2.2.1 -# github3 for generating the change log -github3.py==3.2.0 +django-debug-toolbar==4.3.0 # Update after Django 4.2 diff --git a/requirements/test.txt b/requirements/test.txt index ab909c697e..dcf2644501 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -2,36 +2,31 @@ -r base.txt # general -coverage==4.5.4 -coveralls==1.9.2 -tox==3.14.3 -psutil==5.6.7 +coverage==7.6.1 +coveralls==4.0.1 +tox==4.20.0 # Keep this in sync with ci.yml +psutil==6.0.0 # python testing -Faker==0.9.3 -mock==2.0.0 -vcrpy==4.2.1 -pytest==7.4.4 -pytest-django==4.7.0 -# Lock urllib3 to v1 until vcrpy supports it -urllib3<2 +Faker==29.0.0 +mock==5.1.0 +vcrpy==6.0.1 +pytest==8.3.3 +pytest-django==4.9.0 +urllib3==1.26.20 # TODO update after vcrpy supports v2 # static code analysis -pycodestyle==2.11.1 -pre-commit==3.7.0 -ruff==0.3.4 +pre-commit==3.8.0 +ruff==0.6.5 # documentation and spelling -Sphinx==7.2.6 +Sphinx==7.4.7 # TODO update after python 3.9 sphinxcontrib-spelling==8.0.0 sphinx_rtd_theme==2.0.0 docutils==0.20.1 # property-based testing -hypothesis==6.94.0 - -# For running the server -uWSGI==2.0.23; sys_platform != "win32" +hypothesis==6.112.1 # static type checking -mypy==1.9.0 +mypy==1.11.2 diff --git a/seed/context_processors.py b/seed/context_processors.py index 0600592f0b..6de12c5d78 100644 --- a/seed/context_processors.py +++ b/seed/context_processors.py @@ -1,7 +1,7 @@ from django.core.cache import cache -def global_vars(request): +def global_vars(_request): method_2fa = cache.get("method_2fa") user_email = cache.get("user_email") return {"method_2fa": method_2fa, "user_email": user_email} diff --git a/seed/filtersets.py b/seed/filtersets.py index f9faa9b0c9..99267f1b47 100644 --- a/seed/filtersets.py +++ b/seed/filtersets.py @@ -7,27 +7,16 @@ FilterSet classes to provide advanced filtering API endpoints. """ -from datetime import datetime - -import pytz -from dateutil.relativedelta import relativedelta from django.db.models import Q -from django.utils.timezone import make_aware -from django_filters import BaseInFilter, CharFilter, DateFilter, NumberFilter +from django_filters import CharFilter, DateFilter, NumberFilter from django_filters.rest_framework import FilterSet -from seed.models import Cycle, GreenAssessment, GreenAssessmentProperty, PropertyState, PropertyView -from seed.models import StatusLabel as Label +from seed.models import GreenAssessment, GreenAssessmentProperty, PropertyView # Oops! we override a builtin in some of the models property_decorator = property -# Public Classes and Functions -class NumberInFilter(BaseInFilter, NumberFilter): - pass - - class GreenAssessmentFilterSet(FilterSet): name = CharFilter(field_name="name", lookup_expr="exact") award_body = CharFilter(field_name="award_body", lookup_expr="exact") @@ -50,50 +39,6 @@ class Meta: fields = ("year", "assessment", "rating", "view") -class LabelFilterSet(FilterSet): - """Provide filtering for Label by property id, taxlot id, name or color.""" - - property = NumberInFilter(field_name="property__pk", lookup_expr="in") - taxlot = NumberInFilter(field_name="taxlot__pk", lookup_expr="in") - - class Meta: - model = Label - fields = ["name", "color", "property", "taxlot"] - - -class CycleFilterSet(FilterSet): - """Provide filtering for Cycle by name, start date, end date or - calendar year.""" - - start_lte = DateFilter(field_name="start", lookup_expr="lte") - end_gte = DateFilter(field_name="end", lookup_expr="gte") - year = CharFilter(method="year_filter") - - class Meta: - model = Cycle - fields = ["name", "start_lte", "end_gte", "year"] - - def year_filter(self, queryset, name, value): - """ - Provide close enough filtering for Cycle spanning the single calendar - year supplied to the filter. - """ - max_time_diff = 26 - name = f"{value} Calendar Year" - cycles = queryset.filter(name__icontains=name) - if not cycles: - start = make_aware(datetime(int(value), 1, 1), pytz.UTC) - end = start + relativedelta(years=1) - relativedelta(seconds=1) - - # to eliminate the question of timezone saved in vs timezone - # queried from, start and end dates are nudge1d in by the max - # possible time difference between 2 servers - start = start + relativedelta(hours=max_time_diff) - end = end - relativedelta(hours=max_time_diff) - cycles = queryset.filter(start__lte=start, end__gte=end) - return cycles - - class PropertyViewFilterSet(FilterSet): """Provide advanced filtering for PropertyView @@ -127,37 +72,3 @@ def identifier_filter(self, queryset, name, value): home_energy_score_id = Q(state__home_energy_score_id=value) query = jurisdiction_property_id | custom_id_1 | pm_property_id | home_energy_score_id | ubid return queryset.filter(query) - - -class PropertyStateFilterSet(FilterSet): - """Provide advanced filtering for PropertyState - - Filter options for propertystate by energy_score (gte), city, - pm_parent_property_id, and property_identifier. - - The property_identifier filter provides a single query parameter key for - filtering against any of the property ID type fields. - (jurisdiction_property_id, custom_id_1, pm_property_id or - home_energy_score_id) - """ - - energy_score = NumberFilter(field_name="energy_score", lookup_expr="gte") - property_identifier = CharFilter(method="identifier_filter") - - class Meta: - model = PropertyState - fields = ["energy_score", "city", "pm_parent_property_id", "property_identifier"] - - def identifier_filter(self, queryset, name, value): - """ - Filter queryset for case-insensitive value matching - jurisdiction_property_id OR custom_id_1 OR pm_property_id - OR home_energy_score_id. - """ - jurisdiction_property_id = Q(jurisdiction_property_id__iexact=value) - custom_id_1 = Q(custom_id_1__iexact=value) - pm_property_id = Q(pm_property_id=value) - ubid = Q(ubid__iexact=value) - home_energy_score_id = Q(home_energy_score_id=value) - query = jurisdiction_property_id | custom_id_1 | pm_property_id | home_energy_score_id | ubid - return queryset.filter(query) diff --git a/seed/management/commands/_localtools.py b/seed/management/commands/_localtools.py deleted file mode 100644 index 4108b53419..0000000000 --- a/seed/management/commands/_localtools.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md - -:author Nathan Addy -:description Helper methods for a couple (possibly deprecated) management tasks -""" - - -def write_to_file(msg): - pass - - -def logging_info(msg): - s = f"INFO: {msg}" - print(s) - write_to_file(s) - - -def get_core_organizations(): - # IDs of the 12 organizations defined by robin 6/6/16. - # Google Doc for file describing this: - # https://docs.google.com/document/u/4/d/1z1FScU-lysmgkCNGa9-hH0PCQudpzV_IG2IKcxYzyfM/edit - # [69,20,156,49,7,10,181,117,105,126, 124,6] - GOOD_ORGS = [20, 7, 49, 69, 10, 181, 156, 117, 124, 105, 126, 6] - if len(GOOD_ORGS) != 12: - raise ValueError("Invalid number of core organization ids") - return GOOD_ORGS diff --git a/seed/management/commands/erase_data_from_orgs.py b/seed/management/commands/erase_data_from_orgs.py deleted file mode 100644 index ecb037f23d..0000000000 --- a/seed/management/commands/erase_data_from_orgs.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md -""" - -import collections -import logging - -from _localtools import logging_info -from django.core.management.base import BaseCommand - -from seed.models import PropertyState, TaxLotState - -logging.basicConfig(level=logging.DEBUG) - - -class Command(BaseCommand): - def add_arguments(self, parser): - parser.add_argument("--org", dest="organization", default=False) - parser.add_argument("--stats", dest="stats", default=False, action="store_true") - - def handle(self, *args, **options): - logging_info(f"RUN create_m2m_relationships_organization with args={args},kwds={options}") - if options["organization"]: - core_organization = list(map(int, options["organization"].split(","))) - else: - core_organization = [20, 69] - - logging_info(f"Processing organization list: {core_organization}") - - for org in core_organization: - delete_data_from_org(org) - - logging_info("END create_m2m_relationships_organization") - - -def delete_data_from_org(org_pk): - tax_attrs_to_clear = collections.defaultdict(list) - property_attrs_to_clear = collections.defaultdict(list) - - tax_attrs_to_clear[69] = ["address_line_1", "city", "state", "postal_code"] - property_attrs_to_clear[69] = ["address_line_1", "city", "state", "postal_code"] - - for ndx, property_state in enumerate(PropertyState.objects.filter(organization_id=org_pk).all()): - for pa in property_attrs_to_clear[org_pk]: - setattr(property_state, pa, None) - property_state.save() - - for ndx, taxlot_state in enumerate(TaxLotState.objects.filter(organization_id=org_pk).all()): - for ta in tax_attrs_to_clear[org_pk]: - setattr(taxlot_state, ta, None) - taxlot_state.save() diff --git a/seed/management/commands/flush_db.py b/seed/management/commands/flush_db.py new file mode 100644 index 0000000000..c0044eda12 --- /dev/null +++ b/seed/management/commands/flush_db.py @@ -0,0 +1,32 @@ +""" +SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. +See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md + +This command is similar to `manage.py flush` except that it preserves the static EEEJ and Uniformat data +""" + +from django.core.management.base import BaseCommand +from django.db import connection + + +class Command(BaseCommand): + help = "Flush the database except for static tables" + + def handle(self, *args, **kwargs): + tables_to_ignore = [ + "django_content_type", + "django_migrations", + "django_site", + "seed_eeejcejst", + "seed_eeejhud", + "seed_uniformat", + ] + + with connection.cursor() as cursor: + all_tables = connection.introspection.table_names() + for table in all_tables: + if table not in tables_to_ignore: + cursor.execute(f'TRUNCATE TABLE "{table}" RESTART IDENTITY CASCADE;') + # self.stdout.write(self.style.SUCCESS(f'Truncated table: {table}')) + # else: + # self.stdout.write(self.style.WARNING(f'Skipped table: {table}')) diff --git a/seed/management/commands/prune_old_organizations.py b/seed/management/commands/prune_old_organizations.py deleted file mode 100644 index 4b227dbd40..0000000000 --- a/seed/management/commands/prune_old_organizations.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md - -Delete all organizations that are not part of the main 12. -See code for organization list and source documentation. -""" - -import logging - -from _localtools import get_core_organizations -from django.core.management.base import BaseCommand - -import seed.models -import seed.tasks - -logging.basicConfig(level=logging.DEBUG) - - -def get_organizations_to_delete(): - """Get all organizations that are not in the global white list.""" - - all_organizations = seed.models.Organization.objects.all() - bad_organizations = [org for org in all_organizations if org.id not in get_core_organizations()] - return bad_organizations - - -def destroy_organization(org): - """Delete an organization using the Celery information.""" - logging.info(f"Deleting organization {org}") - seed.tasks.delete_organization(org.pk) - - -class Command(BaseCommand): - def handle(self, *args, **options): - """Delete all organizations that are not in Robin's whitelist.""" - - logging.debug("**NOTE - Celery server must be running for this operation to work") - - deprecated_organizations = get_organizations_to_delete() - - logging.info(f"Deleting {deprecated_organizations} deprecated organizations.") - for org in deprecated_organizations: - destroy_organization(org) diff --git a/seed/migrations/0001_initial.py b/seed/migrations/0001_initial.py index 263c38b3ce..717d36e6fe 100644 --- a/seed/migrations/0001_initial.py +++ b/seed/migrations/0001_initial.py @@ -1,4 +1,3 @@ -import autoslug.fields import django.db.models.deletion import django.utils.timezone import django_extensions.db.fields @@ -338,7 +337,6 @@ class Migration(migrations.Migration): ), ), ("name", models.CharField(max_length=255, verbose_name="name")), - ("slug", autoslug.fields.AutoSlugField(populate_from=b"name", editable=True, unique=True, verbose_name="slug")), ("description", models.TextField(null=True, verbose_name="description", blank=True)), ("status", models.IntegerField(default=1, verbose_name="status", choices=[(0, "Inactive"), (1, "Active")])), ], @@ -365,7 +363,7 @@ class Migration(migrations.Migration): default=django.utils.timezone.now, verbose_name="modified", editable=False, blank=True ), ), - ("compliant", models.NullBooleanField()), + ("compliant", models.BooleanField(null=True)), ("approved_date", models.DateField(null=True, verbose_name="approved_date", blank=True)), ( "approver", diff --git a/seed/migrations/0038_auto_20161008_2244.py b/seed/migrations/0038_auto_20161008_2244.py index eb2cf09ca6..666835ec69 100644 --- a/seed/migrations/0038_auto_20161008_2244.py +++ b/seed/migrations/0038_auto_20161008_2244.py @@ -19,7 +19,7 @@ class Migration(migrations.Migration): ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("created", django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name="created")), ("modified", django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name="modified")), - ("compliant", models.NullBooleanField()), + ("compliant", models.BooleanField(null=True)), ("approved_date", models.DateField(blank=True, null=True, verbose_name="approved_date")), ( "approver", @@ -52,7 +52,7 @@ class Migration(migrations.Migration): ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("created", django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name="created")), ("modified", django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name="modified")), - ("compliant", models.NullBooleanField()), + ("compliant", models.BooleanField(null=True)), ("approved_date", models.DateField(blank=True, null=True, verbose_name="approved_date")), ( "approver", diff --git a/seed/migrations/0068_green_assessments.py b/seed/migrations/0068_green_assessments.py index 35de54e350..7ccf622f3f 100644 --- a/seed/migrations/0068_green_assessments.py +++ b/seed/migrations/0068_green_assessments.py @@ -54,7 +54,7 @@ class Migration(migrations.Migration): ("version", models.CharField(blank=True, max_length=50, null=True)), ("date", models.DateField(blank=True, null=True)), ("target_date", models.DateField(blank=True, null=True)), - ("eligibility", models.NullBooleanField()), + ("eligibility", models.BooleanField(null=True)), ("_expiration_date", models.DateField(blank=True, null=True)), ("extra_data", models.JSONField(blank=True, default=dict)), ("assessment", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="seed.GreenAssessment")), diff --git a/seed/migrations/0096_auto_20181107_0904.py b/seed/migrations/0096_auto_20181107_0904.py index 4be258a015..c3103b2466 100644 --- a/seed/migrations/0096_auto_20181107_0904.py +++ b/seed/migrations/0096_auto_20181107_0904.py @@ -1,6 +1,5 @@ # Generated by Django 1.11.16 on 2018-11-07 17:04 -import autoslug.fields from django.db import migrations, models @@ -142,11 +141,6 @@ class Migration(migrations.Migration): name="note_type", field=models.IntegerField(choices=[(0, "Note"), (1, "Log")], default=0, null=True), ), - migrations.AlterField( - model_name="project", - name="slug", - field=autoslug.fields.AutoSlugField(editable=True, populate_from="name", unique=True, verbose_name="slug"), - ), migrations.AlterField( model_name="propertystate", name="data_state", diff --git a/seed/models/columns.py b/seed/models/columns.py index c2c744ffcb..7619e7e1a2 100644 --- a/seed/models/columns.py +++ b/seed/models/columns.py @@ -966,7 +966,7 @@ def _serialize_for_extra_data(column_value): setattr(datum, new_column.column_name, getattr(datum, self.column_name)) setattr(datum, self.column_name, None) datum.save() - except (ValidationError, DataError): + except (ValidationError, DataError, ValueError): return [ False, "The column data aren't formatted properly for the new column due to type constraints (e.g., Datatime, Quantities, etc.).", diff --git a/seed/search.py b/seed/search.py index 24f237a6d7..a1ee9ebb80 100644 --- a/seed/search.py +++ b/seed/search.py @@ -156,7 +156,7 @@ def build_shared_buildings_orgs(orgs): # this is a parent org, so get all of the child orgs other_orgs.extend(org.child_orgs.all()) other_orgs.append(org) - # remove dups + # remove dupes other_orgs = list(set(other_orgs)) return other_orgs @@ -274,7 +274,7 @@ def inventory_search_filter_sort(inventory_type, params, user, cycle_id=None): cycle_id=cycle_id, ) - if inventory != []: + if inventory: # full text search across a couple common fields inventory = search_inventory(inventory_type, params["q"], queryset=inventory) diff --git a/seed/serializers/meter_readings.py b/seed/serializers/meter_readings.py index b651c5016d..dbbbbed9ba 100644 --- a/seed/serializers/meter_readings.py +++ b/seed/serializers/meter_readings.py @@ -3,6 +3,7 @@ See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md """ +from collections import OrderedDict from typing import Tuple import dateutil.parser @@ -107,7 +108,7 @@ def create(self, validated_data) -> MeterReading: return updated_reading def to_representation(self, obj): - result = super().to_representation(obj) + result = OrderedDict(super().to_representation(obj)) # TODO: we need to actually read the units from the meter, then convert accordingly. # SEED stores all energy data in kBtus diff --git a/seed/test_helpers/factory/__init__.py b/seed/test_helpers/factory/__init__.py deleted file mode 100644 index eddb0b294a..0000000000 --- a/seed/test_helpers/factory/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md -""" diff --git a/seed/test_helpers/factory/helpers.py b/seed/test_helpers/factory/helpers.py deleted file mode 100644 index f8b54fa986..0000000000 --- a/seed/test_helpers/factory/helpers.py +++ /dev/null @@ -1,1936 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md -""" - -import base64 -import datetime -import random -from decimal import Decimal, getcontext - -getcontext().prec = 7 - - -class DjangoFunctionalFactory: - @classmethod - def rand_int(cls, start=0, end=100): - return random.randint(start, end) - - @classmethod - def rand_float(cls, start=0, end=100): - return random.uniform(start, end) - - @classmethod - def rand_str(cls, length=None): - # from http://stackoverflow.com/questions/785058/random-strings-in-python-2-6-is-this-ok - if not length: - length = cls.rand_int(end=10) - nbits = length * 6 + 1 - bits = random.getrandbits(nbits) - uc = "%0x" % bits - newlen = int(len(uc) / 2) * 2 - ba = bytearray.fromhex(uc[:newlen]) - return base64.urlsafe_b64encode(str(ba))[:length] - - @classmethod - def rand_phone(cls): - area = cls.rand_int(start=100, end=999) - first = cls.rand_int(start=100, end=999) - last = cls.rand_int(start=1000, end=9999) - return f"{area}-{first}-{last}" - - @classmethod - def rand_street_address(cls): - s = f"{cls.rand_int(end=10000)} {cls.rand_plant_name()} {cls.rand_street_suffix()}" - return s[:63] - - @classmethod - def rand_city(cls): - return f"{cls.rand_plant_name()}{cls.rand_city_suffix()}" - - @classmethod - def rand_bool(cls): - return cls.rand_int(0, 1) == 0 - - @classmethod - def rand_name(cls): - return RANDOM_NAME_SOURCE[cls.rand_int(0, len(RANDOM_NAME_SOURCE) - 1)] - - @classmethod - def rand_plant_name(cls): - return RANDOM_PLANT_NAME_SOURCE[cls.rand_int(0, len(RANDOM_PLANT_NAME_SOURCE) - 1)] - - @classmethod - def rand_street_suffix(cls): - return RANDOM_STREET_SUFFIX_SOURCE[cls.rand_int(0, len(RANDOM_STREET_SUFFIX_SOURCE) - 1)] - - @classmethod - def rand_city_suffix(cls): - return RANDOM_CITY_SUFFIX_SOURCE[cls.rand_int(0, len(RANDOM_CITY_SUFFIX_SOURCE) - 1)] - - @classmethod - def rand_date(cls, start_year=1900, end_year=2011): - return datetime.date(year=cls.rand_int(start_year, end_year), month=cls.rand_int(1, 12), day=cls.rand_int(1, 28)) - - @classmethod - def rand_currency(cls, start=0, end=100): - return Decimal(cls.rand_int(start=start * 100, end=end * 100)) / 100 - - @classmethod - def rand_email(cls): - return f"{cls.rand_name().lower()}@{cls.rand_domain()}" - - @classmethod - def rand_domain(cls): - return RANDOM_EMAIL_DOMAINS[cls.rand_int(0, len(RANDOM_EMAIL_DOMAINS) - 1)] - - @classmethod - def valid_test_cc_number(cls): - return "4242424242424242" - - @classmethod - def invalid_test_cc_number(cls): - return "4242424242424241" - - @classmethod - def test_cc_number(cls, valid=True): - if valid: - return cls.valid_test_cc_number() - else: - return cls.invalid_test_cc_number() - - -RANDOM_NAME_SOURCE = [ - "Atricia", - "Linda", - "Barbara", - "Elizabeth", - "Jennifer", - "Maria", - "Susan", - "Margaret", - "Dorothy", - "Lisa", - "Nancy", - "Karen", - "Betty", - "Helen", - "Sandra", - "Donna", - "Carol", - "Ruth", - "Sharon", - "Michelle", - "Laura", - "Sarah", - "Kimberly", - "Deborah", - "Jessica", - "Shirley", - "Cynthia", - "Angela", - "Melissa", - "Brenda", - "Amy", - "Anna", - "Rebecca", - "Virginia", - "Kathleen", - "Pamela", - "Martha", - "Debra", - "Amanda", - "Stephanie", - "Carolyn", - "Christine", - "Marie", - "Janet", - "Catherine", - "Frances", - "Ann", - "Joyce", - "Diane", - "Alice", - "Julie", - "Heather", - "Teresa", - "Doris", - "Gloria", - "Evelyn", - "Jean", - "Cheryl", - "Mildred", - "Katherine", - "Joan", - "Ashley", - "Judith", - "Rose", - "Janice", - "Kelly", - "Nicole", - "Judy", - "Christina", - "Kathy", - "Theresa", - "Beverly", - "Denise", - "Tammy", - "Irene", - "Jane", - "Lori", - "Rachel", - "Marilyn", - "Andrea", - "Kathryn", - "Louise", - "Sara", - "Anne", - "Jacquelin", - "Wanda", - "Bonnie", - "Julia", - "Ruby", - "Lois", - "Tina", - "Phyllis", - "Norma", - "Paula", - "Diana", - "Annie", - "Lillian", - "Emily", - "Robin", - "Peggy", - "Crystal", - "Gladys", - "Rita", - "Dawn", - "Connie", - "Florence", - "Tracy", - "Edna", - "Tiffany", - "Carmen", - "Rosa", - "Cindy", - "Grace", - "Wendy", - "Victoria", - "Edith", - "Kim", - "Sherry", - "Sylvia", - "Josephine", - "Thelma", - "Shannon", - "Sheila", - "Ethel", - "Ellen", - "Elaine", - "Marjorie", - "Carrie", - "Charlotte", - "Monica", - "Esther", - "Pauline", - "Emma", - "Juanita", - "Anita", - "Rhonda", - "Hazel", - "Amber", - "Eva", - "Debbie", - "April", - "Leslie", - "Clara", - "Lucille", - "Jamie", - "Joanne", - "Eleanor", - "Valerie", - "Danielle", - "Megan", - "Alicia", - "Suzanne", - "Michele", - "Gail", - "Bertha", - "Darlene", - "Veronica", - "Jill", - "Erin", - "Geraldine", - "Lauren", - "Cathy", - "Joann", - "Lorraine", - "Lynn", - "Sally", - "Regina", - "Erica", - "Beatrice", - "Dolores", - "Bernice", - "Audrey", - "Yvonne", - "Annette", - "June", - "Samantha", - "Marion", - "Dana", - "Stacy", - "Ana", - "Renee", - "Ida", - "Vivian", - "Roberta", - "Holly", - "Brittany", - "Melanie", - "Loretta", - "Yolanda", - "Jeanette", - "Laurie", - "Katie", - "Kristen", - "Vanessa", - "Alma", - "Sue", - "Elsie", - "Beth", - "Jeanne", - "Vicki", - "Carla", - "Tara", - "Rosemary", - "Eileen", - "Terri", - "Gertrude", - "Lucy", - "Tonya", - "Ella", - "Stacey", - "Wilma", - "Gina", - "Kristin", - "Jessie", - "Natalie", - "Agnes", - "Vera", - "Willie", - "Charlene", - "Bessie", - "Delores", - "Melinda", - "Pearl", - "Arlene", - "Maureen", - "Colleen", - "Allison", - "Tamara", - "Joy", - "Georgia", - "Constance", - "Lillie", - "Claudia", - "Jackie", - "Marcia", - "Tanya", - "Nellie", - "Minnie", - "Marlene", - "Heidi", - "Glenda", - "Lydia", - "Viola", - "Courtney", - "Marian", - "Stella", - "Caroline", - "Dora", - "Jo", - "Vickie", - "Mattie", - "Terry", - "Maxine", - "Irma", - "Mabel", - "Marsha", - "Myrtle", - "Lena", - "Christy", - "Deanna", - "Patsy", - "Hilda", - "Gwendolyn", - "Jennie", - "Nora", - "Margie", - "Nina", - "Cassandra", - "Leah", - "Penny", - "Kay", - "Priscilla", - "Naomi", - "Carole", - "Brandy", - "Olga", - "Billie", - "Dianne", - "Tracey", - "Leona", - "Jenny", - "Felicia", - "Sonia", - "Miriam", - "Velma", - "Becky", - "Bobbie", - "Violet", - "Kristina", - "Toni", - "Misty", - "Mae", - "Shelly", - "Daisy", - "Ramona", - "Sherri", - "Erika", - "Katrina", - "Claire", - "Lindsey", - "Lindsay", - "Geneva", - "Guadalupe", - "Belinda", - "Margarita", - "Sheryl", - "Cora", - "Faye", - "Ada", - "Natasha", - "Sabrina", - "Isabel", - "Marguerit", - "Hattie", - "Harriet", - "Molly", - "Cecilia", - "Kristi", - "Brandi", - "Blanche", - "Sandy", - "Rosie", - "Joanna", - "Iris", - "Eunice", - "Angie", - "Inez", - "Lynda", - "Madeline", - "Amelia", - "Alberta", - "Genevieve", - "Monique", - "Jodi", - "Janie", - "Maggie", - "Kayla", - "Sonya", - "Jan", - "Lee", - "Kristine", - "Candace", - "Fannie", - "Maryann", - "Opal", - "Alison", - "Yvette", - "Melody", - "Luz", - "Susie", - "Olivia", - "Flora", - "Shelley", - "Kristy", - "Mamie", - "Lula", - "Lola", - "Verna", - "Beulah", - "Antoinett", - "Candice", - "Juana", - "Jeannette", - "Pam", - "Kelli", - "Hannah", - "Whitney", - "Bridget", - "Karla", - "Celia", - "Latoya", - "Patty", - "Shelia", - "Gayle", - "Della", - "Vicky", - "Lynne", - "Sheri", - "Marianne", - "Kara", - "Jacquelyn", - "Erma", - "Blanca", - "Myra", - "Leticia", - "Pat", - "Krista", - "Roxanne", - "Angelica", - "Johnnie", - "Robyn", - "Francis", - "Adrienne", - "Rosalie", - "Alexandra", - "Brooke", - "Bethany", - "Sadie", - "Bernadett", - "Traci", - "Jody", - "Kendra", - "Jasmine", - "Nichole", - "Rachael", - "Chelsea", - "Mable", - "Ernestine", - "Muriel", - "Marcella", - "Elena", - "Krystal", - "Angelina", - "Nadine", - "Kari", - "Estelle", - "Dianna", - "Paulette", - "Lora", - "Mona", - "Doreen", - "Rosemarie", - "Angel", - "Desiree", - "Antonia", - "Hope", - "Ginger", - "Janis", - "Betsy", - "Christie", - "Freda", - "Mercedes", - "Meredith", - "Lynette", - "Teri", - "Cristina", - "Eula", - "Leigh", - "Meghan", - "Sophia", - "Eloise", - "James", - "John", - "Robert", - "Michael", - "William", - "David", - "Richard", - "Charles", - "Joseph", - "Thomas", - "Christoph", - "Daniel", - "Paul", - "Mark", - "Donald", - "George", - "Kenneth", - "Steven", - "Edward", - "Brian", - "Ronald", - "Anthony", - "Kevin", - "Jason", - "Matthew", - "Gary", - "Timothy", - "Jose", - "Larry", - "Jeffrey", - "Frank", - "Scott", - "Eric", - "Stephen", - "Andrew", - "Raymond", - "Gregory", - "Joshua", - "Jerry", - "Dennis", - "Walter", - "Patrick", - "Peter", - "Harold", - "Douglas", - "Henry", - "Carl", - "Arthur", - "Ryan", - "Roger", - "Joe", - "Juan", - "Jack", - "Albert", - "Jonathan", - "Justin", - "Terry", - "Gerald", - "Keith", - "Samuel", - "Willie", - "Ralph", - "Lawrence", - "Nicholas", - "Roy", - "Benjamin", - "Bruce", - "Brandon", - "Adam", - "Harry", - "Fred", - "Wayne", - "Billy", - "Steve", - "Louis", - "Jeremy", - "Aaron", - "Randy", - "Howard", - "Eugene", - "Carlos", - "Russell", - "Bobby", - "Victor", - "Martin", - "Ernest", - "Phillip", - "Todd", - "Jesse", - "Craig", - "Alan", - "Shawn", - "Clarence", - "Sean", - "Philip", - "Chris", - "Johnny", - "Earl", - "Jimmy", - "Antonio", - "Danny", - "Bryan", - "Tony", - "Luis", - "Mike", - "Stanley", - "Leonard", - "Nathan", - "Dale", - "Manuel", - "Rodney", - "Curtis", - "Norman", - "Allen", - "Marvin", - "Vincent", - "Glenn", - "Jeffery", - "Travis", - "Jeff", - "Chad", - "Jacob", - "Lee", - "Melvin", - "Alfred", - "Kyle", - "Francis", - "Bradley", - "Jesus", - "Herbert", - "Frederick", - "Ray", - "Joel", - "Edwin", - "Don", - "Eddie", - "Ricky", - "Troy", - "Randall", - "Barry", - "Alexander", - "Bernard", - "Mario", - "Leroy", - "Francisco", - "Marcus", - "Micheal", - "Theodore", - "Clifford", - "Miguel", - "Oscar", - "Jay", - "Jim", - "Tom", - "Calvin", - "Alex", - "Jon", - "Ronnie", - "Bill", - "Lloyd", - "Tommy", - "Leon", - "Derek", - "Warren", - "Darrell", - "Jerome", - "Floyd", - "Leo", - "Alvin", - "Tim", - "Wesley", - "Gordon", - "Dean", - "Greg", - "Jorge", - "Dustin", - "Pedro", - "Derrick", - "Dan", - "Lewis", - "Zachary", - "Corey", - "Herman", - "Maurice", - "Vernon", - "Roberto", - "Clyde", - "Glen", - "Hector", - "Shane", - "Ricardo", - "Sam", - "Rick", - "Lester", - "Brent", - "Ramon", - "Charlie", - "Tyler", - "Gilbert", - "Gene", - "Marc", - "Reginald", - "Ruben", - "Brett", - "Angel", - "Nathaniel", - "Rafael", - "Leslie", - "Edgar", - "Milton", - "Raul", - "Ben", - "Chester", - "Cecil", - "Duane", - "Franklin", - "Andre", - "Elmer", - "Brad", - "Gabriel", - "Ron", - "Mitchell", - "Roland", - "Arnold", - "Harvey", - "Jared", - "Adrian", - "Karl", - "Cory", - "Claude", - "Erik", - "Darryl", - "Jamie", - "Neil", - "Jessie", - "Christian", - "Javier", - "Fernando", - "Clinton", - "Ted", - "Mathew", - "Tyrone", - "Darren", - "Lonnie", - "Lance", - "Cody", - "Julio", - "Kelly", - "Kurt", - "Allan", - "Nelson", - "Guy", - "Clayton", - "Hugh", - "Max", - "Dwayne", - "Dwight", - "Armando", - "Felix", - "Jimmie", - "Everett", - "Jordan", - "Ian", - "Wallace", - "Ken", - "Bob", - "Jaime", - "Casey", - "Alfredo", - "Alberto", - "Dave", - "Ivan", - "Johnnie", - "Sidney", - "Byron", - "Julian", - "Isaac", - "Morris", - "Clifton", - "Willard", - "Daryl", - "Ross", - "Virgil", - "Andy", - "Marshall", - "Salvador", - "Perry", - "Kirk", - "Sergio", - "Marion", - "Tracy", - "Seth", - "Kent", - "Terrance", - "Rene", - "Eduardo", - "Terrence", - "Enrique", - "Freddie", - "Wade", - "Austin", - "Stuart", - "Fredrick", - "Arturo", - "Alejandro", - "Jackie", - "Joey", - "Nick", - "Luther", - "Wendell", - "Jeremiah", - "Evan", - "Julius", - "Dana", - "Donnie", - "Otis", - "Shannon", - "Trevor", - "Oliver", - "Luke", - "Homer", - "Gerard", - "Doug", - "Kenny", - "Hubert", - "Angelo", - "Shaun", - "Lyle", - "Matt", - "Lynn", - "Alfonso", - "Orlando", - "Rex", - "Carlton", - "Ernesto", - "Cameron", - "Neal", - "Pablo", - "Lorenzo", - "Omar", - "Wilbur", - "Blake", - "Grant", - "Horace", - "Roderick", - "Kerry", - "Abraham", - "Willis", - "Rickey", - "Jean", - "Ira", - "Andres", - "Cesar", - "Johnathan", - "Malcolm", - "Rudolph", - "Damon", - "Kelvin", - "Rudy", - "Preston", - "Alton", - "Archie", - "Marco", - "Wm", - "Pete", - "Randolph", - "Garry", - "Geoffrey", - "Jonathon", - "Felipe", - "Bennie", - "Gerardo", - "Ed", - "Dominic", - "Robin", - "Loren", - "Delbert", - "Colin", - "Guillermo", - "Earnest", - "Lucas", - "Benny", - "Noel", - "Spencer", - "Rodolfo", - "Myron", - "Edmund", - "Garrett", - "Salvatore", - "Cedric", - "Lowell", - "Gregg", - "Sherman", - "Wilson", - "Devin", - "Sylvester", - "Kim", - "Roosevelt", - "Israel", - "Jermaine", - "Forrest", - "Wilbert", - "Leland", - "Simon", - "Guadalupe", - "Clark", - "Irving", - "Carroll", - "Bryant", - "Owen", - "Rufus", - "Woodrow", - "Sammy", - "Kristophe", - "Mack", - "Levi", - "Marcos", - "Gustavo", - "Jake", - "Lionel", - "Marty", - "Taylor", - "Ellis", - "Dallas", - "Gilberto", - "Clint", - "Nicolas", - "Laurence", - "Ismael", - "Orville", - "Drew", - "Jody", - "Ervin", - "Dewey", - "Al", - "Wilfred", - "Josh", - "Hugo", - "Ignacio", - "Caleb", - "Tomas", - "Sheldon", - "Erick", - "Frankie", - "Stewart", - "Doyle", - "Darrel", - "Rogelio", - "Terence", - "Santiago", - "Alonzo", - "Elias", - "Bert", - "Elbert", - "Ramiro", - "Conrad", - "Pat", - "Noah", - "Grady", - "Phil", - "Cornelius", - "Lamar", - "Rolando", - "Clay", - "Percy", - "Dexter", - "Bradford", - "Merle", - "Darin", - "Amos", - "Terrell", - "Moses", - "Irvin", - "Saul", - "Roman", - "Darnell", - "Randal", - "Tommie", - "Timmy", - "Darrin", - "Winston", - "Brendan", - "Toby", - "Van", - "Abel", - "Dominick", - "Boyd", - "Courtney", - "Jan", - "Emilio", - "Elijah", - "Cary", - "Domingo", - "Santos", - "Aubrey", - "Emmett", - "Marlon", - "Emanuel", - "Jerald", - "Edmond", - "Emil", - "Dewayne", - "Will", - "Otto", - "Teddy", - "Reynaldo", - "Bret", - "Morgan", - "Jess", - "Trent", - "Humberto", - "Emmanuel", - "Stephan", - "Louie", - "Vicente", - "Lamont", - "Stacy", - "Garland", - "Miles", - "Micah", - "Efrain", - "Billie", - "Logan", - "Heath", - "Rodger", - "Harley", - "Demetrius", - "Ethan", - "Eldon", - "Rocky", - "Pierre", - "Junior", - "Freddy", - "Eli", - "Bryce", - "Antoine", - "Robbie", - "Kendall", - "Royce", - "Sterling", - "Mickey", - "Chase", - "Grover", - "Elton", - "Cleveland", - "Dylan", - "Chuck", - "Damian", - "Reuben", - "Stan", - "August", - "Leonardo", - "Jasper", - "Russel", - "Erwin", - "Benito", - "Hans", - "Monte", - "Blaine", - "Ernie", - "Curt", - "Quentin", - "Agustin", - "Murray", - "Jamal", - "Devon", - "Adolfo", - "Harrison", - "Tyson", - "Burton", - "Brady", - "Elliott", - "Wilfredo", - "Bart", - "Jarrod", - "Vance", - "Denis", - "Damien", - "Joaquin", - "Harlan", - "Desmond", - "Elliot", - "Darwin", - "Ashley", - "Gregorio", - "Buddy", - "Xavier", - "Kermit", - "Roscoe", - "Esteban", - "Anton", - "Solomon", - "Scotty", - "Norbert", - "Elvin", - "Williams", - "Nolan", - "Carey", - "Rod", - "Quinton", - "Hal", - "Brain", - "Rob", - "Elwood", - "Kendrick", - "Darius", - "Moises", - "Son", - "Marlin", - "Fidel", - "Thaddeus", - "Cliff", - "Marcel", - "Ali", - "Jackson", - "Raphael", - "Bryon", - "Armand", - "Alvaro", - "Jeffry", - "Dane", - "Joesph", - "Thurman", - "Ned", - "Sammie", - "Rusty", - "Michel", - "Monty", - "Rory", - "Fabian", - "Reggie", - "Mason", - "Graham", - "Kris", - "Isaiah", - "Vaughn", - "Gus", - "Avery", - "Loyd", - "Diego", - "Alexis", - "Adolph", - "Norris", - "Millard", - "Rocco", - "Gonzalo", - "Derick", - "Rodrigo", - "Gerry", - "Stacey", - "Carmen", - "Wiley", - "Rigoberto", - "Alphonso", - "Ty", - "Shelby", - "Rickie", - "Noe", - "Vern", - "Bobbie", - "Reed", - "Jefferson", - "Elvis", - "Bernardo", - "Mauricio", - "Hiram", - "Donovan", - "Basil", - "Riley", - "Ollie", - "Nickolas", - "Maynard", - "Scot", - "Vince", - "Quincy", - "Eddy", - "Sebastian", - "Federico", - "Ulysses", - "Heriberto", - "Donnell", - "Cole", - "Denny", - "Davis", - "Gavin", - "Emery", - "Ward", - "Romeo", - "Jayson", - "Dion", - "Dante", - "Clement", - "Coy", - "Odell", - "Maxwell", - "Jarvis", - "Bruno", - "Issac", - "Mary", - "Dudley", - "Brock", - "Sanford", - "Colby", - "Carmelo", - "Barney", - "Nestor", - "Hollis", - "Stefan", - "Donny", - "Art", - "Linwood", - "Beau", - "Weldon", - "Galen", - "Isidro", - "Truman", - "Delmar", - "Johnathon", - "Silas", - "Frederic", - "Dick", - "Kirby", - "Irwin", - "Cruz", - "Merlin", - "Merrill", - "Charley", - "Marcelino", - "Lane", - "Harris", - "Cleo", - "Carlo", - "Trenton", - "Kurtis", - "Hunter", - "Aurelio", - "Winfred", - "Vito", - "Collin", - "Denver", - "Carter", - "Leonel", - "Emory", - "Pasquale", - "Mohammad", - "Mariano", - "Danial", - "Blair", - "Landon", - "Dirk", - "Branden", - "Adan", - "Numbers", - "Clair", - "Buford", - "German", - "Bernie", - "Wilmer", - "Joan", - "Emerson", - "Zachery", - "Fletcher", - "Jacques", - "Errol", - "Dalton", - "Monroe", - "Josue", - "Dominique", - "Edwardo", - "Booker", - "Wilford", - "Sonny", - "Shelton", - "Carson", - "Theron", - "Raymundo", - "Daren", - "Tristan", - "Houston", - "Robby", - "Lincoln", - "Jame", - "Genaro", - "Gale", - "Bennett", - "Octavio", - "Cornell", - "Laverne", - "Hung", - "Arron", - "Antony", - "Herschel", - "Alva", - "Giovanni", - "Garth", - "Cyrus", - "Cyril", - "Ronny", - "Stevie", - "Lon", - "Freeman", - "Erin", - "Duncan", - "Kennith", - "Carmine", - "Augustine", - "Young", - "Erich", - "Chadwick", - "Wilburn", - "Russ", - "Reid", - "Myles", - "Anderson", - "Morton", - "Jonas", - "Forest", - "Mitchel", - "Mervin", - "Zane", - "Rich", - "Jamel", - "Lazaro", - "Alphonse", - "Randell", - "Major", - "Johnie", - "Jarrett", - "Brooks", - "Ariel", - "Abdul", - "Dusty", - "Luciano", - "Lindsey", - "Tracey", - "Seymour", - "Scottie", - "Eugenio", - "Mohammed", - "Sandy", - "Valentin", - "Chance", - "Arnulfo", - "Lucien", - "Ferdinand", - "Thad", - "Ezra", - "Sydney", - "Aldo", - "Rubin", - "Royal", - "Mitch", - "Earle", - "Abe", - "Wyatt", - "Marquis", - "Lanny", - "Kareem", - "Jamar", - "Boris", - "Isiah", - "Emile", - "Elmo", - "Aron", - "Leopoldo", - "Everette", - "Josef", - "Gail", - "Eloy", - "Dorian", - "Rodrick", - "Reinaldo", - "Lucio", - "Jerrod", - "Weston", - "Hershel", - "Barton", - "Parker", - "Lemuel", - "Lavern", - "Burt", - "Jules", - "Gil", - "Eliseo", - "Ahmad", - "Nigel", - "Efren", - "Antwan", - "Alden", - "Margarito", - "Coleman", - "Refugio", - "Dino", - "Osvaldo", - "Les", - "Deandre", - "Normand", - "Kieth", - "Ivory", - "Andrea", - "Trey", - "Norberto", - "Napoleon", - "Jerold", - "Fritz", - "Rosendo", - "Milford", - "Sang", - "Deon", - "Christope", - "Alfonzo", - "Lyman", - "Josiah", - "Brant", - "Wilton", - "Rico", - "Jamaal", - "Dewitt", - "Carol", - "Brenton", - "Yong", - "Olin", - "Foster", - "Faustino", - "Claudio", - "Judson", - "Gino", - "Edgardo", - "Berry", - "Alec", - "Tanner", - "Jarred", - "Donn", - "Trinidad", - "Tad", - "Shirley", - "Prince", - "Porfirio", - "Odis", - "Maria", - "Lenard", - "Chauncey", - "Chang", - "Tod", - "Mel", - "Marcelo", - "Kory", - "Augustus", - "Keven", - "Hilario", - "Bud", - "Sal", - "Rosario", - "Orval", - "Mauro", - "Dannie", - "Zachariah", - "Olen", - "Anibal", - "Milo", - "Jed", - "Frances", - "Thanh", - "Dillon", - "Amado", - "Newton", - "Connie", - "Lenny", - "Tory", - "Richie", - "Lupe", - "Horacio", - "Brice", - "Mohamed", - "Delmer", - "Dario", - "Reyes", - "Dee", - "Mac", - "Jonah", - "Jerrold", - "Robt", - "Hank", - "Sung", - "Rupert", - "Rolland", - "Kenton", - "Damion", - "Chi", - "Antone", - "Waldo", - "Fredric", - "Bradly", - "Quinn", - "Kip", - "Burl", - "Walker", - "Tyree", - "Jefferey", - "Ahmed", - "Willy", - "Stanford", - "Oren", - "Noble", - "Moshe", - "Mikel", - "Enoch", - "Brendon", - "Quintin", - "Jamison", - "Florencio", - "Darrick", - "Tobias", - "Minh", - "Hassan", - "Giuseppe", - "Demarcus", - "Cletus", - "Tyrell", - "Lyndon", - "Keenan", - "Werner", - "Theo", - "Geraldo", - "Lou", - "Columbus", - "Chet", - "Bertram", - "Markus", - "Huey", - "Hilton", - "Dwain", - "Donte", - "Tyron", - "Omer", - "Isaias", - "Hipolito", - "Fermin", - "Chung", - "Adalberto", - "Valentine", - "Jamey", - "Bo", - "Barrett", - "Whitney", - "Teodoro", - "Mckinley", - "Maximo", - "Garfield", - "Sol", - "Raleigh", - "Lawerence", - "Abram", - "Rashad", - "King", - "Emmitt", - "Daron", - "Chong", - "Samual", - "Paris", - "Otha", - "Miquel", - "Lacy", - "Eusebio", - "Dong", - "Domenic", - "Darron", - "Buster", - "Antonia", - "Wilber", - "Renato", - "Jc", - "Hoyt", - "Haywood", - "Ezekiel", - "Chas", - "Florentin", - "Elroy", - "Clemente", - "Arden", - "Neville", - "Kelley", - "Edison", - "Deshawn", - "Carrol", - "Shayne", - "Nathanial", - "Jordon", - "Danilo", - "Claud", - "Val", - "Sherwood", - "Raymon", - "Rayford", - "Cristobal", - "Ambrose", - "Titus", - "Hyman", - "Felton", - "Ezequiel", - "Erasmo", - "Stanton", - "Lonny", - "Len", - "Ike", - "Milan", - "Lino", - "Jarod", - "Herb", - "Andreas", - "Walton", - "Rhett", - "Palmer", - "Jude", - "Douglass", - "Cordell", - "Oswaldo", - "Ellsworth", - "Virgilio", - "Toney", - "Nathanael", - "Del", - "Britt", - "Benedict", - "Mose", - "Hong", - "Leigh", - "Johnson", - "Isreal", - "Gayle", - "Garret", - "Fausto", - "Asa", - "Arlen", - "Zack", - "Warner", - "Modesto", - "Francesco", - "Manual", - "Jae", - "Gaylord", - "Gaston", - "Filiberto", - "Deangelo", - "Michale", - "Granville", - "Wes", - "Malik", - "Zackary", - "Tuan", - "Nicky", - "Eldridge", - "Cristophe", - "Cortez", - "Antione", - "Malcom", - "Long", - "Korey", - "Jospeh", - "Colton", - "Waylon", - "Von", - "Hosea", - "Shad", - "Santo", - "Rudolf", - "Rolf", - "Rey", - "Renaldo", - "Marcellus", - "Lucius", - "Lesley", - "Kristofer", - "Boyce", - "Benton", - "Man", - "Kasey", - "Jewell", - "Hayden", - "Harland", - "Arnoldo", - "Rueben", - "Leandro", - "Kraig", - "Jerrell", - "Jeromy", - "Hobert", - "Cedrick", - "Arlie", - "Winford", - "Wally", - "Patricia", - "Luigi", - "Keneth", - "Jacinto", - "Graig", - "Franklyn", - "Edmundo", - "Sid", - "Porter", - "Leif", - "Lauren", - "Jeramy", - "Elisha", - "Buck", - "Willian", - "Vincenzo", - "Shon", - "Michal", - "Lynwood", - "Lindsay", - "Jewel", - "Jere", - "Hai", - "Elden", - "Dorsey", - "Darell", - "Broderick", - "Alonso", -] - -RANDOM_PLANT_NAME_SOURCE = [ - "Abelia", - "Acacia", - "Acer", - "Acevedo", - "Afra", - "Akina", - "Alaleh", - "Alani", - "Alder", - "Almond", - "Althea ", - "Alyssum", - "Amaranta", - "Amaryllis", - "Anita", - "Apricot", - "Arousa", - "Arusa", - "Ash", - "Aspen ", - "Aster", - "Astera", - "Avishan", - "Ayame", - "Ayla", - "Azalea", - "Azargol", - "Azargoon", - "Azarin", - "Azhand", - "Babuk", - "Bahar", - "Baharak", - "Banafsheh", - "Barnacle", - "Basil", - "Bay", - "Beech", - "Begonia", - "Belladonna", - "Birch", - "Blackberry", - "Blossom", - "Bluebell ", - "Booker", - "Botan", - "Bramble", - "Bryony", - "Bud", - "Burke ", - "Buttercup", - "Cactus", - "Caltha", - "Camelai", - "Camellia", - "Carnation", - "Cedar", - "Cherise", - "Cherry", - "Cinnamon", - "Cliantha", - "Clover", - "Cosmos", - "Cyclamen", - "Cypress", - "Daffodil", - "Dahlia", - "Daisy", - "Dandelion", - "Daphne", - "Dianthe", - "Dianthus", - "Enola ", - "Eranthe", - "Fern", - "Fiorenza", - "Fleur", - "Fern", - "Fiorenza", - "Fleur", - "Flora", - "Freesia", - "Fuchsia", - "Gardenia", - "Garland", - "Gazania", - "Geranium", - "Ginger", - "Gooseberry", - "Gul", - "Hawthorne", - "Hazel", - "Holly", - "Hollyhock", - "Honeysuckle", - "Hyacinth", - "Iris ", - "Ivy", - "Jacaranda", - "Jasmine", - "Jessamine", - "Juniper", - "Kalei", - "Lantana", - "Laurel", - "Leilani", - "Licorice ", - "Lilac", - "Lily ", - "Lobelia", - "Lotus", - "Magnolia", - "Mallow ", - "Mandrake", - "Maple", - "Marguerite", - "Marigold", - "Mayflower", - "Miki", - "Mimosa", - "Mulberry", - "Myrtle ", - "Nihal", - "Olive", - "Pansy ", - "Patience", - "Peach", - "Peony", - "Peppermint", - "Periwinkle", - "Persimmon", - "Petunia", - "Pimpernel", - "Poppy", - "Posey", - "Primrose", - "Pumpkin", - "Quince", - "Rose", - "Rosemary", - "Saffron", - "Sage", - "Shamrock", - "Snapdragon", - "Snowdrop", - "Sorrel", - "Sunflower", - "Sweet Pea", - "Tansy ", - "Thistle", - "Tiger-lily", - "Truffle", - "Tulip", - "Verbena ", - "Violet", - "Willow", - "Yasaman", - "Yasmin", - "Yasminah", - "Yew", - "Zara", -] - -RANDOM_STREET_SUFFIX_SOURCE = ["St.", "Ave.", "Blvd.", "Ln.", "Ct.", "Pl.", "Way"] - -RANDOM_EMAIL_DOMAINS = ["example.com", "example.net", "example.org"] -# 'gmail.com', 'yahoo.com', 'hotmail.com', 'live.com', -# 'comcast.net', 'qwest.com', - -RANDOM_CITY_SUFFIX_SOURCE = ["ville", "berg", "ton", "y", "", "land"] diff --git a/seed/test_helpers/first_500_buildings.csv b/seed/test_helpers/first_500_buildings.csv deleted file mode 100644 index 8d46b45b91..0000000000 --- a/seed/test_helpers/first_500_buildings.csv +++ /dev/null @@ -1,501 +0,0 @@ -tax_lot_id,address_line_1,city,state,postal_code,year_built,site_eui,owner,owner_email,owner_telephone,owner_address,owner_city_state,owner_postal_code -11588,1151 Lambert Street,Boring,Oregon,97039,2002,216,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -48810,1071 Jones Street,Boring,Oregon,97017,1907,437,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -54953,611 Ortega Avenue,Boring,Oregon,97020,1882,64,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -38880,1181 Robbins Loop,Boring,Oregon,97078,1936,578,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -96237,1381 James Road,Boring,Oregon,97086,1927,159,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -23719,681 Faulkner Boulevard,Boring,Oregon,97054,1924,307,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -54476,821 Brown Street,Boring,Oregon,97057,1944,215,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -86298,1341 Gallagher Street,Boring,Oregon,97005,1931,283,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -18796,841 Patton Street,Boring,Oregon,97064,1933,218,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -39345,1091 Hawkins Street,Boring,Oregon,97058,1951,397,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -41157,1171 Boyd Avenue,Boring,Oregon,97011,1961,224,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -57559,1371 Collins Lane,Boring,Oregon,97030,1893,469,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -94399,911 Cline Avenue,Boring,Oregon,97004,1955,196,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -61752,771 Smith Lane,Boring,Oregon,97021,1943,427,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -96486,1251 Khan Road,Boring,Oregon,97000,1950,274,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -69492,981 Dennis Boulevard,Boring,Oregon,97040,1895,268,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -62284,1311 Stokes Avenue,Boring,Oregon,97003,1953,505,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -68724,1021 Holmes Avenue,Boring,Oregon,97069,1885,480,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -87972,1321 Ortega Avenue,Boring,Oregon,97014,1934,162,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -40539,911 Miller Road,Boring,Oregon,97012,1958,312,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -10286,651 Nicholson Road,Boring,Oregon,97063,1881,285,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -97775,1091 Boyd Avenue,Boring,Oregon,97077,1980,357,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -93844,631 Petersen Avenue,Boring,Oregon,97039,1926,521,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -64551,841 Jones Street,Boring,Oregon,97042,1957,101,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -74882,911 Lopez Road,Boring,Oregon,97028,1998,507,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -29810,721 Perry Avenue,Boring,Oregon,97024,1979,161,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -67950,631 Wagner Avenue,Boring,Oregon,97010,2006,590,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -52734,651 Williams Street,Boring,Oregon,97029,1884,208,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -81631,991 Sanders Road,Boring,Oregon,97087,1913,318,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -71886,731 Powell Loop,Boring,Oregon,97087,1884,412,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -20707,1211 Henson Avenue,Boring,Oregon,97091,1994,358,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -49211,1071 Cross Loop,Boring,Oregon,97065,1945,97,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -15146,1181 Allen Avenue,Boring,Oregon,97056,1894,97,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -36133,741 Smith Avenue,Boring,Oregon,97040,1889,257,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -28369,801 Kennedy Street,Boring,Oregon,97084,1951,451,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -71809,1371 Morris Road,Boring,Oregon,97047,2007,394,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -14400,961 Brooks Avenue,Boring,Oregon,97097,2006,374,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -41976,1231 White Street,Boring,Oregon,97073,1887,578,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -13610,911 Roberts Street,Boring,Oregon,97029,1926,328,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -05327,771 Levine Boulevard,Boring,Oregon,97044,2014,184,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -62237,921 Martin Avenue,Boring,Oregon,97095,1925,149,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -84125,1181 Pittman Road,Boring,Oregon,97003,1999,316,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -56910,781 Smith Road,Boring,Oregon,97088,1967,563,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -78682,811 Garrett Boulevard,Boring,Oregon,97003,1992,114,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -80416,1271 Conley Road,Boring,Oregon,97077,2015,444,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -34635,1291 Summers Street,Boring,Oregon,97093,1893,421,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -84953,1331 Howell Street,Boring,Oregon,97058,1937,451,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -26801,821 Hensley Street,Boring,Oregon,97097,1969,50,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -96671,1261 Roy Boulevard,Boring,Oregon,97020,1916,589,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -54908,731 Hartman Street,Boring,Oregon,97023,1889,367,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -58424,741 Scott Avenue,Boring,Oregon,97061,1923,352,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -06667,1381 Delgado Loop,Boring,Oregon,97013,1961,462,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -35389,1341 Carson Street,Boring,Oregon,97003,1986,247,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -31741,651 Gutierrez Boulevard,Boring,Oregon,97024,1903,465,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -35153,1181 Cole Road,Boring,Oregon,97047,1962,248,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -23055,751 Hunter Loop,Boring,Oregon,97088,2004,544,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -15814,731 Jones Road,Boring,Oregon,97010,1985,96,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -63346,711 Jones Street,Boring,Oregon,97007,1890,398,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -89498,821 Wallace Street,Boring,Oregon,97081,1886,220,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -84785,641 Smith Avenue,Boring,Oregon,97011,1928,73,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -92901,1361 Salazar Avenue,Boring,Oregon,97017,1881,106,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -67598,681 Shaw Avenue,Boring,Oregon,97023,1997,223,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -25460,1341 Robinson Avenue,Boring,Oregon,97024,2009,107,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -01286,691 Chung Lane,Boring,Oregon,97039,1945,468,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -55193,701 Ellis Avenue,Boring,Oregon,97028,2001,279,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -29649,1011 Brown Loop,Boring,Oregon,97017,1938,417,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -38218,611 Burgess Lane,Boring,Oregon,97041,1962,363,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -12922,1181 Peterson Avenue,Boring,Oregon,97035,1911,529,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -32854,741 Chung Boulevard,Boring,Oregon,97042,1909,114,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -08790,871 Stewart Loop,Boring,Oregon,97074,1900,527,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -96836,1091 Skinner Avenue,Boring,Oregon,97087,2012,166,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -55532,751 Kim Loop,Boring,Oregon,97089,1934,519,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -85801,1231 Casey Loop,Boring,Oregon,97056,1936,248,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -19931,681 Moran Avenue,Boring,Oregon,97040,1993,395,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -37273,1371 Dalton Boulevard,Boring,Oregon,97054,1934,573,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -94099,971 Bryant Street,Boring,Oregon,97042,1904,600,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -00458,1011 Chang Road,Boring,Oregon,97074,1937,563,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -89836,1371 Combs Avenue,Boring,Oregon,97010,1932,214,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -12424,1181 King Road,Boring,Oregon,97016,1961,272,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -90436,1191 Johnson Street,Boring,Oregon,97026,1953,526,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -55489,941 Mcfarland Street,Boring,Oregon,97062,1961,430,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -47708,1131 Ross Street,Boring,Oregon,97008,1975,165,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -89349,631 Lopez Road,Boring,Oregon,97014,1986,473,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -96233,661 Tran Loop,Boring,Oregon,97044,1993,248,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -85233,1221 Santiago Street,Boring,Oregon,97024,1940,386,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -97609,1391 Lamb Street,Boring,Oregon,97010,1959,375,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -13006,691 Franklin Avenue,Boring,Oregon,97002,1947,437,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -89893,891 Schultz Boulevard,Boring,Oregon,97099,1910,133,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -09100,811 Johnson Road,Boring,Oregon,97029,1939,413,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -45935,731 Smith Street,Boring,Oregon,97046,1980,200,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -64436,1101 Taylor Avenue,Boring,Oregon,97013,1891,163,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -85535,1191 Kelly Loop,Boring,Oregon,97016,1890,302,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -75023,881 Myers Street,Boring,Oregon,97022,1923,490,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -98816,1211 Oliver Street,Boring,Oregon,97011,1943,177,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -38317,1331 Hernandez Road,Boring,Oregon,97012,1931,160,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -88378,1101 Jones Road,Boring,Oregon,97007,1933,254,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -80771,611 Allen Street,Boring,Oregon,97037,1957,497,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -69429,1191 Kelley Street,Boring,Oregon,97017,1985,206,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -49436,1181 Jones Boulevard,Boring,Oregon,97048,1977,327,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -88322,1021 Benjamin Road,Boring,Oregon,97024,1895,379,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -45722,1171 Porter Lane,Boring,Oregon,97038,1978,208,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -02833,621 Rich Lane,Boring,Oregon,97002,2005,583,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -21470,681 Frank Loop,Boring,Oregon,97068,1899,533,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -84835,1171 Pitts Road,Boring,Oregon,97059,1938,94,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -65288,881 Morrow Avenue,Boring,Oregon,97048,2013,501,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -57234,1331 Brown Street,Boring,Oregon,97069,2015,336,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -49232,1021 King Loop,Boring,Oregon,97033,1962,347,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -61399,1151 Fletcher Lane,Boring,Oregon,97021,1884,128,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -93551,1201 Rodriguez Boulevard,Boring,Oregon,97007,2006,407,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -64229,951 Lambert Road,Boring,Oregon,97099,1881,516,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -23455,901 Jones Avenue,Boring,Oregon,97009,1897,500,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -02202,1401 Brown Boulevard,Boring,Oregon,97017,1962,510,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -94511,1181 Chase Road,Boring,Oregon,97017,1885,174,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -65188,1031 Curtis Street,Boring,Oregon,97006,1885,402,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -14652,1031 Perez Road,Boring,Oregon,97032,2012,272,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -09177,941 Turner Street,Boring,Oregon,97036,1984,102,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -44140,971 Ewing Street,Boring,Oregon,97013,1962,279,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -92108,1381 Morales Road,Boring,Oregon,97085,1987,585,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -35469,871 Pope Street,Boring,Oregon,97080,1920,464,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -77029,701 Graham Lane,Boring,Oregon,97091,1882,144,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -12204,1021 Walker Street,Boring,Oregon,97015,2008,239,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -63682,951 Simmons Loop,Boring,Oregon,97027,1987,294,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -83142,1101 Howell Avenue,Boring,Oregon,97010,2008,423,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -64662,841 Barnes Road,Boring,Oregon,97011,1895,371,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -20654,601 Jenkins Road,Boring,Oregon,97067,1930,104,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -22827,1011 Boone Boulevard,Boring,Oregon,97014,2015,531,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -12913,831 Romero Street,Boring,Oregon,97030,1976,589,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -25292,1231 Wade Street,Boring,Oregon,97033,1954,473,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -50740,741 Strong Avenue,Boring,Oregon,97036,1984,580,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -35761,981 Davis Loop,Boring,Oregon,97098,1895,265,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -79274,1291 Burch Road,Boring,Oregon,97010,1944,583,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -54360,701 Long Street,Boring,Oregon,97015,2015,112,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -48871,1221 Phillips Road,Boring,Oregon,97087,1901,396,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -70048,1091 Henry Street,Boring,Oregon,97033,1961,468,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -54378,981 Barker Avenue,Boring,Oregon,97062,1908,473,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -32217,721 Meyer Road,Boring,Oregon,97024,1992,492,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -51263,1251 Johnson Boulevard,Boring,Oregon,97067,1907,508,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -30387,661 Rogers Loop,Boring,Oregon,97069,1890,309,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -40888,1201 Jackson Avenue,Boring,Oregon,97016,1968,429,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -95270,791 Jones Street,Boring,Oregon,97065,1990,368,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -95739,661 Rogers Boulevard,Boring,Oregon,97010,1992,377,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -95725,961 Day Street,Boring,Oregon,97039,1908,450,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -27613,1331 Phillips Street,Boring,Oregon,97010,1994,568,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -82841,681 Holloway Street,Boring,Oregon,97079,1984,189,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -59187,1101 Williams Avenue,Boring,Oregon,97084,1922,186,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -44685,701 Torres Avenue,Boring,Oregon,97047,1882,100,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -57212,1381 Campbell Lane,Boring,Oregon,97045,1973,549,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -46063,811 Sampson Lane,Boring,Oregon,97055,1934,494,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -41147,821 Good Lane,Boring,Oregon,97038,1977,597,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -90612,731 Henry Lane,Boring,Oregon,97026,1995,221,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -30975,851 Rodgers Road,Boring,Oregon,97085,2015,598,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -32100,1211 Carey Road,Boring,Oregon,97071,1886,521,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -06267,701 Morales Lane,Boring,Oregon,97045,1963,400,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -86981,771 Bates Street,Boring,Oregon,97071,1970,92,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -10581,1301 Campbell Lane,Boring,Oregon,97025,1973,76,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -72491,641 Stevens Street,Boring,Oregon,97059,1960,381,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -13638,1141 Robinson Street,Boring,Oregon,97096,1893,431,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -05319,701 Williams Street,Boring,Oregon,97048,1930,123,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -10887,711 Roberts Avenue,Boring,Oregon,97087,1974,174,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -57488,1171 Franco Loop,Boring,Oregon,97014,2015,383,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -58434,991 Lloyd Street,Boring,Oregon,97024,1886,129,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -13301,1101 Osborn Avenue,Boring,Oregon,97037,1924,437,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -84078,841 Robinson Avenue,Boring,Oregon,97018,1929,480,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -39164,1251 Scott Boulevard,Boring,Oregon,97016,1954,451,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -18769,1121 Harrison Boulevard,Boring,Oregon,97097,1915,369,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -73542,771 Sutton Lane,Boring,Oregon,97069,1900,290,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -36336,1251 Knight Road,Boring,Oregon,97079,1927,357,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -10095,721 White Road,Boring,Oregon,97044,1933,92,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -12257,1181 Hall Street,Boring,Oregon,97004,1937,178,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -37217,1011 Johnson Avenue,Boring,Oregon,97003,1972,347,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -23147,1171 Frey Loop,Boring,Oregon,97086,1893,331,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -60497,1101 Patterson Road,Boring,Oregon,97023,1941,513,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -54710,821 Long Avenue,Boring,Oregon,97002,1887,89,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -12777,1111 Aguirre Boulevard,Boring,Oregon,97076,1934,572,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -41649,1021 Russell Street,Boring,Oregon,97073,1891,480,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -79769,901 Orozco Avenue,Boring,Oregon,97009,1972,586,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -38183,1131 Simon Street,Boring,Oregon,97015,1897,469,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -81460,1071 Johnson Boulevard,Boring,Oregon,97016,1978,136,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -20034,701 Lyons Road,Boring,Oregon,97045,1907,174,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -45151,621 Bailey Street,Boring,Oregon,97059,1907,199,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -54430,1191 Nelson Boulevard,Boring,Oregon,97012,1943,126,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -56847,1371 Bell Loop,Boring,Oregon,97044,1933,219,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -84991,971 Butler Boulevard,Boring,Oregon,97046,1989,102,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -16681,1341 Bowers Road,Boring,Oregon,97052,1974,385,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -41938,601 Thompson Loop,Boring,Oregon,97041,1940,519,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -95427,691 Patel Road,Boring,Oregon,97068,1884,491,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -85867,1311 Ford Street,Boring,Oregon,97098,2005,533,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -89998,1391 Harding Avenue,Boring,Oregon,97099,1884,246,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -91592,1161 Murphy Avenue,Boring,Oregon,97060,1896,160,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -85800,1331 Hoffman Lane,Boring,Oregon,97032,1985,265,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -52004,791 Randolph Road,Boring,Oregon,97080,1999,50,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -20915,1021 Weiss Road,Boring,Oregon,97061,1923,52,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -13919,1281 Martinez Street,Boring,Oregon,97079,2008,349,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -38507,1151 Ingram Avenue,Boring,Oregon,97013,1897,405,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -42651,721 Buckley Street,Boring,Oregon,97080,2011,482,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -70824,891 Sullivan Avenue,Boring,Oregon,97001,1897,545,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -36092,1351 Dennis Street,Boring,Oregon,97024,1990,503,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -90619,1361 Castillo Road,Boring,Oregon,97047,1937,296,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -01864,1101 Smith Avenue,Boring,Oregon,97016,1964,286,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -57504,1171 Wells Street,Boring,Oregon,97022,2013,352,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -54828,891 Jensen Street,Boring,Oregon,97006,1928,472,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -80353,731 Williams Avenue,Boring,Oregon,97093,1964,232,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -59011,1011 Smith Avenue,Boring,Oregon,97094,1905,545,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -43996,1041 Reid Avenue,Boring,Oregon,97081,1945,133,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -47849,1261 Ruiz Avenue,Boring,Oregon,97050,1995,377,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -72483,1081 Simpson Street,Boring,Oregon,97072,1916,429,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -07825,1031 Ramos Avenue,Boring,Oregon,97059,1923,515,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -55217,1311 Galloway Street,Boring,Oregon,97001,2000,169,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -23230,1351 Smith Street,Boring,Oregon,97069,1901,95,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -20577,1331 Rowe Street,Boring,Oregon,97028,1906,305,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -19850,1301 Mitchell Lane,Boring,Oregon,97036,1883,239,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -13420,751 Lambert Boulevard,Boring,Oregon,97057,1887,92,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -12460,611 Leonard Boulevard,Boring,Oregon,97094,1894,146,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -12316,751 Butler Lane,Boring,Oregon,97022,1996,87,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -56343,1091 Roberts Street,Boring,Oregon,97010,1970,590,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -02482,1271 Perez Avenue,Boring,Oregon,97069,1900,521,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -19400,961 Baldwin Loop,Boring,Oregon,97026,1953,130,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -66771,1261 Moore Avenue,Boring,Oregon,97024,1938,71,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -95830,1141 Mcfarland Street,Boring,Oregon,97021,1921,148,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -98363,851 Smith Avenue,Boring,Oregon,97090,1943,313,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -14355,991 Harrison Avenue,Boring,Oregon,97023,2015,263,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -01495,631 Price Street,Boring,Oregon,97027,1901,566,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -00621,1281 Nielsen Road,Boring,Oregon,97013,1924,526,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -46056,1351 Howard Avenue,Boring,Oregon,97063,1925,358,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -18437,841 Strickland Avenue,Boring,Oregon,97036,1938,143,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -77554,661 Anderson Avenue,Boring,Oregon,97068,1972,328,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -73785,931 Good Loop,Boring,Oregon,97033,1891,537,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -77976,861 Moore Lane,Boring,Oregon,97049,1973,480,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -54266,1001 Soto Road,Boring,Oregon,97061,2006,236,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -43132,621 Carter Avenue,Boring,Oregon,97049,1915,302,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -41204,1401 Ramirez Boulevard,Boring,Oregon,97084,1932,299,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -33868,1231 Moran Avenue,Boring,Oregon,97062,1936,139,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -38662,791 Beasley Avenue,Boring,Oregon,97084,1922,64,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99294,771 Clark Street,Boring,Oregon,97008,1985,528,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -97502,731 Hill Road,Boring,Oregon,97099,1908,457,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -36303,1121 King Street,Boring,Oregon,97080,2003,586,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -39047,821 Barker Avenue,Boring,Oregon,97095,1947,333,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -03158,1291 Williams Avenue,Boring,Oregon,97093,1912,342,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -04192,641 Roberts Boulevard,Boring,Oregon,97096,1930,569,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -34512,671 Chang Street,Boring,Oregon,97053,1885,541,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -82998,671 Lewis Street,Boring,Oregon,97012,1938,303,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -87537,761 Duran Lane,Boring,Oregon,97071,1956,545,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -80331,1041 Thompson Boulevard,Boring,Oregon,97089,1952,334,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -76595,741 Newman Lane,Boring,Oregon,97030,1892,554,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -66148,651 Spencer Loop,Boring,Oregon,97082,1898,271,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -75331,1371 Byrd Street,Boring,Oregon,97070,1965,179,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -09298,741 Anderson Loop,Boring,Oregon,97099,1884,327,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -26936,611 Jimenez Street,Boring,Oregon,97074,1909,377,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -11517,1291 James Avenue,Boring,Oregon,97027,1927,578,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -95276,691 Nelson Road,Boring,Oregon,97004,2003,259,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -17207,911 Scott Road,Boring,Oregon,97076,1991,293,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -79538,1341 Ruiz Street,Boring,Oregon,97006,1880,501,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -62198,921 Jenkins Avenue,Boring,Oregon,97003,1998,313,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -15107,901 Williams Street,Boring,Oregon,97032,1885,50,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -15016,861 Cervantes Avenue,Boring,Oregon,97051,1881,404,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -04569,971 Jenkins Avenue,Boring,Oregon,97090,1893,113,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -31057,881 Boyd Street,Boring,Oregon,97000,1927,77,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -59369,991 Leblanc Boulevard,Boring,Oregon,97000,1934,427,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -55287,901 Gonzalez Street,Boring,Oregon,97083,1964,206,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -90078,961 Hansen Street,Boring,Oregon,97014,1940,505,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -51171,1231 Murphy Lane,Boring,Oregon,97031,1894,413,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -54948,961 Alexander Street,Boring,Oregon,97095,1992,567,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -28922,1361 Hernandez Avenue,Boring,Oregon,97030,1918,493,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -53071,1171 Ford Lane,Boring,Oregon,97001,1935,428,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -61814,891 Washington Avenue,Boring,Oregon,97039,1924,148,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -87584,611 Edwards Loop,Boring,Oregon,97037,1977,572,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -26728,1261 Arellano Street,Boring,Oregon,97084,1919,176,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -82562,1081 Russell Avenue,Boring,Oregon,97048,1897,477,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -28957,1101 Wilkins Boulevard,Boring,Oregon,97041,2008,419,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -30372,1091 Haley Road,Boring,Oregon,97021,1963,376,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -45099,1231 Gibson Street,Boring,Oregon,97098,1935,202,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -74029,651 Miles Lane,Boring,Oregon,97024,1966,578,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -47794,1291 Kramer Street,Boring,Oregon,97025,1924,379,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -33855,1391 Page Road,Boring,Oregon,97083,1982,401,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -57822,1131 Rodriguez Boulevard,Boring,Oregon,97073,1916,175,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -22107,821 Harrison Street,Boring,Oregon,97087,1971,526,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -62353,781 Beasley Avenue,Boring,Oregon,97035,1977,423,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -85273,1201 Thomas Road,Boring,Oregon,97012,1918,542,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -91413,661 Stafford Road,Boring,Oregon,97045,1997,462,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -84319,961 Allen Lane,Boring,Oregon,97091,1954,563,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -62549,1171 White Avenue,Boring,Oregon,97069,1880,270,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -82242,901 Leonard Street,Boring,Oregon,97021,1916,472,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -16956,1191 Adams Street,Boring,Oregon,97091,1943,254,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -56315,1031 Cannon Road,Boring,Oregon,97011,1958,540,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -69926,1211 Church Street,Boring,Oregon,97024,1937,119,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -81896,1051 Moran Lane,Boring,Oregon,97037,2009,90,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -49493,1301 Stone Loop,Boring,Oregon,97013,1964,579,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -60695,1001 Jenkins Street,Boring,Oregon,97073,1941,291,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -64711,681 Turner Street,Boring,Oregon,97095,1949,376,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -13506,1341 Riley Street,Boring,Oregon,97055,1907,390,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -53952,1141 Sparks Avenue,Boring,Oregon,97029,1927,384,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -06879,831 Murray Road,Boring,Oregon,97088,1880,230,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -94379,971 Ochoa Avenue,Boring,Oregon,97087,1889,471,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -57987,691 Snyder Loop,Boring,Oregon,97042,1937,589,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -31081,911 Keller Street,Boring,Oregon,97042,1893,440,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -15540,621 Jones Avenue,Boring,Oregon,97042,1917,412,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -11509,831 Sanchez Avenue,Boring,Oregon,97010,1980,248,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -18280,1241 Adams Street,Boring,Oregon,97096,1893,333,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -13283,651 Brown Boulevard,Boring,Oregon,97079,1988,297,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -51846,901 Powell Road,Boring,Oregon,97091,1937,150,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -95853,711 Jones Road,Boring,Oregon,97048,1976,398,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -42454,1251 Randall Street,Boring,Oregon,97033,1959,431,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99415,1021 Grimes Street,Boring,Oregon,97066,1935,481,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -48847,741 Diaz Avenue,Boring,Oregon,97030,1981,88,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -87164,781 Charles Street,Boring,Oregon,97097,2005,455,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -42854,981 Vega Avenue,Boring,Oregon,97038,1886,244,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -30723,1341 Sullivan Street,Boring,Oregon,97087,1967,390,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -24014,1171 Day Avenue,Boring,Oregon,97068,1924,197,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -26842,1331 Davis Avenue,Boring,Oregon,97045,1887,178,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -56274,881 Romero Street,Boring,Oregon,97004,1976,542,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -73164,901 Sanchez Lane,Boring,Oregon,97093,1885,310,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -83282,651 Hoffman Avenue,Boring,Oregon,97028,2010,429,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -89299,831 Coleman Avenue,Boring,Oregon,97066,1964,90,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -26227,1121 Anderson Street,Boring,Oregon,97071,1999,294,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -55371,661 Mendez Lane,Boring,Oregon,97033,1912,57,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -09023,1171 Branch Street,Boring,Oregon,97077,1969,136,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -31946,601 Lee Avenue,Boring,Oregon,97034,1964,530,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -19173,1031 Farley Avenue,Boring,Oregon,97044,1959,262,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -11470,1201 Mcguire Boulevard,Boring,Oregon,97023,1931,68,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -39689,1061 Smith Street,Boring,Oregon,97030,2007,337,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -92313,651 Mann Loop,Boring,Oregon,97083,1942,409,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -45799,1281 Campbell Boulevard,Boring,Oregon,97025,2002,89,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -46906,1311 Hanson Avenue,Boring,Oregon,97030,1959,423,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -33903,741 Buck Road,Boring,Oregon,97099,1903,165,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -58464,601 Weaver Avenue,Boring,Oregon,97044,1904,253,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -05774,911 Holmes Road,Boring,Oregon,97026,1959,135,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -06236,1361 Lee Road,Boring,Oregon,97069,1885,525,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -69394,1281 Wilson Road,Boring,Oregon,97006,1995,366,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -34820,601 Lambert Road,Boring,Oregon,97082,2015,112,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -41908,871 Rodriguez Street,Boring,Oregon,97034,1974,382,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -09835,1291 Farmer Street,Boring,Oregon,97046,1904,515,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -15330,1181 Gonzalez Street,Boring,Oregon,97075,1937,81,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -21102,1241 Anderson Street,Boring,Oregon,97030,1958,425,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -88731,1151 Reyes Street,Boring,Oregon,97014,2005,188,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -18581,1221 Young Avenue,Boring,Oregon,97083,1971,472,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -02743,1351 Parker Loop,Boring,Oregon,97016,1988,289,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -35400,691 Ford Avenue,Boring,Oregon,97033,1929,334,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99431,631 Carson Street,Boring,Oregon,97017,1900,300,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -86057,1031 Clark Avenue,Boring,Oregon,97032,1976,371,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -21471,801 Jensen Street,Boring,Oregon,97032,1952,384,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -08299,1271 Meyer Avenue,Boring,Oregon,97038,1903,149,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -10431,631 Taylor Lane,Boring,Oregon,97030,1984,598,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -20331,1041 Morrow Street,Boring,Oregon,97000,1902,216,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -59601,1121 Kelley Street,Boring,Oregon,97010,1911,159,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -61131,791 Brady Street,Boring,Oregon,97031,1947,406,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -07922,1221 Cole Road,Boring,Oregon,97025,1908,471,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -77280,931 James Street,Boring,Oregon,97002,1917,55,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -94330,1261 Johnson Loop,Boring,Oregon,97082,1997,433,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -25378,1281 Moore Avenue,Boring,Oregon,97037,1922,88,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -86474,761 Brown Road,Boring,Oregon,97087,1985,190,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -86002,1251 Mccullough Street,Boring,Oregon,97015,1908,449,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -07692,1331 Stewart Road,Boring,Oregon,97037,1977,97,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -44137,611 Rodriguez Loop,Boring,Oregon,97088,1977,103,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -12871,1181 James Lane,Boring,Oregon,97099,1947,436,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -30261,671 Rodriguez Loop,Boring,Oregon,97024,1950,265,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -07911,761 Murillo Loop,Boring,Oregon,97070,1965,228,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -08657,1341 Moore Street,Boring,Oregon,97056,1994,477,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -85551,731 Vincent Avenue,Boring,Oregon,97053,1883,466,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -94613,1271 Brown Avenue,Boring,Oregon,97044,1976,123,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -84969,731 Velez Boulevard,Boring,Oregon,97029,1901,561,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -59225,1131 Hicks Street,Boring,Oregon,97012,1986,502,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -64808,761 Wagner Road,Boring,Oregon,97039,1890,155,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -55115,601 Turner Lane,Boring,Oregon,97034,1924,68,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -90168,1111 George Street,Boring,Oregon,97075,1939,194,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -78492,811 Johnson Street,Boring,Oregon,97070,1955,230,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -31299,1051 Jones Road,Boring,Oregon,97045,2011,151,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -23781,1331 Proctor Street,Boring,Oregon,97076,1939,55,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -45422,761 Dean Lane,Boring,Oregon,97045,1929,538,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -63250,1121 Hudson Lane,Boring,Oregon,97072,1924,445,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -17958,881 Mcintyre Street,Boring,Oregon,97035,1986,586,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -68857,1261 Garcia Street,Boring,Oregon,97071,1945,338,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -84343,1251 Ward Avenue,Boring,Oregon,97053,1965,67,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -06096,1031 Walker Boulevard,Boring,Oregon,97009,2004,562,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -41958,651 Miller Avenue,Boring,Oregon,97021,1951,221,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -69482,1331 Harris Street,Boring,Oregon,97023,1946,138,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -32333,631 Paul Street,Boring,Oregon,97096,1921,373,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -90495,1261 Haley Street,Boring,Oregon,97069,1884,124,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -44244,1281 Banks Boulevard,Boring,Oregon,97027,1985,314,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -18174,811 Turner Street,Boring,Oregon,97036,1926,231,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -61552,891 Nelson Avenue,Boring,Oregon,97042,2008,577,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -75454,1041 Anderson Boulevard,Boring,Oregon,97031,1901,496,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -28573,1131 Johnson Avenue,Boring,Oregon,97048,1977,573,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -85026,891 Thomas Street,Boring,Oregon,97047,1999,143,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -37616,1221 Jones Street,Boring,Oregon,97082,1939,585,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -61242,611 Navarro Lane,Boring,Oregon,97036,1983,367,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -05031,1031 Kim Avenue,Boring,Oregon,97098,1898,511,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -69482,611 Dickerson Avenue,Boring,Oregon,97068,2000,137,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -45528,931 Hernandez Road,Boring,Oregon,97051,1976,229,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -89854,651 Moreno Loop,Boring,Oregon,97061,1905,416,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -75909,1311 Palmer Boulevard,Boring,Oregon,97065,1892,126,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -27443,651 Stephens Street,Boring,Oregon,97021,1957,237,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -81126,621 Fields Avenue,Boring,Oregon,97038,1964,551,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -32291,1191 Simpson Avenue,Boring,Oregon,97057,1980,61,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -63511,1171 Gray Avenue,Boring,Oregon,97091,1991,76,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -67623,1051 Cain Street,Boring,Oregon,97028,1946,391,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -84997,881 Watson Lane,Boring,Oregon,97044,1903,474,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -34015,1031 Smith Street,Boring,Oregon,97056,1989,287,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -67068,961 Weaver Road,Boring,Oregon,97019,1941,346,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -41250,881 Everett Avenue,Boring,Oregon,97028,1932,370,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -05056,681 Krause Road,Boring,Oregon,97045,1984,187,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -21287,1281 Schaefer Lane,Boring,Oregon,97060,1882,433,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -97435,891 Martin Street,Boring,Oregon,97032,1971,301,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -61167,1111 Estrada Lane,Boring,Oregon,97099,1917,235,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -29502,1321 Arnold Road,Boring,Oregon,97073,1881,65,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -35771,1271 Riley Boulevard,Boring,Oregon,97018,2001,397,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -64305,951 Erickson Road,Boring,Oregon,97027,1979,180,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -30556,681 Bentley Avenue,Boring,Oregon,97004,1898,286,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -03638,741 Wright Street,Boring,Oregon,97084,2015,587,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -65605,901 Gonzalez Avenue,Boring,Oregon,97019,2005,306,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -36557,1261 Palmer Avenue,Boring,Oregon,97017,2007,546,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -84034,1181 Smith Lane,Boring,Oregon,97049,1887,71,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -06819,741 Carter Street,Boring,Oregon,97018,1919,561,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -16668,1061 Rivers Avenue,Boring,Oregon,97081,1895,579,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99168,881 Ortiz Street,Boring,Oregon,97079,1956,520,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -35527,681 Taylor Street,Boring,Oregon,97036,1898,220,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -01837,1341 Kelly Street,Boring,Oregon,97073,1977,410,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -38832,741 Hurley Avenue,Boring,Oregon,97024,1896,75,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -69701,1371 Campbell Street,Boring,Oregon,97046,1992,386,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -19223,1161 Pierce Street,Boring,Oregon,97002,1997,262,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -66247,981 Miller Road,Boring,Oregon,97034,1911,286,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -01090,1201 Anderson Avenue,Boring,Oregon,97003,1901,185,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -45322,861 Mitchell Avenue,Boring,Oregon,97039,1893,386,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -80704,1221 Blevins Road,Boring,Oregon,97065,1985,380,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -15989,601 Waters Road,Boring,Oregon,97099,1910,319,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99557,751 Ramos Boulevard,Boring,Oregon,97034,1987,250,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -89911,861 Vaughn Street,Boring,Oregon,97019,1888,63,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -92124,1341 Alexander Street,Boring,Oregon,97026,1919,531,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -64601,1081 Johnson Lane,Boring,Oregon,97040,1895,352,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -95745,1071 Johnson Avenue,Boring,Oregon,97014,1934,244,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -05467,651 Pittman Avenue,Boring,Oregon,97081,2011,536,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -61091,1251 Fisher Lane,Boring,Oregon,97012,1897,567,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -61123,1141 Mitchell Street,Boring,Oregon,97049,1976,117,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -55945,1231 Butler Loop,Boring,Oregon,97098,1881,312,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -26412,1061 Arnold Avenue,Boring,Oregon,97032,1957,129,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -09974,1231 Fowler Avenue,Boring,Oregon,97041,1917,459,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -77722,1001 Fischer Lane,Boring,Oregon,97068,1958,385,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -99500,771 Trevino Lane,Boring,Oregon,97034,1897,71,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -19290,1321 Holmes Street,Boring,Oregon,97032,1934,301,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -08823,701 Henry Avenue,Boring,Oregon,97071,1985,448,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -12542,661 Ortiz Loop,Boring,Oregon,97015,1921,75,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -07651,841 Baker Boulevard,Boring,Oregon,97037,1998,229,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -54664,1021 Gonzalez Avenue,Boring,Oregon,97015,1916,596,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -28860,771 Johnson Avenue,Boring,Oregon,97042,1912,523,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -57971,1211 Riley Street,Boring,Oregon,97094,1998,552,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -85014,1191 Macias Street,Boring,Oregon,97080,1983,571,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -16993,1221 Williams Avenue,Boring,Oregon,97019,1938,245,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -03069,861 Delacruz Street,Boring,Oregon,97063,1925,299,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -29195,1261 Taylor Avenue,Boring,Oregon,97009,1918,364,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -70635,1081 Weaver Avenue,Boring,Oregon,97052,1970,226,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -87873,1351 Wilson Street,Boring,Oregon,97008,1946,279,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -43970,681 Matthews Street,Boring,Oregon,97030,1931,442,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -18758,971 Morris Boulevard,Boring,Oregon,97000,2005,373,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -82808,661 Russell Avenue,Boring,Oregon,97028,1948,370,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -66604,611 Welch Avenue,Boring,Oregon,97034,2011,537,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -90521,831 Tucker Street,Boring,Oregon,97014,1889,430,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -17043,1401 White Street,Boring,Oregon,97039,2004,183,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -77800,1001 Krause Street,Boring,Oregon,97031,1911,325,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -62347,1121 Tate Road,Boring,Oregon,97042,2015,60,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -43858,961 Horne Avenue,Boring,Oregon,97085,1893,366,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -78212,651 Schneider Street,Boring,Oregon,97031,1887,371,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -93111,1201 Mcintosh Avenue,Boring,Oregon,97088,1944,267,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -78460,1401 Richardson Avenue,Boring,Oregon,97081,1992,556,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -80606,1321 Cain Lane,Boring,Oregon,97072,1965,405,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -10795,801 Williams Loop,Boring,Oregon,97088,2003,227,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -97832,1271 Nguyen Road,Boring,Oregon,97030,1950,62,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -69802,861 Walker Road,Boring,Oregon,97016,1914,386,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -04951,921 Hubbard Avenue,Boring,Oregon,97072,1953,292,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -88880,1191 Mckinney Street,Boring,Oregon,97010,1918,108,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -34686,741 Dunn Lane,Boring,Oregon,97095,1890,429,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -14686,861 Allen Street,Boring,Oregon,97065,1986,162,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -46699,1281 Castillo Street,Boring,Oregon,97085,2003,456,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -40303,611 Roberts Street,Boring,Oregon,97027,1940,472,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -94719,761 Richards Avenue,Boring,Oregon,97034,2003,166,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -66435,1261 Cobb Loop,Boring,Oregon,97053,1886,303,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -49507,1381 Lang Avenue,Boring,Oregon,97058,1981,98,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -56558,1361 Ramirez Street,Boring,Oregon,97049,1969,190,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -42483,841 Tran Avenue,Boring,Oregon,97016,1970,303,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -27632,791 Reynolds Street,Boring,Oregon,97056,1982,186,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -24514,1271 Jacobs Street,Boring,Oregon,97052,2000,180,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -95704,931 Forbes Avenue,Boring,Oregon,97042,1992,481,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -72128,981 Salazar Street,Boring,Oregon,97053,1892,61,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -07495,851 Wise Lane,Boring,Oregon,97033,1942,591,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -44465,1241 Mora Avenue,Boring,Oregon,97089,1982,368,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -41409,821 Ellis Lane,Boring,Oregon,97057,1893,370,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -09423,1111 Lloyd Road,Boring,Oregon,97001,1965,475,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -04908,1021 Young Street,Boring,Oregon,97034,1977,287,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 -20096,631 Drake Road,Boring,Oregon,97020,1972,527,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -85903,981 Roberts Lane,Boring,Oregon,97046,1974,71,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -60105,881 Banks Avenue,Boring,Oregon,97071,1970,488,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -04966,1111 Wilson Street,Boring,Oregon,97050,1956,112,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -40914,751 Chavez Road,Boring,Oregon,97095,1910,71,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -82159,1281 Sweeney Lane,Boring,Oregon,97023,1917,304,Russell Parrish Ltd,michael00@russell-parrish.com,08110738504,1261 Beard Avenue,"Christophermouth, WI",19853 -95681,631 Salinas Street,Boring,Oregon,97082,1985,86,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -70920,1011 Peterson Loop,Boring,Oregon,97016,1983,521,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -89694,941 Barnett Loop,Boring,Oregon,97075,1949,327,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -91490,1081 Swanson Loop,Boring,Oregon,97050,1951,121,Tucker and Sons,duartetracey@tucker.com,556.006.3148x627,641 Jones Avenue,"South Jessica, MT",60406 -81591,681 Rice Avenue,Boring,Oregon,97070,1955,384,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -54079,721 Robinson Avenue,Boring,Oregon,97032,2003,458,Hunt Ltd,ashleyjohnson@hunt.com,862.994.8898,1231 Roberts Street,"Spencerside, TX",75614 -52466,821 Martin Street,Boring,Oregon,97038,1908,382,Thompson Phillips LLC,troberts@thompson-phillips.info,(169)538-7880,691 Moran Loop,"Anthonyshire, IA",34479 -21981,871 Johnson Road,Boring,Oregon,97089,1986,441,Sanders Sanchez PLC,jerryball@sanders-sanchez.org,192.332.4246x60466,1251 Pierce Street,"Bryanland, PA",83877 diff --git a/seed/tests/test_analysis_pipelines.py b/seed/tests/test_analysis_pipelines.py index 5414e1c05f..3d87da2afd 100644 --- a/seed/tests/test_analysis_pipelines.py +++ b/seed/tests/test_analysis_pipelines.py @@ -1076,7 +1076,7 @@ def test_get_location(self): location, status = _get_location(self.property_view) self.assertEqual(status, "success") self.assertTrue(location is not None) - self.assertEqual(location, "730 Garcia Street, Boring, Oregon, 97080") + self.assertEqual(location, "1070 Hunt Street, Boring, Oregon, 97015") def test_get_data_for_census_tract_fetch(self): pvids = [self.property_view.id] @@ -1091,7 +1091,7 @@ def test_get_data_for_census_tract_fetch(self): "geocoding_confidence": None, "tract": None, "valid_coords": False, - "location": "730 Garcia Street, Boring, Oregon, 97080", + "location": "1070 Hunt Street, Boring, Oregon, 97015", } }, ) diff --git a/seed/tests/test_audit_template_configs.py b/seed/tests/test_audit_template_configs.py index e0e3eaa850..aa311b648b 100644 --- a/seed/tests/test_audit_template_configs.py +++ b/seed/tests/test_audit_template_configs.py @@ -57,10 +57,10 @@ def test_audit_template_config_create(self): assert data["update_at_hour"] == 23 assert data["update_at_minute"] == 59 - # testing one to one relationship + # testing one-to-one relationship response = self.client.post(url, params, content_type="application/json") assert response.status_code == 400 - assert response.json()["errors"] == {"organization": ["This field must be unique."]} + assert response.json()["errors"] == {"organization": ["audit template config with this organization already exists."]} def test_audit_template_config_update(self): # Invalid params diff --git a/seed/tests/test_element_views.py b/seed/tests/test_element_views.py index cfd4ec14f0..eeb7ed395c 100644 --- a/seed/tests/test_element_views.py +++ b/seed/tests/test_element_views.py @@ -195,7 +195,7 @@ def test_get_org_element_permissions(self): self.login_as_child_member() response = self.client.get(url) assert response.status_code == 404 - assert response.json() == {"detail": "Not found."} + assert response.json() == {"detail": "No Element matches the given query."} # root user can see element self.login_as_root_member() diff --git a/seed/tests/test_property_views.py b/seed/tests/test_property_views.py index 970c414262..85e5041a90 100644 --- a/seed/tests/test_property_views.py +++ b/seed/tests/test_property_views.py @@ -173,7 +173,7 @@ def test_create_property_in_diff_org(self): url = reverse("api:v3:properties-list") + f"?organization_id={org_2.pk}" response = self.client.post(url, params, content_type="application/json") self.assertEqual(response.status_code, 403) - self.assertEqual(response.json()["detail"], "You do not have permission to perform this action.") + self.assertEqual(response.json()["detail"], "Incorrect org id.") def test_create_property_with_protected_fields(self): state = self.property_state_factory.get_property_state() diff --git a/seed/views/properties.py b/seed/views/properties.py deleted file mode 100644 index a2c28a72a6..0000000000 --- a/seed/views/properties.py +++ /dev/null @@ -1,1295 +0,0 @@ -""" -SEED Platform (TM), Copyright (c) Alliance for Sustainable Energy, LLC, and other contributors. -See also https://github.com/SEED-platform/seed/blob/main/LICENSE.md -""" - -import contextlib -import json - -from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator -from django.http import JsonResponse -from rest_framework import status -from rest_framework.decorators import action -from rest_framework.renderers import JSONRenderer -from rest_framework.viewsets import ViewSet - -from seed.decorators import ajax_request_class -from seed.filtersets import PropertyStateFilterSet, PropertyViewFilterSet -from seed.lib.superperms.orgs.decorators import has_perm_class -from seed.lib.superperms.orgs.models import AccessLevelInstance, Organization -from seed.models import ( - AUDIT_USER_EDIT, - DATA_STATE_MATCHING, - MERGE_STATE_DELETE, - MERGE_STATE_MERGED, - MERGE_STATE_NEW, - VIEW_LIST, - VIEW_LIST_PROPERTY, - Column, - ColumnListProfile, - ColumnListProfileColumn, - Cycle, - Measure, - Meter, - Note, - PropertyAuditLog, - PropertyMeasure, - PropertyState, - PropertyView, - Simulation, - StatusLabel, - TaxLotProperty, - TaxLotView, -) -from seed.models import Property as PropertyModel -from seed.serializers.pint import PintJSONEncoder, add_pint_unit_suffix, apply_display_unit_preferences -from seed.serializers.properties import PropertySerializer, PropertyStateSerializer, PropertyViewAsStateSerializer, PropertyViewSerializer -from seed.serializers.taxlots import TaxLotViewSerializer -from seed.utils.api import ProfileIdMixin, api_endpoint_class -from seed.utils.match import match_merge_link -from seed.utils.merge import merge_properties -from seed.utils.properties import get_changed_fields, pair_unpair_property_taxlot, properties_across_cycles, update_result_with_master -from seed.utils.viewsets import SEEDOrgCreateUpdateModelViewSet, SEEDOrgModelViewSet - -# Global toggle that controls whether or not to display the raw extra -# data fields in the columns returned for the view. -DISPLAY_RAW_EXTRADATA = True -DISPLAY_RAW_EXTRADATA_TIME = True - - -class GBRPropertyViewSet(SEEDOrgCreateUpdateModelViewSet): - """Properties API Endpoint - - Returns:: - { - 'status': 'success', - 'properties': [ - { - 'id': Property primary key, - 'parent_property': dict of associated parent property - 'labels': list of associated label ids - } - ] - } - - - retrieve: - Return a Property instance by pk if it is within specified org. - - list: - Return all Properties available to user through specified org. - - create: - Create a new Property within user`s specified org. - - delete: - Remove an existing Property. - - update: - Update a Property record. - - partial_update: - Update one or more fields on an existing Property. - """ - - serializer_class = PropertySerializer - model = PropertyModel - data_name = "properties" - - -class PropertyStateViewSet(SEEDOrgCreateUpdateModelViewSet): - """Property State API Endpoint - - Returns:: - { - 'status': 'success', - 'properties': [ - { - all PropertyState fields/values - } - ] - } - - - retrieve: - Return a PropertyState instance by pk if it is within specified org. - - list: - Return all PropertyStates available to user through specified org. - - create: - Create a new PropertyState within user`s specified org. - - delete: - Remove an existing PropertyState. - - update: - Update a PropertyState record. - - partial_update: - Update one or more fields on an existing PropertyState.""" - - serializer_class = PropertyStateSerializer - model = PropertyState - filter_class = PropertyStateFilterSet - data_name = "properties" - - -class PropertyViewViewSet(SEEDOrgModelViewSet): - """PropertyViews API Endpoint - - Returns:: - { - 'status': 'success', - 'properties': [ - { - 'id': PropertyView primary key, - 'property_id': id of associated Property, - 'state': dict of associated PropertyState values (writeable), - 'cycle': dict of associated Cycle values, - 'certifications': dict of associated GreenAssessmentProperties values - } - ] - } - - - retrieve: - Return a PropertyView instance by pk if it is within specified org. - - list: - Return all PropertyViews available to user through specified org. - - create: - Create a new PropertyView within user`s specified org. - - delete: - Remove an existing PropertyView. - - update: - Update a PropertyView record. - - partial_update: - Update one or more fields on an existing PropertyView. - """ - - serializer_class = PropertyViewAsStateSerializer - model = PropertyView - filter_class = PropertyViewFilterSet - orgfilter = "property__organization_id" - data_name = "property_views" - queryset = PropertyView.objects.all() - - -class PropertyViewSet(ViewSet, ProfileIdMixin): - renderer_classes = (JSONRenderer,) - serializer_class = PropertySerializer - - def _get_filtered_results(self, request, profile_id): - page = request.query_params.get("page", 1) - per_page = request.query_params.get("per_page", 1) - org_id = request.query_params.get("organization_id", None) - cycle_id = request.query_params.get("cycle") - # check if there is a query parameter for the profile_id. If so, then use that one - profile_id = request.query_params.get("profile_id", profile_id) - - if not org_id: - return JsonResponse( - {"status": "error", "message": "Need to pass organization_id as query parameter"}, status=status.HTTP_400_BAD_REQUEST - ) - - if cycle_id: - cycle = Cycle.objects.get(organization_id=org_id, pk=cycle_id) - else: - cycle = Cycle.objects.filter(organization_id=org_id).order_by("name") - if cycle: - cycle = cycle.first() - else: - return JsonResponse( - {"status": "error", "message": "Could not locate cycle", "pagination": {"total": 0}, "cycle_id": None, "results": []} - ) - - # Return property views limited to the 'inventory_ids' list. Otherwise, if selected is empty, return all - if request.data.get("inventory_ids"): - property_views_list = ( - PropertyView.objects.select_related("property", "state", "cycle") - .filter(property_id__in=request.data["inventory_ids"], property__organization_id=org_id, cycle=cycle) - .order_by("id") - ) # TODO: test adding .only(*fields['PropertyState']) - else: - property_views_list = ( - PropertyView.objects.select_related("property", "state", "cycle") - .filter(property__organization_id=org_id, cycle=cycle) - .order_by("id") - ) # TODO: test adding .only(*fields['PropertyState']) - - paginator = Paginator(property_views_list, per_page) - - try: - property_views = paginator.page(page) - page = int(page) - except PageNotAnInteger: - property_views = paginator.page(1) - page = 1 - except EmptyPage: - property_views = paginator.page(paginator.num_pages) - page = paginator.num_pages - - org = Organization.objects.get(pk=org_id) - - # Retrieve all the columns that are in the db for this organization - columns_from_database = Column.retrieve_all(org_id, "property", False) - - # This uses an old method of returning the show_columns. There is a new method that - # is preferred in v2.1 API with the ProfileIdMixin. - if profile_id is None: - show_columns = None - elif profile_id == -1: - show_columns = list(Column.objects.filter(organization_id=org_id).values_list("id", flat=True)) - else: - try: - profile = ColumnListProfile.objects.get( - organization=org, id=profile_id, profile_location=VIEW_LIST, inventory_type=VIEW_LIST_PROPERTY - ) - show_columns = list( - ColumnListProfileColumn.objects.filter(column_list_profile_id=profile.id).values_list("column_id", flat=True) - ) - except ColumnListProfile.DoesNotExist: - show_columns = None - - related_results = TaxLotProperty.serialize(property_views, show_columns, columns_from_database) - - # collapse units here so we're only doing the last page; we're already a - # realized list by now and not a lazy queryset - unit_collapsed_results = [apply_display_unit_preferences(org, x) for x in related_results] - - response = { - "pagination": { - "page": page, - "start": paginator.page(page).start_index(), - "end": paginator.page(page).end_index(), - "num_pages": paginator.num_pages, - "has_next": paginator.page(page).has_next(), - "has_previous": paginator.page(page).has_previous(), - "total": paginator.count, - }, - "cycle_id": cycle.id, - "results": unit_collapsed_results, - } - - return JsonResponse(response) - - def _move_relationships(self, old_state, new_state): - """ - In general, we move the old relationships to the new state since the old state should not be - accessible anymore. If we ever unmerge, then we need to decide who gets the data.. both? - - :param old_state: PropertyState - :param new_state: PropertyState - :return: PropertyState, updated new_state - """ - for s in old_state.scenarios.all(): - s.property_state = new_state - s.save() - - # Move the measures to the new state - for m in PropertyMeasure.objects.filter(property_state=old_state): - m.property_state = new_state - m.save() - - # Move the old building file to the new state to preserve the history - for b in old_state.building_files.all(): - b.property_state = new_state - b.save() - - for s in Simulation.objects.filter(property_state=old_state): - s.property_state = new_state - s.save() - - return new_state - - @api_endpoint_class - @ajax_request_class - @has_perm_class("requires_viewer") - def list(self, request): - """ - List all the properties with all columns - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: cycle - description: The ID of the cycle to get properties - required: true - paramType: query - - name: page - description: The current page of properties to return - required: false - paramType: query - - name: per_page - description: The number of items per page to return - required: false - paramType: query - """ - return self._get_filtered_results(request, profile_id=-1) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("requires_viewer") - @action(detail=False, methods=["POST"]) - def cycles(self, request): - """ - List all the properties with all columns - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: profile_id - description: Either an id of a list settings profile, or undefined - paramType: body - - name: cycle_ids - description: The IDs of the cycle to get properties - required: true - paramType: query - """ - org_id = request.data.get("organization_id", None) - profile_id = request.data.get("profile_id", -1) - cycle_ids = request.data.get("cycle_ids", []) - - if not org_id: - return JsonResponse( - {"status": "error", "message": "Need to pass organization_id as query parameter"}, status=status.HTTP_400_BAD_REQUEST - ) - - root = AccessLevelInstance.objects.get(organization_id=org_id, depth=1) - response = properties_across_cycles(org_id, root, profile_id, cycle_ids) - - return JsonResponse(response) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("requires_viewer") - @action(detail=False, methods=["POST"]) - def filter(self, request): - """ - List all the properties - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: cycle - description: The ID of the cycle to get properties - required: true - paramType: query - - name: page - description: The current page of properties to return - required: false - paramType: query - - name: per_page - description: The number of items per page to return - required: false - paramType: query - - name: profile_id - description: Either an id of a list settings profile, or undefined - paramType: body - """ - if "profile_id" not in request.data or request.data["profile_id"] == "None": - profile_id = None - else: - profile_id = request.data["profile_id"] - - # ensure that profile_id is an int - with contextlib.suppress(TypeError): - profile_id = int(profile_id) - - return self._get_filtered_results(request, profile_id=profile_id) - - @api_endpoint_class - @ajax_request_class - @action(detail=False, methods=["POST"]) - def meters_exist(self, request): - """ - Check to see if the given Properties (given by ID) have Meters. - --- - parameters: - - name: inventory_ids - description: Array containing Property IDs. - paramType: body - """ - body = request.data - property_ids = body.get("inventory_ids", []) - - return Meter.objects.filter(property_id__in=property_ids).exists() - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=False, methods=["POST"]) - def merge(self, request): - """ - Merge multiple property records into a single new record, and run this - new record through a match and merge round within it's current Cycle. - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: state_ids - description: Array containing property state ids to merge - paramType: body - """ - body = request.data - - state_ids = body.get("state_ids", []) - organization_id = int(request.query_params.get("organization_id", None)) - - # Check the number of state_ids to merge - if len(state_ids) < 2: - return JsonResponse( - {"status": "error", "message": "At least two ids are necessary to merge"}, status=status.HTTP_400_BAD_REQUEST - ) - - merged_state = merge_properties(state_ids, organization_id, "Manual Match") - - merge_count, link_count, _view = match_merge_link(merged_state) - - result = {"status": "success"} - - result.update( - { - "match_merged_count": merge_count, - "match_link_count": link_count, - } - ) - - return result - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["POST"]) - def unmerge(self, request, pk=None): - """ - Unmerge a property view into two property views - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - try: - old_view = PropertyView.objects.select_related("property", "cycle", "state").get( - id=pk, property__organization_id=self.request.GET["organization_id"] - ) - except PropertyView.DoesNotExist: - return {"status": "error", "message": f"property view with id {pk} does not exist"} - - # Duplicate pairing - paired_view_ids = list( - TaxLotProperty.objects.filter(property_view_id=old_view.id).order_by("taxlot_view_id").values_list("taxlot_view_id", flat=True) - ) - - # Capture previous associated labels - label_ids = list(old_view.labels.all().values_list("id", flat=True)) - - notes = old_view.notes.all() - for note in notes: - note.property_view = None - - merged_state = old_view.state - if merged_state.data_state != DATA_STATE_MATCHING or merged_state.merge_state != MERGE_STATE_MERGED: - return {"status": "error", "message": f"property view with id {pk} is not a merged property view"} - - log = PropertyAuditLog.objects.select_related("parent_state1", "parent_state2").filter(state=merged_state).order_by("-id").first() - - if log.parent_state1 is None or log.parent_state2 is None: - return {"status": "error", "message": f"property view with id {pk} must have two parent states"} - - state1 = log.parent_state1 - state2 = log.parent_state2 - cycle_id = old_view.cycle_id - - # Clone the property record twice, then copy over meters - old_property = old_view.property - new_property = old_property - new_property.id = None - new_property.save() - - new_property_2 = PropertyModel.objects.get(pk=new_property.id) - new_property_2.id = None - new_property_2.save() - - PropertyModel.objects.get(pk=new_property.id).copy_meters(old_view.property_id) - PropertyModel.objects.get(pk=new_property_2.id).copy_meters(old_view.property_id) - - # If canonical Property is NOT associated to a different -View, delete it - if not PropertyView.objects.filter(property_id=old_view.property_id).exclude(id=old_view.id).exists(): - PropertyModel.objects.get(pk=old_view.property_id).delete() - - # Create the views - new_view1 = PropertyView(cycle_id=cycle_id, property_id=new_property.id, state=state1) - new_view2 = PropertyView(cycle_id=cycle_id, property_id=new_property_2.id, state=state2) - - # Mark the merged state as deleted - merged_state.merge_state = MERGE_STATE_DELETE - merged_state.save() - - # Change the merge_state of the individual states - if log.parent1.name in {"Import Creation", "Manual Edit"} and log.parent1.import_filename is not None: - # State belongs to a new record - state1.merge_state = MERGE_STATE_NEW - else: - state1.merge_state = MERGE_STATE_MERGED - if log.parent2.name in {"Import Creation", "Manual Edit"} and log.parent2.import_filename is not None: - # State belongs to a new record - state2.merge_state = MERGE_STATE_NEW - else: - state2.merge_state = MERGE_STATE_MERGED - # In most cases data_state will already be 3 (DATA_STATE_MATCHING), but if one of the parents was a - # de-duplicated record then data_state will be 0. This step ensures that the new states will be 3. - state1.data_state = DATA_STATE_MATCHING - state2.data_state = DATA_STATE_MATCHING - state1.save() - state2.save() - - # Delete the audit log entry for the merge - log.delete() - - old_view.delete() - new_view1.save() - new_view2.save() - - # Associate labels - label_objs = StatusLabel.objects.filter(pk__in=label_ids) - new_view1.labels.set(label_objs) - new_view2.labels.set(label_objs) - - # Duplicate notes to the new views - for note in notes: - created = note.created - updated = note.updated - note.id = None - note.property_view = new_view1 - note.save() - ids = [note.id] - note.id = None - note.property_view = new_view2 - note.save() - ids.append(note.id) - # Correct the created and updated times to match the original note - Note.objects.filter(id__in=ids).update(created=created, updated=updated) - - for paired_view_id in paired_view_ids: - TaxLotProperty(primary=True, cycle_id=cycle_id, property_view_id=new_view1.id, taxlot_view_id=paired_view_id).save() - TaxLotProperty(primary=True, cycle_id=cycle_id, property_view_id=new_view2.id, taxlot_view_id=paired_view_id).save() - - return {"status": "success", "view_id": new_view1.id} - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["POST"]) - def links(self, request, pk=None): - """ - Get property details for each linked property across org cycles - --- - parameters: - - name: pk - description: The primary key of the PropertyView - required: true - paramType: path - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - organization_id = request.data.get("organization_id", None) - base_view = PropertyView.objects.select_related("cycle").filter(pk=pk, cycle__organization_id=organization_id) - - if base_view.exists(): - result = {"data": []} - - # Grab extra_data columns to be shown in the results - all_extra_data_columns = Column.objects.filter( - organization_id=organization_id, is_extra_data=True, table_name="PropertyState" - ).values_list("column_name", flat=True) - - linked_views = ( - PropertyView.objects.select_related("cycle") - .filter(property_id=base_view.get().property_id, cycle__organization_id=organization_id) - .order_by("-cycle__start") - ) - for linked_view in linked_views: - state_data = PropertyStateSerializer(linked_view.state, all_extra_data_columns=all_extra_data_columns).data - - state_data["cycle_id"] = linked_view.cycle.id - state_data["view_id"] = linked_view.id - result["data"].append(state_data) - - return JsonResponse(result, encoder=PintJSONEncoder, status=status.HTTP_200_OK) - else: - result = {"status": "error", "message": f"property view with id {pk} does not exist in given organization"} - return JsonResponse(result) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["POST"]) - def match_merge_link(self, request, pk=None): - """ - Runs match merge link for an individual property. - - Note that this method can return a view_id of None if the given -View - was not involved in a merge. - """ - state = PropertyState.objects.get(pk=pk) - merge_count, link_count, view = match_merge_link(state) - - result = { - "view_id": view.id, - "match_merged_count": merge_count, - "match_link_count": link_count, - } - - return JsonResponse(result) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["PUT"]) - def pair(self, request, pk=None): - """ - Pair a taxlot to this property - --- - parameter_strategy: replace - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: taxlot_id - description: The taxlot id to pair up with this property - required: true - paramType: query - - name: pk - description: pk (property ID) - required: true - paramType: path - """ - # TODO: Call with PUT /api/v2/properties/1/pair/?taxlot_id=1&organization_id=1 - organization_id = int(request.query_params.get("organization_id")) - property_id = int(pk) - taxlot_id = int(request.query_params.get("taxlot_id")) - return pair_unpair_property_taxlot(property_id, taxlot_id, organization_id, True) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["PUT"]) - def unpair(self, request, pk=None): - """ - Unpair a taxlot from this property - --- - parameter_strategy: replace - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: taxlot_id - description: The taxlot id to unpair from this property - required: true - paramType: query - - name: pk - description: pk (property ID) - required: true - paramType: path - """ - # TODO: Call with PUT /api/v2/properties/1/unpair/?taxlot_id=1&organization_id=1 - organization_id = int(request.query_params.get("organization_id")) - property_id = int(pk) - taxlot_id = int(request.query_params.get("taxlot_id")) - return pair_unpair_property_taxlot(property_id, taxlot_id, organization_id, False) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("requires_viewer") - @action(detail=False, methods=["GET"]) - def columns(self, request): - """ - List all property columns - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: used_only - description: Determine whether or not to show only the used fields. Ones that have been mapped - type: boolean - required: false - paramType: query - """ - org_id = request.query_params.get("organization_id", None) - if not org_id: - return JsonResponse( - {"status": "error", "message": "Need to pass organization_id as query parameter"}, status=status.HTTP_400_BAD_REQUEST - ) - org_id = int(org_id) - - try: - Organization.objects.get(pk=org_id) - except Organization.DoesNotExist: - return JsonResponse( - {"status": "error", "message": "organization with id %s does not exist" % org_id}, status=status.HTTP_404_NOT_FOUND - ) - - only_used = json.loads(request.query_params.get("only_used", "false")) - columns = Column.retrieve_all(org_id, "property", only_used) - organization = Organization.objects.get(pk=org_id) - columns_with_units = [add_pint_unit_suffix(organization, x) for x in columns] - - return JsonResponse({"status": "success", "columns": columns_with_units}) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("requires_viewer") - @action(detail=False, methods=["GET"]) - def mappable_columns(self, request): - """ - List only property columns that are mappable - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - organization_id = int(request.query_params.get("organization_id")) - columns = Column.retrieve_mapping_columns(organization_id, "property") - - return JsonResponse({"status": "success", "columns": columns}) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["DELETE"]) - def delete(self, request, pk=None): - """ - Delete a single property state from a property_viewID. Not sure why we - are deleting only the state, but it is matching the functionality that is in - the batch_delete request. - --- - parameters: - - name: pk - description: Primary key to delete - require: true - """ - num_objs, del_items = PropertyView.objects.filter(state__id=int(pk)).delete() - if num_objs > 0: - return JsonResponse({"status": "success", "message": del_items}) - else: - return JsonResponse({"status": "error", "message": "No PropertyStates removed"}, status=status.HTTP_400_BAD_REQUEST) - - @api_endpoint_class - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=False, methods=["DELETE"]) - def batch_delete(self, request): - """ - Batch delete several properties - --- - parameters: - - name: selected - description: A list of property ids to delete - many: true - required: true - """ - property_states = request.data.get("selected", []) - resp = PropertyState.objects.filter(pk__in=property_states).delete() - - if resp[0] == 0: - return JsonResponse({"status": "warning", "message": "No action was taken"}) - - return JsonResponse({"status": "success", "properties": resp[1]["seed.PropertyState"]}) - - def _get_property_view(self, pk): - """ - Return the property view - - :param pk: id, The property view ID - :param cycle_pk: cycle - :return: - """ - try: - property_view = PropertyView.objects.select_related("property", "cycle", "state").get( - id=pk, property__organization_id=self.request.GET["organization_id"] - ) - result = {"status": "success", "property_view": property_view} - except PropertyView.DoesNotExist: - result = {"status": "error", "message": f"property view with id {pk} does not exist"} - return result - - def _get_taxlots(self, pk): - lot_view_pks = TaxLotProperty.objects.filter(property_view_id=pk).values_list("taxlot_view_id", flat=True) - lot_views = TaxLotView.objects.filter(pk__in=lot_view_pks).select_related("cycle", "state").prefetch_related("labels") - lots = [] - for lot in lot_views: - lots.append(TaxLotViewSerializer(lot).data) - return lots - - @api_endpoint_class - @ajax_request_class - @action(detail=True, methods=["GET"]) - def taxlots(self, pk): - """ - Get related TaxLots for this property - """ - return JsonResponse(self._get_taxlots(pk)) - - def get_history(self, property_view): - """Return history in reverse order""" - - # access the history from the property state - history, master = property_view.state.history() - - # convert the history and master states to StateSerializers - master["state"] = PropertyStateSerializer(master["state_data"]).data - del master["state_data"] - del master["state_id"] - - for h in history: - h["state"] = PropertyStateSerializer(h["state_data"]).data - del h["state_data"] - del h["state_id"] - - return history, master - - @api_endpoint_class - @ajax_request_class - def retrieve(self, request, pk=None): - """ - Get property details - --- - parameters: - - name: pk - description: The primary key of the PropertyView - required: true - paramType: path - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - result = self._get_property_view(pk) - if result.get("status", None) != "error": - property_view = result.pop("property_view") - result = {"status": "success"} - result.update(PropertyViewSerializer(property_view).data) - # remove PropertyView id from result - result.pop("id") - - # Grab extra_data columns to be shown in the result - organization_id = request.query_params["organization_id"] - all_extra_data_columns = Column.objects.filter( - organization_id=organization_id, is_extra_data=True, table_name="PropertyState" - ).values_list("column_name", flat=True) - - result["state"] = PropertyStateSerializer(property_view.state, all_extra_data_columns=all_extra_data_columns).data - result["taxlots"] = self._get_taxlots(property_view.pk) - result["history"], master = self.get_history(property_view) - result = update_result_with_master(result, master) - return JsonResponse(result, encoder=PintJSONEncoder, status=status.HTTP_200_OK) - else: - return JsonResponse(result, status=status.HTTP_404_NOT_FOUND) - - @api_endpoint_class - @ajax_request_class - def update(self, request, pk=None): - """ - Update a property and run the updated record through a match and merge - round within it's current Cycle. - - - looks up the property view - - casts it as a PropertyState - - builds a hash with all the same keys as the original property state - - checks if any fields have changed - - if nothing has changed, return 422 - Really? Not sure how I feel about that one, it *is* processable - - get the property audit log for this property state - - if the new property state has extra_data, the original extra_data is updated - - and then whoa stuff about the audit log? - - I'm going to assume 'Import Creation' is the key I'm looking for - - create a serializer for the new property state - - if it's valid, save this new serialized data to the db - - assign it to the original property view and save the property view - - create a new property audit log for this change - - return a 200 if created - - --- - parameters: - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - data = request.data - - result = self._get_property_view(pk) - if result.get("status", None) != "error": - property_view = result.pop("property_view") - property_state_data = PropertyStateSerializer(property_view.state).data - - # get the property state information from the request - new_property_state_data = data["state"] - - # set empty strings to None - for key, val in new_property_state_data.items(): - if val == "": - new_property_state_data[key] = None - - changed_fields, previous_data = get_changed_fields(property_state_data, new_property_state_data) - if not changed_fields: - result.update({"status": "success", "message": "Records are identical"}) - return JsonResponse(result, status=status.HTTP_204_NO_CONTENT) - else: - # Not sure why we are going through the pain of logging this all right now... need to - # reevaluate this. - log = PropertyAuditLog.objects.select_related().filter(state=property_view.state).order_by("-id").first() - - # if checks above pass, create an exact copy of the current state for historical purposes - if log.name == "Import Creation": - # Add new state by removing the existing ID. - property_state_data.pop("id") - # Remove the import_file_id for the first edit of a new record - # If the import file has been deleted and this value remains the serializer won't be valid - property_state_data.pop("import_file") - new_property_state_serializer = PropertyStateSerializer(data=property_state_data) - if new_property_state_serializer.is_valid(): - # create the new property state, and perform an initial save / moving relationships - new_state = new_property_state_serializer.save() - - # Since we are creating a new relationship when we are manually editing the Properties, then - # we need to move the relationships over to the new manually edited record. - new_state = self._move_relationships(property_view.state, new_state) - new_state.save() - - # then assign this state to the property view and save the whole view - property_view.state = new_state - property_view.save() - - PropertyAuditLog.objects.create( - organization=log.organization, - parent1=log, - parent2=None, - parent_state1=log.state, - parent_state2=None, - state=new_state, - name="Manual Edit", - description=None, - import_filename=log.import_filename, - record_type=AUDIT_USER_EDIT, - ) - - result.update({"state": new_property_state_serializer.data}) - - # save the property view so that the datetime gets updated on the property. - property_view.save() - else: - result.update( - {"status": "error", "message": f"Invalid update data with errors: {new_property_state_serializer.errors}"} - ) - return JsonResponse(result, encoder=PintJSONEncoder, status=status.HTTP_422_UNPROCESSABLE_ENTITY) - - # redo assignment of this variable in case this was an initial edit - property_state_data = PropertyStateSerializer(property_view.state).data - - if "extra_data" in new_property_state_data: - property_state_data["extra_data"].update(new_property_state_data["extra_data"]) - - property_state_data.update({k: v for k, v in new_property_state_data.items() if k != "extra_data"}) - - log = PropertyAuditLog.objects.select_related().filter(state=property_view.state).order_by("-id").first() - - if log.name in {"Manual Edit", "Manual Match", "System Match", "Merge current state in migration"}: - # Convert this to using the serializer to save the data. This will override the previous values - # in the state object. - - # Note: We should be able to use partial update here and pass in the changed fields instead of the - # entire state_data. - updated_property_state_serializer = PropertyStateSerializer(property_view.state, data=property_state_data) - if updated_property_state_serializer.is_valid(): - # create the new property state, and perform an initial save / moving - # relationships - updated_property_state_serializer.save() - - result.update({"state": updated_property_state_serializer.data}) - - # save the property view so that the datetime gets updated on the property. - property_view.save() - - Note.create_from_edit(request.user.id, property_view, new_property_state_data, previous_data) - - merge_count, link_count, view = match_merge_link(property_view.state) - - result.update( - { - "view_id": view.id, - "match_merged_count": merge_count, - "match_link_count": link_count, - } - ) - - return JsonResponse(result, encoder=PintJSONEncoder, status=status.HTTP_200_OK) - else: - result.update( - {"status": "error", "message": f"Invalid update data with errors: {updated_property_state_serializer.errors}"} - ) - return JsonResponse(result, encoder=PintJSONEncoder, status=status.HTTP_422_UNPROCESSABLE_ENTITY) - else: - result = {"status": "error", "message": "Unrecognized audit log name: " + log.name} - return JsonResponse(result, status=status.HTTP_422_UNPROCESSABLE_ENTITY) - else: - return JsonResponse(result, status=status.HTTP_404_NOT_FOUND) - - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["PUT"], url_path="update_measures") - def add_measures(self, request, pk=None): - """ - Update the measures applied to the building. There are two options, one for adding - measures and one for removing measures. - - --- - type: - status: - required: true - type: string - message: - required: true - type: object - added_measure_ids: - required: true - type: array - description: list of measure ids that were added to the property - removed_measure_ids: - required: true - type: array - description: list of measure ids that were removed from the property - existing_measure_ids: - required: true - type: array - description: list of measure ids that already existed for the property - parameters: - - name: cycle_id - description: The cycle id for filtering the property view - required: true - paramType: query - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: add_measures - description: list of measure_ids or measure long names to add to property - type: array - required: false - paramType: form - - name: remove_measures - description: list of measure_ids or measure long names to remove from property - type: array - required: false - paramType: form - - name: implementation_status - description: Enum on type of measures. Recommended, Proposed, Implemented - required: true - paramType: form - type: string - enum: ["Recommended", "Proposed", "Implemented"] - """ - cycle_pk = request.query_params.get("cycle_id", None) - if not cycle_pk: - return JsonResponse({"status": "error", "message": "Must pass cycle_id as query parameter"}) - - implementation_status = PropertyMeasure.str_to_impl_status(request.data.get("implementation_status", None)) - if not implementation_status: - return JsonResponse({"status": "error", "message": "None or invalid implementation_status type"}) - - result = self._get_property_view(pk) - pv = None - if result.get("status", None) != "error": - pv = result.pop("property_view") - else: - return JsonResponse(result) - - # get the list of measures to add/remove and return the ids - add_measure_ids = Measure.validate_measures(request.data.get("add_measures", []).split(",")) - remove_measure_ids = Measure.validate_measures(request.data.get("remove_measures", []).split(",")) - - # add_measures = request.data - message_add = [] - message_remove = [] - message_existed = [] - - property_state_id = pv.state.pk - - for m in add_measure_ids: - _join, created = PropertyMeasure.objects.get_or_create( - property_state_id=property_state_id, measure_id=m, implementation_status=implementation_status - ) - if created: - message_add.append(m) - else: - message_existed.append(m) - - for m in remove_measure_ids: - qs = PropertyMeasure.objects.filter( - property_state_id=property_state_id, measure_id=m, implementation_status=implementation_status - ) - if qs.exists(): - qs.delete() - message_remove.append(m) - - return JsonResponse( - { - "status": "success", - "message": "Updated measures for property state", - "added_measure_ids": message_add, - "removed_measure_ids": message_remove, - "existing_measure_ids": message_existed, - } - ) - - # TODO: fix the url_path to be nested. I want the url_path to be measures and have get,post,put - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["DELETE"], url_path="delete_measures") - def delete_measures(self, request, pk=None): - """ - Delete measures. Allow the user to define which implementation type to delete - --- - type: - status: - required: true - type: string - message: - required: true - type: string - parameters: - - name: cycle_id - description: The cycle id for filtering the property view - required: true - paramType: query - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - - name: implementation_status - description: Enum on type of measures. Recommended, Proposed, Implemented - required: false - paramType: form - type: string - enum: ["Recommended", "Proposed", "Implemented"] - """ - cycle_pk = request.query_params.get("cycle_id", None) - if not cycle_pk: - return JsonResponse({"status": "error", "message": "Must pass cycle_id as query parameter"}) - - impl_status = request.data.get("implementation_status", None) - if not impl_status: - impl_status = [PropertyMeasure.RECOMMENDED, PropertyMeasure.IMPLEMENTED, PropertyMeasure.PROPOSED] - else: - impl_status = [PropertyMeasure.str_to_impl_status(impl_status)] - - result = self._get_property_view(pk) - pv = None - if result.get("status", None) != "error": - pv = result.pop("property_view") - else: - return JsonResponse(result) - - property_state_id = pv.state.pk - del_count, _ = PropertyMeasure.objects.filter( - property_state_id=property_state_id, - implementation_status__in=impl_status, - ).delete() - - return JsonResponse({"status": "status", "message": f"Deleted {del_count} measures"}) - - # TODO: fix the url_path to be nested. I want the url_path to be measures and have get,post,put - @ajax_request_class - @has_perm_class("can_modify_data") - @action(detail=True, methods=["GET"], url_path="measures") - def get_measures(self, request, pk=None): - """ - Get the list of measures for a property and the given cycle - --- - type: - status: - required: true - type: string - message: - required: true - type: object - measures: - required: true - type: object - description: list of measure objects for the property - parameters: - - name: cycle_id - description: The cycle id for filtering the property view - required: true - paramType: query - - name: organization_id - description: The organization_id for this user's organization - required: true - paramType: query - """ - cycle_pk = request.query_params.get("cycle_id", None) - if not cycle_pk: - return JsonResponse({"status": "error", "message": "Must pass cycle_id as query parameter"}) - - result = self._get_property_view(pk) - if result.get("status", None) != "error": - pv = result.pop("property_view") - property_state_id = pv.state.pk - join = PropertyMeasure.objects.filter(property_state_id=property_state_id).select_related("measure") - result = [] - for j in join: - result.append( - { - "implementation_type": j.get_implementation_status_display(), - "category": j.measure.category, - "category_display_name": j.measure.category_display_name, - "name": j.measure.name, - "display_name": j.measure.display_name, - "unique_name": f"{j.measure.category}.{j.measure.name}", - "pk": j.measure.id, - } - ) - - return JsonResponse( - { - "status": "success", - "message": f"Found {len(result)} measures", - "measures": result, - } - ) - else: - return JsonResponse(result) - - -def diffupdate(old, new): - """Returns lists of fields changed""" - changed_fields = [] - changed_extra_data = [] - for k, v in new.items(): - if old.get(k, None) != v or k not in old: - changed_fields.append(k) - if "extra_data" in changed_fields: - changed_fields.remove("extra_data") - changed_extra_data, _ = diffupdate(old["extra_data"], new["extra_data"]) - return changed_fields, changed_extra_data diff --git a/seed/views/v3/green_assessment_properties.py b/seed/views/v3/green_assessment_properties.py index f6cd4983de..6a2d247716 100644 --- a/seed/views/v3/green_assessment_properties.py +++ b/seed/views/v3/green_assessment_properties.py @@ -92,7 +92,7 @@ class GreenAssessmentPropertyViewSet(SEEDOrgModelViewSet): serializer_class = GreenAssessmentPropertySerializer model = GreenAssessmentProperty orgfilter = "assessment__organization_id" - filter_class = GAPropertyFilterSet + filterset_class = GAPropertyFilterSet @action(detail=True, methods=["get"]) @has_perm_class("requires_root_member_access") diff --git a/seed/views/v3/green_assessment_urls.py b/seed/views/v3/green_assessment_urls.py index da43fa73e4..90cae8e96e 100644 --- a/seed/views/v3/green_assessment_urls.py +++ b/seed/views/v3/green_assessment_urls.py @@ -135,4 +135,4 @@ class GreenAssessmentURLViewSet(SEEDOrgModelViewSet): serializer_class = GreenAssessmentURLSerializer model = GreenAssessmentURL orgfilter = "property_assessment__assessment__organization_id" - filter_fields = ("property_assessment__id",) + filterset_fields = ("property_assessment__id",) diff --git a/seed/views/v3/green_assessments.py b/seed/views/v3/green_assessments.py index 1a11e8bb47..a5d899fcf1 100644 --- a/seed/views/v3/green_assessments.py +++ b/seed/views/v3/green_assessments.py @@ -181,4 +181,4 @@ class GreenAssessmentViewSet(SEEDOrgCreateUpdateModelViewSet): serializer_class = GreenAssessmentSerializer model = GreenAssessment - filter_class = GreenAssessmentFilterSet + filterset_class = GreenAssessmentFilterSet diff --git a/seed/views/v3/property_views.py b/seed/views/v3/property_views.py index 0175526f4f..b0b4f7b16f 100644 --- a/seed/views/v3/property_views.py +++ b/seed/views/v3/property_views.py @@ -89,7 +89,7 @@ def get_queryset(self): serializer_class = BriefPropertyViewSerializer pagination_class = None model = PropertyView - filter_class = PropertyViewFilterSet + filterset_class = PropertyViewFilterSet orgfilter = "property__organization_id" data_name = "property_views" queryset = PropertyView.objects.all() diff --git a/seed/views/v3/sensors.py b/seed/views/v3/sensors.py index b40240f3f9..7434cd4678 100644 --- a/seed/views/v3/sensors.py +++ b/seed/views/v3/sensors.py @@ -13,6 +13,9 @@ class SensorViewSet(generics.GenericAPIView, viewsets.ViewSet, OrgMixin, ProfileIdMixin): + # For the Swagger page, GenericAPIView asserts a value exists for `queryset` + queryset = Sensor.objects.none() + @ajax_request_class @has_perm_class("requires_member") @has_hierarchy_access(property_view_id_kwarg="property_pk") diff --git a/seed/views/v3/tax_lot_properties.py b/seed/views/v3/tax_lot_properties.py index 7d38e09f3c..2a7f5f0f65 100644 --- a/seed/views/v3/tax_lot_properties.py +++ b/seed/views/v3/tax_lot_properties.py @@ -46,6 +46,8 @@ class TaxLotPropertyViewSet(GenericViewSet, OrgMixin): viewset for any tax lot / property join API call. """ + # For the Swagger page, GenericViewSet asserts a value exists for `queryset` + queryset = TaxLotProperty.objects.none() renderer_classes = (JSONRenderer,) serializer_class = TaxLotPropertySerializer diff --git a/tox.ini b/tox.ini index 08c7063831..9b66bc257f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,106 +1,74 @@ [tox] -envlist= - python, - precommit, - docs, - functional, - apitest, - lint, - lint-fix -skipsdist=True +env_list = + python + precommit + docs + functional + apitest + lint +no_package = True + +[testenv] +deps = -r requirements/test.txt [testenv:python] -deps= - -r{toxinidir}/requirements/test.txt -commands= - ./manage.py flush --noinput +commands = + python manage.py flush_db coverage run manage.py test coveralls -passenv= +pass_env = + DISPLAY DJANGO_LOG_LEVEL DJANGO_SETTINGS_MODULE - DISPLAY - SEED_PM_UN SEED_PM_PW - TRAVIS - TRAVIS_JOB_ID - TRAVIS_BRANCH + SEED_PM_UN TESTING_MAPQUEST_API_KEY -whitelist_externals= - cp +allowlist_externals = python [testenv:precommit] -basepython=python -deps= - -r{toxinidir}/requirements/test.txt -commands= - pre-commit run --all-files {posargs} +commands = pre-commit run --all-files {posargs} [testenv:docs] -changedir=docs -deps= - -r{toxinidir}/requirements/test.txt -commands= +change_dir = docs +commands = # After we fix doc build links/issues, then add the -W flag - ; make spelling SPHINXOPTS='-W --keep-going' - make spelling - sphinx-build -b html -d {envtmpdir}/doctrees {toxinidir}/docs/source {envtmpdir}/html -whitelist_externals= - make - cp + # make spelling SPHINXOPTS='-W --keep-going' + sphinx-build -M spelling source build + sphinx-build -b html -d {envtmpdir}/doctrees source {envtmpdir}/html [testenv:mypy] -basepython=python -deps= - mypy == 1.0.0 -commands=mypy --install-types --non-interactive --show-error-codes {toxinidir} +deps = mypy +commands = mypy --install-types --non-interactive --show-error-codes . [testenv:functional] -commands= - ./manage.py flush --noinput +deps = +commands = npm install npm test -deps= - -r{toxinidir}/requirements/test.txt -passenv= - DJANGO_SETTINGS_MODULE - DISPLAY - COVERALLS_REPO_TOKEN - TRAVIS - SAUCE_USERNAME - SAUCE_ACCESS_KEY - TRAVIS_JOB_NUMBER - TRAVIS_BUILD_NUMBER - MAPQUEST_API_KEY -whitelist_externals= - cp - npm +pass_env = DISPLAY +allowlist_externals = npm [testenv:apitest] -setenv= - CELERY_ALWAYS_EAGER = false - ; when running the API tests make sure to not use always eager -commands= - {toxinidir}/bin/apitest_start_server.sh - python {toxinidir}/seed/tests/api/test_seed_host_api.py --noinput --nofile -deps= - -r{toxinidir}/requirements/test.txt -passenv= - DJANGO_SETTINGS_MODULE -whitelist_externals= - cp +# when running the API tests make sure to not use always eager +setenv = CELERY_ALWAYS_EAGER=false +commands = + sh ./bin/apitest_start_server.sh + python seed/tests/api/test_seed_host_api.py --noinput --nofile +pass_env = DJANGO_SETTINGS_MODULE +allowlist_externals = python + sh [testenv:lint] -commands= - npm install --ignore-scripts +deps = +commands = + npm install npm run lint -whitelist_externals= - npm +allowlist_externals = npm [testenv:lint-fix] -commands= - npm install --ignore-scripts +deps = +commands = + npm install npm run lint:fix -whitelist_externals= - npm +allowlist_externals = npm