diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ef70c1..93bb4d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,4 +82,6 @@ jobs: activate-environment: true - name: Run tests - run: pixi run test + run: | + pixi run python -m ipykernel install --name flopy4 --user + pixi run test diff --git a/docs/examples/array_example.py b/docs/examples/array_example.py index afc641f..468f501 100644 --- a/docs/examples/array_example.py +++ b/docs/examples/array_example.py @@ -12,11 +12,28 @@ # name: python3 # --- -# This example demonstrates the `MFArray` class. +# # Array variables +# +# This example demonstrates how to work with array input variables. +# +# ## Overview +# +# FloPy works natively with NumPy arrays. Array input data can be provided +# as `ndarray` (or anything acting like one). FloPy also provides an array +# subclass `MFArray` supporting some special behaviors: +# +# - more efficient memory usage for constant arrays +# - convenient layered array manipulation +# - applying a multiplication factor +# +# TODO: rewrite the io stuff (external/internal) once that is moved to a +# separate layer from MFArray # + from pathlib import Path +from tempfile import TemporaryDirectory +import flopy import git import matplotlib.pyplot as plt import numpy as np @@ -271,3 +288,218 @@ mlmfa.sum() mlmfa.min(), mlmfa.mean(), mlmfa.max() + + +# ## Grid-shaped array data +# +# Most MODFLOW array data are two (row, column) or three (layer, +# row, column) dimensional and represent data on the model grid. +# grid. Other MODFLOW array data contain data by stress period. +# The following list summarizes the types of MODFLOW array data. + +# * Time-invariant multi-dimensional array data. This includes: +# 1. One and two dimensional arrays that do not have a layer dimension. +# Examples include `top`, `delc`, and `delr`. +# 2. Three dimensional arrays that can contain a layer dimension. +# Examples include `botm`, `idomain`, and `k`. +# * Transient arrays that can change with time and therefore contain arrays of +# data for one or more stress periods. Examples include `irch` and +# `recharge` in the `RCHA` package. +# +# In the example below a three dimensional ndarray is constructed for the +# `DIS` package's `botm` array. First, the a simulation and groundwater-flow +# model are set up. + +# set up where simulation workspace will be stored +temp_dir = TemporaryDirectory() +workspace = temp_dir.name +name = "grid_array_example" + +# create the FloPy simulation and tdis objects +sim = flopy.mf6.MFSimulation( + sim_name=name, exe_name="mf6", version="mf6", sim_ws=workspace +) +tdis = flopy.mf6.modflow.mftdis.ModflowTdis( + sim, + pname="tdis", + time_units="DAYS", + nper=2, + perioddata=[(1.0, 1, 1.0), (1.0, 1, 1.0)], +) +# create the Flopy groundwater flow (gwf) model object +model_nam_file = f"{name}.nam" +gwf = flopy.mf6.ModflowGwf(sim, modelname=name, model_nam_file=model_nam_file) +# create the flopy iterative model solver (ims) package object +ims = flopy.mf6.modflow.mfims.ModflowIms(sim, pname="ims", complexity="SIMPLE") + +# Then a three-dimensional ndarray of floating point values is created using +# numpy's `linspace` method. + +bot = np.linspace(-50.0 / 3.0, -3.0, 3) +delrow = delcol = 4.0 + +# The `DIS` package is then created passing the three-dimensional array to the +# `botm` parameter. The `botm` array defines the model's cell bottom +# elevations. + +dis = flopy.mf6.modflow.mfgwfdis.ModflowGwfdis( + gwf, + pname="dis", + nogrb=True, + nlay=3, + nrow=10, + ncol=10, + delr=delrow, + delc=delcol, + top=0.0, + botm=bot, +) + +# ## Adding MODFLOW Grid Array Data +# MODFLOW grid array data, like the data found in the `NPF` package's +# `GridData` block, can be specified as: +# +# 1. A constant value +# 2. A n-dimensional list +# 3. A numpy ndarray +# +# Additionally, layered grid data (generally arrays with a layer dimension) can +# be specified by layer. +# +# In the example below `icelltype` is specified as constants by layer, `k` is +# specified as a numpy ndarray, `k22` is specified as an array by layer, and +# `k33` is specified as a constant. + +# First `k` is set up as a 3 layer, by 10 row, by 10 column array with all +# values set to 10.0 using numpy's full method. + +k = np.full((3, 10, 10), 10.0) + +# Next `k22` is set up as a three dimensional list of nested lists. This +# option can be useful for those that are familiar with python lists but are +# not familiar with the numpy library. + +k22_row = [] +for row in range(0, 10): + k22_row.append(8.0) +k22_layer = [] +for col in range(0, 10): + k22_layer.append(k22_row) +k22 = [k22_layer, k22_layer, k22_layer] + +# `K33` is set up as a single constant value. Whenever an array has all the +# same values the easiest and most efficient way to set it up is as a constant +# value. Constant values also take less space to store. + +k33 = 1.0 + +# The `k`, `k22`, and `k33` values defined above are then passed in on +# construction of the npf package. + +npf = flopy.mf6.ModflowGwfnpf( + gwf, + pname="npf", + save_flows=True, + icelltype=[1, 1, 1], + k=k, + k22=k22, + k33=k33, + xt3doptions="xt3d rhs", + rewet_record="REWET WETFCT 1.0 IWETIT 1 IHDWET 0", +) + +# ### Layered Data +# +# When we look at what will be written to the npf input file, we +# see that the entire `npf.k22` array is written as one long array with the +# number of values equal to `nlay` * `nrow` * `ncol`. And this whole-array +# specification may be of use in some cases. Often times, however, it is +# easier to work with each layer separately. An `MFArray` object, such as +# `npf.k22` can be converted to a layered array as follows. + +npf.k22.make_layered() + +# By changing `npf.k22` to layered, we are then able to manage each layer +# separately. Before doing so, however, we need to pass in data that can be +# separated into three layers. An array of the correct size is one option. + +shp = npf.k22.array.shape +a = np.arange(shp[0] * shp[1] * shp[2]).reshape(shp) +npf.k22 = a + +# Now that `npf.k22` has been set to be layered, if we print information about +# it, we see that each layer is stored separately, however, `npf.k22.array` +# will still return a full three-dimensional array. + +type(npf.k22) +npf.k22 + +# We also see that each layer is printed separately to the npf +# Package input file, and that the LAYERED keyword is activated: + +npf.k22 + +# Working with a layered array provides lots of flexibility. For example, +# constants can be set for some layers, but arrays for others: + +npf.k22.set_data([1, a[2], 200]) +npf.k22 + +# The array can be interacted with as usual for NumPy arrays: +npf.k22 = np.stack( + [ + 100 * np.ones((10, 10)), + 50 * np.ones((10, 10)), + 30 * np.ones((10, 10)), + ] +) +npf.k22 + +# ## Adding MODFLOW Stress Period Array Data +# Transient array data spanning multiple stress periods must be specified as a +# dictionary of arrays, where the dictionary key is the stress period, +# expressed as a zero-based integer, and the dictionary value is the grid +# data for that stress period. + +# In the following example a `RCHA` package is created. First a dictionary +# is created that contains recharge for the model's two stress periods. +# Recharge is specified as a constant value in this example, though it could +# also be specified as a 3-dimensional ndarray or list of lists. + +rch_sp1 = 0.01 +rch_sp2 = 0.03 +rch_spd = {0: rch_sp1, 1: rch_sp2} + +# The `RCHA` package is created and the dictionary constructed above is passed +# in as the `recharge` parameter. + +rch = flopy.mf6.ModflowGwfrcha( + gwf, readasarrays=True, pname="rch", print_input=True, recharge=rch_spd +) + +# Below the `NPF` `k` array is retrieved using the various methods highlighted +# above. + +# First, view the `k` array. + +npf.k + +# `repr` gives a string representation of the data. + +repr(npf.k) + +# `str` gives a similar string representation of the data. + +str(npf.k) + +# Next, view the 4-dimensional array. + +rch.recharge + +# `repr` gives a string representation of the data. + +repr(rch.recharge) + +# str gives a similar representation of the data. + +str(rch.recharge) diff --git a/docs/examples/attrs_demo.py b/docs/examples/attrs_demo.py new file mode 100644 index 0000000..2ac0a52 --- /dev/null +++ b/docs/examples/attrs_demo.py @@ -0,0 +1,246 @@ +# # Attrs demo + +# This example demonstrates a tentative `attrs`-based object model. + +from pathlib import Path +from typing import List, Literal, Optional, Union + +# ## GWF IC +import numpy as np +from attr import asdict, define, field, fields_dict +from cattr import Converter +from numpy.typing import NDArray + +# We can define block classes where variable descriptions become +# the variable's docstring. Ideally we can come up with a Python +# input specification that is equivalent to (and convertible to) +# the original MF6 input specification, while knowing as little +# as possible about the MF6 input format; but anything we can't +# get rid of can go in field `metadata`. + + +@define +class Options: + export_array_ascii: bool = field( + default=False, + metadata={"longname": "export array variables to netcdf output files"}, + ) + """ + keyword that specifies input griddata arrays should be + written to layered ascii output files. + """ + + export_array_netcdf: bool = field( + default=False, metadata={"longname": "starting head"} + ) + """ + keyword that specifies input griddata arrays should be + written to the model output netcdf file. + """ + + +# Eventually we may be able to take advantage of NumPy +# support for shape parameters: +# https://github.com/numpy/numpy/issues/16544 +# +# We can still take advantage of type parameters. + + +@define +class PackageData: + strt: NDArray[np.float64] = field( + metadata={"longname": "starting head", "shape": ("nodes")} + ) + """ + is the initial (starting) head---that is, head at the + beginning of the GWF Model simulation. STRT must be specified for + all simulations, including steady-state simulations. One value is + read for every model cell. For simulations in which the first stress + period is steady state, the values used for STRT generally do not + affect the simulation (exceptions may occur if cells go dry and (or) + rewet). The execution time, however, will be less if STRT includes + hydraulic heads that are close to the steady-state solution. A head + value lower than the cell bottom can be provided if a cell should + start as dry. + """ + + +# Putting it all together: + + +@define +class GwfIc: + options: Options = field() + packagedata: PackageData = field() + + +# ## GWF OC +# +# The output control package has a more complicated variable structure. +# Below docstrings/descriptions are omitted for space-saving. + + +@define +class Format: + columns: int = field() + width: int = field() + digits: int = field() + format: Literal["exponential", "fixed", "general", "scientific"] = field() + + +@define +class Options: + budget_file: Optional[Path] = field(default=None) + budget_csv_file: Optional[Path] = field(default=None) + head_file: Optional[Path] = field(default=None) + printhead: Optional[Format] = field(default=None) + + +# It's awkward to have single-parameter classes, but +# it's the only way I got `cattrs` to distinguish a +# number of choices with the same shape in a union +# like `OCSetting`. There may be a better way. + + +@define +class All: + all: bool = field() + + +@define +class First: + first: bool = field() + + +@define +class Last: + last: bool = field() + + +@define +class Steps: + steps: List[int] = field() + + +@define +class Frequency: + frequency: int = field() + + +PrintSave = Literal["print", "save"] +RType = Literal["budget", "head"] +OCSetting = Union[All, First, Last, Steps, Frequency] + + +@define +class OutputControlData: + printsave: PrintSave = field() + rtype: RType = field() + ocsetting: OCSetting = field() + + @classmethod + def from_tuple(cls, t): + t = list(t) + printsave = t.pop(0) + rtype = t.pop(0) + ocsetting = { + "all": All, + "first": First, + "last": Last, + "steps": Steps, + "frequency": Frequency, + }[t.pop(0).lower()](t) + return cls(printsave, rtype, ocsetting) + + +Period = List[OutputControlData] +Periods = List[Period] + + +@define +class GwfOc: + options: Options = field() + periods: Periods = field() + + +# We now set up a `cattrs` converter to convert an unstructured +# representation of the package input data to a structured form. + +converter = Converter() + + +# Register a hook for the `OutputControlData.from_tuple` method. +# MODFLOW 6 defines records as tuples, from which we'll need to +# instantiate objects. + + +def output_control_data_hook(value, _) -> OutputControlData: + return OutputControlData.from_tuple(value) + + +converter.register_structure_hook(OutputControlData, output_control_data_hook) + + +# We can inspect the input specification with `attrs` machinery. + + +spec = fields_dict(OutputControlData) +assert len(spec) == 3 + +ocsetting = spec["ocsetting"] +assert ocsetting.type is OCSetting + + +# We can define a block with some data. + + +options = Options( + budget_file="some/file/path.cbc", +) +assert isinstance(options.budget_file, str) # TODO path +assert len(asdict(options)) == 4 + + +# We can load a record from a tuple. + + +ocdata = OutputControlData.from_tuple(("print", "budget", "steps", 1, 3, 5)) +assert ocdata.printsave == "print" +assert ocdata.rtype == "budget" +assert ocdata.ocsetting == Steps([1, 3, 5]) + + +# We can load the full package from an unstructured dictionary, +# as would be returned by a separate IO layer in the future. +# (Either hand-written or using e.g. lark.) + + +gwfoc = converter.structure( + { + "options": { + "budget_file": "some/file/path.cbc", + "head_file": "some/file/path.hds", + "printhead": { + "columns": 1, + "width": 10, + "digits": 8, + "format": "scientific", + }, + }, + "periods": [ + [ + ("print", "budget", "steps", 1, 3, 5), + ("save", "head", "frequency", 2), + ] + ], + }, + GwfOc, +) +assert gwfoc.options.budget_file == Path("some/file/path.cbc") +assert gwfoc.options.printhead.width == 10 +assert gwfoc.options.printhead.format == "scientific" +period = gwfoc.periods[0] +assert len(period) == 2 +assert period[0] == OutputControlData.from_tuple( + ("print", "budget", "steps", 1, 3, 5) +) diff --git a/docs/examples/input_data_model_example.py b/docs/examples/input_data_model_example.py new file mode 100644 index 0000000..5c694b7 --- /dev/null +++ b/docs/examples/input_data_model_example.py @@ -0,0 +1,83 @@ +# # Input data model +# +# TODO: flesh this out, describe prospective plan for type hints, +# determine whether we want to work directly with numpy or with +# e.g. xarray, etc. This will probably evolve for a while as we +# rework the prototype with c/attrs +# +# FloPy organizes input variables in components: simulations, models, +# packages, and subpackages. +# +# ```mermaid +# classDiagram +# Simulation *-- "1+" Package +# Simulation *-- "1+" Model +# Simulation *-- "1+" Variable +# Model *-- "1+" Package +# Model *-- "1+" Subpackage +# Model *-- "1+" Variable +# Package *-- "1+" Subpackage +# Package *-- "1+" Variable +# ``` +# +# Note that this is not identical to the underlying object model, which +# is yet to be determined. TODO: update this once we have a full prototype. +# +# # Variable types +# +# Variables are scalars, paths, arrays, or composite types: list, sum, union. +# +# MODFLOW 6 defines the following scalar types: +# +# - `keyword` +# - `integer` +# - `double precision` +# - `string` +# +# And the following composites: +# +# - `record`: product type +# - `keystring`: union type +# - `recarray`: list type +# +# Scalars may (and `recarray` must) have a `shape`. If a scalar has a `shape`, +# its type becomes a homogeneous scalar array. A `recarray` may contain records +# or unions of records as items. +# +# We map this typology roughly to the following in Python: +# +# TODO: update the following as we develop a more concrete idea of what +# type hints corresponding to the mf6 input data model will look like + +# + +from os import PathLike +from typing import ( + Any, + Iterable, + Tuple, + Union, +) + +from numpy.typing import ArrayLike +from pandas import DataFrame + +Scalar = Union[bool, int, float, str] +Path = PathLike +Array = ArrayLike +Record = Tuple[Union[Scalar, "Record"], ...] +Table = Union[Iterable[Record], DataFrame] +List = Iterable[Any] +Variable = Union[Scalar, Array, Record, Table, List] +# - + +# Note that: +# +# - Keystrings are omitted above, since a keystring simply becomes a +# `Union` of records or scalars. +# - List input may be regular (items all have the same record type) or +# irregular (items are unions of records). +# - A table is a special case of list input; since it is regular it can +# be represented as a dataframe. +# - While MODFLOW 6 typically formulates file path inputs as records with +# 3 fields (identifying keyword, `filein`/`fileout`, and filename), FloPy +# simply accepts `PathLike`. diff --git a/docs/examples/record_example.py b/docs/examples/record_example.py new file mode 100644 index 0000000..df1a057 --- /dev/null +++ b/docs/examples/record_example.py @@ -0,0 +1,12 @@ +# # Record variables +# +# This example demonstrates how to work with record input variables. +# +# A record variable is a product type. Record fields can be scalars, +# other record variables, or unions of such. +# +# MODFLOW 6 represents records as (possibly variadic) tuples. FloPy +# supports both a low-level tuple interface for records, conforming +# to MODFLOW 6, and a high-level, strongly-typed record interface. +# +# TODO flesh out diff --git a/flopy4/typing.py b/flopy4/typing.py index 3ad3f22..cfe9379 100644 --- a/flopy4/typing.py +++ b/flopy4/typing.py @@ -1,6 +1,6 @@ """Enumerates supported input variable types.""" -from pathlib import Path +from os import PathLike from typing import ( Iterable, Tuple, @@ -9,21 +9,25 @@ from numpy.typing import ArrayLike -Scalar = Union[bool, int, float, str, Path] +Scalar = Union[bool, int, float, str] """A scalar input variable.""" -Array = ArrayLike -"""An array input variable""" +Path = PathLike +"""A file path input variable.""" -Table = Iterable["Record"] -"""A table input variable.""" +Array = ArrayLike +"""An array input variable.""" Record = Tuple[Union[Scalar, "Record"], ...] """A record input variable.""" +Table = Iterable["Record"] +"""A table input variable.""" + + Variable = Union[Scalar, Array, Table, Record] """An input variable.""" diff --git a/pixi.lock b/pixi.lock index 1cc48eb..8272c1c 100644 --- a/pixi.lock +++ b/pixi.lock @@ -191,7 +191,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -358,7 +358,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -525,7 +525,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -702,7 +702,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -851,7 +851,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1002,7 +1002,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1162,7 +1162,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1308,7 +1308,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1456,7 +1456,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1616,7 +1616,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1763,7 +1763,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -1912,7 +1912,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz + - pypi: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl - pypi: https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/3a/5d8680279ada9571de8469220069d27024ee47624af534e537c9ff49a450/ipython-8.28.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl @@ -2160,11 +2160,11 @@ packages: requires_dist: - six>=1.12.0 - typing ; python_full_version < '3.5' - - astroid<2,>=1 ; python_full_version < '3.0' and extra == 'astroid' - - astroid<4,>=2 ; python_full_version >= '3.0' and extra == 'astroid' + - astroid>=1,<2 ; python_full_version < '3.0' and extra == 'astroid' + - astroid>=2,<4 ; python_full_version >= '3.0' and extra == 'astroid' - pytest ; extra == 'test' - - astroid<2,>=1 ; python_full_version < '3.0' and extra == 'test' - - astroid<4,>=2 ; python_full_version >= '3.0' and extra == 'test' + - astroid>=1,<2 ; python_full_version < '3.0' and extra == 'test' + - astroid>=2,<4 ; python_full_version >= '3.0' and extra == 'test' - kind: pypi name: async-lru version: 2.0.4 @@ -2253,7 +2253,7 @@ packages: requires_dist: - six>=1.9.0 - webencodings - - tinycss2<1.3,>=1.1.0 ; extra == 'css' + - tinycss2>=1.1.0,<1.3 ; extra == 'css' requires_python: '>=3.8' - kind: pypi name: build @@ -2386,7 +2386,7 @@ packages: requires_dist: - attrs>=23.1.0 - exceptiongroup>=1.1.1 ; python_full_version < '3.11' - - typing-extensions!=4.6.3,>=4.1.0 ; python_full_version < '3.11' + - typing-extensions>=4.1.0,!=4.6.3 ; python_full_version < '3.11' - pymongo>=4.4.0 ; extra == 'bson' - cbor2>=5.4.6 ; extra == 'cbor2' - msgpack>=1.0.5 ; extra == 'msgpack' @@ -2533,7 +2533,7 @@ packages: version: 0.4.6 url: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl sha256: 4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7' + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' - kind: pypi name: comm version: 0.2.2 @@ -3049,7 +3049,7 @@ packages: name: flopy4 version: 0.0.1.dev0 path: . - sha256: 46f0c14db79a4a397d25784553531ba81338f135efd9998bbe756f935d200d25 + sha256: 10b6bc5a5652b61e05f803f7e88cd7deaf2327a104eb259564ee77431121d011 requires_dist: - attrs - cattrs @@ -3061,6 +3061,7 @@ packages: - toml>=0.10 - build ; extra == 'build' - twine ; extra == 'build' + - flopy4[build,lint,test] ; extra == 'dev' - ruff ; extra == 'lint' - flopy4[lint] ; extra == 'test' - coverage ; extra == 'test' @@ -3082,7 +3083,7 @@ packages: url: https://files.pythonhosted.org/packages/08/07/aa85cc62abcc940b25d14b542cf585eebf4830032a7f6a1395d696bb3231/fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl sha256: 93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3107,7 +3108,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3119,7 +3120,7 @@ packages: url: https://files.pythonhosted.org/packages/27/b6/f9d365932dcefefdcc794985f8846471e60932070c557e0f66ed195fccec/fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl sha256: 54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3144,7 +3145,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3156,7 +3157,7 @@ packages: url: https://files.pythonhosted.org/packages/63/f1/3a081cd047d83b5966cb0d7ef3fea929ee6eddeb94d8fbfdb2a19bd60cc7/fonttools-4.54.1-cp311-cp311-win_amd64.whl sha256: 07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6 requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3181,7 +3182,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3193,7 +3194,7 @@ packages: url: https://files.pythonhosted.org/packages/71/73/545c817e34b8c34585291951722e1a5ae579380deb009576d9d244b13ab0/fonttools-4.54.1-cp310-cp310-win_amd64.whl sha256: dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3218,7 +3219,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3230,7 +3231,7 @@ packages: url: https://files.pythonhosted.org/packages/96/13/748b7f7239893ff0796de11074b0ad8aa4c3da2d9f4d79a128b0b16147f3/fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl sha256: 82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07 requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3255,7 +3256,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3267,7 +3268,7 @@ packages: url: https://files.pythonhosted.org/packages/aa/2c/8b5d82fe2d9c7f260fb73121418f5e07d4e38c329ea3886a5b0e55586113/fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl sha256: 5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20 requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3292,7 +3293,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3304,7 +3305,7 @@ packages: url: https://files.pythonhosted.org/packages/b9/0a/a57caaff3bc880779317cb157e5b49dc47fad54effe027016abd355b0651/fonttools-4.54.1-cp312-cp312-win_amd64.whl sha256: e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3329,7 +3330,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3341,7 +3342,7 @@ packages: url: https://files.pythonhosted.org/packages/db/f9/285c9a2d0e86b9bf2babfe19bec00502361fda56cea144d6a269ab9a32e6/fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl sha256: 7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2 requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3366,7 +3367,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3378,7 +3379,7 @@ packages: url: https://files.pythonhosted.org/packages/e5/12/9a45294a7c4520cc32936edd15df1d5c24af701d2f5f51070a9a43d7664b/fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl sha256: 278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e requires_dist: - - fs<3,>=2.2.0 ; extra == 'all' + - fs>=2.2.0,<3 ; extra == 'all' - lxml>=4.0 ; extra == 'all' - zopfli>=0.1.4 ; extra == 'all' - lz4>=1.7.4.2 ; extra == 'all' @@ -3403,7 +3404,7 @@ packages: - uharfbuzz>=0.23.0 ; extra == 'repacker' - sympy ; extra == 'symfont' - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs<3,>=2.2.0 ; extra == 'ufo' + - fs>=2.2.0,<3 ; extra == 'ufo' - unicodedata2>=15.1.0 ; python_full_version < '3.13' and extra == 'unicode' - zopfli>=0.1.4 ; extra == 'woff' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' @@ -3423,7 +3424,7 @@ packages: url: https://files.pythonhosted.org/packages/fd/5b/8f0c4a5bb9fd491c277c21eff7ccae71b47d43c4446c9d0c6cff2fe8c2c4/gitdb-4.0.11-py3-none-any.whl sha256: 81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 requires_dist: - - smmap<6,>=3.0.1 + - smmap>=3.0.1,<6 requires_python: '>=3.7' - kind: pypi name: gitpython @@ -3431,18 +3432,18 @@ packages: url: https://files.pythonhosted.org/packages/e9/bd/cc3a402a6439c15c3d4294333e13042b915bbeab54edc457c723931fed3f/GitPython-3.1.43-py3-none-any.whl sha256: eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff requires_dist: - - gitdb<5,>=4.0.1 + - gitdb>=4.0.1,<5 - typing-extensions>=3.7.4.3 ; python_full_version < '3.8' - sphinx==4.3.2 ; extra == 'doc' - sphinx-rtd-theme ; extra == 'doc' - - sphinxcontrib-applehelp<=1.0.4,>=1.0.2 ; extra == 'doc' + - sphinxcontrib-applehelp>=1.0.2,<=1.0.4 ; extra == 'doc' - sphinxcontrib-devhelp==1.0.2 ; extra == 'doc' - - sphinxcontrib-htmlhelp<=2.0.1,>=2.0.0 ; extra == 'doc' + - sphinxcontrib-htmlhelp>=2.0.0,<=2.0.1 ; extra == 'doc' - sphinxcontrib-qthelp==1.0.3 ; extra == 'doc' - sphinxcontrib-serializinghtml==1.1.5 ; extra == 'doc' - sphinx-autodoc-typehints ; extra == 'doc' - coverage[toml] ; extra == 'test' - - ddt!=1.4.3,>=1.1.1 ; extra == 'test' + - ddt>=1.1.1,!=1.4.3 ; extra == 'test' - mypy ; extra == 'test' - pre-commit ; extra == 'test' - pytest>=7.3.1 ; extra == 'test' @@ -3468,11 +3469,11 @@ packages: sha256: 27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f requires_dist: - certifi - - h11<0.15,>=0.13 - - anyio<5.0,>=4.0 ; extra == 'asyncio' - - h2<5,>=3 ; extra == 'http2' + - h11>=0.13,<0.15 + - anyio>=4.0,<5.0 ; extra == 'asyncio' + - h2>=3,<5 ; extra == 'http2' - socksio==1.* ; extra == 'socks' - - trio<1.0,>=0.22.0 ; extra == 'trio' + - trio>=0.22.0,<1.0 ; extra == 'trio' requires_python: '>=3.8' - kind: pypi name: httpx @@ -3489,8 +3490,8 @@ packages: - brotlicffi ; platform_python_implementation != 'CPython' and extra == 'brotli' - click==8.* ; extra == 'cli' - pygments==2.* ; extra == 'cli' - - rich<14,>=10 ; extra == 'cli' - - h2<5,>=3 ; extra == 'http2' + - rich>=10,<14 ; extra == 'cli' + - h2>=3,<5 ; extra == 'http2' - socksio==1.* ; extra == 'socks' - zstandard>=0.18.0 ; extra == 'zstd' requires_python: '>=3.8' @@ -3524,7 +3525,7 @@ packages: - jaraco-tidelift>=1.4 ; extra == 'doc' - pytest-enabler>=2.2 ; extra == 'enabler' - ipython ; extra == 'perf' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - packaging ; extra == 'test' - pyfakefs ; extra == 'test' - flufl-flake8 ; extra == 'test' @@ -3542,8 +3543,8 @@ packages: - kind: pypi name: interegular version: 0.3.3 - url: https://files.pythonhosted.org/packages/dc/9d/8b6dde58a028a3962ce17e84d5fe73758df61378e00ef8ac3d85da34b0ff/interegular-0.3.3.tar.gz - sha256: d9b697b21b34884711399ba0f0376914b81899ce670032486d0d048344a76600 + url: https://files.pythonhosted.org/packages/c4/01/72d6472f80651673716d1deda2a5bbb633e563ecf94f4479da5519d69d25/interegular-0.3.3-py37-none-any.whl + sha256: b0c07007d48c89d6d19f7204972d369b2a77222722e126b6aa63aa721dc3b19c requires_python: '>=3.7' - kind: pypi name: ipykernel @@ -3556,7 +3557,7 @@ packages: - debugpy>=1.6.5 - ipython>=7.23.1 - jupyter-client>=6.1.12 - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - matplotlib-inline>=0.1 - nest-asyncio - packaging @@ -3595,7 +3596,7 @@ packages: - decorator - jedi>=0.16 - matplotlib-inline - - prompt-toolkit<3.1.0,>=3.0.41 + - prompt-toolkit>=3.0.41,<3.1.0 - pygments>=2.4.0 - stack-data - traitlets>=5.13.0 @@ -3697,7 +3698,7 @@ packages: - furo ; extra == 'doc' - sphinx-lint ; extra == 'doc' - jaraco-tidelift>=1.4 ; extra == 'doc' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - pytest-checkdocs>=2.4 ; extra == 'test' - pytest-cov ; extra == 'test' - pytest-mypy ; extra == 'test' @@ -3722,7 +3723,7 @@ packages: - sphinx-lint ; extra == 'doc' - jaraco-tidelift>=1.4 ; extra == 'doc' - pytest-enabler>=2.2 ; extra == 'enabler' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - jaraco-classes ; extra == 'test' - pytest-mypy ; extra == 'type' requires_python: '>=3.8' @@ -3732,7 +3733,7 @@ packages: url: https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl sha256: e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0 requires_dist: - - parso<0.9.0,>=0.8.3 + - parso>=0.8.3,<0.9.0 - jinja2==2.11.3 ; extra == 'docs' - markupsafe==1.1.1 ; extra == 'docs' - pygments==2.8.1 ; extra == 'docs' @@ -3859,7 +3860,7 @@ packages: sha256: e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f requires_dist: - importlib-metadata>=4.8.3 ; python_full_version < '3.10' - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - python-dateutil>=2.8.2 - pyzmq>=23.0 - tornado>=6.2 @@ -3890,7 +3891,7 @@ packages: - ipykernel>=6.14 - ipython - jupyter-client>=7.0.0 - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - prompt-toolkit>=3.0.30 - pygments - pyzmq>=17 @@ -3965,7 +3966,7 @@ packages: - argon2-cffi>=21.1 - jinja2>=3.0.3 - jupyter-client>=7.4.4 - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - jupyter-events>=0.9.0 - jupyter-server-terminals>=0.4.4 - nbconvert>=6.4.4 @@ -4001,7 +4002,7 @@ packages: - pytest-console-scripts ; extra == 'test' - pytest-jupyter[server]>=0.7 ; extra == 'test' - pytest-timeout ; extra == 'test' - - pytest<9,>=7.0 ; extra == 'test' + - pytest>=7.0,<9 ; extra == 'test' - requests ; extra == 'test' requires_python: '>=3.8' - kind: pypi @@ -4043,8 +4044,8 @@ packages: - jinja2>=3.0.3 - jupyter-core - jupyter-lsp>=2.0.0 - - jupyter-server<3,>=2.4.0 - - jupyterlab-server<3,>=2.27.1 + - jupyter-server>=2.4.0,<3 + - jupyterlab-server>=2.27.1,<3 - notebook-shim>=0.2 - packaging - setuptools>=40.1.0 @@ -4065,7 +4066,7 @@ packages: - pytest-check-links ; extra == 'docs' - pytest-jupyter ; extra == 'docs' - sphinx-copybutton ; extra == 'docs' - - sphinx<7.3.0,>=1.8 ; extra == 'docs' + - sphinx>=1.8,<7.3.0 ; extra == 'docs' - altair==5.3.0 ; extra == 'docs-screenshots' - ipython==8.16.1 ; extra == 'docs-screenshots' - ipywidgets==8.1.2 ; extra == 'docs-screenshots' @@ -4087,7 +4088,7 @@ packages: - requests ; extra == 'test' - requests-cache ; extra == 'test' - virtualenv ; extra == 'test' - - copier<10,>=9 ; extra == 'upgrade-extension' + - copier>=9,<10 ; extra == 'upgrade-extension' - jinja2-time<0.3 ; extra == 'upgrade-extension' - pydantic<3.0 ; extra == 'upgrade-extension' - pyyaml-include<3.0 ; extra == 'upgrade-extension' @@ -4110,7 +4111,7 @@ packages: - jinja2>=3.0.3 - json5>=0.9.0 - jsonschema>=4.18.0 - - jupyter-server<3,>=1.21 + - jupyter-server>=1.21,<3 - packaging>=21.3 - requests>=2.31 - autodoc-traits ; extra == 'docs' @@ -4126,12 +4127,12 @@ packages: - hatch ; extra == 'test' - ipykernel ; extra == 'test' - openapi-core~=0.18.0 ; extra == 'test' - - openapi-spec-validator<0.8.0,>=0.6.0 ; extra == 'test' + - openapi-spec-validator>=0.6.0,<0.8.0 ; extra == 'test' - pytest-console-scripts ; extra == 'test' - pytest-cov ; extra == 'test' - pytest-jupyter[server]>=0.6.2 ; extra == 'test' - pytest-timeout ; extra == 'test' - - pytest<8,>=7.0 ; extra == 'test' + - pytest>=7.0,<8 ; extra == 'test' - requests-mock ; extra == 'test' - ruamel-yaml ; extra == 'test' - sphinxcontrib-spelling ; extra == 'test' @@ -4235,7 +4236,7 @@ packages: - sphinx-lint ; extra == 'doc' - jaraco-tidelift>=1.4 ; extra == 'doc' - pytest-enabler>=2.2 ; extra == 'enabler' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - pyfakefs ; extra == 'test' - pytest-mypy ; extra == 'type' - pygobject-stubs ; extra == 'type' @@ -4303,7 +4304,7 @@ packages: sha256: c2276486b02f0f1b90be155f2c8ba4a8e194d42775786db622faccd652d8e80c requires_dist: - atomicwrites ; extra == 'atomic-cache' - - interegular<0.4.0,>=0.3.1 ; extra == 'interegular' + - interegular>=0.3.1,<0.4.0 ; extra == 'interegular' - js2py ; extra == 'nearley' - regex ; extra == 'regex' requires_python: '>=3.8' @@ -5116,7 +5117,7 @@ packages: sha256: f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f requires_dist: - jupyter-client>=6.1.12 - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - nbformat>=5.1 - traitlets>=5.4 - pre-commit ; extra == 'dev' @@ -5135,7 +5136,7 @@ packages: - nbconvert>=7.0.0 ; extra == 'test' - pytest-asyncio ; extra == 'test' - pytest-cov>=4.0 ; extra == 'test' - - pytest<8,>=7.0 ; extra == 'test' + - pytest>=7.0,<8 ; extra == 'test' - testpath ; extra == 'test' - xmltodict ; extra == 'test' requires_python: '>=3.8.0' @@ -5153,7 +5154,7 @@ packages: - jupyter-core>=4.7 - jupyterlab-pygments - markupsafe>=2.0 - - mistune<4,>=2.0.3 + - mistune>=2.0.3,<4 - nbclient>=0.5.0 - nbformat>=5.7 - packaging @@ -5198,7 +5199,7 @@ packages: requires_dist: - fastjsonschema>=2.15 - jsonschema>=2.6 - - jupyter-core!=5.0.*,>=4.12 + - jupyter-core>=4.12,!=5.0.* - traitlets>=5.1 - myst-parser ; extra == 'docs' - pydata-sphinx-theme ; extra == 'docs' @@ -5268,10 +5269,10 @@ packages: url: https://files.pythonhosted.org/packages/46/77/53732fbf48196af9e51c2a61833471021c1d77d335d57b96ee3588c0c53d/notebook-7.2.2-py3-none-any.whl sha256: c89264081f671bc02eec0ed470a627ed791b9156cad9285226b31611d3e9fe1c requires_dist: - - jupyter-server<3,>=2.4.0 - - jupyterlab-server<3,>=2.27.1 - - jupyterlab<4.3,>=4.2.0 - - notebook-shim<0.3,>=0.2 + - jupyter-server>=2.4.0,<3 + - jupyterlab-server>=2.27.1,<3 + - jupyterlab>=4.2.0,<4.3 + - notebook-shim>=0.2,<0.3 - tornado>=6.2.0 - hatch ; extra == 'dev' - pre-commit ; extra == 'dev' @@ -5283,8 +5284,8 @@ packages: - sphinxcontrib-spelling ; extra == 'docs' - importlib-resources>=5.0 ; python_full_version < '3.10' and extra == 'test' - ipykernel ; extra == 'test' - - jupyter-server[test]<3,>=2.4.0 ; extra == 'test' - - jupyterlab-server[test]<3,>=2.27.1 ; extra == 'test' + - jupyter-server[test]>=2.4.0,<3 ; extra == 'test' + - jupyterlab-server[test]>=2.27.1,<3 ; extra == 'test' - nbval ; extra == 'test' - pytest-console-scripts ; extra == 'test' - pytest-timeout ; extra == 'test' @@ -5298,7 +5299,7 @@ packages: url: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl sha256: 411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef requires_dist: - - jupyter-server<3,>=1.8 + - jupyter-server>=1.8,<3 - pytest ; extra == 'test' - pytest-console-scripts ; extra == 'test' - pytest-jupyter ; extra == 'test' @@ -6566,7 +6567,7 @@ packages: - platformdirs>=2.5.0 - packaging>=20.0 - requests>=2.19.0 - - tqdm<5.0.0,>=4.41.0 ; extra == 'progress' + - tqdm>=4.41.0,<5.0.0 ; extra == 'progress' - paramiko>=2.7.0 ; extra == 'sftp' - xxhash>=1.4.3 ; extra == 'xxhash' requires_python: '>=3.7' @@ -6671,7 +6672,7 @@ packages: requires_dist: - iniconfig - packaging - - pluggy<2,>=1.5 + - pluggy>=1.5,<2 - exceptiongroup>=1.0.0rc8 ; python_full_version < '3.11' - tomli>=1 ; python_full_version < '3.11' - colorama ; sys_platform == 'win32' @@ -7043,7 +7044,7 @@ packages: sha256: a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 requires_dist: - six>=1.5 - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,>=2.7' + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' - kind: pypi name: python-dotenv version: 1.0.1 @@ -7287,12 +7288,12 @@ packages: url: https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl sha256: 70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 requires_dist: - - charset-normalizer<4,>=2 - - idna<4,>=2.5 - - urllib3<3,>=1.21.1 + - charset-normalizer>=2,<4 + - idna>=2.5,<4 + - urllib3>=1.21.1,<3 - certifi>=2017.4.17 - - pysocks!=1.5.7,>=1.5.6 ; extra == 'socks' - - chardet<6,>=3.0.2 ; extra == 'use-chardet-on-py3' + - pysocks>=1.5.6,!=1.5.7 ; extra == 'socks' + - chardet>=3.0.2,<6 ; extra == 'use-chardet-on-py3' requires_python: '>=3.8' - kind: pypi name: requests-toolbelt @@ -7300,7 +7301,7 @@ packages: url: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl sha256: cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 requires_dist: - - requests<3.0.0,>=2.0.1 + - requests>=2.0.1,<3.0.0 requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' - kind: pypi name: rfc3339-validator @@ -7426,7 +7427,7 @@ packages: - pywin32 ; sys_platform == 'win32' and extra == 'nativelib' - pyobjc-framework-cocoa ; sys_platform == 'darwin' and extra == 'objc' - pywin32 ; sys_platform == 'win32' and extra == 'win32' - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7' + requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*' - kind: pypi name: setuptools version: 75.1.0 @@ -7460,11 +7461,11 @@ packages: - sphinx-inline-tabs ; extra == 'doc' - sphinx-reredirects ; extra == 'doc' - sphinxcontrib-towncrier ; extra == 'doc' - - sphinx-notfound-page<2,>=1 ; extra == 'doc' + - sphinx-notfound-page>=1,<2 ; extra == 'doc' - pyproject-hooks!=1.1 ; extra == 'doc' - towncrier<24.7 ; extra == 'doc' - pytest-enabler>=2.2 ; extra == 'enabler' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - virtualenv>=13.0.0 ; extra == 'test' - wheel>=0.44.0 ; extra == 'test' - pip>=19.1 ; extra == 'test' @@ -7705,7 +7706,7 @@ packages: - pre-commit ; extra == 'test' - pytest-mock ; extra == 'test' - pytest-mypy-testing ; extra == 'test' - - pytest<8.2,>=7.0 ; extra == 'test' + - pytest>=7.0,<8.2 ; extra == 'test' requires_python: '>=3.8' - kind: pypi name: twine @@ -7716,7 +7717,7 @@ packages: - pkginfo>=1.8.1 - readme-renderer>=35.0 - requests>=2.20 - - requests-toolbelt!=0.9.0,>=0.8.0 + - requests-toolbelt>=0.8.0,!=0.9.0 - urllib3>=1.26.0 - importlib-metadata>=3.6 - keyring>=15.1 @@ -7805,8 +7806,8 @@ packages: requires_dist: - brotli>=1.0.9 ; platform_python_implementation == 'CPython' and extra == 'brotli' - brotlicffi>=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'brotli' - - h2<5,>=4 ; extra == 'h2' - - pysocks!=1.5.7,<2.0,>=1.5.6 ; extra == 'socks' + - h2>=4,<5 ; extra == 'h2' + - pysocks>=1.5.6,!=1.5.7,<2.0 ; extra == 'socks' - zstandard>=0.18.0 ; extra == 'zstd' requires_python: '>=3.8' - kind: conda @@ -7963,7 +7964,7 @@ packages: - sphinx-lint ; extra == 'doc' - jaraco-tidelift>=1.4 ; extra == 'doc' - pytest-enabler>=2.2 ; extra == 'enabler' - - pytest!=8.1.*,>=6 ; extra == 'test' + - pytest>=6,!=8.1.* ; extra == 'test' - jaraco-itertools ; extra == 'test' - jaraco-functools ; extra == 'test' - more-itertools ; extra == 'test' diff --git a/pyproject.toml b/pyproject.toml index 880d504..ba7ceea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ dependencies = [ dynamic = ["version"] [project.optional-dependencies] +dev = ["flopy4[lint,test,build]"] lint = [ "ruff" ] diff --git a/test/attrs/test_gwfic.py b/test/attrs/test_gwfic.py deleted file mode 100644 index d407ee0..0000000 --- a/test/attrs/test_gwfic.py +++ /dev/null @@ -1,48 +0,0 @@ -import numpy as np -from attr import define, field -from numpy.typing import NDArray - - -@define -class Options: - export_array_ascii: bool = field( - default=False, - metadata={"longname": "export array variables to netcdf output files"}, - ) - """ - keyword that specifies input griddata arrays should be - written to layered ascii output files. - """ - - export_array_netcdf: bool = field( - default=False, metadata={"longname": "starting head"} - ) - """ - keyword that specifies input griddata arrays should be - written to the model output netcdf file. - """ - - -@define -class PackageData: - strt: NDArray[np.float64] = field( - metadata={"longname": "starting head", "shape": ("nodes")} - ) - """ - is the initial (starting) head---that is, head at the - beginning of the GWF Model simulation. STRT must be specified for - all simulations, including steady-state simulations. One value is - read for every model cell. For simulations in which the first stress - period is steady state, the values used for STRT generally do not - affect the simulation (exceptions may occur if cells go dry and (or) - rewet). The execution time, however, will be less if STRT includes - hydraulic heads that are close to the steady-state solution. A head - value lower than the cell bottom can be provided if a cell should - start as dry. - """ - - -@define -class GwfIc: - options: Options = field() - packagedata: PackageData = field() diff --git a/test/attrs/test_gwfoc.py b/test/attrs/test_gwfoc.py deleted file mode 100644 index 3eeabce..0000000 --- a/test/attrs/test_gwfoc.py +++ /dev/null @@ -1,216 +0,0 @@ -from pathlib import Path -from typing import List, Literal, Optional, Union - -from attr import asdict, define, field, fields_dict -from cattr import Converter - -ArrayFormat = Literal["exponential", "fixed", "general", "scientific"] - - -@define -class PrintFormat: - columns: int = field() - """ - number of columns for writing data - """ - - width: int = field() - """ - width for writing each number - """ - - digits: int = field() - """ - number of digits to use for writing a number - """ - - array_format: ArrayFormat = field() - """ - write format can be EXPONENTIAL, FIXED, GENERAL, or SCIENTIFIC - """ - - -@define -class Options: - budget_file: Optional[Path] = field(default=None) - """ - name of the output file to write budget information - """ - - budget_csv_file: Optional[Path] = field(default=None) - """ - name of the comma-separated value (CSV) output - file to write budget summary information. - A budget summary record will be written to this - file for each time step of the simulation. - """ - - head_file: Optional[Path] = field(default=None) - """ - name of the output file to write head information. - """ - - print_format: Optional[PrintFormat] = field(default=None) - """ - specify format for printing to the listing file - """ - - -@define -class All: - all: bool = field() - """ - keyword to indicate save for all time steps in period. - """ - - -@define -class First: - first: bool = field() - """ - keyword to indicate save for first step in period. - """ - - -@define -class Last: - last: bool = field() - """ - keyword to indicate save for last step in period - """ - - -@define -class Steps: - steps: List[int] = field() - """ - save for each step specified - """ - - -@define -class Frequency: - frequency: int = field() - """ - save at the specified time step frequency. - """ - - -# It's awkward to have single-parameter contexts, but -# it's the only way I got `cattrs` to distinguish the -# choices in the union. There is likely a better way. - - -PrintSave = Literal["print", "save"] -RType = Literal["budget", "head"] -OCSetting = Union[All, First, Last, Steps, Frequency] - - -@define -class OutputControlData: - printsave: PrintSave = field() - rtype: RType = field() - ocsetting: OCSetting = field() - - @classmethod - def from_tuple(cls, t): - t = list(t) - printsave = t.pop(0) - rtype = t.pop(0) - ocsetting = { - "all": All, - "first": First, - "last": Last, - "steps": Steps, - "frequency": Frequency, - }[t.pop(0).lower()](t) - return cls(printsave, rtype, ocsetting) - - -Period = List[OutputControlData] -Periods = List[Period] - - -@define -class GwfOc: - options: Options = field() - """ - options block - """ - - periods: Periods = field() - """ - period blocks - """ - - -# Converter - -converter = Converter() - - -def output_control_data_hook(value, type) -> OutputControlData: - return OutputControlData.from_tuple(value) - - -converter.register_structure_hook(OutputControlData, output_control_data_hook) - - -# Tests - - -def test_spec(): - spec = fields_dict(OutputControlData) - assert len(spec) == 3 - - ocsetting = spec["ocsetting"] - assert ocsetting.type is OCSetting - - -def test_options_to_dict(): - options = Options( - budget_file="some/file/path.cbc", - ) - assert isinstance(options.budget_file, str) # TODO path - assert len(asdict(options)) == 4 - - -def test_output_control_data_from_tuple(): - ocdata = OutputControlData.from_tuple( - ("print", "budget", "steps", 1, 3, 5) - ) - assert ocdata.printsave == "print" - assert ocdata.rtype == "budget" - assert ocdata.ocsetting == Steps([1, 3, 5]) - - -def test_gwfoc_from_dict(): - gwfoc = converter.structure( - { - "options": { - "budget_file": "some/file/path.cbc", - "head_file": "some/file/path.hds", - "print_format": { - "columns": 1, - "width": 10, - "digits": 8, - "array_format": "scientific", - }, - }, - "periods": [ - [ - ("print", "budget", "steps", 1, 3, 5), - ("save", "head", "frequency", 2), - ] - ], - }, - GwfOc, - ) - assert gwfoc.options.budget_file == Path("some/file/path.cbc") - assert gwfoc.options.print_format.width == 10 - assert gwfoc.options.print_format.array_format == "scientific" - period = gwfoc.periods[0] - assert len(period) == 2 - assert period[0] == OutputControlData.from_tuple( - ("print", "budget", "steps", 1, 3, 5) - )