From b4aee3f504e6ad957b7091cd267d1b0a922ca5d7 Mon Sep 17 00:00:00 2001
From: Brandon Rodriguez <brodriguez8774@gmail.com>
Date: Fri, 15 Nov 2019 02:25:15 -0500
Subject: [PATCH] Generally rework project imports to be more library friendly

---
 __init__.py                       | 22 ++++++++++++++++++++++
 documents/references.md           |  7 +++++++
 resources/basic_graph/edge.py     | 20 ++++++++++++++++----
 resources/basic_graph/graph.py    | 20 ++++++++++++++++----
 resources/basic_graph/node.py     | 20 ++++++++++++++++----
 resources/directed_graph/edge.py  | 18 +++++++++++++++---
 resources/directed_graph/graph.py | 18 +++++++++++++++---
 resources/directed_graph/node.py  | 18 +++++++++++++++---
 resources/state_machine/edge.py   | 18 +++++++++++++++---
 resources/state_machine/graph.py  | 19 +++++++++++++++----
 resources/state_machine/node.py   | 18 +++++++++++++++---
 11 files changed, 167 insertions(+), 31 deletions(-)

diff --git a/__init__.py b/__init__.py
index e69de29..eb5e7d3 100644
--- a/__init__.py
+++ b/__init__.py
@@ -0,0 +1,22 @@
+"""
+Library base importing definitions.
+"""
+
+# Import files/values we want to be available to library users.
+from .resources.basic_graph.edge import Edge as BasicEdge
+from .resources.basic_graph.node import Node as BasicNode
+from .resources.basic_graph.graph import Graph as BasicGraph
+from .resources.directed_graph.edge import Edge as DirectedEdge
+from .resources.directed_graph.node import Node as DirectedNode
+from .resources.directed_graph.graph import Graph as DirectedGraph
+from .resources.state_machine.edge import Edge as StateMachineEdge
+from .resources.state_machine.node import Node as StateMachineNode
+from .resources.state_machine.graph import Graph as StateMachineGraph
+
+
+# Define imports when using the * flag on this library.
+__all__ = [
+    BasicEdge, BasicNode, BasicGraph,
+    DirectedEdge, DirectedNode, DirectedGraph,
+    StateMachineEdge, StateMachineNode, StateMachineGraph,
+]
diff --git a/documents/references.md b/documents/references.md
index 1569029..18f386e 100644
--- a/documents/references.md
+++ b/documents/references.md
@@ -8,6 +8,13 @@ All references to external logic. Includes anything from stack overflow links to
 ## New References
 References new to this project.
 
+### Python Project as a Library
+Various recommendations for using a project as a library for other projects:
+* Don't configure extra handlers inside the library: <https://docs.python-guide.org/writing/logging/>
+* General Library Rules, Mostly Concerning \_\_init\_\_.py:
+<https://axialcorps.wordpress.com/2013/08/29/5-simple-rules-for-building-great-python-packages/>
+* Many Recommendations for Project Structure: <https://docs.python-guide.org/writing/structure/>
+
 ### Git Submodules
 Since I don't know how Python projects are exported to be a pip library (and I'm not even sure if that's a good use case
 for this project), it's being set up as a submodule project for now.
diff --git a/resources/basic_graph/edge.py b/resources/basic_graph/edge.py
index 4d40220..57de3be 100644
--- a/resources/basic_graph/edge.py
+++ b/resources/basic_graph/edge.py
@@ -14,15 +14,27 @@ Essentially the "node connection" in a Graph data structure.
 
 # User Class Imports.
 import resources.basic_graph.node as basic_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Edge():
-    def __init__(self, name):
+    def __init__(self, name, *args, **kwargs):
         # Check for passed arg types.
         if name is None:
             raise TypeError('Edge must be passed a string-convertable name.')
diff --git a/resources/basic_graph/graph.py b/resources/basic_graph/graph.py
index c890249..34a7a32 100644
--- a/resources/basic_graph/graph.py
+++ b/resources/basic_graph/graph.py
@@ -15,15 +15,27 @@ from random import randint
 # User Class Imports.
 import resources.basic_graph.edge as basic_edge
 import resources.basic_graph.node as basic_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Graph():
