diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..bad6ba3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + # Check for updates once a week + interval: 'weekly' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc83483..aca255d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,56 +1,58 @@ name: CI on: push: + branches: + - main + - develop pull_request: workflow_dispatch: - # schedule: - # - cron: '0 0 * * *' # Daily “At 00:00” + schedule: + - cron: '0 0 * * *' # Daily “At 00:00” + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: test: - # if: | - # github.repository == 'NCAR/wrf-python' - name: Python (${{ matrix.python-version }}, ${{ matrix.os }}) + name: Python ${{ matrix.python-version }}, ${{ matrix.os }} runs-on: ${{ matrix.os }} defaults: run: shell: bash -l {0} - strategy: fail-fast: false matrix: - os: [ "ubuntu-latest", "macos-latest"] - python-version: [ "3.7", "3.8", "3.9", "3.10" ] - + os: [ "ubuntu-latest", "macos-latest", "macos-14" ] + python-version: [ "3.9", "3.10", "3.11", "3.12" ] steps: - - name: Cancel previous runs - uses: styfle/cancel-workflow-action@0.9.1 - with: - access_token: ${{ github.token }} - - name: Checkout - uses: actions/checkout@v2 + - name: checkout + uses: actions/checkout@v4 + - name: environment setup + uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: - token: ${{ github.token }} - - name: Conda setup - uses: conda-incubator/setup-miniconda@v2 - with: - activate-environment: wrf_python_build python-version: ${{ matrix.python-version }} - channels: conda-forge, ncar - - name: Conda install (Darwin) - if: matrix.os == 'macos-latest' - run: | - conda env update --file build_envs/Darwin.yml --prune - - name: Conda install (Linux) - if: matrix.os == 'ubuntu-latest' + channels: conda-forge + environment-file: build_envs/environment.yml + - name: build WRF-Python run: | - conda env update --file build_envs/Linux.yml --prune - - name: Build WRF-Python - run: | - cd build_scripts - ./gnu_omp.sh - cd .. - - name: Run tests + python -m pip install build + python -m build . + python -m pip install dist/wrf*.whl + - name: run tests run: | cd test/ci_tests python utests.py + - name: check import + if: failure() + run: | + python -m pip show wrf-python + python -m pip show --files wrf-python + prefix="$(python -m pip show --files wrf-python | grep Location: | cut -f2 -d" ")" + echo "Site-packages directory is ${prefix}" + cd "${prefix}" + installed_files="$(python -m pip show --files wrf-python | grep -v -E -e '^[-a-zA-Z]+:')" + ls -l ${installed_files} + file ${installed_files} + python -vvv -dd -c "import wrf" + ldd $(echo ${installed_files} | grep -F -v -e ".py" -e ".dist-info") diff --git a/.github/workflows/pypi.yaml b/.github/workflows/pypi.yaml index 1322433..b79509f 100644 --- a/.github/workflows/pypi.yaml +++ b/.github/workflows/pypi.yaml @@ -8,19 +8,18 @@ jobs: if: github.repository == 'NCAR/wrf-python' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install setuptools setuptools-scm wheel twine check-manifest + python -m pip install build twine - name: Build tarball and wheels run: | - python setup.py sdist bdist_wheel - python -m pip wheel . -w dist --no-deps + python -m build - name: Test the artifacts run: | python -m twine check dist/* @@ -29,26 +28,25 @@ jobs: if: startsWith(github.ref, 'refs/tags') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install setuptools setuptools-scm wheel twine check-manifest + python -m pip install build twine - name: Build tarball and wheels run: | - python setup.py sdist bdist_wheel - python -m pip wheel . -w dist --no-deps + python -m build - name: Test the artifacts run: | python -m twine check dist/* - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@v1.5.0 + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 with: user: __token__ password: ${{ secrets.PYPI_WRF_PYTHON }} skip_existing: true - verbose: true \ No newline at end of file + verbose: true diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000..8cb6480 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,21 @@ +# .readthedocs.yml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +# Required +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "mambaforge-4.10" + jobs: + post_create_environment: + - python -m pip install --no-cache-dir --no-deps . + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: doc/source/conf.py + +conda: + environment: build_envs/environment.yml diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..265c22c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,209 @@ +### setup project ### +# https://numpy.org/doc/stable/f2py/buildtools/skbuild.html +cmake_minimum_required(VERSION 3.18) + +project(${SKBUILD_PROJECT_NAME} + VERSION ${SKBUILD_PROJECT_VERSION} + DESCRIPTION "Utilities for reading WRF output" + LANGUAGES C Fortran + ) + +# Safety net +if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) + message( + FATAL_ERROR + "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.\n" + ) +endif() + +find_package(Python COMPONENTS Interpreter Development.Module NumPy REQUIRED) + +# Ensure scikit-build modules +if (NOT SKBUILD) + # Kanged --> https://github.com/Kitware/torch_liberator/blob/master/CMakeLists.txt + # If skbuild is not the driver; include its utilities in CMAKE_MODULE_PATH + execute_process( + COMMAND "${Python_EXECUTABLE}" + -c "import os, skbuild; print(os.path.dirname(skbuild.__file__))" + OUTPUT_VARIABLE SKBLD_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + list(APPEND CMAKE_MODULE_PATH "${SKBLD_DIR}/resources/cmake") + message(STATUS "Looking in ${SKBLD_DIR}/resources/cmake for CMake modules") +endif() + +# Grab the variables from a local Python installation +# NumPy headers +# F2PY headers +execute_process( + COMMAND "${Python_EXECUTABLE}" + -c "import numpy.f2py; print(numpy.f2py.get_include())" + OUTPUT_VARIABLE F2PY_INCLUDE_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +find_package(OpenMP COMPONENTS Fortran) +set_source_files_properties(fortran/ompgen.F90 PROPERTIES Fortran_PREPROCESS ON) +# TODO: Figure out the conditionals for running the C Preprocessor on Fortran files +# I think the main thing to be changed is -E -cpp +# Intel is -fpp -save-temps or /fpp on Windows +# or call fpp instead of the fortran compiler to get it to stop after preprocessing +if (${OpenMP_Fortran_FOUND}) + # This would probably be cleaner if I shoved it in the subdirectory + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/fortran") + add_executable(sizes "${CMAKE_SOURCE_DIR}/fortran/build_help/omp_sizes.f90") + target_link_libraries(sizes PUBLIC OpenMP::OpenMP_Fortran) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/fortran/ompgen.F90" + DEPENDS "${CMAKE_SOURCE_DIR}/fortran/ompgen.F90.template" + ${CMAKE_SOURCE_DIR}/fortran/build_help/sub_sizes.py + sizes + COMMAND + ${Python_EXECUTABLE} ${CMAKE_SOURCE_DIR}/fortran/build_help/sub_sizes.py + ${CMAKE_SOURCE_DIR}/fortran/ompgen.F90.template + ${CMAKE_CURRENT_BINARY_DIR}/fortran/ompgen.F90 + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + ) + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/fortran/omp.f90" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/fortran/ompgen.F90" + COMMAND ${CMAKE_Fortran_COMPILER} -E "${CMAKE_CURRENT_BINARY_DIR}/fortran/ompgen.F90" + -o "${CMAKE_CURRENT_BINARY_DIR}/fortran/omp.f90" ${OpenMP_Fortran_FLAGS} -cpp + ) +else() + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/fortran/omp.f90" + DEPENDS "${CMAKE_SOURCE_DIR}/fortran/ompgen.F90" + COMMAND ${CMAKE_Fortran_COMPILER} -E fortran/ompgen.F90 -o fortran/omp.f90 -cpp + ) +endif() + +# Prepping the module +set(f2py_module_name "_wrffortran") +set(fortran_src_files + "${CMAKE_SOURCE_DIR}/fortran/wrf_constants.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_testfunc.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_user.f90" + "${CMAKE_SOURCE_DIR}/fortran/rip_cape.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_cloud_fracf.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_fctt.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_user_dbz.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_relhl.f90" + "${CMAKE_SOURCE_DIR}/fortran/calc_uh.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_user_latlon_routines.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_pvo.f90" + "${CMAKE_SOURCE_DIR}/fortran/eqthecalc.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_rip_phys_routines.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_pw.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_vinterp.f90" + "${CMAKE_SOURCE_DIR}/fortran/wrf_wind.f90" + "${CMAKE_CURRENT_BINARY_DIR}/fortran/omp.f90") +set(python_src_files + "${CMAKE_SOURCE_DIR}/src/wrf/__init__.py" + "${CMAKE_SOURCE_DIR}/src/wrf/api.py" + "${CMAKE_SOURCE_DIR}/src/wrf/cache.py" + "${CMAKE_SOURCE_DIR}/src/wrf/computation.py" + "${CMAKE_SOURCE_DIR}/src/wrf/config.py" + "${CMAKE_SOURCE_DIR}/src/wrf/constants.py" + "${CMAKE_SOURCE_DIR}/src/wrf/contrib.py" + "${CMAKE_SOURCE_DIR}/src/wrf/coordpair.py" + "${CMAKE_SOURCE_DIR}/src/wrf/decorators.py" + "${CMAKE_SOURCE_DIR}/src/wrf/destag.py" + "${CMAKE_SOURCE_DIR}/src/wrf/extension.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_cape.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_cloudfrac.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_ctt.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_dbz.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_dewpoint.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_geoht.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_helicity.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_latlon.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_omega.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_precip.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_pressure.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_pw.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_rh.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_slp.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_temp.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_terrain.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_times.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_uvmet.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_vorticity.py" + "${CMAKE_SOURCE_DIR}/src/wrf/g_wind.py" + "${CMAKE_SOURCE_DIR}/src/wrf/geobnds.py" + "${CMAKE_SOURCE_DIR}/src/wrf/interp.py" + "${CMAKE_SOURCE_DIR}/src/wrf/interputils.py" + "${CMAKE_SOURCE_DIR}/src/wrf/latlonutils.py" + "${CMAKE_SOURCE_DIR}/src/wrf/metadecorators.py" + "${CMAKE_SOURCE_DIR}/src/wrf/projection.py" + "${CMAKE_SOURCE_DIR}/src/wrf/projutils.py" + "${CMAKE_SOURCE_DIR}/src/wrf/py3compat.py" + "${CMAKE_SOURCE_DIR}/src/wrf/routines.py" + "${CMAKE_SOURCE_DIR}/src/wrf/specialdec.py" + "${CMAKE_SOURCE_DIR}/src/wrf/units.py" + "${CMAKE_SOURCE_DIR}/src/wrf/util.py" + "${CMAKE_SOURCE_DIR}/src/wrf/version.py" +) +set(f2py_module_c "${f2py_module_name}module.c") + +# Target for enforcing dependencies +add_custom_target(genpyf + DEPENDS "${fortran_src_files}" +) +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}" + "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers.f" + "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers2.f90" + COMMAND ${Python_EXECUTABLE} -m "numpy.f2py" + -m "${f2py_module_name}" + --lower # Important + ${fortran_src_files} + DEPENDS "${fortran_src_files}" # Fortran source +) + +Python_add_library(${f2py_module_name} MODULE + "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}" + "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers.f" + "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers2.f90" + "${F2PY_INCLUDE_DIR}/fortranobject.c" + "${fortran_src_files}") + +target_include_directories(${f2py_module_name} PUBLIC + ${F2PY_INCLUDE_DIR} + ${Python_NumPy_INCLUDE_DIRS} + ${Python_INCLUDE_DIRS}) +set_target_properties(${f2py_module_name} PROPERTIES SUFFIX ".${Python_SOABI}${CMAKE_SHARED_MODULE_SUFFIX}") +set_target_properties(${f2py_module_name} PROPERTIES PREFIX "") + +# https://scikit-build-core.readthedocs.io/en/latest/getting_started.html +target_link_libraries(${f2py_module_name} PRIVATE Python::NumPy) +if (${OpenMP_Fortran_FOUND}) + target_link_libraries(${f2py_module_name} PUBLIC OpenMP::OpenMP_Fortran) +endif() + +# Linker fixes +if (UNIX) + if (APPLE) + set_target_properties(${f2py_module_name} PROPERTIES + LINK_FLAGS '-Wl,-dylib,-undefined,dynamic_lookup') + else() + set_target_properties(${f2py_module_name} PROPERTIES + LINK_FLAGS '-Wl,--allow-shlib-undefined') + endif() +endif() + +add_dependencies(${f2py_module_name} genpyf) + +if (NOT SKBUILD) + string(REGEX REPLACE "^/(usr/(local/)?)?" "" Python_SITEARCH_INSTALL ${Python_SITEARCH}) + string(REGEX REPLACE "^/(usr/(local/)?)?" "" Python_SITELIB_INSTALL ${Python_SITELIB}) + # string(SUBSTRING ${Python_SITEARCH} 1 -1 Python_SITEARCH_INSTALL) + # string(SUBSTRING ${Python_SITELIB} 1 -1 Python_SITELIB_INSTALL) + + install(TARGETS ${f2py_module_name} DESTINATION "${Python_SITEARCH_INSTALL}/wrf/") + install(FILES ${python_src_files} DESTINATION "${Python_SITELIB_INSTALL}/wrf/") + install(FILES src/wrf/data/psadilookup.dat DESTINATION "${Python_SITELIB_INSTALL}/wrf") +else() + # https://scikit-build-core.readthedocs.io/en/latest/cmakelists.html#install-directories + install(TARGETS ${f2py_module_name} DESTINATION "${SKBUILD_PLATLIB_DIR}/wrf/") +endif() diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b132591..fb043f2 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,182 +1,75 @@ -# Contributor Code of Conduct - -## Related Code of Conduct - -Participant Code of Conduct -[https://www2.fin.ucar.edu/ethics/participant-code-conduct](https://www2.fin.ucar.edu/ethics/participant-code-conduct) +# Code of Conduct ## Our Pledge -We, as contributors and maintainers (participants), of WRF-Python pledge to -make participation in our software project and community a safe, productive, -welcoming and inclusive experience for everyone. All participants are required -to abide by this Code of Conduct. This includes respectful treatment of -everyone regardless of age, body size, disability, ethnicity, gender identity -or expression, level of experience, nationality, political affiliation, -veteran status, pregnancy, genetic information, physical appearance, race, -religion, or sexual orientation, as well as any other characteristic protected -under applicable US federal or state law. +We, as contributors, creators, stewards, and maintainers (collectively referred to as "contributors" below), of WRF-Python pledge to make participation in our software, system or hardware project and community a safe, productive, and welcoming experience for everyone. All contributors are required to abide by this Code of Conduct. This includes respectful treatment of everyone regardless of age, body size, disability, ethnicity, gender identity or expression, level of experience, nationality, political affiliation, veteran status, pregnancy, genetic information, physical appearance, race, religion, or sexual orientation, as well as any other characteristic protected under applicable US federal or state law. ## Our Standards Examples of behaviors that contribute to a positive environment include: -* Using welcoming and inclusive language -* Respectful when offering and gracefully accepting constructive criticism -* Acknowledging the contributions of others -* Focusing on what is best for the community -* Showing empathy towards other community members -* Treating everyone with respect and consideration, valuing a diversity of - views and opinions -* Communicating openly with respect for others, critiquing ideas rather than - individuals +- All contributors are treated with respect and consideration +- Be considerate, respectful, and collaborative +- Communicate openly with respect for others, critiquing ideas rather than individuals and gracefully accepting criticism +- Acknowledging the contributions of others +- Avoid personal attacks directed toward other contributors +- Be mindful of your surroundings and of your fellow contributors +- Alert UCAR staff and suppliers/vendors if you notice a dangerous situation or someone in distress +- Respect the rules and policies of the project and venue Examples of unacceptable behavior include, but are not limited to: -* Harassment, intimidation, or discrimination in any form -* Personal attacks directed toward other participants -* Unwelcome sexual attention or advances -* Inappropriate, negative, derogatory comments and/or attacks on personal - beliefs -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Refusing to use the pronouns that someone requests -* Alarming, intimidating, threatening, or hostile comments or conduct -* Physical or verbal abuse by anyone to anyone, including but not limited to a - participant, member of the public, guest, member of any institution or - sponsor -* Comments related to characteristics given in the pledge at the top -* Inappropriate use of nudity and/or sexual images -* Threatening or stalking other participants -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- Harassment, intimidation, or discrimination in any form +- Physical, verbal, or written abuse by anyone to anyone +- Unwelcome sexual attention or advances +- Personal attacks directed at other guests, members, contributors, etc. +- Publishing others’ private information, such as a physical or electronic address, without explicit permission +- Alarming, intimidating, threatening, or hostile comments or conduct +- Inappropriate use of nudity and/or sexual images +- Threatening or stalking anyone, including a contributor +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Scope -This Code of Conduct applies to all spaces managed by the Project whether it -be online or face-to-face. This includes project code, code repository, -associated web pages, documentation, mailing lists, project websites and -wiki pages, issue tracker, meetings, telecons, events, project social media -accounts, and any other forums created by the project team which the community -uses for communication. In addition, violations of this Code of Conduct -outside these spaces may affect a person's ability to participate within them. -Representation of a project may be further defined and clarified by project -maintainers. +This Code of Conduct applies to all spaces managed by the Project whether they be physical, online or face-to-face. This includes project code, code repository, associated web pages, documentation, mailing lists, project websites and wiki pages, issue tracker, meetings, telecons, events, project social media accounts, and any other forums created by the project team which the community uses for communication. In addition, violations of this Code of Conduct outside these spaces may affect a person's ability to participate within them. Representation of a project may be further defined and clarified by project maintainers. ## Community Responsibilities -Everyone in the community is empowered to respond to people who are showing -unacceptable behavior. They can talk to them privately or publicly. Anyone -requested to stop unacceptable behavior is expected to comply immediately. -If the behavior continues concerns may be brought to the project -administrators or to any other party listed in the Reporting section below. +Everyone in the community is empowered to respond to people who are showing unacceptable behavior. They can talk to them privately or publicly. Anyone requested to stop unacceptable behavior is expected to comply immediately. If the behavior continues concerns may be brought to the project administrators or to any other party listed in the Reporting section below. ## Project Administrator Responsibilities -Project Administrators are responsible for clarifying the standards of -acceptable behavior and are encouraged to model appropriate behavior and -provide support when people in the community point out inappropriate behavior. -Project administrator(s) are normally the ones that would be tasked to carry -out the actions in the Consequences section below. +Project administrators are responsible for clarifying the standards of acceptable behavior and are encouraged to model appropriate behavior and provide support when people in the community point out inappropriate behavior. Project administrator(s) are normally the ones that would be tasked to carry out the actions in the Consequences section below. -Project Administrators are also expected to keep this Code of Conduct updated -with the main one housed at UCAR as listed below in the Attribution section. +Project administrators are also expected to keep this Code of Conduct updated with the main one housed at UCAR, as listed below in the Attribution section. ## Reporting -Instances of unacceptable behavior can be brought to the attention of the -project administrator(s) who may take any action as outlined in the -Consequences section below. However, making a report to a project -administrator is not considered an 'official report' to UCAR. +Instances of unacceptable behavior can be brought to the attention of the project administrator(s) who may take any reasonable and necessary action to address and stop the behavior. However, making a report to a project administrator is not considered an ‘official report’ to UCAR. + +Instances of unacceptable behavior may also be reported: +- To [The Chief Human Resources Officer](chro@ucar.edu) who serves as UCAR’s Section 504, Title VI, VII and IX Coordinator; +- Through [UCAR’s Reporting a Concern website](https://www.ucar.edu/who-we-are/ethics); or +- Anonymously through [UCAR’s EthicsPoint Hotline](https://www.ucar.edu/who-we-are/ethics). -Instances of unacceptable behavior may also be reported directly to UCAR via -UCAR's Harassment Reporting and Complaint Procedure at [https://www2.fin.ucar.edu/procedures/hr/harassment-reporting-and-complaint-procedure](https://www2.fin.ucar.edu/procedures/hr/harassment-reporting-and-complaint-procedure), -or anonymously through UCAR's EthicsPoint Hotline at [https://www2.fin.ucar.edu/ethics/anonymous-reporting](https://www2.fin.ucar.edu/ethics/anonymous-reporting). +Complaints received by UCAR will be handled pursuant to the procedures outlined in [UCAR’s Complaint and Investigations Procedures](https://sundog.ucar.edu/Interact/Pages/Content/Document.aspx?id=5140). Complaints to UCAR will be held as confidential as practicable under the circumstances, and retaliation against a person who initiates a complaint or an inquiry about inappropriate behavior will not be tolerated. -Complaints received by UCAR will be handled pursuant to the procedures -outlined in UCAR's Harassment Reporting and Complaint Procedure. Complaints -to UCAR will be held as confidential as practicable under the circumstances, -and retaliation against a person who initiates a complaint or an inquiry about -inappropriate behavior will not be tolerated. +If you require a reasonable accommodation due to a disability or for assistance as an individual with Limited English Proficiency (LEP), please contact UCAR's [Chief Human Resources Officer](chro@ucar.edu). -Any Contributor can use these reporting methods even if they are not directly -affiliated with UCAR. The Frequently Asked Questions (FAQ) page for reporting -is here: [https://www2.fin.ucar.edu/procedures/hr/reporting-faqs](https://www2.fin.ucar.edu/procedures/hr/reporting-faqs). +Any Contributor can use these reporting methods even if they are not directly affiliated with UCAR. The Frequently Asked Questions (FAQ) page for reporting is [here](https://www.ucar.edu/who-we-are/ethics). ## Consequences -Upon receipt of a complaint, the project administrator(s) may take any action -deemed necessary and appropriate under the circumstances. Such action can -include things such as: removing, editing, or rejecting comments, commits, -code, wiki edits, email, issues, and other contributions that are not aligned -to this Code of Conduct, or banning temporarily or permanently any contributor -for other behaviors that are deemed inappropriate, threatening, offensive, or -harmful. Project Administrators also have the right to report violations to -UCAR HR and/or UCAR's Office of Diversity, Equity and Inclusion (ODEI) as -well as a participant's home institution and/or law enforcement. In the event -an incident is reported to UCAR, UCAR will follow its Harassment Reporting -and Complaint Procedure. +Upon receipt of a complaint, the project administrator(s) may take any action deemed necessary and appropriate under the circumstances. Such action can include things such as: removing, editing, or rejecting comments, commits, code, wiki edits, email, issues, and other contributions that are not aligned to this Code of Conduct, or banning temporarily or permanently any contributor for other behaviors that are deemed inappropriate, threatening, offensive, or harmful. Project administrators also have the right to report violations to UCAR HR as well as to a contributor’s home institution and/or law enforcement. In the event an incident is reported to UCAR, UCAR will follow its Complaint and Investigations Procedure. ## Process for Changes -All UCAR managed projects are required to adopt this Contributor Code of -Conduct. Adoption is assumed even if not expressly stated in the repository. -Projects should fill in sections where prompted with project-specific -information, including, project name, email addresses, adoption date, etc. -There is one section below marked "optional" that may not apply to a given -project. +All UCAR managed projects are required to adopt this Contributor Code of Conduct. Adoption is assumed even if not expressly stated in the repository. Projects should fill in sections where prompted with project-specific information, including, project name and adoption date. -Projects that adopt this Code of Conduct need to stay up to date with -UCAR's Contributor Code of Conduct, linked with a DOI in the "Attribution" -section below. Projects can make limited substantive changes to the Code of -Conduct, however, the changes must be limited in scope and may not contradict -the UCAR Contributor Code of Conduct. +Projects that adopt this Code of Conduct need to stay up to date with UCAR's Contributor Code of Conduct, linked with a DOI in the Attribution section below. Projects can make limited substantive changes to the Code of Conduct, however, the changes must be limited in scope and may not contradict the UCAR Contributor Code of Conduct. ## Attribution -This Code of Conduct was originally adapted from the Contributor Covenant, -version 1.4, available at [Contributor-Covenant](http://contributor-covenant.org/version/1/4). -We then aligned it with the UCAR Participant Code of Conduct, which also -borrows from the American Geophysical Union (AGU) Code of Conduct. The UCAR -Participant Code of Conduct applies to both UCAR employees as well as -participants in activities run by UCAR. We modified the "scope" section with -the django project description, and we added "Publication Ethics" from -the NGEET/FATES project. The original version of this for all software -projects that have strong management from UCAR or UCAR staff is available -on the UCAR website at [*Enter DOI link name*] (the date that it was adopted -by this project was [*Enter date adopted*]). When responding to complaints -UCAR HR and ODEI will do so based on the latest published version. Therefore, -any project-specific changes should follow the Process for Changes section -above. - -## Publication Ethics (optional) - -We aim to create an open development environment where developers can be -confident that all members of the community are publishing any research -on the project in an ethical manner. In particular, writing code is a form of -intellectual contribution, and one should expect that all such intellectual -contributions are respected and given credit in any resulting published work. -To support the community and avoid issues of misconduct related to the above -principle, please respect the following rules: - -* Document the version of the code used in any publication, preferably by - either using a release tag (existing or newly created) if possible, or a - commit hash if not. - -* Do not use code from anywhere other than the central project's development - repository main development branch without discussing with the author(s) of - the modified code your intentions for using the code and receiving their - permission to do so. - -* When using project features that have recently been integrated into the - central Project development repository, be mindful of the contributions - of others and, where the novel features qualitatively affect the results, - involve the author(s) of these features in any resulting manuscripts. - Be particularly aware of the concerns of early career researchers, and - ensure they have sufficient time to lead publications using their - developments. - -* When discussing results arising from older project features that have been -described in the literature or releases, accurately cite the publications -describing those features or releases. +This Code of Conduct was originally adapted from the [Contributor Covenant](http://contributor-covenant.org/version/1/4), version 1.4. We then aligned it with the UCAR Participant Code of Conduct, which also borrows from the American Geophysical Union (AGU) Code of Conduct. The UCAR Participant Code of Conduct applies to both UCAR employees as well as participants in activities run by UCAR. The original version of this for all software projects that have strong management from UCAR or UCAR staff is available on the UCAR website at [https://doi.org/10.5065/6w2c-a132](https://doi.org/10.5065/6w2c-a132). The date that it was adopted by this project was April 2, 2025. When responding to complaints, UCAR HR will do so based on the latest published version. Therefore, any project-specific changes should follow the Process for Changes section above. +As an Equal Employment Opportunity Employer and recipient of federal funds, UCAR complies with Title VI, Title VII, and Title IX of the Civil Rights Act; the Rehabilitation Act of 1973, as amended, and the Age Discrimination in Employment Act of 1975, as amended. See [UCAR’s Nondiscrimination Statement](https://www.ucar.edu/who-we-are/ethics-integrity/nondiscrimination). diff --git a/MANIFEST.in b/MANIFEST.in index 79b786b..44c6fbd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,5 @@ include README.md include LICENSE -include requirements.txt include fortran/*.f90 include fortran/*.pyf diff --git a/build_envs/environment.yml b/build_envs/environment.yml new file mode 100644 index 0000000..4c646a3 --- /dev/null +++ b/build_envs/environment.yml @@ -0,0 +1,22 @@ +# Create full conda environment for development, including some useful tools +name: wrf_python_build +channels: + - conda-forge +dependencies: + - python>=3.9, <3.13 + - compilers + - basemap + - cartopy + - jupyter + - matplotlib + - netcdf4 + - numpy + - pycodestyle + - setuptools + - sphinx + - sphinx_rtd_theme + - sphinxcontrib-googleanalytics + - wrapt + - xarray + - python-build + - pip diff --git a/build_envs/platform-specific/README.md b/build_envs/platform-specific/README.md new file mode 100644 index 0000000..de69662 --- /dev/null +++ b/build_envs/platform-specific/README.md @@ -0,0 +1,3 @@ +These platform specific environment files are included here for reference only and not actively tested or maintained. + +We have moved to a single environment file (../environment.yml) for all platforms. diff --git a/build_envs/Linux.yml b/build_envs/platform-specific/linux.yml similarity index 91% rename from build_envs/Linux.yml rename to build_envs/platform-specific/linux.yml index f0609d8..c348960 100644 --- a/build_envs/Linux.yml +++ b/build_envs/platform-specific/linux.yml @@ -3,7 +3,7 @@ name: wrf_python_build channels: - conda-forge dependencies: - - python=3 + - python<3.12 - basemap - cartopy - gcc_linux-64 @@ -11,7 +11,7 @@ dependencies: - jupyter - matplotlib - netcdf4 - - numpy!=1.24.3 + - numpy - pycodestyle - setuptools - sphinx diff --git a/build_envs/platform-specific/macos_arm64.yml b/build_envs/platform-specific/macos_arm64.yml new file mode 100644 index 0000000..2e475f0 --- /dev/null +++ b/build_envs/platform-specific/macos_arm64.yml @@ -0,0 +1,21 @@ +# Create full conda environment for development, including some useful tools +name: wrf_python_build +channels: + - conda-forge +dependencies: + - python<3.12 + - basemap + - cartopy + - clang_osx-arm64 + - gfortran_osx-arm64 + - jupyter + - matplotlib + - netcdf4 + - numpy + - pycodestyle + - setuptools + - sphinx + - sphinx_rtd_theme + - wrapt + - xarray + diff --git a/build_envs/Darwin.yml b/build_envs/platform-specific/macos_x64.yml similarity index 91% rename from build_envs/Darwin.yml rename to build_envs/platform-specific/macos_x64.yml index 3ea338f..2415ebe 100644 --- a/build_envs/Darwin.yml +++ b/build_envs/platform-specific/macos_x64.yml @@ -3,7 +3,7 @@ name: wrf_python_build channels: - conda-forge dependencies: - - python=3 + - python<3.12 - basemap - cartopy - clang_osx-64 @@ -11,7 +11,7 @@ dependencies: - jupyter - matplotlib - netcdf4 - - numpy!=1.24.3 + - numpy - pycodestyle - setuptools - sphinx diff --git a/build_envs/Win64.yml b/build_envs/platform-specific/windows.yml similarity index 91% rename from build_envs/Win64.yml rename to build_envs/platform-specific/windows.yml index 82b3ea0..1053db0 100644 --- a/build_envs/Win64.yml +++ b/build_envs/platform-specific/windows.yml @@ -4,14 +4,14 @@ channels: - conda-forge - msys2 dependencies: - - python=3 + - python<3.12 - basemap - cartopy - jupyter - m2w64-toolchain - matplotlib - netcdf4 - - numpy!=1.24.3 + - numpy - pycodestyle - setuptools - sphinx diff --git a/build_scripts/gnu_omp.sh b/build_scripts/gnu_omp.sh index 03faa1b..46dded6 100755 --- a/build_scripts/gnu_omp.sh +++ b/build_scripts/gnu_omp.sh @@ -11,6 +11,7 @@ $FC -E ompgen.F90 -fopenmp -cpp -o omp.f90 cd .. python setup.py clean --all +export LDFLAGS=" -fopenmp " python setup.py config_fc --f90flags="-mtune=generic -fopenmp" build_ext --libraries="gomp" build pip install . diff --git a/doc/source/conf.py b/doc/source/conf.py index 26a6073..3c89989 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -75,9 +75,12 @@ def mock_asscalar(val): 'sphinx.ext.napoleon', 'sphinx.ext.autosummary', 'sphinx.ext.intersphinx', - 'sphinx.ext.mathjax' + 'sphinx.ext.mathjax', + 'sphinxcontrib.googleanalytics' ] +googleanalytics_id = 'G-6WSSSBGTH8' + #mathjax_path = "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" intersphinx_mapping = { diff --git a/doc/source/contrib.rst b/doc/source/contrib.rst index 0f96d18..d11fa76 100644 --- a/doc/source/contrib.rst +++ b/doc/source/contrib.rst @@ -294,28 +294,13 @@ contributing is: git remote add ncar https://github.com/ncar/wrf-python.git -- To create the development environment, you'll need to run the appropriate - command below for your operating system. - - OSX: - - .. code:: - - conda env create -f build_envs/Darwin.yml - - Linux: - - .. code:: - - conda env create -f build_envs/Linux.yml - - Win64: +- To create the development environment, you'll need to run the command below: .. code:: - conda env create -f build_envs/Win64.yml + conda env create -f build_envs/environment.yml - Note: For Win64, you will also need VS2015 installed on your system. + Note: For Windows, you will also need Visual Studio installed on your system. - Activate your conda environment. diff --git a/doc/source/installation.rst b/doc/source/installation.rst index 4088af2..c35c7fc 100644 --- a/doc/source/installation.rst +++ b/doc/source/installation.rst @@ -4,7 +4,7 @@ Installation Required Dependencies ---------------------- - - Python 2.7, 3.4, or 3.5+ + - Python 3.9+ - numpy (1.11 or later; 1.14 required to build on Windows) - wrapt (1.10 or later) - setuptools (38.0 or later) diff --git a/doc/source/new.rst b/doc/source/new.rst index 6e8719d..364af0b 100644 --- a/doc/source/new.rst +++ b/doc/source/new.rst @@ -4,6 +4,15 @@ What's New Releases ------------- +v1.4.0 (May 2025) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Release 1.4.0 +- Transition to CMake build using scikit-build-core +- Packaging updates and adoption of pyproject.toml +- Support for Python 3.12 +- Support for macOS ARM architecture + v1.3.2 (February 2019) ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/tutorials/wrf_workshop_2019.rst b/doc/source/tutorials/wrf_workshop_2019.rst index d2a1925..7f697e7 100644 --- a/doc/source/tutorials/wrf_workshop_2019.rst +++ b/doc/source/tutorials/wrf_workshop_2019.rst @@ -82,7 +82,7 @@ Step 2: Download Miniconda ---------------------------- For this tutorial, you will need to download and install Miniconda. We are -going to use Python 3.7, but it will also work with Python 2.7. +going to use Python 3.7, but it will also work with Python 2.7. Please use the appropriate link below to download Miniconda for your operating system. diff --git a/fortran/build_help/sub_sizes.py b/fortran/build_help/sub_sizes.py index d69b6e8..bb91eb6 100644 --- a/fortran/build_help/sub_sizes.py +++ b/fortran/build_help/sub_sizes.py @@ -41,6 +41,9 @@ def main(): ompgen_temp_path = os.path.join("..", "ompgen.F90.template") ompgen_out_path = os.path.join("..", "ompgen.F90") + if len(sys.argv) == 3: + ompgen_temp_path = sys.argv[1] + ompgen_out_path = sys.argv[2] with open(ompgen_temp_path, "r") as ompgen_in: ompgen_template = Template(ompgen_in.read()) diff --git a/fortran/omp.f90 b/fortran/omp.f90 index dce6b1d..0480fe6 100644 --- a/fortran/omp.f90 +++ b/fortran/omp.f90 @@ -7,6 +7,9 @@ MODULE omp_constants INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_dynamic = 2 INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_guided = 3 INTEGER(KIND=fomp_sched_kind), PARAMETER :: fomp_sched_auto = 4 +contains + subroutine have_omp_constants() + end subroutine have_omp_constants END MODULE omp_constants diff --git a/fortran/ompgen.F90 b/fortran/ompgen.F90 index 14fa7d4..4b2920b 100644 --- a/fortran/ompgen.F90 +++ b/fortran/ompgen.F90 @@ -20,6 +20,10 @@ MODULE omp_constants INTEGER(KIND=4), PARAMETER :: fomp_sched_auto = 4 #endif +contains + subroutine have_omp_constants() + end subroutine have_omp_constants + END MODULE omp_constants diff --git a/fortran/ompgen.F90.template b/fortran/ompgen.F90.template index 00a50d5..92be74b 100644 --- a/fortran/ompgen.F90.template +++ b/fortran/ompgen.F90.template @@ -20,6 +20,10 @@ MODULE omp_constants INTEGER(KIND=4), PARAMETER :: fomp_sched_auto = 4 #endif +contains + subroutine have_omp_constants() + end subroutine have_omp_constants + END MODULE omp_constants diff --git a/fortran/wrf_constants.f90 b/fortran/wrf_constants.f90 index 0864502..ebc5667 100644 --- a/fortran/wrf_constants.f90 +++ b/fortran/wrf_constants.f90 @@ -69,6 +69,9 @@ MODULE wrf_constants REAL(KIND=8), PARAMETER :: EXPON = RD*USSALR/G REAL(KIND=8), PARAMETER :: EXPONI = 1./EXPON + contains + subroutine have_wrf_constants() + end subroutine have_wrf_constants END MODULE wrf_constants diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..5047e19 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,78 @@ +[build-system] +requires = ["scikit-build-core", "numpy"] +build-backend = "scikit_build_core.build" + +[project] +name = "wrf-python" +authors = [ + { name = "Bill Ladwig" } +] +maintainers = [ + { name = "GeoCAT", email = "geocat@ucar.edu" }, +] +description = "Diagnostic and interpolation routines for WRF-ARW data." +readme = "README.md" +requires-python = ">=3.9, <3.13" +keywords = [ + "python", "wrf-python", "wrf", "forecast", "model", + "weather research and forecasting", "interpolation", + "plotting", "plots", "meteorology", "nwp", + "numerical weather prediction", "diagnostic", + "science", "numpy" +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Science/Research", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Fortran", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Atmospheric Science", + "Topic :: Software Development", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows" +] +license = { text = "Apache-2.0" } +dynamic = [ "version" ] +dependencies = [ + "basemap", + "numpy >=1.11, !=1.24.3", + "setuptools>=61", + "wrapt", + "xarray" +] + +[project.urls] +Repository = "https://github.com/NCAR/wrf-python" +Documentation = "https://wrf-python.rtfd.org" + +[tool.setuptools] +package-data = { "wrf" = ["data/psadilookup.dat"]} +platforms = ["any"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.dynamic] +version = { attr = "wrf.version.__version__" } + +[tool.scikit-build] +cmake.verbose = true +logging.level = "INFO" +minimum-version = "0.8" +cmake.version = ">=3.18" +wheel.packages = ["src/wrf"] + +# To avoid stripping installed libraries +# Packages often want to do their own stripping +# SKBUILD_INSTALL_STRIP: "false" +# install.strip = false + +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "src/wrf/version.py" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index e9cbcfa..0000000 --- a/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -basemap -numpy >=1.11, !=1.24.3 -setuptools -wrapt -xarray diff --git a/setup.py b/setup.py deleted file mode 100755 index 3dbeaf3..0000000 --- a/setup.py +++ /dev/null @@ -1,122 +0,0 @@ -import os -import sys -import setuptools -import socket - -# Bootstrap a numpy installation before trying to import it. -import importlib -try: - numpy_module = importlib.util.find_spec('numpy') - if numpy_module is None: - raise ModuleNotFoundError -except (ImportError, ModuleNotFoundError): - import subprocess - subprocess.call([sys.executable, '-m', 'pip', 'install', 'numpy']) - -if not socket.gethostname().startswith("cheyenne"): - import numpy.distutils.core -else: - import chey_intel - import numpy.distutils.core - import numpy.distutils.fcompiler.intel - - numpy.distutils.fcompiler.intel.IntelFCompiler = chey_intel.IntelFCompiler - numpy.distutils.fcompiler.intel.IntelVisualFCompiler = ( - chey_intel.IntelVisualFCompiler) - numpy.distutils.fcompiler.intel.IntelItaniumFCompiler = ( - chey_intel.IntelItaniumFCompiler) - numpy.distutils.fcompiler.intel.IntelItaniumVisualFCompiler = ( - chey_intel.IntelItaniumVisualFCompiler) - numpy.distutils.fcompiler.intel.IntelEM64VisualFCompiler = ( - chey_intel.IntelEM64VisualFCompiler) - numpy.distutils.fcompiler.intel.IntelEM64TFCompiler = ( - chey_intel.IntelEM64TFCompiler) - -ext1 = numpy.distutils.core.Extension( - name="wrf._wrffortran", - sources=["fortran/wrf_constants.f90", - "fortran/wrf_testfunc.f90", - "fortran/wrf_user.f90", - "fortran/rip_cape.f90", - "fortran/wrf_cloud_fracf.f90", - "fortran/wrf_fctt.f90", - "fortran/wrf_user_dbz.f90", - "fortran/wrf_relhl.f90", - "fortran/calc_uh.f90", - "fortran/wrf_user_latlon_routines.f90", - "fortran/wrf_pvo.f90", - "fortran/eqthecalc.f90", - "fortran/wrf_rip_phys_routines.f90", - "fortran/wrf_pw.f90", - "fortran/wrf_vinterp.f90", - "fortran/wrf_wind.f90", - "fortran/omp.f90"] - ) - -#Note: __version__ will be set in the version.py script loaded below -__version__ = None -with open("src/wrf/version.py") as f: - exec(f.read()) - -on_rtd = os.environ.get("READTHEDOCS", None) == "True" -# on_rtd=True -if on_rtd: - if sys.version_info < (3, 3): - requirements = ["mock"] # for python2 and python < 3.3 - else: - requirements = [] # for >= python3.3 - ext_modules = [] - -else: - # Place install_requires into the text file "requirements.txt" - with open("requirements.txt") as f2: - requirements = f2.read().strip().splitlines() - - # if sys.version_info < (3,3): - # requirements.append("mock") - ext_modules = [ext1] - -numpy.distutils.core.setup( - name='wrf-python', - author="Bill Ladwig", - maintainer="GeoCAT", - maintainer_email="geocat@ucar.edu", - description="Diagnostic and interpolation routines for WRF-ARW data.", - long_description=("A collection of diagnostic and interpolation " - "routines to be used with WRF-ARW data.\n\n" - "GitHub Repository:\n\n" - "https://github.com/NCAR/wrf-python\n\n" - "Documentation:\n\n" - "https://wrf-python.rtfd.org\n"), - url="https://github.com/NCAR/wrf-python", - version=__version__, - package_dir={"": "src"}, - keywords=["python", "wrf-python", "wrf", "forecast", "model", - "weather research and forecasting", "interpolation", - "plotting", "plots", "meteorology", "nwp", - "numerical weather prediction", "diagnostic", - "science", "numpy"], - python_requires='>=3.7', - install_requires=requirements, - classifiers=["Development Status :: 5 - Production/Stable", - "Intended Audience :: Science/Research", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Fortran", - "Programming Language :: Python :: 3.7", - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - "Topic :: Scientific/Engineering :: Atmospheric Science", - "Topic :: Software Development", - "Operating System :: POSIX", - "Operating System :: Unix", - "Operating System :: MacOS", - "Operating System :: Microsoft :: Windows"], - platforms=["any"], - license="Apache License 2.0", - packages=setuptools.find_packages("src"), - ext_modules=ext_modules, - download_url="https://python.org/pypi/wrf-python", - package_data={"wrf": ["data/psadilookup.dat"]}, - scripts=[] -) diff --git a/src/wrf/__init__.py b/src/wrf/__init__.py old mode 100755 new mode 100644 diff --git a/src/wrf/constants.py b/src/wrf/constants.py old mode 100755 new mode 100644 diff --git a/src/wrf/destag.py b/src/wrf/destag.py old mode 100755 new mode 100644 diff --git a/src/wrf/extension.py b/src/wrf/extension.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_cape.py b/src/wrf/g_cape.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_dbz.py b/src/wrf/g_dbz.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_dewpoint.py b/src/wrf/g_dewpoint.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_geoht.py b/src/wrf/g_geoht.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_helicity.py b/src/wrf/g_helicity.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_latlon.py b/src/wrf/g_latlon.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_omega.py b/src/wrf/g_omega.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_precip.py b/src/wrf/g_precip.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_pressure.py b/src/wrf/g_pressure.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_pw.py b/src/wrf/g_pw.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_rh.py b/src/wrf/g_rh.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_slp.py b/src/wrf/g_slp.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_temp.py b/src/wrf/g_temp.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_terrain.py b/src/wrf/g_terrain.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_times.py b/src/wrf/g_times.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_uvmet.py b/src/wrf/g_uvmet.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_vorticity.py b/src/wrf/g_vorticity.py old mode 100755 new mode 100644 diff --git a/src/wrf/g_wind.py b/src/wrf/g_wind.py old mode 100755 new mode 100644 diff --git a/src/wrf/interp.py b/src/wrf/interp.py old mode 100755 new mode 100644 diff --git a/src/wrf/units.py b/src/wrf/units.py old mode 100755 new mode 100644 diff --git a/src/wrf/version.py b/src/wrf/version.py index b7b278a..3e8d9f9 100644 --- a/src/wrf/version.py +++ b/src/wrf/version.py @@ -1 +1 @@ -__version__ = "1.3.4.1" +__version__ = "1.4.0"