Skip to content

Commit

Permalink
Merge branch 'main' into fix-issue-288
Browse files Browse the repository at this point in the history
  • Loading branch information
paddyroddy committed Aug 7, 2023
2 parents 3e6f19e + 44a1187 commit dcf9d74
Show file tree
Hide file tree
Showing 53 changed files with 883 additions and 1,002 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,19 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.9", "3.10"]
python-version: ["3.9", "3.10", "3.11"]
os: [ubuntu-latest]
include:
- os: macos-11
python-version: "3.10"
python-version: "3.11"
- os: macos-latest
python-version: "3.10"
python-version: "3.11"
- os: windows-2019
python-version: "3.10"
python-version: "3.11"
- os: windows-latest
python-version: "3.10"
python-version: "3.11"
- os: ubuntu-20.04
python-version: "3.10"
python-version: "3.11"

steps:
- name: Checkout source
Expand Down
16 changes: 9 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,19 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ["3.9", "3.10"]
python-version: ["3.9", "3.10", "3.11"]
os: [ubuntu-latest]
include:
- os: macos-11
python-version: "3.10"
python-version: "3.11"
- os: macos-latest
python-version: "3.10"
python-version: "3.11"
- os: windows-2019
python-version: "3.10"
python-version: "3.11"
- os: windows-latest
python-version: "3.10"
python-version: "3.11"
- os: ubuntu-20.04
python-version: "3.10"
python-version: "3.11"

steps:
- uses: actions/checkout@v3
Expand All @@ -87,7 +87,9 @@ jobs:
run: python -m pip install tox tox-gh-actions

- name: Test with tox
run: tox
run: tox run
env:
OS: ${{ matrix.os }}

- name: Coverage
uses: codecov/codecov-action@v3
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,7 @@ instance
lib
lib64
local_settings.py
models/MDCK_*
models/test_config.json
models
nosetests.xml
notebooks
parts
Expand Down
2 changes: 1 addition & 1 deletion .napari-hub/DESCRIPTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,5 @@ If working on Apple Silicon make sure to also install the following
packages from `conda-forge`.

```sh
conda install -c conda-forge cvxopt pyqt
conda install -c conda-forge pyqt
```
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.0.262
rev: v0.0.278
hooks:
- id: ruff
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.1
rev: v1.5.3
hooks:
- id: remove-tabs
exclude: Makefile|docs/Makefile|\.bat$
Expand All @@ -22,15 +22,15 @@ repos:
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- repo: https://github.com/psf/black
rev: 23.3.0
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pappasam/toml-sort
rev: v0.23.0
rev: v0.23.1
hooks:
- id: toml-sort-fix
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v15.0.7
rev: v16.0.6
hooks:
- id: clang-format
types_or: [c++, c, cuda]
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ version: 2
build:
os: ubuntu-20.04
tools:
python: "3.10"
python: "3.11"

# Optionally declare the Python requirements required to build your docs
python:
Expand Down
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
graft btrack/libs
prune docs
prune tests
prune models
prune examples
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ ifeq ($(UNAME), Darwin)
# do something OSX
CXX = clang++ -arch x86_64 -arch arm64
EXT = dylib
XLD_FLAGS = -arch x86_64 -arch arm64
XLDFLAGS =
endif

NVCC = nvcc

