Repository: slacgismo/solar-data-tools (language: python)

Issue:
handle NaN values in energy COM calculation



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ab6e030a..b74c6540 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -18,13 +18,13 @@ jobs:
         with:
           python-version: "3.10"
 
-      - name: Install Twine
-        run: sudo pip install twine
+      - name: Install Twine and Build
+        run: sudo pip install twine build
 
       - name: Create the distribution
         run: |
           git fetch --prune --unshallow --tags
-          sudo python setup.py sdist bdist_wheel
+          sudo python3 -m build
 
       - name: Publish package distributions to PyPI
         uses: pypa/gh-action-pypi-publish@release/v1
@@ -55,7 +55,7 @@ jobs:
       - name: Install the Conda Dependencies
         run: |
           conda config --set always_yes yes --set auto_update_conda false
-          conda install conda=24.1.2
+          conda update conda
           conda install -n base conda-libmamba-solver
           conda install python=3.10 conda-build colorama pip ruamel ruamel.yaml rich jsonschema -c conda-forge
           git fetch --prune --unshallow --tags
@@ -71,7 +71,7 @@ jobs:
           conda install anaconda-client
           conda config --set anaconda_upload no --set solver libmamba
           echo yes | anaconda login --username ${{ secrets.ANACONDA_CLOUD_USERNAME }} --password ${{ secrets.ANACONDA_CLOUD_PASSWORD }}
-          VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-) conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge --numpy 1.22.0
+          VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-) conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp          
           echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT
 
       - name: Upload the Anaconda Package
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..99f67f4a
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,132 @@
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+  community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+  any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+  without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official email address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at bennetm@stanford.edu or smiskov@slac.stanford.edu.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
+[https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
\ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 16a0b3e7..00000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,1 +0,0 @@
-include solardatatools/fixtures/*
\ No newline at end of file
diff --git a/README.md b/README.md
index 7a9dfff7..0ab19f81 100644
--- a/README.md
+++ b/README.md
@@ -91,48 +91,43 @@ See [notebooks](/notebooks) folder for examples.
 
 ## Install & Setup
 
-### 3 ways of setting up, either approach works:
+#### Recommended: Install with pip
 
-#### 1) Recommended: Install with pip
+In a fresh Python virtual environment, simply run:
 
-In a fresh Python virtual environment, simply run
+```bash
+$ pip install solar-data-tools
+```
 
+or if you would like to use MOSEK, install the optional dependency as well:
 
 ```bash
-$ pip install solar-data-tools
+$ pip install "solar-data-tools[mosek]"
 ```
 
-#### 2) Creat conda virtual environment from file
+#### Install with conda
 
-Creating the env:
+Creating the environment and directly installing the package and its dependencies:
 
 ```bash
-$ conda env create -f pvi-user.yml
+$ conda create -n pvi-user-conda slacgismo::solar-data-tools
 ```
 
-Starting the env:
+Starting the environment:
 
 ```bash
 $ conda activate pvi_user
 ```
 
-Stopping the env
+Stopping the environment:
 
 ```bash
 $ conda deactivate
 ```
 
-Updating the env with latest
+Or alternatively install the package in an already existing environment:
 
 ```bash
-$ conda env update -f pvi-user.yml
-```
-
-Additional documentation on setting up the Conda environment is available [here](https://github.com/slacgismo/pvinsight-onboarding/blob/main/README.md).
-
-#### 3) General Anaconda Package
-
-```sh
 $ conda install slacgismo::solar-data-tools
 ```
 
@@ -144,7 +139,9 @@ By default, [QSS](https://github.com/cvxgrp/qss) and CLARABEL solvers are used f
 
 #### MOSEK
 
-MOSEK is a commercial software package. It is more stable and offers faster solve times. The included YAML/requirements.txt file will install MOSEK for you, but you will still need to obtain a license. More information is available here:
+MOSEK is a commercial software package. Since it is more stable and offers faster solve times, we provide continuing support for it, however you will still need to obtain a license. If installing with pip, you can install the optional MOSEK dependency by running `pip install "solar-data-tools[mosek]"`. If installing from conda, you will have to manually install MOSEK if you desire to use it as conda does not support optional dependencies like pip. 
+
+More information about MOSEK and how to obtain a license is available here:
 
 * [mosek](https://www.mosek.com/resources/getting-started/)
 * [Free 30-day trial](https://www.mosek.com/products/trial/)
@@ -209,7 +206,3 @@ We use [Semantic Versioning](http://semver.org/) for versioning. For the version
 * **Bennet Meyers** - *Initial work and Main research work* - [Bennet Meyers GitHub](https://github.com/bmeyers)
 
 See also the list of [contributors](https://github.com/bmeyers/solar-data-tools/contributors) who participated in this project.
-
-## License
-
-This project is licensed under the BSD 2-Clause License - see the [LICENSE](LICENSE) file for details
diff --git a/conda_recipe/meta.yaml b/conda_recipe/meta.yaml
index fcb7ae2a..06ef92b0 100644
--- a/conda_recipe/meta.yaml
+++ b/conda_recipe/meta.yaml
@@ -5,60 +5,58 @@ package:
   version: {{ environ.get('VERSION_FROM_GIT_TAG') }}
 
 source:
-  git_url: https://github.com/slacgismo/solar-data-tools
+  # git_url: https://github.com/slacgismo/solar-data-tools
+  path: .. # checked out repo instead of main repo branch
 
 build:
   noarch: python
   number: 0
-  script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "
+  script: {{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv
 
 requirements:
-  build:
-    - cmake
-
   host:
     - pip
     - python
+  run:
+    - pip
+    - python
     - scipy
-    - numpy >=1.22
+    - numpy
     - pandas
-    - seaborn
-    - requests
     - scikit-learn
     - jupyter
     - matplotlib
-    - pvlib
-    - cvxpy>=1.1.0
-    - pykml
-    - haversine
-    - boto3
-    - Mosek
-    - clarabel
-
-  run:
-    - scipy
-    - numpy >=1.22
-    - pandas
     - seaborn
     - requests
-    - scikit-learn
     - pvlib
     - cvxpy
-    - python
+    - pykml
+    - haversine
+    - smart_open
+    - sig-decomp
     - clarabel
+    - qss
+    - tqdm
+    - spcqe
+
+test:
+  imports:
+    - solardatatools
+  commands:
+    - pip check
+  requires:
+    - pip
 
 about:
-  home: https://github.com/bmeyers/solar-data-tools
-  license: BSD
+  home: https://github.com/slacgismo/solar-data-tools
+  license: BSD-2-Clause
+  license_file: LICENSE
   license_family: BSD
-  license_file:
   summary: Tools for performing common tasks on solar PV data signals
-  doc_url:
-  dev_url:
+  doc_url: https://solar-data-tools.readthedocs.io/
 
 extra:
   recipe-maintainers:
     - bmeyers
-    - derins
     - thistleman
-    - alejandro350
+    - pluflou
diff --git a/pvi-user.yml b/pvi-user.yml
deleted file mode 100644
index 42dca5df..00000000
--- a/pvi-user.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-# conda env create -f pvi-user.yml
-name: pvi-user
-channels:
-  - anaconda
-  - conda-forge
-  - defaults
-  - stanfordcvxgrp
-  - slacgismo
-  - mosek
-dependencies:
-  - python=3.10
-  - scipy>=1.11
-  - numpy>=1.22.0
-  - pandas
-  - scikit-learn
-  - jupyter
-  - ipython
-  - matplotlib
-  - seaborn
-  - requests
-  - pvlib
-  - cvxpy>=1.1.0
-  - cmake
-  - pykml
-  - haversine
-  - boto3
-  - qss
-  - sig-decomp
-  - mosek
-  - s3fs
-  - cassandra-driver
-  - openblas
-  - smart_open
-  - solar-data-tools
-  - pv-system-profiler
-  - statistical-clear-sky
-
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 00000000..710a5dd8
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,77 @@
+[build-system]
+requires = ["setuptools>=64.0", "setuptools-scm[toml]"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "solar-data-tools"
+description = "Tools for performing common tasks on solar PV data signals"
+readme = "README.md"
+license.file = "LICENSE"
+authors = [
+  { name = "Bennet Meyers", email = "bennetm@stanford.edu" },
+]
+maintainers = [
+  { name = "Sara Miskovich", email = "smiskov@slac.stanford.edu" },
+]
+keywords = ["solar", "pv", "photovoltaic"]
+requires-python = ">=3.6"
+
+dependencies = [
+    "scipy",
+    "numpy",
+    "pandas",
+    "scikit-learn",
+    "jupyter",
+    "matplotlib",
+    "seaborn",
+    "requests",
+    "pvlib",
+    "cvxpy",
+    "pykml",
+    "haversine",
+    "smart_open",
+    "sig-decomp",
+    "clarabel",
+    "qss",
+    "tqdm",
+    "spcqe"
+]
+
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "License :: OSI Approved :: BSD License",
+    "Programming Language :: Python :: 3 :: Only",
+    "Programming Language :: Python :: 3.6",
+    "Programming Language :: Python :: 3.7",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
+    "Intended Audience :: Science/Research",
+    "Topic :: Scientific/Engineering",
+]
+dynamic = ["version"]
+[tool.setuptools_scm]
+
+[tool.setuptools.packages.find]
+exclude = ["notebooks"]
+
+[tool.setuptools.package-data]
+solardatatools = ["fixtures/*"]
+
+[project.optional-dependencies]
+docs = [
+    "sphinx",
+    "sphinx-changelog>=1.2.0",
+    "sphinx_design",
+]
+mosek = [
+    "mosek"
+]
+
+[project.urls]
+Homepage = "https://github.com/slacgismo/solar-data-tools"
+Documentation = "https://solar-data-tools.readthedocs.io/"
+"Bug Tracker" = "https://github.com/slacgismo/solar-data-tools/issues"
+Discussions = "https://github.com/slacgismo/solar-data-tools/discussions"
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index c2e745e7..6b2dd27a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
-scipy>=1.11
-numpy>=1.22.0
+scipy
+numpy
 pandas
 scikit-learn
 jupyter
@@ -7,15 +7,11 @@ matplotlib
 seaborn
 requests
 pvlib
-cvxpy>=1.3.2
-cmake
+cvxpy
 pykml
 haversine
-boto3
 smart_open
-cassandra-driver
 sig-decomp
-osqp
 clarabel
 qss
 tqdm
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 02cf7ba1..00000000
--- a/setup.py
+++ /dev/null
@@ -1,198 +0,0 @@
-"""A setuptools based setup module.
-See:
-https://packaging.python.org/en/latest/distributing.html
-https://github.com/pypa/sampleproject
-"""
-
-# Always prefer setuptools over distutils
-import subprocess
-from setuptools import setup, find_packages
-from pathlib import Path
-
-# io.open is needed for projects that support Python 2.7
-# It ensures open() defaults to text mode with universal newlines,
-# and accepts an argument to specify the text encoding
-# Python 3 only projects can skip this import
-from io import open
-
-here = Path()
-
-# Get the long description from the README file
-with open((here / "README.md"), encoding="utf-8") as f:
-    long_description = f.read()
-
-# get all the git tags from the cmd line that follow our versioning pattern
-git_tags = subprocess.Popen(
-    ["git", "tag", "--list", "v*[0-9]", "--sort=version:refname"],
-    stdout=subprocess.PIPE,
-)
-tags = git_tags.stdout.read()
-git_tags.stdout.close()
-tags = tags.decode("utf-8").split("\n")
-tags.sort()
-
-# PEP 440 won't accept the v in front, so here we remove it, strip the new line and decode the byte stream
-VERSION_FROM_GIT_TAG = tags[-1][1:]
-
-with open((here / "requirements.txt"), encoding="utf-8") as f:
-    install_requires = f.read().splitlines()
-# removes comments in the requirements file
-dependencies = [dependency for dependency in install_requires if (dependency[0] != "#")]
-
-setup(
-    # This is the name of your project. The first time you publish this
-    # package, this name will be registered for you. It will determine how
-    # users can install this project, e.g.:
-    #
-    # $ pip install sampleproject
-    #
-    # And where it will live on PyPI: https://pypi.org/project/sampleproject/
-    #
-    # There are some restrictions on what makes a valid project name
-    # specification here:
-    # https://packaging.python.org/specifications/core-metadata/#name
-    name="solar-data-tools",  # Required
-    # Versions should comply with PEP 440:
-    # https://www.python.org/dev/peps/pep-0440/
-    #
-    # For a discussion on single-sourcing the version across setup.py and the
-    # project code, see
-    # https://packaging.python.org/en/latest/single_source_version.html
-    version=VERSION_FROM_GIT_TAG,  # Required
-    # This is a one-line description or tagline of what your project does. This
-    # corresponds to the "Summary" metadata field:
-    # https://packaging.python.org/specifications/core-metadata/#summary
-    description="Tools for performing common tasks on solar PV data signals",  # Optional
-    # This is an optional longer description of your project that represents
-    # the body of text which users will see when they visit PyPI.
-    #
-    # Often, this is the same as your README, so you can just read it in from
-    # that file directly (as we have already done above)
-    #
-    # This field corresponds to the "Description" metadata field:
-    # https://packaging.python.org/specifications/core-metadata/#description-optional
-    long_description=long_description,  # Optional
-    # Denotes that our long_description is in Markdown; valid values are
-    # text/plain, text/x-rst, and text/markdown
-    #
-    # Optional if long_description is written in reStructuredText (rst) but
-    # required for plain-text or Markdown; if unspecified, "applications should
-    # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and
-    # fall back to text/plain if it is not valid rst" (see link below)
-    #
-    # This field corresponds to the "Description-Content-Type" metadata field:
-    # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional
-    long_description_content_type="text/markdown",  # Optional (see note above)
-    # This should be a valid link to your project's main homepage.
-    #
-    # This field corresponds to the "Home-Page" metadata field:
-    # https://packaging.python.org/specifications/core-metadata/#home-page-optional
-    url="https://github.com/bmeyers/solar-data-tools",  # Optional
-    # This should be your name or the name of the organization which owns the
-    # project.
-    author="SLAC National Accelerator Laboratory - Bennet Meyers",  # Optional
-    # This should be a valid email address corresponding to the author listed
-    # above.
-    author_email="bennetm@stanford.edu",  # Optional
-    # Classifiers help users find your project by categorizing it.
-    #
-    # For a list of valid classifiers, see https://pypi.org/classifiers/
-    classifiers=[  # Optional
-        # How mature is this project? Common values are
-        #   3 - Alpha
-        #   4 - Beta
-        #   5 - Production/Stable
-        "Development Status :: 3 - Alpha",
-        # Indicate who your project is intended for
-        "Intended Audience :: Science/Research",
-        "Topic :: Scientific/Engineering",
-        # Pick your license as you wish
-        "License :: OSI Approved :: BSD License",
-        # Specify the Python versions you support here. In particular, ensure
-        # that you indicate whether you support Python 2, Python 3 or both.
-        # These classifiers are *not* checked by 'pip install'. See instead
-        # 'python_requires' below.
-        # 'Programming Language :: Python :: 2',
-        # 'Programming Language :: Python :: 2.7',
-        "Programming Language :: Python :: 3",
-        # 'Programming Language :: Python :: 3.4',
-        # 'Programming Language :: Python :: 3.5',
-        "Programming Language :: Python :: 3.6",
-        "Programming Language :: Python :: 3.7",
-    ],
-    # This field adds keywords for your project which will appear on the
-    # project page. What does your project relate to?
-    #
-    # Note that this is a string of words separated by whitespace, not a list.
-    keywords="solar pv photovoltaic",  # Optional
-    # You can just specify package directories manually here if your project is
-    # simple. Or you can use find_packages().
-    #
-    # Alternatively, if you just want to distribute a single Python file, use
-    # the `py_modules` argument instead as follows, which will expect a file
-    # called `my_module.py` to exist:
-    #
-    #   py_modules=["my_module"],
-    #
-    packages=find_packages(exclude=["notebooks"]),  # Required
-    # Specify which Python versions you support. In contrast to the
-    # 'Programming Language' classifiers above, 'pip install' will check this
-    # and refuse to install the project if the version does not match. If you
-    # do not support Python 2, you can simplify this to '>=3.5' or similar, see
-    # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
-    # python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4',
-    python_requires=">=3.6, <4",
-    # This field lists other packages that your project depends on to run.
-    # Any package you put here will be installed by pip when your project is
-    # installed, so they must be valid existing projects.
-    #
-    # For an analysis of "install_requires" vs pip's requirements files see:
-    # https://packaging.python.org/en/latest/requirements.html
-    install_requires=dependencies,  # Optional
-    # List additional groups of dependencies here (e.g. development
-    # dependencies). Users will be able to install these using the "extras"
-    # syntax, for example:
-    #
-    #   $ pip install sampleproject[dev]
-    #
-    # Similar to `install_requires` above, these must be valid existing
-    # projects.
-    extras_require={"dev": ["check-manifest"], "test": ["coverage"]},  # Optional
-    # If there are data files included in your packages that need to be
-    # installed, specify them here.
-    #
-    # If using Python 2.6 or earlier, then these have to be included in
-    # MANIFEST.in as well.
-    package_data={'fixtures': ['solardatatools/fixtures/*']},
-    include_package_data=True,
-    # Although 'package_data' is the preferred approach, in some case you may
-    # need to place data files outside of your packages. See:
-    # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files
-    #
-    # In this case, 'data_file' will be installed into '<sys.prefix>/my_data'
-    # data_files=[('my_data', ['data/data_file'])],  # Optional
-    # To provide executable scripts, use entry points in preference to the
-    # "scripts" keyword. Entry points provide cross-platform support and allow
-    # `pip` to create the appropriate form of executable for the target
-    # platform.
-    #
-    # For example, the following would provide a command called `sample` which
-    # executes the function `main` from this package when invoked:
-    # entry_points={  # Optional
-    #    'console_scripts': [
-    #        'sample=sample:main',
-    #    ],
-    # },
-    # List additional URLs that are relevant to your project as a dict.
-    #
-    # This field corresponds to the "Project-URL" metadata fields:
-    # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use
-    #
-    # Examples listed include a pattern for specifying where the package tracks
-    # issues, where the source is hosted, where to say thanks to the package
-    # maintainers, and where to support the project financially. The key is
-    # what's used to render the link text on PyPI.
-    project_urls={  # Optional
-        "Bug Reports": "https://github.com/bmeyers/solar-data-tools/issues"
-    },
-)


Test patch:
diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml
index 012845d8..a09d3b58 100644
--- a/.github/workflows/test-build.yml
+++ b/.github/workflows/test-build.yml
@@ -14,13 +14,13 @@ jobs:
         with:
           python-version: "3.10"
 
-      - name: Install Twine
-        run: sudo pip install twine
+      - name: Install Twine and Build
+        run: sudo pip install twine build
 
       - name: Create the distribution
         run: |
           git fetch --prune --unshallow --tags
-          sudo python setup.py sdist bdist_wheel
+          sudo python3 -m build
 
   build-conda:
     runs-on: ubuntu-latest
@@ -48,7 +48,7 @@ jobs:
       - name: Install the Conda Dependencies
         run: |
           conda config --set always_yes yes --set auto_update_conda false
-          conda install conda=24.1.2
+          conda update conda
           conda install -n base conda-libmamba-solver
           conda install python=3.10 conda-build colorama pip ruamel ruamel.yaml rich jsonschema -c conda-forge
           git fetch --prune --unshallow --tags
@@ -63,5 +63,5 @@ jobs:
         run: |
           conda install anaconda-client
           conda config --set anaconda_upload no --set solver libmamba
-          VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge --numpy 1.22.0
+          VERSION_FROM_GIT_TAG=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)test conda build . -c mosek -c anaconda -c pvlib -c slacgismo -c conda-forge -c stanfordcvxgrp
           echo "gitversion=$(git tag --list "v*[0-9]" --sort=version:refname | tail -1 | cut -c 2-)" >> $GITHUB_OUTPUT
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 677f9109..a85eb94b 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,41 +1,60 @@
 name: Tests
 
-on: [push]
+on:
+  pull_request:
+    branches:
+      - "main"
+env:
+  # todo(nimish): extend to matrix of python versions/OS
+  AWS_REGION: "us-west-1"
+  USE_MOSEK: "false"
+
 jobs:
-    run-tests:
-        runs-on: ubuntu-latest
-        environment: test
-        steps:
-          - name: Checkout Repository
-            uses: actions/checkout@v3
+  run-tests:
+    runs-on: ubuntu-latest
+    environment: test
+    strategy:
+      fail-fast: false
+      matrix:
+        python-version: ["3.10", "3.11", "3.12"]
+    steps:
+      - name: Configure AWS Credentials
+        uses: aws-actions/configure-aws-credentials@v4
+        if: env.USE_MOSEK == 'true'
+        with:
+          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
+          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
+          aws-region: ${{ env.AWS_REGION }}
 
-# Necessary action when needing to use AWS credentials.
-          - name: Configure AWS Credentials
-            uses: aws-actions/configure-aws-credentials@v1
-            with:
-              aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
-              aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
-              aws-region: us-west-1
+      - name: Setup Mosek License File
+        if: env.USE_MOSEK == 'true'
+        env:
+          MOSEK_LICENSE: "s3://slac.gismo.ci.artifacts/mosek.license/mosek.lic"
+        run: |
+          sudo mkdir /root/mosek
+          mkdir $HOME/mosek
+          aws s3 cp ${{env.MOSEK_LICENSE}} $HOME/mosek/mosek.lic
+          sudo cp $HOME/mosek/mosek.lic /root/mosek/mosek.lic
 
-          - name: Install Python
-            uses: actions/setup-python@v3
-            with:
-              python-version: '3.10'
+      - name: Checkout Repository
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 1
+          fetch-tags: true
 
-          - name: Install Dependencies
-            run: |
-              sudo $pythonLocation/bin/python3 -m pip install -r requirements.txt
-              sudo $pythonLocation/bin/python3 -m pip install awscli coverage
-              sudo $pythonLocation/bin/python3 -m pip install setuptools --upgrade
-              $pythonLocation/bin/python3 -m pip list
+      - name: Install Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: ${{ matrix.python-version }}
 
-          - name: Setup Mosek License File
-            run: |
-              sudo mkdir /root/mosek
-              mkdir $HOME/mosek
-              aws s3 cp s3://slac.gismo.ci.artifacts/mosek.license/mosek.lic $HOME/mosek/mosek.lic
-              sudo cp $HOME/mosek/mosek.lic /root/mosek/mosek.lic
+      - name: Install Python Dependencies
+        run: |
+          curl -LsSf https://astral.sh/uv/install.sh | sh
+          uv pip install --system --break-system-packages -r requirements.txt
+          uv pip install --system --break-system-packages pytest pytest-cov pytest-github-report pytest-github-actions-annotate-failures
 
-# Current unit test is not consistent. Occasionally fails despite usually passing. Needs to be fixed.
-          - name: Run Unit Tests
-            run: sudo $pythonLocation/bin/python3 -m coverage run -m unittest
+      - name: Run Unit Tests
+        env:
+          pytest_github_report: true
+          pytest_verbosity: 2
+        run: pytest -v --cov=src --cov-report=xml --cov-report=term-missing --color=yes tests/