Skip to content

Commit

Permalink
Merge pull request #65 from MODFLOW-USGS/v0.1.5
Browse files Browse the repository at this point in the history
Release 0.1.5
  • Loading branch information
wpbonelli authored Jan 19, 2023
2 parents ef70874 + 85a75cb commit 59100aa
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 113 deletions.
29 changes: 29 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[flake8]
exclude =
.git
__pycache__
build
dist
examples
autotest
ignore =
# https://flake8.pycqa.org/en/latest/user/error-codes.html
F401,
# https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
# Indentation
E121, E122, E126, E127, E128,
# Whitespace
E203, E221, E222, E226, E231, E241,
# Import
E402,
# Line length
E501, E502,
# Statement
E722, E741,
# Whitespace warning
W291, W292, W293,
# Blank line warning
W391,
# Line break warning
W503, W504
statistics = True
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
with:
python-version: 3.8
cache: 'pip'
cache-dependency-path: setup.cfg
cache-dependency-path: pyproject.toml

- name: Install Python packages
run: |
Expand Down Expand Up @@ -132,7 +132,7 @@ jobs:
python-version: ${{ matrix.python }}
cache: 'pip'
cache-dependency-path: |
modflow-devtools/setup.cfg
modflow-devtools/pyproject.toml
modflow6-examples/etc/requirements*.txt
- name: Install Python packages
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
with:
python-version: 3.8
cache: 'pip'
cache-dependency-path: setup.cfg
cache-dependency-path: pyproject.toml

- name: Install Python dependencies
run: |
Expand Down Expand Up @@ -214,7 +214,7 @@ jobs:
with:
python-version: 3.8
cache: 'pip'
cache-dependency-path: setup.cfg
cache-dependency-path: pyproject.toml

- name: Install Python dependencies
run: |
Expand Down
6 changes: 6 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### Version 0.1.5

#### Refactoring

