Skip to content

Commit

Permalink
- improved type-hinting using PathLike, IO & Sequence
Browse files Browse the repository at this point in the history
- fix some linting errors
  • Loading branch information
dugalh committed Jan 29, 2024
1 parent 04641ba commit 9490c6e
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 121 deletions.
3 changes: 2 additions & 1 deletion orthority/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
"""Orthorectification toolkit."""
import os
import pathlib

from orthority.camera import create_camera
from orthority.enums import CameraType, Interp, Compress
from orthority.enums import CameraType, Compress, Interp
from orthority.ortho import Ortho

# enable on-demand download and caching of proj transformation grids
Expand Down
25 changes: 13 additions & 12 deletions orthority/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import re
import sys
from pathlib import Path
from typing import Sequence
from urllib.parse import urlparse

import click
Expand Down Expand Up @@ -117,7 +118,7 @@ class CondReqOption(click.Option):
"""

# adapted from https://stackoverflow.com/questions/44247099/click-command-line-interfaces-make-options-required-if-other-optional-option-is
def __init__(self, *args, not_required: list[str] | None = None, **kwargs):
def __init__(self, *args, not_required: Sequence[str] | None = None, **kwargs):
self.not_required = not_required or []
click.Option.__init__(self, *args, **kwargs)

Expand Down Expand Up @@ -172,8 +173,8 @@ def _crs_cb(ctx: click.Context, param: click.Parameter, crs: str):


def _src_files_cb(
ctx: click.Context, param: click.Parameter, src_files: tuple[str, ...]
) -> tuple[OpenFile, ...]:
ctx: click.Context, param: click.Parameter, src_files: Sequence[str]
) -> Sequence[OpenFile]:
"""Click callback to form a list of source file OpenFile instances. ``src_files`` can be a
list of file paths / URIs, or a list of path / URI glob patterns.
"""
Expand Down Expand Up @@ -265,7 +266,7 @@ def _odm_out_dir_cb(ctx: click.Context, param: click.Parameter, out_dir: str) ->


def _ortho(
src_files: tuple[OpenFile, ...],
src_files: Sequence[OpenFile],
dem_file: OpenFile,
int_param_dict: dict[str, dict],
ext_param_dict: dict[str, dict],
Expand Down Expand Up @@ -304,9 +305,9 @@ def _ortho(
with dem_ctx as dem_im:
# validate dem_band
if dem_band <= 0 or dem_band > dem_im.count:
dem_name = utils.get_filename(dem_im)
raise click.BadParameter(
f"DEM band {dem_band} is invalid for '{dem_im.filename}' with {dem_im.count} "
f"band(s).",
f"DEM band {dem_band} is invalid for '{dem_name}' with {dem_im.count} band(s).",
param_hint="'-db' / '--dem-band'",
)

Expand Down Expand Up @@ -570,7 +571,7 @@ def _ortho(
@click.option('--quiet', '-q', count=True, help='Decrease verbosity.')
@click.version_option(version=__version__, message='%(version)s')
@click.pass_context
def cli(ctx: click.Context, verbose, quiet):
def cli(ctx: click.Context, verbose, quiet) -> None:
"""Orthorectification toolkit."""
verbosity = verbose - quiet
_configure_logging(verbosity)
Expand Down Expand Up @@ -614,7 +615,7 @@ def ortho(
lla_crs: rio.CRS,
radians: bool,
**kwargs,
):
) -> None:
"""
Orthorectify SOURCE images with camera model(s) defined by interior and exterior parameter
files.
Expand Down Expand Up @@ -643,7 +644,7 @@ def ortho(
"""
# read interior params
try:
int_param_suffix = Path(int_param_file.full_name).suffix.lower()
int_param_suffix = Path(int_param_file.path).suffix.lower()
if int_param_suffix in ['.yaml', '.yml']:
int_param_dict = param_io.read_oty_int_param(int_param_file)
elif int_param_suffix == '.json':
Expand All @@ -655,7 +656,7 @@ def ortho(

# read exterior params
try:
ext_param_suffix = Path(ext_param_file.full_name).suffix.lower()
ext_param_suffix = Path(ext_param_file.path).suffix.lower()
if ext_param_suffix in ['.csv', '.txt']:
reader = param_io.CsvReader(ext_param_file, crs=crs, lla_crs=lla_crs, radians=radians)
elif ext_param_suffix == '.json':
Expand Down Expand Up @@ -706,7 +707,7 @@ def ortho(
@export_params_option
@out_dir_option
@overwrite_option
def exif(src_files: tuple[OpenFile, ...], crs: rio.CRS, lla_crs: rio.CRS, **kwargs):
def exif(src_files: Sequence[OpenFile], crs: rio.CRS, lla_crs: rio.CRS, **kwargs) -> None:
"""
Orthorectify SOURCE images with camera model(s) defined by image EXIF / XMP tags.
Expand Down Expand Up @@ -795,7 +796,7 @@ def odm(
resolution: tuple[float, float],
out_dir: OpenFile,
**kwargs,
):
) -> None:
"""
Orthorectify images in a processed OpenDroneMap dataset that includes a DSM.
Expand Down
19 changes: 10 additions & 9 deletions orthority/exif.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from __future__ import annotations

import logging
from pathlib import Path
from os import PathLike
from typing import Sequence
from xml.etree import cElementTree as ET

import numpy as np
Expand All @@ -32,7 +33,7 @@
dji=dict(
lla_keys=[
'{http://www.dji.com/drone-dji/1.0/}GpsLatitude',
'{http://www.dji.com/drone-dji/1.0/}GpsLongtitude',
'{http://www.dji.com/drone-dji/1.0/}GpsLongitude',
'{http://www.dji.com/drone-dji/1.0/}AbsoluteAltitude',
],
rpy_keys=[
Expand Down Expand Up @@ -105,7 +106,7 @@ class Exif:
object in binary mode ('rb'), or a dataset reader.
"""