# If your compiler is a bit older you may need to change -std=c++17 to -std=c++0x
# If your compiler is a bit older you may need to change -std=c++11 to -std=c++0x
#-I/usr/include/python2.7 -L/usr/lib/python2.7 # -O3
LLDBFLAGS =
CXXFLAGS = -c -std=c++17 -m64 -fPIC -I"./btrack/include" \
CXXFLAGS = -c -std=c++11 -m64 -fPIC -I"./btrack/include" \
-DDEBUG=false -DBUILD_SHARED_LIB
OPTFLAGS = -O3
LDFLAGS = -shared $(XLDFLAGS)
Expand Down
9 changes: 0 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,6 @@ it is now built against `C++=17`.
pip install btrack
```

#### Installing on Apple Silicon

Run the above command with `pip` and then also install the following with
[conda](https://github.com/conda-forge/miniforge).

```sh
conda install -c conda-forge cvxopt
```

## Usage examples

Visit [btrack documentation](https://btrack.readthedocs.io) to learn how to use it and see other examples.
Expand Down
49 changes: 17 additions & 32 deletions btrack/btypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import ctypes
from collections import OrderedDict
from typing import Any, NamedTuple, Optional
from typing import Any, ClassVar, NamedTuple, Optional

import numpy as np

Expand Down Expand Up @@ -86,7 +86,7 @@ class PyTrackObject(ctypes.Structure):
"""

_fields_ = [
_fields_: ClassVar[list] = [
("ID", ctypes.c_long),
("x", ctypes.c_double),
("y", ctypes.c_double),
Expand All @@ -109,9 +109,7 @@ def __init__(self):

@property
def properties(self) -> dict[str, Any]:
if self.dummy:
return {}
return self._properties
return {} if self.dummy else self._properties

@properties.setter
def properties(self, properties: dict[str, Any]):
Expand All @@ -129,10 +127,8 @@ def set_features(self, keys: list[str]) -> None:
self.n_features = 0
return

if not all(k in self.properties for k in keys):
missing_features = list(
set(keys).difference(set(self.properties.keys()))
)
if any(k not in self.properties for k in keys):
missing_features = list(set(keys).difference(set(self.properties.keys())))
raise KeyError(f"Feature(s) missing: {missing_features}.")

# store a reference to the numpy array so that Python maintains
Expand All @@ -153,7 +149,7 @@ def to_dict(self) -> dict[str, Any]:
for k, _ in PyTrackObject._fields_
if k not in ("features", "n_features")
}
node.update(self.properties)
node |= self.properties
return node

@staticmethod
Expand All @@ -174,9 +170,7 @@ def from_dict(properties: dict[str, Any]) -> PyTrackObject:
setattr(obj, key, float(new_data))

# we can add any extra details to the properties dictionary
obj.properties = {
k: v for k, v in properties.items() if k not in fields.keys()
}
obj.properties = {k: v for k, v in properties.items() if k not in fields}
return obj

def __repr__(self):
Expand Down Expand Up @@ -221,7 +215,7 @@ class PyTrackingInfo(ctypes.Structure):
"""

_fields_ = [
_fields_: ClassVar[list] = [
("error", ctypes.c_uint),
("n_tracks", ctypes.c_uint),
("n_active", ctypes.c_uint),
Expand All @@ -239,8 +233,7 @@ def to_dict(self) -> dict[str, Any]:
"""Return a dictionary of the statistics"""
# TODO(arl): make this more readable by converting seconds, ms
# and interpreting error messages?
stats = {k: getattr(self, k) for k, typ in PyTrackingInfo._fields_}
return stats
return {k: getattr(self, k) for k, typ in PyTrackingInfo._fields_}

@property
def tracker_active(self) -> bool:
Expand Down Expand Up @@ -269,7 +262,7 @@ class PyGraphEdge(ctypes.Structure):
source timestamp, we just assume that the tracker has done it's job.
"""

_fields_ = [
_fields_: ClassVar[list] = [
("source", ctypes.c_long),
("target", ctypes.c_long),
("score", ctypes.c_double),
Expand All @@ -278,8 +271,7 @@ class PyGraphEdge(ctypes.Structure):

def to_dict(self) -> dict[str, Any]:
"""Return a dictionary describing the edge."""
edge = {k: getattr(self, k) for k, _ in PyGraphEdge._fields_}
return edge
return {k: getattr(self, k) for k, _ in PyGraphEdge._fields_}


class Tracklet:
Expand Down Expand Up @@ -353,7 +345,7 @@ class Tracklet:
x values.
"""

def __init__(
def __init__( # noqa: PLR0913
self,
ID: int,
data: list[PyTrackObject],
Expand Down Expand Up @@ -397,11 +389,7 @@ def properties(self) -> dict[str, np.ndarray]:
# this to fill the properties array with NaN for dummy objects
property_shapes = {
k: next(
(
np.asarray(o.properties[k]).shape
for o in self._data
if not o.dummy
),
(np.asarray(o.properties[k]).shape for o in self._data if not o.dummy),
None,
)
for k in keys
Expand Down Expand Up @@ -489,9 +477,7 @@ def softmax(self) -> list:

@property
def is_root(self) -> bool:
return (
self.parent == 0 or self.parent is None or self.parent == self.ID
)
return self.parent == 0 or self.parent is None or self.parent == self.ID

@property
def is_leaf(self) -> bool:
Expand Down Expand Up @@ -526,9 +512,9 @@ def to_dict(
"""Return a dictionary of the tracklet which can be used for JSON
export. This is an ordered dictionary for nicer JSON output.
"""
trk_tuple = tuple([(p, getattr(self, p)) for p in properties])
trk_tuple = tuple((p, getattr(self, p)) for p in properties)
data = OrderedDict(trk_tuple)
data.update(self.properties)
data |= self.properties
return data

def to_array(
Expand Down Expand Up @@ -576,8 +562,7 @@ def _pandas_html_repr(obj):
import pandas as pd
except ImportError:
return (
"<b>Install pandas for nicer, tabular rendering.</b> <br>"
+ obj.__repr__()
"<b>Install pandas for nicer, tabular rendering.</b> <br>" + obj.__repr__()
)

obj_as_dict = obj.to_dict()
Expand Down
11 changes: 4 additions & 7 deletions btrack/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import os
from pathlib import Path
from typing import Optional
from typing import ClassVar, Optional

import numpy as np
from pydantic import BaseModel, conlist, validator
Expand Down Expand Up @@ -95,25 +95,22 @@ class TrackerConfig(BaseModel):

@validator("volume", pre=True, always=True)
def _parse_volume(cls, v):
if isinstance(v, tuple):
return ImagingVolume(*v)
return v
return ImagingVolume(*v) if isinstance(v, tuple) else v

@validator("tracking_updates", pre=True, always=True)
def _parse_tracking_updates(cls, v):
_tracking_updates = v
if all(isinstance(k, str) for k in _tracking_updates):
_tracking_updates = [
constants.BayesianUpdateFeatures[k.upper()]
for k in _tracking_updates
constants.BayesianUpdateFeatures[k.upper()] for k in _tracking_updates
]
_tracking_updates = list(set(_tracking_updates))
return _tracking_updates

class Config:
arbitrary_types_allowed = True
validate_assignment = True
json_encoders = {
json_encoders: ClassVar[dict] = {
np.ndarray: lambda x: x.ravel().tolist(),
}

Expand Down
Loading

0 comments on commit dcf9d74

Please sign in to comment.