* [refactor(metadata)](https://github.com/MODFLOW-USGS/modflow-devtools/commit/2edeacfd8cb10081c22d1ab0799aba1fa7522c0d): Use pyproject.toml, retire setup.cfg (#63). Committed by w-bonelli on 2023-01-19.

### Version 0.1.4

#### Bug fixes
Expand Down
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
global-exclude .DS_Store *.pyc *.pyo *.pyd *.swp *.bak *~ .* *.sh *.yml *.md *.toml
exclude autotest/*
include pyproject.toml
include version.txt
include version.txt
include README.md
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MODFLOW developer tools

### Version 0.1.4 — release candidate
### Version 0.1.5 — release candidate
[![GitHub tag](https://img.shields.io/github/tag/MODFLOW-USGS/modflow-devtools.svg)](https://github.com/MODFLOW-USGS/modflow-devtools/tags/latest)
[![PyPI Version](https://img.shields.io/pypi/v/modflow-devtools.png)](https://pypi.python.org/pypi/modflow-devtools)
[![PyPI Versions](https://img.shields.io/pypi/pyversions/modflow-devtools.png)](https://pypi.python.org/pypi/modflow-devtools)
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

project = "modflow-devtools"
author = "MODFLOW Team"
release = "0.1.4"
release = "0.1.5"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
33 changes: 32 additions & 1 deletion docs/md/zip.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,34 @@
# `MFZipFile`

Python's [`ZipFile`](https://docs.python.org/3/library/zipfile.html) doesn't [preserve file permissions at extraction time](https://bugs.python.org/issue15795). The `MFZipFile` subclass modifies `ZipFile.extract()` to do so, as per the recommendation [here](https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries), and maintains identical behavior otherwise.
Python's [`ZipFile`](https://docs.python.org/3/library/zipfile.html) doesn't [preserve file permissions at extraction time](https://bugs.python.org/issue15795). The `MFZipFile` subclass:

- modifies `ZipFile.extract()` to preserve permissions per the [recommendation here](https://stackoverflow.com/questions/39296101/python-zipfile-removes-execute-permissions-from-binaries)
- adds a static `ZipFile.compressall()` method to create a zip file from files and directories
- maintains an otherwise identical API

## `compressall`

The `compressall` method is a static method that creates a zip file from lists of files and/or directories. It is a convenience method that wraps `ZipFile.write()`, `ZipFile.close()`, etc.

```python
from zipfile import ZipFile
from modflow_devtools.zip import MFZipFile

def test_compressall(function_tmpdir):
zip_file = function_tmpdir / "output.zip"

input_dir = function_tmpdir / "input"
input_dir.mkdir()

with open(input_dir / "data.txt", "w") as f:
f.write("hello world")

MFZipFile.compressall(str(zip_file), dir_pths=str(input_dir))
assert zip_file.exists()

output_dir = function_tmpdir / "output"
output_dir.mkdir()

ZipFile(zip_file).extractall(path=str(output_dir))
assert (output_dir / "data.txt").is_file()
```
4 changes: 2 additions & 2 deletions modflow_devtools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__author__ = "Joseph D. Hughes"
__date__ = "Jan 18, 2023"
__version__ = "0.1.4"
__date__ = "Jan 19, 2023"
__version__ = "0.1.5"
__maintainer__ = "Joseph D. Hughes"
__email__ = "[email protected]"
__status__ = "Production"
Expand Down
92 changes: 92 additions & 0 deletions modflow_devtools/test/test_zip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os
import shutil
import sys
import zipfile
from os import environ
from pathlib import Path
from pprint import pprint
from zipfile import ZipFile

import pytest
from modflow_devtools.markers import excludes_platform
from modflow_devtools.misc import get_suffixes, set_dir
from modflow_devtools.zip import MFZipFile

_bin_path = Path(environ.get("BIN_PATH")).expanduser().absolute()
_ext, _ = get_suffixes(sys.platform)


@pytest.fixture(scope="module")
def empty_archive(module_tmpdir) -> Path:
# https://stackoverflow.com/a/25195628/6514033
data = b"PK\x05\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
path = module_tmpdir / "empty.zip"

with open(path, "wb") as zip:
zip.write(data)

return path


@pytest.fixture(scope="module")
def nonempty_archive(module_tmpdir) -> Path:
if not _bin_path.is_dir():
pytest.skip(f"BIN_PATH ({_bin_path}) is not a directory")

zip_path = module_tmpdir / "nonempty.zip"
txt_path = module_tmpdir / "hw.txt"
exe_path = _bin_path / f"mf6{_ext}"

# create a zip file with a text file and an executable
shutil.copy(exe_path, module_tmpdir)
with open(txt_path, "w") as f:
f.write("hello world")

with set_dir(module_tmpdir):
zip = MFZipFile(zip_path.name, "w")
zip.write(txt_path.name, compress_type=zipfile.ZIP_DEFLATED)
zip.write(exe_path.name, compress_type=zipfile.ZIP_DEFLATED)
zip.close()

return zip_path


def test_compressall(function_tmpdir):
zip_file = function_tmpdir / "output.zip"
input_dir = function_tmpdir / "input"
input_dir.mkdir()

with open(input_dir / "data.txt", "w") as f:
f.write("hello world")

MFZipFile.compressall(str(zip_file), dir_pths=str(input_dir))

pprint(list(function_tmpdir.iterdir()))
assert zip_file.exists()

output_dir = function_tmpdir / "output"
output_dir.mkdir()

ZipFile(zip_file).extractall(path=str(output_dir))

pprint(list(output_dir.iterdir()))
assert (output_dir / "data.txt").is_file()


def test_extractall_empty(empty_archive, function_tmpdir):
zf = MFZipFile(empty_archive, "r")
zf.extractall(str(function_tmpdir))

assert not any(function_tmpdir.iterdir())


@pytest.mark.parametrize("mf", [True, False])
@excludes_platform("Windows")
def test_preserves_execute_permission(function_tmpdir, nonempty_archive, mf):
zip = MFZipFile(nonempty_archive) if mf else ZipFile(nonempty_archive)
zip.extractall(path=str(function_tmpdir))

exe_path = function_tmpdir / f"mf6{_ext}"

assert exe_path.is_file()
assert os.access(exe_path, os.X_OK) == mf
80 changes: 78 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,80 @@
[build-system]
# Minimum requirements for the build system to execute
requires = [
"setuptools>=45",
"wheel",
"setuptools>=61",
]
build-backend = "setuptools.build_meta"

[project]
name = "modflow-devtools"
description = "Python tools for MODFLOW development"
authors = [
{name = "Joseph D. Hughes", email = "[email protected]"},
]
maintainers = [
{name = "Joseph D. Hughes", email = "[email protected]"},
]
keywords = [
"MODFLOW",
"development",
"utilities",
"groundwater",
"hydrogeology"
]
readme = "README.md"
license = {text = "CC0"}
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Science/Research",
"License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Topic :: Scientific/Engineering :: Hydrology"
]
requires-python = ">=3.8"
dependencies = [
"numpy",
"pytest"
]
dynamic = ["version"]

[project.optional-dependencies]
lint = [
"black",
"cffconvert",
"flake8",
"isort",
"pylint"
]
test = [
"modflow-devtools[lint]",
"coverage",
"flaky",
"filelock",
"meson!=0.63.0",
"ninja",
"pytest-cases",
"pytest-cov",
"pytest-dotenv",
"pytest-xdist",
"PyYaml"
]
docs = [
"sphinx",
"sphinx-rtd-theme",
"myst-parser"
]

[project.urls]
"Documentation" = "https://modflow-devtools.readthedocs.io/en/latest/"
"Bug Tracker" = "https://github.com/MODFLOW-USGS/modflow-devtools/issues"
"Source Code" = "https://github.com/MODFLOW-USGS/modflow-devtools"


[tool.black]
line-length = 79
target_version = ["py37"]
Expand All @@ -19,6 +88,13 @@ profile = "black"
src_paths = ["src/modflow_devtools"]
line_length = 79

[tool.setuptools]
include-package-data = true
zip-safe = false

[tool.setuptools.dynamic]
version = {file = "version.txt"}

[tool.setuptools_scm]
fallback_version = "999"

Expand Down
Loading

0 comments on commit 59100aa

Please sign in to comment.