From 702a4e77969dbf5aa749ed0246d6877604afb625 Mon Sep 17 00:00:00 2001
From: "m.slavoshevski@cian.ru" <m.slavoshevski@cian.ru>
Date: Tue, 17 Dec 2019 20:22:12 +0300
Subject: [PATCH 1/2] HiveTableTarget inherited from HivePartitionTarget

---
 luigi/contrib/hive.py     | 65 +++++++++++++--------------------------
 test/contrib/hive_test.py |  5 +--
 2 files changed, 25 insertions(+), 45 deletions(-)

diff --git a/luigi/contrib/hive.py b/luigi/contrib/hive.py
index ac07103329..03e481d7da 100644
--- a/luigi/contrib/hive.py
+++ b/luigi/contrib/hive.py
@@ -469,34 +469,6 @@ def run_job(self, job, tracking_url_callback=None):
             return luigi.contrib.hadoop.run_and_track_hadoop_job(arglist, job.set_tracking_url)
 
 
-class HiveTableTarget(luigi.Target):
-    """
-    exists returns true if the table exists.
-    """
-
-    def __init__(self, table, database='default', client=None):
-        self.database = database
-        self.table = table
-        self.client = client or get_default_client()
-
-    def exists(self):
-        logger.debug("Checking if Hive table '%s.%s' exists", self.database, self.table)
-        return self.client.table_exists(self.table, self.database)
-
-    @property
-    def path(self):
-        """
-        Returns the path to this table in HDFS.
-        """
-        location = self.client.table_location(self.table, self.database)
-        if not location:
-            raise Exception("Couldn't find location for table: {0}".format(str(self)))
-        return location
-
-    def open(self, mode):
-        return NotImplementedError("open() is not supported for HiveTableTarget")
-
-
 class HivePartitionTarget(luigi.Target):
     """
     exists returns true if the table's partition exists.
@@ -507,7 +479,6 @@ def __init__(self, table, partition, database='default', fail_missing_table=True
         self.table = table
         self.partition = partition
         self.client = client or get_default_client()
-
         self.fail_missing_table = fail_missing_table
 
     def exists(self):
@@ -516,7 +487,7 @@ def exists(self):
                 "Checking Hive table '{d}.{t}' for partition {p}".format(
                     d=self.database,
                     t=self.table,
-                    p=str(self.partition)
+                    p=str(self.partition or {})
                 )
             )
 
@@ -543,14 +514,28 @@ def path(self):
         return location
 
     def open(self, mode):
-        return NotImplementedError("open() is not supported for HivePartitionTarget")
+        return NotImplementedError("open() is not supported for {}".format(self.__class__.__name__))
+
+
+class HiveTableTarget(HivePartitionTarget):
+    """
+    exists returns true if the table exists.
+    """
+
+    def __init__(self, table, database='default', client=None):
+        super(HiveTableTarget, self).__init__(
+            table=table,
+            partition=None,
+            database=database,
+            fail_missing_table=True,
+            client=client,
+        )
 
 
 class ExternalHiveTask(luigi.ExternalTask):
     """
     External task that depends on a Hive table/partition.
     """
-
     database = luigi.Parameter(default='default')
     table = luigi.Parameter()
     partition = luigi.DictParameter(
@@ -559,14 +544,8 @@ class ExternalHiveTask(luigi.ExternalTask):
     )
 
     def output(self):
-        if self.partition:
-            return HivePartitionTarget(
-                database=self.database,
-                table=self.table,
-                partition=self.partition,
-            )
-        else:
-            return HiveTableTarget(
-                database=self.database,
-                table=self.table,
-            )
+        return HivePartitionTarget(
+            database=self.database,
+            table=self.table,
+            partition=self.partition,
+        )
diff --git a/test/contrib/hive_test.py b/test/contrib/hive_test.py
index 7dac032baf..a50cd0f8f3 100644
--- a/test/contrib/hive_test.py
+++ b/test/contrib/hive_test.py
@@ -460,7 +460,7 @@ def test_hive_table_target(self):
         client = mock.Mock()
         target = luigi.contrib.hive.HiveTableTarget(database='db', table='foo', client=client)
         target.exists()
-        client.table_exists.assert_called_with('foo', 'db')
+        client.table_exists.assert_called_with('foo', 'db', None)
 
     def test_hive_partition_target(self):
         client = mock.Mock()
@@ -480,9 +480,10 @@ class _Task(luigi.contrib.hive.ExternalHiveTask):
         output = _Task().output()
 
         # assert
-        assert isinstance(output, luigi.contrib.hive.HiveTableTarget)
+        assert isinstance(output, luigi.contrib.hive.HivePartitionTarget)
         assert output.database == 'schema1'
         assert output.table == 'table1'
+        assert output.partition == {}
 
     def test_partition_exists(self):
         # arrange

From 76a4a2b609534d938983ad4f72712b0bae2e7830 Mon Sep 17 00:00:00 2001
From: "m.slavoshevski@cian.ru" <m.slavoshevski@cian.ru>
Date: Mon, 30 Dec 2019 11:13:44 +0300
Subject: [PATCH 2/2] docstrings improved

---
 luigi/contrib/hive.py | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/luigi/contrib/hive.py b/luigi/contrib/hive.py
index 03e481d7da..189d96e987 100644
--- a/luigi/contrib/hive.py
+++ b/luigi/contrib/hive.py
@@ -471,10 +471,20 @@ def run_job(self, job, tracking_url_callback=None):
 
 class HivePartitionTarget(luigi.Target):
     """
-    exists returns true if the table's partition exists.
+    Target representing Hive table or Hive partition
     """
 
     def __init__(self, table, partition, database='default', fail_missing_table=True, client=None):
+        """
+        @param table: Table name
+        @type table: str
+        @param partition: partition specificaton in form of
+        dict of {"partition_column_1": "partition_value_1", "partition_column_2": "partition_value_2", ... }
+        If `partition` is `None` or `{}` then target is Hive nonpartitioned table
+        @param database: Database name
+        @param fail_missing_table: flag to ignore errors raised due to table nonexistence
+        @param client: `HiveCommandClient` instance. Default if `client is None`
+        """
         self.database = database
         self.table = table
         self.partition = partition
@@ -482,6 +492,9 @@ def __init__(self, table, partition, database='default', fail_missing_table=True
         self.fail_missing_table = fail_missing_table
 
     def exists(self):
+        """
+        returns `True` if the partition/table exists
+        """
         try:
             logger.debug(
                 "Checking Hive table '{d}.{t}' for partition {p}".format(
@@ -513,13 +526,10 @@ def path(self):
             raise Exception("Couldn't find location for table: {0}".format(str(self)))
         return location
 
-    def open(self, mode):
-        return NotImplementedError("open() is not supported for {}".format(self.__class__.__name__))
-
 
 class HiveTableTarget(HivePartitionTarget):
     """
-    exists returns true if the table exists.
+    Target representing non-partitioned table
     """
 
     def __init__(self, table, database='default', client=None):
@@ -527,7 +537,7 @@ def __init__(self, table, database='default', client=None):
             table=table,
             partition=None,
             database=database,
-            fail_missing_table=True,
+            fail_missing_table=False,
             client=client,
         )