Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ jobs:
run: uv sync --dev

- name: Run tests with coverage
run: uv run pytest -v --cov=src --cov-report=term --cov-report=xml
run: uv run pytest -v --cov=src --cov-branch --cov-report=term --cov-report=xml

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}

lint:
runs-on: ubuntu-latest
Expand Down
46 changes: 26 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

![PyPI Version](https://img.shields.io/pypi/v/casregnum)
![CI](https://github.com/molshape/CASRegistryNumbers/actions/workflows/ci.yml/badge.svg)
[![codecov](https://codecov.io/github/molshape/CASRegistryNumbers/graph/badge.svg?token=5HZN6RX2XA)](https://codecov.io/github/molshape/CASRegistryNumbers) \
![Python Versions](https://img.shields.io/pypi/pyversions/casregnum)
![License](https://img.shields.io/github/license/molshape/casregnum) \
![GitHub stars](https://img.shields.io/github/stars/molshape/casregnum)
Expand All @@ -10,7 +11,7 @@
Python class to manage, check and sort CAS Registry Numbers® (CAS RN®).

<details>
<summary>Table of Content</summary>
<summary>Table of Contents</summary>

1. [Description](#description)
2. [How to install and uninstall?](#how-to-install-and-uninstall)
Expand All @@ -23,17 +24,25 @@ Python class to manage, check and sort CAS Registry Numbers&reg; (CAS RN&reg;).
**casregnum** is a Python class to manage, check, and sort CAS Registry Numbers&reg; (CAS RN&reg;) by the [Chemical Abstracts Service](https://www.cas.org/). Check their official [FAQ website](https://www.cas.org/support/documentation/chemical-substances/faqs) for more information on CAS numbers.


## How to install and uninstall?
## How to install and uninstall
**casregnum** can be installed from the [Python Package Index (PyPI)](https://pypi.org/) repository by calling

pip install casregnum
pip install casregnum

or

uv add casregnum

In order to uninstall **casregnum** from your local environment use

pip uninstall casregnum
pip uninstall casregnum

or

uv remove casregnum


## How to use?
## How to use
**casregnum** provides the `CAS` class for creating a CAS Registry Number&reg; instance:

```Python
Expand Down Expand Up @@ -81,18 +90,15 @@ for i, isomer in enumerate(sorted(octanes), start=1):
print()
```

will generate the following output:

```
str: 58-08-2
int: 58082
check digit: 2
58-08-2 == 58-08-2: True
58-08-2 > 58-08-2: False
79-33-4 > 10326-41-7: False
79-33-4 < 10326-41-7: True
111-65-9, 540-84-1, 560-21-4, 563-16-6, 564-02-3, 565-75-3,
583-48-2, 584-94-1, 589-43-5, 589-53-7, 589-81-1, 590-73-8,
592-13-2, 592-27-8, 594-82-1, 609-26-7, 619-99-8, 1067-08-9,
```

This will generate the following output:

str: 58-08-2
int: 58082
check digit: 2
58-08-2 == 58-08-2: True
58-08-2 > 58-08-2: False
79-33-4 > 10326-41-7: False
79-33-4 < 10326-41-7: True
111-65-9, 540-84-1, 560-21-4, 563-16-6, 564-02-3, 565-75-3,
583-48-2, 584-94-1, 589-43-5, 589-53-7, 589-81-1, 590-73-8,
592-13-2, 592-27-8, 594-82-1, 609-26-7, 619-99-8, 1067-08-9,
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "casregnum"
version = "1.1.0"
version = "1.1.1"
description = "Python class to manage, check and sort CAS Registry Numbers® (CAS RN®)"
readme = "README.md"
authors = [
Expand Down
4 changes: 2 additions & 2 deletions src/casregnum/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
try:
from importlib.metadata import version
__version__ = version("casregnum")
except ImportError:
__version__ = "unknown"
except ImportError: # pragma: no cover
__version__ = "unknown" # pragma: no cover
28 changes: 15 additions & 13 deletions src/casregnum/casregnum.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import re

"""
Class for CAS Registry Numbers® (CAS RN®)
allows to manage, check and sort CAS Registry Numbers®
Expand All @@ -8,6 +6,10 @@
and the calculation method to determine the check digit
"""

from __future__ import annotations

import re


class CAS:
"""
Expand Down Expand Up @@ -53,15 +55,15 @@ def __format__(self, format_spec) -> str:
return f"{self.cas_string:{format_spec}}"

# checks if two CAS Registry Numbers are equal
def __eq__(self, other: object) -> bool:
def __eq__(self, other: CAS) -> bool:
if not isinstance(other, CAS):
return False
raise TypeError("Comparisons can only be made between CAS objects.")
return self.cas_integer == other.cas_integer

# checks if self.cas_integer < other.cas_integer
def __lt__(self, other: object) -> bool:
def __lt__(self, other: CAS) -> bool:
if not isinstance(other, CAS):
return NotImplemented
raise TypeError("Comparisons can only be made between CAS objects.")
return self.cas_integer < other.cas_integer

# Returns CAS Registry Number
Expand All @@ -70,7 +72,7 @@ def cas_string(self) -> str:
"""
Returns the CAS Registry Number as a formatted string (e.g. "58-08-2").
"""
return self.__cas_string
return self._cas_string

# Sets CAS Registry Number
# if the passed input value is a string, parse the string according to _____00-00-0
Expand All @@ -79,23 +81,23 @@ def cas_string(self) -> str:
def cas_string(self, cas_rn: str) -> None:
# convert (formatted) CAS string into integer
if regex_cas := re.match(r"^(\d{2,7})\-(\d{2})-(\d{1})$", cas_rn):
self.cas_integer = self.__cas_integer = int(
self.cas_integer = self._cas_integer = int(
regex_cas.group(1) + regex_cas.group(2) + regex_cas.group(3)
)
# cas_rn is not following the notation rule for CAS numbers => ValueError
else:
raise ValueError(
f"Invalid CAS number format for '{cas_rn}' (must follow the notation _____00-00-0)"
)
self.__cas_string = cas_rn
self._cas_string = cas_rn

# Returns CAS Registry Number as an integer (without the hyphens)
@property
def cas_integer(self) -> int:
"""
Returns the CAS Registry Number as an integer (e.g. 58082).
"""
return self.__cas_integer
return self._cas_integer

@cas_integer.setter
def cas_integer(self, cas_rn: int) -> None:
Expand All @@ -106,15 +108,15 @@ def cas_integer(self, cas_rn: int) -> None:
raise ValueError(
f"Invalid CAS number '{cas_rn}' (must be an integer between 10004 and 9999999995)"
)
self.__cas_integer = cas_rn
self._cas_integer = cas_rn

# Returns check digit of the CAS Registry Number
@property
def check_digit(self) -> int:
"""
Returns the check digit of the CAS Registry Number (e.g. 2 for "58-08-2").
"""
return self.__check_digit
return self._check_digit

# Sets the CAS Registry Number check digit
@check_digit.setter
Expand All @@ -134,4 +136,4 @@ def check_digit(self, digit_to_test: int) -> None:
f"Invalid CAS number '{self.cas_string}' "
f"(found check digit '{digit_to_test}', but expected '{check_sum % 10}')"
)
self.__check_digit = int(digit_to_test)
self._check_digit = int(digit_to_test)
26 changes: 18 additions & 8 deletions test/test_functionality.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,21 +78,31 @@ def test_for_sorting(octanes, octanes_sorted):
# Tests for error handling


@pytest.mark.xfail(raises=TypeError)
def test_cas_equal_invalid(caffeine):
with pytest.raises(TypeError):
assert caffeine == "theine"


def test_cas_lesser_than_invalid(l_lacticacid):
with pytest.raises(TypeError):
assert l_lacticacid < "D-lactic acid"


def test_cas_invalid_input():
CAS(6417.5)
with pytest.raises(TypeError):
CAS(6417.5)


@pytest.mark.xfail(raises=ValueError)
def test_cas_format_unreadable():
CAS("64 - 17 - 5")
with pytest.raises(ValueError):
CAS("64 - 17 - 5")


@pytest.mark.xfail(raises=ValueError)
def test_cas_range_error():
CAS(100)
with pytest.raises(ValueError):
CAS(100)


@pytest.mark.xfail(raises=ValueError)
def test_cas_check_digit_error():
CAS("64-17-6")
with pytest.raises(ValueError):
CAS("64-17-6")
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading