diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000000000000000000000000000000..16beae29cc7f31303c709b4981421f395512d84b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,148 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +max_line_length = 120 +tab_width = 4 +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = false +ij_shell_use_unix_line_separator = true + +[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}] +indent_size = 2 +ij_json_array_wrapping = split_into_lines +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = split_into_lines +ij_json_property_alignment = do_not_align +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_insert_quote_arrows_on_wrap = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_keep_line_breaks_inside_text_blocks = true +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.py,*.pyw}] +max_line_length = 88 +ij_python_align_collections_and_comprehensions = true +ij_python_align_multiline_imports = true +ij_python_align_multiline_parameters = true +ij_python_align_multiline_parameters_in_calls = false +ij_python_blank_line_at_file_end = true +ij_python_blank_lines_after_imports = 1 +ij_python_blank_lines_after_local_imports = 0 +ij_python_blank_lines_around_class = 1 +ij_python_blank_lines_around_method = 1 +ij_python_blank_lines_around_top_level_classes_functions = 2 +ij_python_blank_lines_before_first_method = 0 +ij_python_call_parameters_new_line_after_left_paren = true +ij_python_call_parameters_right_paren_on_new_line = true +ij_python_call_parameters_wrap = normal +ij_python_dict_alignment = 2 +ij_python_dict_new_line_after_left_brace = true +ij_python_dict_new_line_before_right_brace = true +ij_python_dict_wrapping = 1 +ij_python_from_import_new_line_after_left_parenthesis = true +ij_python_from_import_new_line_before_right_parenthesis = true +ij_python_from_import_parentheses_force_if_multiline = true +ij_python_from_import_trailing_comma_if_multiline = false +ij_python_from_import_wrapping = 1 +ij_python_hang_closing_brackets = false +ij_python_keep_blank_lines_in_code = 1 +ij_python_keep_blank_lines_in_declarations = 1 +ij_python_keep_indents_on_empty_lines = false +ij_python_keep_line_breaks = true +ij_python_method_parameters_new_line_after_left_paren = true +ij_python_method_parameters_right_paren_on_new_line = true +ij_python_method_parameters_wrap = normal +ij_python_new_line_after_colon = true +ij_python_new_line_after_colon_multi_clause = true +ij_python_optimize_imports_always_split_from_imports = false +ij_python_optimize_imports_case_insensitive_order = false +ij_python_optimize_imports_join_from_imports_with_same_source = false +ij_python_optimize_imports_sort_by_type_first = true +ij_python_optimize_imports_sort_imports = true +ij_python_optimize_imports_sort_names_in_from_imports = false +ij_python_space_after_comma = true +ij_python_space_after_number_sign = true +ij_python_space_after_py_colon = true +ij_python_space_before_backslash = true +ij_python_space_before_comma = false +ij_python_space_before_for_semicolon = false +ij_python_space_before_lbracket = false +ij_python_space_before_method_call_parentheses = false +ij_python_space_before_method_parentheses = false +ij_python_space_before_number_sign = true +ij_python_space_before_py_colon = false +ij_python_space_within_empty_method_call_parentheses = false +ij_python_space_within_empty_method_parentheses = false +ij_python_spaces_around_additive_operators = true +ij_python_spaces_around_assignment_operators = true +ij_python_spaces_around_bitwise_operators = true +ij_python_spaces_around_eq_in_keyword_argument = false +ij_python_spaces_around_eq_in_named_parameter = false +ij_python_spaces_around_equality_operators = true +ij_python_spaces_around_multiplicative_operators = true +ij_python_spaces_around_power_operator = false +ij_python_spaces_around_relational_operators = true +ij_python_spaces_around_shift_operators = true +ij_python_spaces_within_braces = false +ij_python_spaces_within_brackets = false +ij_python_spaces_within_method_call_parentheses = false +ij_python_spaces_within_method_parentheses = false +ij_python_use_continuation_indent_for_arguments = true +ij_python_use_continuation_indent_for_collection_and_comprehensions = false +ij_python_use_continuation_indent_for_parameters = true +ij_python_wrap_long_lines = false + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..499f958b2b1d3bfa2cb18834fdd25fca3716f884 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +dist/* +*.egg-info +*.pyc +.tox + +.coverage +coverage.xml +htmlcov/* +build +dist + +# Documentation +docs/source/source_documentation +!docs/source/source_documentation/index.rst +docs/build + +# Setuptools SCM +sid/_version.py + +# IDE configuration +.vscode +.idea diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..c7c6e90fb2a4ce0a47ade68c4f79b2855a551579 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,227 @@ +default: + image: + name: $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG + pull_policy: always + before_script: + - python --version # For debugging + cache: + paths: + - .cache/pip + # Do not cache .tox, to recreate virtualenvs for every step + +stages: + - prepare + - lint + # check if this needs to be a separate step + # - build_extensions + - test + - package + - images + - integration + - publish # publish instead of deploy + +# Caching of dependencies to speed up builds +variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + +include: + - template: Security/SAST.gitlab-ci.yml + - template: Security/Dependency-Scanning.gitlab-ci.yml + - template: Security/Secret-Detection.gitlab-ci.yml + +# Prepare image to run ci on +trigger_prepare: + stage: prepare + trigger: + strategy: depend + include: .prepare.gitlab-ci.yml + +run_black: + stage: lint + script: + - tox -e black + allow_failure: true + +run_flake8: + stage: lint + script: + - tox -e pep8 + allow_failure: true + +run_pylint: + stage: lint + script: + - tox -e pylint + allow_failure: true + +# build_extensions: +# stage: build_extensions +# script: +# - echo "build fortran/c/cpp extension source code" + +sast: + variables: + SAST_EXCLUDED_ANALYZERS: brakeman, flawfinder, kubesec, nodejs-scan, phpcs-security-audit, + pmd-apex, security-code-scan, sobelow, spotbugs + stage: test + +dependency_scanning: + # override default before_script, job won't have Python available + before_script: + - uname + +secret_detection: + # override default before_script, job won't have Python available + before_script: + - uname + +# Basic setup for all Python versions for which we don't have a base image +.run_unit_test_version_base: + before_script: + - python --version # For debugging + - python -m pip install --upgrade pip + - python -m pip install --upgrade tox twine + +# Run all unit tests for Python versions except the base image +run_unit_tests: + extends: .run_unit_test_version_base + stage: test + image: python:3.${PY_VERSION} + script: + - tox -e py3${PY_VERSION} + parallel: + matrix: # use the matrix for testing + - PY_VERSION: [8, 9, 10, 11] + +# Run code coverage on the base image thus also performing unit tests +run_unit_tests_coverage: + stage: test + script: + - tox -e coverage + coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/' + artifacts: + reports: + coverage_report: + coverage_format: cobertura + path: coverage.xml + paths: + - htmlcov/* + +package_files: + stage: package + artifacts: + expire_in: 1w + paths: + - dist/* + script: + - tox -e build + +package_docs: + stage: package + artifacts: + expire_in: 1w + paths: + - docs/build/* + script: + - tox -e docs + +docker_build: + stage: images + image: docker:latest + needs: + - package_files + tags: + - dind + before_script: [] + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker build -f docker/sid/Dockerfile . --build-arg BUILD_ENV=copy --tag $CI_REGISTRY_IMAGE/sid:$CI_COMMIT_REF_SLUG + # enable this push line once you have configured docker registry cleanup policy + # - docker push $CI_REGISTRY_IMAGE/sid:$CI_COMMIT_REF_SLUG + +run_integration_tests: + stage: integration + allow_failure: true + needs: + - package_files + script: + - echo "make sure to move out of source dir" + - echo "install package from filesystem (or use the artefact)" + - echo "run against foreign systems (e.g. databases, cwl etc.)" + - exit 1 + +publish_on_gitlab: + stage: publish + environment: gitlab + needs: + - package_files + when: manual + rules: + - if: $CI_COMMIT_TAG + script: + - echo "run twine for gitlab" + - | + TWINE_PASSWORD=${CI_JOB_TOKEN} \ + TWINE_USERNAME=gitlab-ci-token \ + python -m twine upload \ + --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/* + +publish_on_test_pypi: + stage: publish + environment: pypi-test + needs: + - package_files + when: manual + rules: + - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' + script: + - echo "run twine for test pypi" + # - | + # TWINE_PASSWORD=${PIPY_TOKEN} \ + # TWINE_USERNAME=${PIPY_USERNAME} \ + # TODO: replace URL with a pipy URL + # python -m twine upload \ + # --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/* + - exit 1 + +publish_on_pypi: + stage: publish + environment: pypi + needs: + - package_files + when: manual + rules: + - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' + script: + - echo "run twine for pypi" + # - | + # TWINE_PASSWORD=${PIPY_TOKEN} \ + # TWINE_USERNAME=${PIPY_USERNAME} \ + # TODO: replace URL with a pipy URL + # python -m twine upload \ + # --repository-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi dist/* + - exit 1 + +publish_to_readthedocs: + stage: publish + allow_failure: true + environment: readthedocs + needs: + - package_docs + when: manual + rules: + - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' + script: + - echo "scp docs/* ???" + - exit 1 + +release_job: + stage: publish + image: registry.gitlab.com/gitlab-org/release-cli:latest + rules: + - if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"' + script: + - echo "running release_job" + release: + tag_name: '$CI_COMMIT_TAG' + description: '$CI_COMMIT_TAG - $CI_COMMIT_TAG_MESSAGE' diff --git a/.prepare.gitlab-ci.yml b/.prepare.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..3e48a271564faec892e42aab9f947d946ecc4d7b --- /dev/null +++ b/.prepare.gitlab-ci.yml @@ -0,0 +1,23 @@ +stages: + - build + +build_ci_runner_image: + stage: build + image: docker + tags: + - dind + script: + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - | + if docker pull $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG; then + docker build --cache-from $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG --tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG docker/ci-runner + else + docker pull $CI_REGISTRY_IMAGE/ci-build-runner:latest || true + docker build --cache-from $CI_REGISTRY_IMAGE/ci-build-runner:latest --tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG docker/ci-runner + fi + - docker push $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG # push the image + - | + if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then + docker image tag $CI_REGISTRY_IMAGE/ci-build-runner:$CI_COMMIT_REF_SLUG $CI_REGISTRY_IMAGE/ci-build-runner:latest + docker push $CI_REGISTRY_IMAGE/ci-build-runner:latest + fi diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000000000000000000000000000000000000..c4a3399ac9b36be786467e020c84f95e09db0606 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include LICENSE +include README.md + +recursive-include docs * +recursive-exclude tests * diff --git a/docker/ci-runner/Dockerfile b/docker/ci-runner/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..6cb46437656aad64d8292c0a10f6edaffffba8e3 --- /dev/null +++ b/docker/ci-runner/Dockerfile @@ -0,0 +1,4 @@ +FROM python:3.12 + +RUN python -m pip install --upgrade pip +RUN python -m pip install --upgrade tox twine diff --git a/docker/sid/Dockerfile b/docker/sid/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..ceea7e721fc3acaa124184e709986e04dbd9a3dd --- /dev/null +++ b/docker/sid/Dockerfile @@ -0,0 +1,18 @@ +ARG BUILD_ENV=no_copy + +FROM python:3.11 AS build_no_copy +ADD ../../requirements.txt . +COPY ../.. /work +RUN rm -r /work/dist | true +RUN python -m pip install --user tox +WORKDIR /work +RUN python -m tox -e build + +FROM python:3.11 AS build_copy +COPY dist /work/dist + +FROM build_${BUILD_ENV} AS build + +FROM python:3.11-slim +COPY --from=build /work/dist /dist +RUN python -m pip install /dist/*.whl diff --git a/docs/cleanup.py b/docs/cleanup.py new file mode 100644 index 0000000000000000000000000000000000000000..3a4508d859234544bea35b1008e3c8e4f73d7cc0 --- /dev/null +++ b/docs/cleanup.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +import os + +file_dir = os.path.dirname(os.path.realpath(__file__)) + +clean_dir = os.path.join(file_dir, "source", "source_documentation") +print(f"Cleaning.. {clean_dir}/*") + +if not os.path.exists(clean_dir): + exit() + +for file_name in os.listdir(clean_dir): + file = os.path.join(clean_dir, file_name) + + if file_name == "index.rst": + continue + + print(f"Removing.. {file}") + os.remove(file) diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..3c6e46c6db7ddaf65e47cfa22c9ec0b914f7fd38 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,5 @@ +sphinx!=1.6.6,!=1.6.7,>=1.6.5 # BSD +sphinx-rtd-theme>=0.4.3 #MIT +sphinxcontrib-apidoc>=0.3.0 #BSD +myst-parser>=2.0 # MIT +docutils>=0.17 # BSD diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..049edbb63d22442d7c9513ef3e7bb72d93f8c48f --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,93 @@ +# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +import os + +from sid._version import __version__ + +# -- General configuration ---------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.viewcode", + "sphinxcontrib.apidoc", + "sphinx_rtd_theme", + "myst_parser" +] + +# Assumes tox is used to call sphinx-build +project_root_directory = os.getcwd() + +apidoc_module_dir = "../../sid" +apidoc_output_dir = "source_documentation" +apidoc_excluded_paths = [] +apidoc_separate_modules = True +apidoc_toc_file = False +# This should include private methods but does not work +# https://github.com/sphinx-contrib/apidoc/issues/14 +apidoc_extra_args = ["--private"] + +# The suffix of source filenames. +source_suffix = [".rst"] + +# The master toctree document. +master_doc = "index" + +# General information about the project. +project = "sid" +copyright = "2023, ASTRON" + +# openstackdocstheme options +repository_name = "https://git.astron.nl/lofar2.0/sid" +bug_project = "none" +bug_tag = "" +html_last_updated_fmt = "%Y-%m-%d %H:%M" + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +version = __version__ + +modindex_common_prefix = ["sid."] + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = "sphinx" + +# -- Options for HTML output -------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +# html_theme_path = ["."] +html_theme = "sphinx_rtd_theme" +html_static_path = ["static"] +html_css_files = [ + "css/custom.css", +] + +# Output file base name for HTML help builder. +htmlhelp_basename = "%sdoc" % project + +# Conf.py variables exported to sphinx rst files access using |NAME| +variables_to_export = [ + "project", + "copyright", + "version", +] + +# Write to rst_epilog to export `variables_to_export` extract using `locals()` +# https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-rst_epilog +frozen_locals = dict(locals()) +rst_epilog = "\n".join( + map( + lambda x: f".. |{x}| replace:: {frozen_locals[x]}", # noqa: F821 + variables_to_export, + ) +) +# Pep is not able to determine that frozen_locals always exists so noqa +del frozen_locals diff --git a/docs/source/index.rst b/docs/source/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..c786f976ad074d142a3edeae6f54a4f1fb8a3c64 --- /dev/null +++ b/docs/source/index.rst @@ -0,0 +1,16 @@ +==================================================== +Welcome to the documentation of sid +==================================================== + +.. + To define more variables see rst_epilog generation in conf.py + +Documentation for version: |version| + +Contents: + +.. toctree:: + :maxdepth: 2 + + readme + source_documentation/index diff --git a/docs/source/readme.rst b/docs/source/readme.rst new file mode 100644 index 0000000000000000000000000000000000000000..87c96deef60fc04b35a8b9b9cca2f72b7e64e70c --- /dev/null +++ b/docs/source/readme.rst @@ -0,0 +1,2 @@ +.. include:: ../../README.md + :parser: myst_parser.sphinx_ diff --git a/docs/source/static/css/custom.css b/docs/source/static/css/custom.css new file mode 100644 index 0000000000000000000000000000000000000000..3ea8a2fc0c9c1ecb2b318cbc32edf90d2940c38d --- /dev/null +++ b/docs/source/static/css/custom.css @@ -0,0 +1,14 @@ +.orange { color: #c65d09; } + +.green { color: #5dc609; } + +.yellow { color: #c6c609; } + +.bolditalic { + font-weight: bold; + font-style: italic; +} + +.rst-content code, .rst-content tt, code { + white-space: break-spaces; +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000000000000000000000000000000000..f325d08c503701ce9cb8a88ad89797bded24c23d --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,13 @@ +[build-system] +requires = [ + "setuptools>=62.6", + "setuptools_scm[toml]>=8.0", + "wheel" +] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +version_file = "sid/_version.py" + +[tool.pylint] +ignore = "_version.py" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..8f81bc285d0db9ea0945151fed0cd47eec4ee6a2 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +importlib-metadata>=0.12, <5.0;python_version<"3.8" +numpy diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000000000000000000000000000000000000..43649afca400f4cceec1e6e66ddae9f8512fe8aa --- /dev/null +++ b/setup.cfg @@ -0,0 +1,37 @@ +[metadata] +name = sid +description = Software interface description +long_description = file: README.md +long_description_content_type = text/markdown +url = https://git.astron.nl/lofar2.0/sid +license = Apache License 2.0 +classifiers = + Development Status :: 3 - Alpha + Environment :: Web Environment + Intended Audience :: Developers + Intended Audience :: Science/Research + License :: OSI Approved :: Apache Software License + Operating System :: OS Independent + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3 :: Only + 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 + Topic :: Internet :: WWW/HTTP + Topic :: Internet :: WWW/HTTP :: Dynamic Content + Topic :: Scientific/Engineering + Topic :: Scientific/Engineering :: Astronomy + +[options] +include_package_data = true +packages = find: +python_requires = >=3.8 +install_requires = file: requirements.txt + +[flake8] +max-line-length = 88 +extend-ignore = E203 +exclude=.venv,.git,.tox,dist,docs,*lib/python*,*egg,_version.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..b908cbe55cb344569d32de1dfc10ca7323828dc5 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +import setuptools + +setuptools.setup() diff --git a/sid/README.md b/sid/README.md new file mode 100644 index 0000000000000000000000000000000000000000..949233db4b600dfb96b7c5cecb95a4b469ddbfff --- /dev/null +++ b/sid/README.md @@ -0,0 +1,53 @@ +# sid + + + +<!--  --> + +Software interface description + +## Installation +``` +pip install . +``` + +## Setup + +One time template setup should include configuring the docker registry to regularly cleanup old images of +the CI/CD pipelines. And you can consider creating protected version tags for software releases: + +1. [Cleanup Docker Registry Images](https://git.astron.nl/groups/templates/-/wikis/Cleanup-Docker-Registry-Images) +2. [Setup Protected Verson Tags](https://git.astron.nl/groups/templates/-/wikis/Setting-up-Protected-Version-Tags) + +Once the cleanup policy for docker registry is setup you can uncomment the `docker push` comment in the `.gitlab-ci.yml` +file from the `docker_build` job. This will allow to download minimal docker images with your Python package installed. + +## Usage +```python +from sid import cool_module + +cool_module.greeter() # prints "Hello World" +``` + +## Contributing + +To contribute, please create a feature branch and a "Draft" merge request. +Upon completion, the merge request should be marked as ready and a reviewer +should be assigned. + +Verify your changes locally and be sure to add tests. Verifying local +changes is done through `tox`. + +```pip install tox``` + +With tox the same jobs as run on the CI/CD pipeline can be ran. These +include unit tests and linting. + +```tox``` + +To automatically apply most suggested linting changes execute: + +```tox -e format``` + +## License +This project is licensed under the Apache License Version 2.0 diff --git a/sid/__init__.py b/sid/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..763e0f6888777a890d7c208e2e39ac283f61f090 --- /dev/null +++ b/sid/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +""" sid """ diff --git a/sid/cool_module.py b/sid/cool_module.py new file mode 100644 index 0000000000000000000000000000000000000000..de82c46c186cce3880ff8f56d87ba4406ee195ce --- /dev/null +++ b/sid/cool_module.py @@ -0,0 +1,9 @@ +# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +""" Cool module containing functions, classes and other useful things """ + + +def greeter(): + """Prints a nice message""" + print("Hello World!") diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/requirements.txt b/tests/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..f14d0b907ce977320ba250046dfab52a3101800a --- /dev/null +++ b/tests/requirements.txt @@ -0,0 +1,7 @@ +autopep8 >= 1.7.0 # MIT +black >= 22.0.0 # MIT +build >= 0.8.0 # MIT +flake8 >= 5.0.0 # MIT +pylint >= 2.15.0 # GPLv2 +pytest >= 7.0.0 # MIT +pytest-cov >= 3.0.0 # MIT diff --git a/tests/test_cool_module.py b/tests/test_cool_module.py new file mode 100644 index 0000000000000000000000000000000000000000..5bf21b15b285b380071c60b06dc1c3abeeb56e47 --- /dev/null +++ b/tests/test_cool_module.py @@ -0,0 +1,16 @@ +# Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy) +# SPDX-License-Identifier: Apache-2.0 + +"""Testing of the Cool Module""" +from unittest import TestCase + +from sid.cool_module import greeter + + +class TestCoolModule(TestCase): + """Test Case of the Cool Module""" + + def test_greeter(self): + """Testing that the greeter does not crash""" + greeter() + self.assertEqual(2 + 2, 4) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000000000000000000000000000000000000..792079e9dfd75fe8cb0adf19c73fd1503c15bc06 --- /dev/null +++ b/tox.ini @@ -0,0 +1,58 @@ +[tox] +# Generative environment list to test all supported Python versions +envlist = py3{9,10,11,12,13},black,pep8,pylint +min_version = 4.3.3 +requires = + tox-ignore-env-name-mismatch >= 0.2.0 + +[testenv] +usedevelop = True +package = wheel +wheel_build_env = .pkg + +setenv = + PYTHONWARNINGS=default::DeprecationWarning +deps = + -r{toxinidir}/requirements.txt + -r{toxinidir}/tests/requirements.txt +commands = + {envpython} --version + {envpython} -m pytest tests/{posargs} + +[testenv:coverage] +commands = + {envpython} --version + {envpython} -m pytest --cov-report term --cov-report xml --cov-report html --cov=sid tests/{posargs} + +# Use generative name and command prefixes to reuse the same virtualenv +# for all linting jobs. +[testenv:{pep8,black,pylint,format}] +usedevelop = False +package = editable +envdir = {toxworkdir}/linting +commands = + pep8: {envpython} -m flake8 --version + pep8: {envpython} -m flake8 sid tests + black: {envpython} -m black --version + black: {envpython} -m black --check --diff sid tests + pylint: {envpython} -m pylint --version + pylint: {envpython} -m pylint sid tests + format: {envpython} -m autopep8 -v -aa --in-place --recursive sid + format: {envpython} -m autopep8 -v -aa --in-place --recursive tests + format: {envpython} -m black -v sid tests + +[testenv:docs] +; unset LC_ALL / LANGUAGE from testenv, would fail sphinx otherwise +setenv = +deps = + -r{toxinidir}/requirements.txt + -r{toxinidir}/docs/requirements.txt +changedir = {toxinidir} +commands = + {envpython} docs/cleanup.py + sphinx-build -b html docs/source docs/build/html + +[testenv:build] +usedevelop = False +deps = build +commands = {envpython} -m build