william-silversmith: @shangmu what do you think of this fix? Originally I wanted people to specify bbox via any corners of the bounding box, but it seems like slice notation has additional semantics that make this approach non-sensical, so I added special casing for it.
diff --git a/cloudvolume/frontends/precomputed.py b/cloudvolume/frontends/precomputed.py
index 807561d..6717c5e 100644
--- a/cloudvolume/frontends/precomputed.py
+++ b/cloudvolume/frontends/precomputed.py
@@ -522,6 +522,7 @@ class CloudVolumePrecomputed(object):
 
     slices = self.meta.bbox(self.mip).reify_slices(slices, bounded=self.bounded)
     steps = Vec(*[ slc.step for slc in slices ])
+    slices = [ slice(slc.start, slc.stop) for slc in slices ]
     channel_slice = slices.pop()
     requested_bbox = Bbox.from_slices(slices)
 
diff --git a/cloudvolume/lib.py b/cloudvolume/lib.py
index e3d00fb..2fae1f0 100644
--- a/cloudvolume/lib.py
+++ b/cloudvolume/lib.py
@@ -403,9 +403,13 @@ class Bbox(object):
         slices, bounded=bounded, autocrop=autocrop
       )
 
+    for slc in slices:
+      if slc.step not in (None, 1):
+        raise ValueError("Non-unitary steps are unsupported. Got: " + str(slc.step))
+
     return Bbox(
       [ slc.start for slc in slices ],
-      [ slc.stop for slc in slices ]
+      [ (slc.start if slc.stop < slc.start else slc.stop) for slc in slices ]
     )
 
   @classmethod

Writing to volume (by slicing notation) is not properly checking slice.start < slice.stop
cv[(slice(0,1),slice(0,1),slice(779,344))] = 0  appears to clear out 344:779 rather than the expected behavior of not writing anything because the effective range is empty.
diff --git a/test/test_lib.py b/test/test_lib.py
index c175b5b..0813598 100644
--- a/test/test_lib.py
+++ b/test/test_lib.py
@@ -101,6 +101,21 @@ def test_bbox_division():
   bbox /= 3.0 
   assert np.all(x == point333)
 
+def test_bbox_slicing():
+  bbx_rect = Bbox.from_slices(np.s_[1:10,1:10,1:10])
+  bbx_plane = Bbox.from_slices(np.s_[1:10,10:1,1:10])
+
+  assert bbx_rect == Bbox((1,1,1), (10,10,10))
+  assert bbx_plane == Bbox((1,10,1), (10, 10, 10))
+
+  try:
+    bbx_plane = Bbox.from_slices(np.s_[1:10,10:1:-1,1:10])
+    assert False
+  except ValueError:
+    pass
+
+  bbx_plane = Bbox.from_slices(np.s_[1:10,10:1:1,1:10])
+  assert bbx_plane == Bbox((1,10,1), (10, 10, 10))
 
 
 def test_bbox_intersection():

pip install -e .[all_viewers]
parse_log_pytest
requirements.txt
pytest pytest-cov
apt-get update apt-get install -y g++ python3-dev libffi-dev
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==25.3.0
boto3==1.37.23
botocore==1.37.23
Brotli==1.1.0
cachetools==5.5.2
certifi==2025.1.31
cffi==1.17.1
chardet==5.2.0
charset-normalizer==3.4.1
click==8.1.8
cloud-files==5.1.0
-e git+https://github.com/seung-lab/cloud-volume.git@9395505a1d7baca9a1cd78b5150fec579120569b#egg=cloud_volume
compressed_segmentation==2.3.2
contourpy==1.3.0
coverage==7.8.0
crc32c==2.7.1
cryptography==44.0.2
cycler==0.12.1
deflate==0.8.0
dill==0.3.9
DracoPy==1.5.0
exceptiongroup==1.2.2
fasteners==0.19
fastremap==1.15.1
fonttools==4.56.0
fpzip==1.2.5
gevent==24.11.1
google-api-core==2.24.2
google-auth==2.38.0
google-cloud-core==2.4.3
google-cloud-storage==3.1.0
google-crc32c==1.7.1
google-resumable-media==2.7.2
googleapis-common-protos==1.69.2
greenlet==3.1.1
idna==3.10
importlib_metadata==8.6.1
importlib_resources==6.5.2
inflection==0.5.1
iniconfig==2.1.0
jmespath==1.0.1
json5==0.10.0
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
kiwisolver==1.4.7
Markdown==3.7
matplotlib==3.9.4
multiprocess==0.70.17
numpy==2.0.2
orjson==3.10.16
packaging==24.2
pathos==0.3.3
pillow==11.1.0
pluggy==1.5.0
posix_ipc==1.0.4
pox==0.3.5
ppft==1.7.6.9
proto-plus==1.26.1
protobuf==6.30.2
psutil==5.4.3
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.22
pyOpenSSL==25.0.0
pyparsing==3.2.3
pytest==8.3.5
pytest-cov==6.0.0
python-dateutil==2.9.0.post0
python-jsonschema-objects==0.5.7
referencing==0.36.2
requests==2.32.3
rpds-py==0.24.0
rsa==4.9
s3transfer==0.11.4
six==1.17.0
tenacity==9.0.0
tomli==2.2.1
tqdm==4.67.1
typing_extensions==4.13.0
urllib3==1.26.20
urllib3-secure-extra==0.1.0
vtk==9.4.2
zipp==3.21.0
zope.event==5.0
zope.interface==7.2
zstandard==0.23.0

