Repository: chezou/tabula-py

Issue:
Assert column option
**Is your feature request related to a problem? Please describe.**
When given invalid columns option, it passes through to tabula-java and the error message isn't clear.
https://stackoverflow.com/questions/70925281/error-in-tabula-tabula-py-when-specifying-area-parameter

**Describe the solution you'd like**
<!--- A clear and concise description of what you want to happen. -->
Have a validation before calling tabula-java would be nice.

**Describe alternatives you've considered**
<!--- A clear and concise description of any alternative solutions or features you've considered. -->
Just google.

**Additional context**
<!--- Add any other context or screenshots about the feature request here. -->

Discussion:

Patch:
diff --git a/tabula/util.py b/tabula/util.py
index ed0a61e..eacbad2 100644
--- a/tabula/util.py
+++ b/tabula/util.py
@@ -208,12 +208,14 @@ class TabulaOption:
                 if any(type(e) in [list, tuple] for e in self.area):
                     for e in self.area:
                         e = cast(Iterable[float], e)
+                        _validate_area(e)
                         __area = _format_with_relative(e, self.relative_area)
                         __options += ["--area", __area]
                         multiple_areas = True
 
                 else:
                     area = cast(Iterable[float], self.area)
+                    _validate_area(area)
                     __area = _format_with_relative(area, self.relative_area)
                     __options += ["--area", __area]
 
@@ -233,6 +235,9 @@ class TabulaOption:
             __options += ["--outfile", self.output_path]
 
         if self.columns:
+            if self.columns != sorted(self.columns):
+                raise ValueError("columns option should be sorted")
+
             __columns = _format_with_relative(self.columns, self.relative_columns)
             __options += ["--columns", __columns]
 
@@ -253,3 +258,20 @@ def _format_with_relative(values: Iterable[float], is_relative: bool) -> str:
     value_str = ",".join(map(str, values))
 
     return f"{percent}{value_str}"
+
+
+def _validate_area(values: Iterable[float]) -> None:
+    value_length = len(list(values))
+    if value_length != 4:
+        raise ValueError(
+            f"area should have 4 values for each option but {values} has {value_length}"
+        )
+    top, left, bottom, right = values
+    if top >= bottom:
+        raise ValueError(
+            f"area option bottom={bottom} should be greater than top={top}"
+        )
+    if left >= right:
+        raise ValueError(
+            f"area option right={right} should be greater than left={left}"
+        )


Test patch:
diff --git a/tests/test_util.py b/tests/test_util.py
index 579e2f2..8202360 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -76,6 +76,30 @@ class TestUtil(unittest.TestCase):
         self.assertTrue(fname.endswith("123456789012345678901234567890.pdf"))
         self.addCleanup(os.remove, fname)
 
+    def test_tabula_option_area_order(self):
+        self.assertTrue(
+            type(tabula.util.TabulaOption(area=[2, 3, 4, 6]).build_option_list()), list
+        )
+        with self.assertRaises(ValueError):
+            tabula.util.TabulaOption(area=[3, 4, 1]).build_option_list()
+        with self.assertRaises(ValueError):
+            tabula.util.TabulaOption(area=[3, 4, 1, 2]).build_option_list()
+        self.assertTrue(
+            type(tabula.util.TabulaOption(area=[[2, 3, 4, 6]]).build_option_list()),
+            list,
+        )
+        with self.assertRaises(ValueError):
+            tabula.util.TabulaOption(area=[[3, 4, 1]]).build_option_list()
+        with self.assertRaises(ValueError):
+            tabula.util.TabulaOption(area=[[3, 4, 1, 2]]).build_option_list()
+
+    def test_tabula_option_columns_order(self):
+        self.assertTrue(
+            type(tabula.util.TabulaOption(columns=[2, 3, 4]).build_option_list()), list
+        )
+        with self.assertRaises(ValueError):
+            tabula.util.TabulaOption(columns=[3, 4, 1]).build_option_list()
+
 
 if __name__ == "__main__":
     unittest.main()