diff --git a/src/_core/src/pybind.cpp b/src/_core/src/pybind.cpp index 3d1dafa..96501f5 100644 --- a/src/_core/src/pybind.cpp +++ b/src/_core/src/pybind.cpp @@ -90,8 +90,23 @@ PYBIND11_MODULE(_core, m) { "BitInFormat", R"pbdoc(The BitInFormat class specifies an extractable archive format.)pbdoc") .def("value", &bit7z::BitInFormat::value, py::doc(R"pbdoc(the value of the format in the 7z SDK.)pbdoc")) - .def("__eq__", &bit7z::BitInFormat::operator==) - .def("__ne__", &bit7z::BitInFormat::operator!=); + .def("__hash__", [](const bit7z::BitInFormat &self) { return std::hash()(self.value()); }) + .def( + "__eq__", + [](const bit7z::BitInFormat &self, const py::object &other) { + if (py::isinstance(other)) + return self == *py::cast(other); + return false; + }, + py::is_operator()) + .def( + "__ne__", + [](const bit7z::BitInFormat &self, const py::object &other) { + if (py::isinstance(other)) + return self != *py::cast(other); + return false; + }, + py::is_operator()); // bit7z::BitInOutFormat class bindings py::class_( @@ -329,7 +344,11 @@ PYBIND11_MODULE(_core, m) { "BitGenericItem", R"pbdoc(The BitGenericItem interface class represents a generic item (either inside or outside an archive).)pbdoc") - .def("is_dir", &bit7z::BitGenericItem::isDir) + .def( + "is_dir", + &bit7z::BitGenericItem::isDir, + py::doc( + R"pbdoc(true if and only if the item is a directory (i.e., it has the property BitProperty::IsDir))pbdoc")) .def("size", &bit7z::BitGenericItem::size, py::doc(R"pbdoc(the uncompressed size of the item.)pbdoc")) .def( "name", @@ -370,9 +389,41 @@ PYBIND11_MODULE(_core, m) { m, "BitArchiveItemOffset", R"pbdoc(The BitArchiveItemOffset class represents an archived item but doesn't store its properties.)pbdoc") - .def("__eq__", &bit7z::BitArchiveItemOffset::operator==) - .def("__ne__", &bit7z::BitArchiveItemOffset::operator!=) - .def("__iadd__", [](bit7z::BitArchiveItemOffset &self, int val) { return self.operator++(val); }) + .def( + "__eq__", + [](const bit7z::BitArchiveItemOffset &self, py::object other) { + if (py::isinstance(other)) + return self == *py::cast(other); + return false; + }, + py::arg("other"), + py::is_operator()) + .def("__hash__", + [](const bit7z::BitArchiveItemOffset &self) { + return std::hash()(self.index()) ^ (std::hash()(self.isDir()) << 1) + ^ (std::hash()(self.size()) << 2) ^ (std::hash()(self.packSize()) << 3) + ^ (std::hash()(self.crc()) << 4) + ^ (std::hash()(self.creationTime().time_since_epoch().count()) << 5) + ^ (std::hash()(self.lastAccessTime().time_since_epoch().count()) << 6) + ^ (std::hash()(self.lastWriteTime().time_since_epoch().count()) << 7) + ^ (std::hash()(self.attributes()) << 8) ^ (std::hash()(self.path()) << 9) + ^ (std::hash()(self.name()) << 10) + ^ (std::hash()(self.extension()) << 11) + ^ (std::hash()(bit7z::to_tstring(self.nativePath())) << 12); + }) + .def( + "__ne__", + [](const bit7z::BitArchiveItemOffset &self, py::object other) { + if (py::isinstance(other)) + return self != *py::cast(other); + return false; + }, + py::arg("other"), + py::is_operator()) + .def( + "__iadd__", + [](bit7z::BitArchiveItemOffset &self, int val) { return self.operator++(val); }, + py::is_operator()) .def("item_property", &bit7z::BitArchiveItemOffset::itemProperty, py::doc(R"pbdoc(Gets the specified item property. diff --git a/src/pybit7z/_core.pyi b/src/pybit7z/_core.pyi index 5c15c39..0a708d4 100644 --- a/src/pybit7z/_core.pyi +++ b/src/pybit7z/_core.pyi @@ -669,8 +669,10 @@ class BitArchiveItemOffset(BitArchiveItem): """ The BitArchiveItemOffset class represents an archived item but doesn't store its properties. """ - + def __eq__(self, other: typing.Any) -> bool: ... + def __hash__(self) -> int: ... def __iadd__(self, arg0: int) -> BitArchiveItemOffset: ... + def __ne__(self, other: typing.Any) -> bool: ... def item_property(self, arg0: BitProperty) -> BitPropVariant: """ Gets the specified item property. @@ -992,7 +994,10 @@ class BitGenericItem: """ the item attributes. """ - def is_dir(self) -> bool: ... + def is_dir(self) -> bool: + """ + true if and only if the item is a directory (i.e., it has the property BitProperty::IsDir) + """ def name(self) -> str: """ the name of the item, if available or inferable from the path, or an empty string otherwise. @@ -1010,7 +1015,9 @@ class BitInFormat: """ The BitInFormat class specifies an extractable archive format. """ - + def __eq__(self, arg0: typing.Any) -> bool: ... + def __hash__(self) -> int: ... + def __ne__(self, arg0: typing.Any) -> bool: ... def value(self) -> int: """ the value of the format in the 7z SDK. diff --git a/tests/test_bit7z.py b/tests/test_bit7z.py index ddd6adc..81135f3 100644 --- a/tests/test_bit7z.py +++ b/tests/test_bit7z.py @@ -38,6 +38,18 @@ def large_file(temp_dir): return file_path +def test_format(): + """Test format from bit7z""" + assert core.FormatSevenZip.extension().endswith(".7z") + assert core.FormatSevenZip != core.FormatZip + assert core.FormatSevenZip == core.FormatSevenZip + assert core.FormatSevenZip.has_feature(core.FormatFeatures.CompressionLevel) + assert core.FormatSevenZip.has_feature(core.FormatFeatures.Encryption) + assert core.FormatSevenZip.has_feature(core.FormatFeatures.MultipleFiles) + assert core.FormatSevenZip.has_feature(core.FormatFeatures.HeaderEncryption) + assert core.FormatSevenZip.has_feature(core.FormatFeatures.SolidArchive) + + def test_format_features(): """Test format features detection""" fmt_7z = core.FormatSevenZip