name: cloud-volume
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==25.3.0
      - boto3==1.37.23
      - botocore==1.37.23
      - brotli==1.1.0
      - cachetools==5.5.2
      - certifi==2025.1.31
      - cffi==1.17.1
      - chardet==5.2.0
      - charset-normalizer==3.4.1
      - click==8.1.8
      - cloud-files==5.1.0
      - compressed-segmentation==2.3.2
      - contourpy==1.3.0
      - coverage==7.8.0
      - crc32c==2.7.1
      - cryptography==44.0.2
      - cycler==0.12.1
      - deflate==0.8.0
      - dill==0.3.9
      - dracopy==1.5.0
      - exceptiongroup==1.2.2
      - fasteners==0.19
      - fastremap==1.15.1
      - fonttools==4.56.0
      - fpzip==1.2.5
      - gevent==24.11.1
      - google-api-core==2.24.2
      - google-auth==2.38.0
      - google-cloud-core==2.4.3
      - google-cloud-storage==3.1.0
      - google-crc32c==1.7.1
      - google-resumable-media==2.7.2
      - googleapis-common-protos==1.69.2
      - greenlet==3.1.1
      - idna==3.10
      - importlib-metadata==8.6.1
      - importlib-resources==6.5.2
      - inflection==0.5.1
      - iniconfig==2.1.0
      - jmespath==1.0.1
      - json5==0.10.0
      - jsonschema==4.23.0
      - jsonschema-specifications==2024.10.1
      - kiwisolver==1.4.7
      - markdown==3.7
      - matplotlib==3.9.4
      - multiprocess==0.70.17
      - numpy==2.0.2
      - orjson==3.10.16
      - packaging==24.2
      - pathos==0.3.3
      - pillow==11.1.0
      - pluggy==1.5.0
      - posix-ipc==1.0.4
      - pox==0.3.5
      - ppft==1.7.6.9
      - proto-plus==1.26.1
      - protobuf==6.30.2
      - psutil==5.4.3
      - pyasn1==0.6.1
      - pyasn1-modules==0.4.2
      - pycparser==2.22
      - pyopenssl==25.0.0
      - pyparsing==3.2.3
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - python-dateutil==2.9.0.post0
      - python-jsonschema-objects==0.5.7
      - referencing==0.36.2
      - requests==2.32.3
      - rpds-py==0.24.0
      - rsa==4.9
      - s3transfer==0.11.4
      - six==1.17.0
      - tenacity==9.0.0
      - tomli==2.2.1
      - tqdm==4.67.1
      - typing-extensions==4.13.0
      - urllib3==1.26.20
      - urllib3-secure-extra==0.1.0
      - vtk==9.4.2
      - zipp==3.21.0
      - zope-event==5.0
      - zope-interface==7.2
      - zstandard==0.23.0
prefix: /opt/conda/envs/cloud-volume

test/test_lib.py::test_bbox_slicing
test/test_lib.py::test_divisors test/test_lib.py::test_find_closest_divisor test/test_lib.py::test_bbox_subvoxel test/test_lib.py::test_vec_division test/test_lib.py::test_bbox_division test/test_lib.py::test_bbox_intersect test/test_lib.py::test_bbox_intersection test/test_lib.py::test_bbox_hashing test/test_lib.py::test_bbox_serialize test/test_lib.py::test_bbox_volume test/test_lib.py::test_jsonify test/test_lib.py::test_bbox_from_filename
cloudvolume/lib.py cloudvolume/frontends/precomputed.py
cloudvolume/lib.py cloudvolume/frontends/precomputed.py