Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

New helper classes for carbon footprint #437

Merged
merged 6 commits into from
Feb 7, 2025
Merged

New helper classes for carbon footprint #437

merged 6 commits into from
Feb 7, 2025

Conversation

gmaze
Copy link
Member

@gmaze gmaze commented Feb 4, 2025

Introduce new utility classes to easily compute argopy carbon footprint.

The goal is to get easy access to this metric for a specific release.

We use the Green-Coding Solutions API to retrieve energy consumption data.

Combined with the github API, this class provides an easy method to retrieve the CI activities of argopy.

API looks like this:

from argopy.utils import GreenCoding, Github

GreenCoding().measurements(branch='master', start_date='2024-01-01')
GreenCoding().measurements(branch='385/merge', start_date='2024-01-01')
GreenCoding().total_measurements(branches=['master', '385/merge'])
GreenCoding().footprint_for_release('v1.0.0')
GreenCoding().footprint_since_last_release()

Github().releases
Github().lastrelease_date
Github().lastrelease_tag
Github().get_PRtitle(385)
Github().get_PRmerged(start_date='2024-01-01', end_date='2025-01-01')
Github().get_PRmerged_since('2025-01-01')
Github().lastPRs
Github().release2PRs('v0.1.17')

@gmaze gmaze added enhancement New feature or request CI Continuous Integration tools python-environment About Python environment setup labels Feb 4, 2025
@gmaze gmaze self-assigned this Feb 4, 2025
Copy link

codecov bot commented Feb 4, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
1690 1 1689 641
View the top 1 failed tests by shortest run time
test_stores_float.py::Test_FloatStore_Online::test_wmo[wmo=13857, host='local', cached]
Stack Traces | 2.07s run time
self = <argopy.tests.test_stores_float.Test_FloatStore_Online object at 0x7f869ed97a90>
request = <SubRequest 'store_maker' for <Function test_wmo[wmo=13857, host='local', cached]>>

    @pytest.fixture
    def store_maker(self, request):
        """Fixture to create a Float store instance for a given wmo and host"""
        log.debug("-"*50)
        log.debug(request)
        wmo = request.param[0]
        host = self._patch_ftp(VALID_HOSTS[request.param[1]])
        cache = request.param[2]
    
        xfail, reason = False, ""
        if not HAS_S3FS and 's3' in host:
            xfail, reason = True, 's3fs not available'
        # elif 's3' in host:
        #     xfail, reason = True, 's3 is experimental'
    
>       yield self.get_a_floatstore(wmo, host=host, cache=cache, xfail=xfail, reason=reason)

argopy/tests/test_stores_float.py:142: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
argopy/tests/test_stores_float.py:125: in get_a_floatstore
    return self.call_floatstore(WMO, store_args, **kwargs)
argopy/tests/test_stores_float.py:115: in call_floatstore
    return core(WMO, store_args)
argopy/tests/test_stores_float.py:107: in core
    af = self.floatstore(WMO, **fargs)
.../float/implementations/argo_float_online.py:36: in __init__
    self.load_metadata()  # must come before load_dac because DAC is read from eafleetmonitoring metadata
.../float/implementations/argo_float_online.py:63: in load_metadata
    self._metadata = httpstore(cache=self.cache, cachedir=self.cachedir).open_json(
.../stores/implementations/http.py:903: in open_json
    data = self.download_url(url, **dwn_opts)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <argopy.stores.implementations.http.httpstore object at 0x7f86630056c0>
url = 'https://fleetmonitoring.euro-argo.eu/floats/13857', max_attempt = 5
cat_opts = {}, errors = 'raise'

    def download_url(
        self, url, max_attempt: int = 5, cat_opts: dict = {}, errors: str = "raise"
    ) -> Any:
        """Resilient URL data downloader
    
        This is basically a :func:`fsspec.implementations.http.HTTPFileSystem.cat_file` that is able to handle a 429 "Too many requests" error from a server, by waiting and sending requests several time.
    
        Parameters
        ----------
        url: str
            URL to download
        max_attempt: int, default = 5
            Maximum number of attempts to perform before failing
        cat_opts: dict, default = {}
            Options to be passed to the HTTPFileSystem cat_file method
        errors: str, default: ``raise``
            Define how to handle errors:
                - ``raise`` (default): Raise any error encountered
                - ``ignore``: Do not stop processing, simply issue a debug message in logging console
                - ``silent``:  Do not stop processing and do not issue log message
    
        """
    
        def make_request(
            ffs,
            url,
            n_attempt: int = 1,
            max_attempt: int = 5,
            cat_opts: dict = {},
            errors: str = "raise",
        ):
            data = None
            if n_attempt <= max_attempt:
                try:
                    data = ffs.cat_file(url, **cat_opts)
                except FileNotFoundError as e:
                    if errors == "raise":
                        raise e
                    elif errors == "ignore":
                        log.error("FileNotFoundError raised from: %s" % url)
                except aiohttp.ClientResponseError as e:
                    if e.status == 413:
                        if errors == "raise":
                            raise e
                        elif errors == "ignore":
                            log.error(
                                "Error %i (Payload Too Large) raised with %s"
                                % (e.status, url)
                            )
    
                    elif e.status == 429:
                        retry_after = int(e.headers.get("Retry-After", 5))
                        log.debug(
                            f"Error {e.status} (Too many requests). Retry after {retry_after} seconds. Tentative {n_attempt}/{max_attempt}"
                        )
                        time.sleep(retry_after)
                        n_attempt += 1
                        make_request(ffs, url, n_attempt=n_attempt, cat_opts=cat_opts)
                    else:
                        # Handle other client response errors
                        print(f"Error: {e}")
                except aiohttp.ClientError as e:
                    if errors == "raise":
                        raise e
                    elif errors == "ignore":
                        log.error("Error: {e}")
                except fsspec.FSTimeoutError as e:
                    if errors == "raise":
                        raise e
                    elif errors == "ignore":
                        log.error("Error: {e}")
            else:
                if errors == "raise":
                    raise ValueError(
                        f"Error: All attempts failed to download this url: {url}"
                    )
                elif errors == "ignore":
                    log.error("Error: All attempts failed to download this url: {url}")
    
            return data, n_attempt
    
        url = self.curateurl(url)
        data, n = make_request(
            self.fs,
            url,
            max_attempt=max_attempt,
            cat_opts=cat_opts,
            errors=errors,
        )
    
        if data is None:
            if errors == "raise":
>               raise FileNotFoundError(url)
E               FileNotFoundError: https://fleetmonitoring.euro-argo.eu/floats/13857

.../stores/implementations/http.py:176: FileNotFoundError

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

@gmaze gmaze marked this pull request as ready for review February 5, 2025 09:03
@gmaze gmaze changed the title New ArgopyCarbon class New helper classes for carbon footprint Feb 7, 2025
@gmaze gmaze merged commit b878edc into master Feb 7, 2025
39 checks passed
@gmaze gmaze deleted the carbonfootprint branch February 7, 2025 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI Continuous Integration tools enhancement New feature or request python-environment About Python environment setup
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant