|
2 | 2 |
|
3 | 3 | import contextlib |
4 | 4 | import logging |
| 5 | +import os |
5 | 6 | from pathlib import Path |
6 | 7 | from typing import Optional, Union |
7 | 8 |
|
|
14 | 15 | ScienceFilePath, |
15 | 16 | generate_imap_file_path, |
16 | 17 | ) |
| 18 | +from imap_data_access.utils import ReleaseType |
17 | 19 |
|
18 | 20 | logger = logging.getLogger(__name__) |
19 | 21 |
|
@@ -529,3 +531,131 @@ def upload(file_path: Union[Path, str]) -> None: |
529 | 531 | ) |
530 | 532 |
|
531 | 533 | logger.info("File %s uploaded successfully", file_path) |
| 534 | + |
| 535 | + |
| 536 | +def release( |
| 537 | + *, |
| 538 | + instrument: str, |
| 539 | + release_type: str, |
| 540 | + start_date: str, |
| 541 | + end_date: str, |
| 542 | + release_number: Optional[int] = None, |
| 543 | + exclude_file: Optional[Union[Path, str]] = None, |
| 544 | + manifest_file: Optional[Union[Path, str]] = None, |
| 545 | +) -> None: |
| 546 | + """Submit a release file to the data archive API. |
| 547 | +
|
| 548 | + Parameters |
| 549 | + ---------- |
| 550 | + instrument : str |
| 551 | + Instrument name (e.g., ``mag``, ``swe``) |
| 552 | + release_type : str |
| 553 | + Type of release: |
| 554 | + - 'release': IMAP mission-wide public release. By default, all files |
| 555 | + are released unless specified in the exception list to be withheld. |
| 556 | + - 'early-release': Early release of selected files approved by both |
| 557 | + instrument and project. |
| 558 | + - 'unrelease': Unrelease previously released files due to various |
| 559 | + causes and reasons. |
| 560 | + start_date : str |
| 561 | + Start date in YYYYMMDD format |
| 562 | + end_date : str |
| 563 | + End date in YYYYMMDD format |
| 564 | + release_number : int, optional |
| 565 | + Release number. Defaults to ``None``. Required if release_type is |
| 566 | + 'release' and should be an integer value. |
| 567 | + exclude_file : str, optional |
| 568 | + Path to exclude file containing list of files to exclude from public release. |
| 569 | + manifest_file : str, optional |
| 570 | + Path to manifest file containing list of files to apply action to in |
| 571 | + 'early-release' or 'unrelease' types. |
| 572 | +
|
| 573 | + Raises |
| 574 | + ------ |
| 575 | + ValueError |
| 576 | + If API key is not configured or if any of the required parameters are invalid |
| 577 | + IMAPDataAccessError |
| 578 | + If the API request fails |
| 579 | + """ |
| 580 | + # Check for API key - required for release operations |
| 581 | + if not imap_data_access.config["API_KEY"]: |
| 582 | + raise ValueError( |
| 583 | + "API key is required for release operations. " |
| 584 | + "Set the IMAP_API_KEY environment variable or use --api-key argument." |
| 585 | + ) |
| 586 | + |
| 587 | + # Validate instrument |
| 588 | + if instrument not in imap_data_access.VALID_INSTRUMENTS: |
| 589 | + raise ValueError( |
| 590 | + "Not a valid instrument, please choose from " |
| 591 | + + ", ".join(imap_data_access.VALID_INSTRUMENTS) |
| 592 | + ) |
| 593 | + |
| 594 | + # Validate release_type |
| 595 | + valid_release_types = [e.value for e in ReleaseType] |
| 596 | + if release_type not in valid_release_types: |
| 597 | + raise ValueError( |
| 598 | + f"Not a valid release type, please choose from {valid_release_types}" |
| 599 | + ) |
| 600 | + |
| 601 | + # Validate release_type == "release" requires release_number |
| 602 | + if release_type == ReleaseType.RELEASE.value and release_number is None: |
| 603 | + raise ValueError( |
| 604 | + "The 'release_number' parameter is required for 'release' release type." |
| 605 | + ) |
| 606 | + |
| 607 | + # Validate start_date |
| 608 | + if not file_validation.ImapFilePath.is_valid_date(start_date): |
| 609 | + raise ValueError("Not a valid start date, use format 'YYYYMMDD'.") |
| 610 | + |
| 611 | + # Validate end_date |
| 612 | + if not file_validation.ImapFilePath.is_valid_date(end_date): |
| 613 | + raise ValueError("Not a valid end date, use format 'YYYYMMDD'.") |
| 614 | + |
| 615 | + # Handle exclude file upload if provided |
| 616 | + if exclude_file is not None: |
| 617 | + # Upload the exclude file using the standard upload function |
| 618 | + upload(exclude_file) |
| 619 | + logger.info("Exclude file uploaded successfully") |
| 620 | + |
| 621 | + # Handle manifest file upload if provided |
| 622 | + if manifest_file is not None: |
| 623 | + # Upload the manifest file using the standard upload function |
| 624 | + upload(manifest_file) |
| 625 | + logger.info("Manifest file uploaded successfully") |
| 626 | + |
| 627 | + # Build release parameters |
| 628 | + release_params = { |
| 629 | + "instrument": instrument, |
| 630 | + "release_type": release_type, |
| 631 | + "start_date": start_date, |
| 632 | + "end_date": end_date, |
| 633 | + } |
| 634 | + |
| 635 | + # Add release_number only if release_type is 'release' |
| 636 | + if release_type == ReleaseType.RELEASE.value: |
| 637 | + release_params["release_number"] = release_number |
| 638 | + |
| 639 | + # Add optional parameters if provided |
| 640 | + if exclude_file is not None: |
| 641 | + # API only needs the filename, not the full path |
| 642 | + release_params["exclude_file"] = os.path.basename(exclude_file) |
| 643 | + |
| 644 | + if manifest_file is not None: |
| 645 | + # API only needs the filename, not the full path |
| 646 | + release_params["manifest_file"] = os.path.basename(manifest_file) |
| 647 | + |
| 648 | + logger.debug("Input release parameters: %s", release_params) |
| 649 | + |
| 650 | + url = f"{_get_base_url()}/release" |
| 651 | + request = requests.Request(method="GET", url=url, params=release_params).prepare() |
| 652 | + |
| 653 | + logger.info("Submitting release request to %s with params %s", url, release_params) |
| 654 | + with _make_request(request) as response: |
| 655 | + result = response.json() |
| 656 | + logger.debug("Received JSON: %s", result) |
| 657 | + |
| 658 | + logger.info( |
| 659 | + f"Release request submitted successfully for {instrument} " |
| 660 | + f"from {start_date} to {end_date}." |
| 661 | + ) |
0 commit comments