-    def __init__(self):
+    def __init__(self, *args, **kwargs):
         # Lists of nodes and edges in graph.
         self._edges = {}
         self._nodes = {}
diff --git a/resources/basic_graph/node.py b/resources/basic_graph/node.py
index 2dfdb50..a811174 100644
--- a/resources/basic_graph/node.py
+++ b/resources/basic_graph/node.py
@@ -14,15 +14,27 @@ Essentially the "vertex" in a Graph data structure.
 
 # User Class Imports.
 import resources.basic_graph.edge as basic_edge
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Node():
-    def __init__(self, name):
+    def __init__(self, name, *args, **kwargs):
         # Check for passed arg types.
         if name is None:
             raise TypeError('Node must be passed a string-convertable name.')
diff --git a/resources/directed_graph/edge.py b/resources/directed_graph/edge.py
index 4302a25..0f1efef 100644
--- a/resources/directed_graph/edge.py
+++ b/resources/directed_graph/edge.py
@@ -15,11 +15,23 @@ Essentially the "node connection" in a Graph data structure.
 # User Class Imports.
 import resources.basic_graph.edge as basic_edge
 import resources.directed_graph.node as directed_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Edge(basic_edge.Edge):
diff --git a/resources/directed_graph/graph.py b/resources/directed_graph/graph.py
index 97097eb..20753a8 100644
--- a/resources/directed_graph/graph.py
+++ b/resources/directed_graph/graph.py
@@ -16,11 +16,23 @@ import math
 import resources.basic_graph.graph as basic_graph
 import resources.directed_graph.edge as directed_edge
 import resources.directed_graph.node as directed_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Graph(basic_graph.Graph):
diff --git a/resources/directed_graph/node.py b/resources/directed_graph/node.py
index 634d49e..801c751 100644
--- a/resources/directed_graph/node.py
+++ b/resources/directed_graph/node.py
@@ -15,11 +15,23 @@ Essentially the "vertex" in a Graph data structure.
 # User Class Imports.
 import resources.basic_graph.node as basic_node
 import resources.directed_graph.edge as directed_edge
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Node(basic_node.Node):
diff --git a/resources/state_machine/edge.py b/resources/state_machine/edge.py
index 6a1fbdc..36a9310 100644
--- a/resources/state_machine/edge.py
+++ b/resources/state_machine/edge.py
@@ -14,11 +14,23 @@ Essentially the "node connection" in a Graph data structure.
 # User Class Imports.
 import resources.directed_graph.edge as directed_edge
 import resources.state_machine.node as sm_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Edge(directed_edge.Edge):
diff --git a/resources/state_machine/graph.py b/resources/state_machine/graph.py
index 499c889..fe5430f 100644
--- a/resources/state_machine/graph.py
+++ b/resources/state_machine/graph.py
@@ -10,17 +10,28 @@ Parent structure containing various Nodes and Edges.
 """
 
 # System Imports.
-import math
 
 # User Class Imports.
 import resources.directed_graph.graph as directed_graph
 import resources.state_machine.edge as sm_edge
 import resources.state_machine.node as sm_node
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Graph(directed_graph.Graph):
diff --git a/resources/state_machine/node.py b/resources/state_machine/node.py
index 965e837..3be00b6 100644
--- a/resources/state_machine/node.py
+++ b/resources/state_machine/node.py
@@ -14,11 +14,23 @@ Essentially the "vertex" in a Graph data structure.
 # User Class Imports.
 import resources.directed_graph.node as directed_node
 import resources.state_machine.edge as sm_edge
-from resources import logging as init_logging
 
 
-# Initialize Logger.
-logger = init_logging.get_logger(__name__)
+# Initialize logging.
+# Since this is a library, we specifically only modify logging if the library is being run alone.
+try:
+    # First, try to import the variable specific to our library logging.
+    from resources.logging import graph_library_logger
+
+    # It worked, so we know the project is being run stand alone, probably as a unittest.
+    # Proceed to configure logging.
+    from resources.logging import get_logger as init_logging
+    logger = init_logging(__name__)
+except ModuleNotFoundError:
+    # Above import failed. Project is being run as a library.
+    # Just import existing logger and do not modify.
+    import logging as init_logging
+    logger = init_logging.getLogger('graph_library')
 
 
 class Node(directed_node.Node):
-- 
GitLab