def __init__(self, file: str | Path | OpenFile | rio.DatasetReader):
def __init__(self, file: str | PathLike | OpenFile | rio.DatasetReader):
self._filename = utils.get_filename(file)
with utils.suppress_no_georef(), rio.Env(GDAL_NUM_THREADS='ALL_CPUS'), utils.OpenRaster(
file, 'r'
Expand All @@ -121,7 +122,7 @@ def __init__(self, file: str | Path | OpenFile | rio.DatasetReader):
xmp_str = xmp_dict['xml:XMP'].strip('xml:XMP=')
xmp_dict = _xml_to_flat_dict(xmp_str)
else:
logger.debug(f"'{Path(self._filename).name}' contains no XMP metadata")
logger.debug(f"'{self._filename}' contains no XMP metadata")

self._make, self._model, self._serial = self._get_make_model_serial(exif_dict)
self._tag_im_size = self._get_tag_im_size(exif_dict)
Expand Down Expand Up @@ -213,12 +214,12 @@ def rpy(self) -> tuple[float, float, float] | None:
return self._rpy

@property
def dewarp(self) -> tuple[float] | None:
def dewarp(self) -> Sequence[float] | None:
"""Dewarp parameters."""
return self._dewarp

@staticmethod
def _get_exif_float(exif_dict: dict[str, str], key: str) -> float | tuple[float] | None:
def _get_exif_float(exif_dict: dict[str, str], key: str) -> float | tuple[float, ...] | None:
"""Convert numeric EXIF tag to float(s)."""
if key not in exif_dict:
return None
Expand Down Expand Up @@ -295,7 +296,7 @@ def _get_orientation(exif_dict: dict[str, str]) -> int | None:

@staticmethod
def _get_lla(exif_dict: dict[str, str]) -> tuple[float, float, float] | None:
"""Return the (latitutde, longitude, altitude) EXIF image location with latitude, longitude
"""Return the (latitude, longitude, altitude) EXIF image location with latitude, longitude
in decimal degrees, and altitude in meters.
"""
lat_ref_key = 'EXIF_GPSLatitudeRef'
Expand All @@ -306,7 +307,7 @@ def _get_lla(exif_dict: dict[str, str]) -> tuple[float, float, float] | None:
return None

# get latitude, longitude
def dms_to_decimal(dms: tuple[float], ref: str):
def dms_to_decimal(dms: Sequence[float], ref: str):
"""Convert (degrees, minutes, seconds) tuple to decimal degrees, applying reference
sign.
"""
Expand Down Expand Up @@ -345,7 +346,7 @@ def _get_xmp_rpy(xmp_dict: dict[str, str]) -> tuple[float, float, float] | None:
return None

@staticmethod
def _get_xmp_dewarp(xmp_dict: dict[str, str]) -> tuple[float] | None:
def _get_xmp_dewarp(xmp_dict: dict[str, str]) -> Sequence[float] | None:
"""Return the camera dewarp parameters if they exist."""
for schema_name, xmp_schema in _xmp_schemas.items():
dewarp_str = xmp_dict.get(xmp_schema['dewarp_key'], None)
Expand Down
17 changes: 9 additions & 8 deletions orthority/ortho.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
# You should have received a copy of the GNU Affero General Public License along with Orthority.
# If not, see <https://www.gnu.org/licenses/>.

"""Orthrectification using DEM and camera model input."""
"""Orthorectification using DEM and camera model input."""
from __future__ import annotations

import logging
import os
import threading
from concurrent.futures import as_completed, ThreadPoolExecutor
from pathlib import Path
from os import PathLike
from typing import Sequence

import cv2
import numpy as np
Expand Down Expand Up @@ -99,8 +100,8 @@ class Ortho:

def __init__(
self,
src_file: str | Path | OpenFile | rio.DatasetReader,
dem_file: str | Path | OpenFile | rio.DatasetReader,
src_file: str | PathLike | OpenFile | rio.DatasetReader,
dem_file: str | PathLike | OpenFile | rio.DatasetReader,
camera: Camera,
crs: str | CRS | None = None,
dem_band: int = 1,
Expand Down Expand Up @@ -154,7 +155,7 @@ def _parse_crs(self, crs: str | CRS) -> CRS:
return crs

def _get_init_dem(
self, dem_file: str | rio.DatasetReader, dem_band: int
self, dem_file: str | PathLike | rio.DatasetReader, dem_band: int
) -> tuple[np.ndarray, rio.Affine, CRS, bool]:
"""Return an initial DEM array in its own CRS and resolution. Includes the corresponding
DEM transform, CRS, and flag indicating ortho and DEM CRS equality in return values.
Expand Down Expand Up @@ -419,7 +420,7 @@ def inv_transform(transform: rio.Affine, xy: np.ndarray) -> np.ndarray:
def _create_ortho_profile(
self,
src_im: rio.DatasetReader,
shape: tuple[int, ...],
shape: Sequence[int],
transform: rio.Affine,
dtype: str,
compress: str | Compress | None,
Expand Down Expand Up @@ -630,7 +631,7 @@ def _remap(
# in _remap_tile (requires N-up transform).
# float64 precision is needed for the (x, y) ortho grids in world coordinates for e.g. high
# resolution drone imagery.
# gdal / rio geotransform origin refers to the pixel UL corner while OpenCV remap etc
# gdal / rio geotransform origin refers to the pixel UL corner while OpenCV remap etc.
# integer pixel coords refer to pixel centers, so the (x, y) coords are offset by half a
# pixel to account for this.

Expand Down Expand Up @@ -692,7 +693,7 @@ def _remap(

def process(
self,
ortho_file: str | Path | OpenFile,
ortho_file: str | PathLike | OpenFile,
resolution: tuple[float, float] = _default_config['resolution'],
interp: str | Interp = _default_config['interp'],
dem_interp: str | Interp = _default_config['dem_interp'],
Expand Down
Loading

0 comments on commit 9490c6e

Please sign in to comment.