pyMez Module Specification


  1. Module Naming Convention
  2. Modules are named as UpperCamelCase (breaking from python tradition)

    GeneralModels

  3. Module Info and Docstring
  4. Module Info is a comment block with stuff like your name and license. The Module Docstring is the first quoted string and should provide information about the module. It is my habit to keep docstrings to a paragraph with links for expanded examples and help documentation. For example:

    """
    Graph Models stores sub classes of graphs that define data translations. All edges
    or the functions that define translations from one format to another
    are found in <a href="./Translations.m.html">`pyMez.Code.DataHandlers.Translations`</a>.
    Currently, the module networkx is used to display the graph.
    
    Examples
    --------
        #!python
        >>from pyMez import *
        >>image_graph=ImageGraph()
        >>image_graph.set_state('png','my_png.png')
        >>image_graph.move_to_node('EmbeddedHtml')
        >>output=image_graph.data
        >>print output
    
    
    <a href="../../../Examples/Html/GraphModels_Example.html">GraphModels Example</a>
    
    Requirements
    ------------
    + [sys](https://docs.python.org/2/library/sys.html)
    + [os](https://docs.python.org/2/library/os.html?highlight=os#module-os)
    + [networkx](http://networkx.github.io/)
    + [numpy](http://www.numpy.org/)
    + [pyMez](https://github.com/aricsanders/pyMez)
    
    Help
    ---------------
    <a href="./index.html">`pyMez.Code.DataHandlers`</a>
    <div>
    <a href="../../../pyMez_Documentation.html">Documentation Home</a> |
    <a href="../../index.html">API Documentation Home</a> |
    <a href="../../Examples/Html/Examples_Home.html">Examples Home</a> |
    <a href="../../../Reference_Index.html">Index</a>
    </div>
       """
    

  5. Module Imports
    1. Standard Imports
    2. Imports that are in the standard library and should always work if you have python installed properly. They should be namspaced,

      import os
      

    3. 3rd Party Imports

    4. Imports from within the user defined package or other places that HAD to be loaded separately. These imports should have a try: except: structure. That is, if they fail the program should default to something useful.

      try:
              from Code.DataHandlers.GeneralModels import *
          except:
              print("The module pyMez.Code.DataHandlers.GeneralModels was not found,"
                    "please put it on the python path")
              raise  ImportError
      

    5. Module Constants
    6. The constants that can be used through out the module. Constant names should be ALL_UPPERCASE_WITH_UNDERSCORES.

      S2P_COMPLEX_COLUMN_NAMES=["Frequency","S11","S21","S12","S22"]
      

    7. Module Functions
    8. A module function takes a variable(s) and maps it to another variable(s). Function names should be all_lowercase_with_underscores.

      def x_squared(x):
        "A function that maps x->x**2"
        return x**2
      

    9. Module Class Definitions

    10. A module class is a complex data container which can inherit functions (methods) and variables (attributes) from other objects. They are the foundation of Object Oriented programming. Module names should be TitleCaseWithNoSpaces. Methods and attributes should be either all_lowercase_with_underscores or lowerThenTitleCaseWithNoSpaces. It is common for me to define aliases for methods so that both MyClass.myMethod() and MyClass.my_method() work.

      class MyClass():
        "An empty class for demonstration"
        pass
      

    11. Module Scripts
    12. A module script is a function or procedure that does something and returns at most a boolean value. The reason they are not defined with module functions is so that they can use all of the class definitions. The reason they are not only in the Module runner is so that they can be accessed by importing the module. I usually try to put one of the following words in the name: test,script or robot and the name is all_lowercase_with_underscores.

      def test_f(x_test=2):
          "Tests the function f"
          print("The Result of f({0}) is {1}".format(x_test,f(x_test)))
      

    13. Module Runner
    14. The statement if __name__ == '__main__': at the end of the module determines the module's behavior if it is opened as a file or ran from a shell prompt as $python ModuleName.py.

      I usually just call module script(s) of interest here.

      if __name__=='__main__':
        test_f()
      

      </ol> Notes:


      There are several exceptions to the naming rules

      1. The word py in my code is always lowercase
      2. The words HTML and XML are always capitalized
      3. If there is a case sensitive quantity in the name of a function it has it's original case get_Id()
      4. Avoid relative imports such as from . import a, instead inject a folder above it into sys.path and import the module using the full name space, this keeps the module from breaking when called as a script.
        sys.path.append(os.path.join(os.path.dirname( __file__ ), '..','..'))
        try:
         from Code.Utils.Alias import *
         METHOD_ALIASES=1
        except:
         print("The module pyMez.Code.Utils.Alias was not found")
         METHOD_ALIASES=0
         pass
        

An example

#-----------------------------------------------------------------------------
# Name:        alias.py
# Purpose:     Function that provides exec string to define common aliases for 
#              for functions
# Author:      Aric Sanders
# Created:     2/21/2016
# License:     MIT License
#-----------------------------------------------------------------------------
""" Module that defines functions for handling alias definitions in Classes """

#-------------------------------------------------------------------------------
# Standard imports

import re
import types

#-------------------------------------------------------------------------------
# Module Functions

def alias(object):
    """ Creates aliases that map all non built-in methods to  
    both lowerCapitalCase and all_lower_with_underscore naming conventions the
    output is a list of strings to be used with exec(list[i]) """

    old_names=[]
    split_name=[]
    exec_list=[]
    new_name=''

    # Get all the atributes without __ in the begining
    for attribute in dir(object):
        if not re.match('_',attribute):
            try:
                if type(eval('object.%s'%attribute)) is types.MethodType:
                    old_names.append(attribute)
            except:pass
    # If they are camelCase make them all lower with underscores or vice versa
    for name in old_names:
        if re.search(r'[A-Z]+',name) and not re.search(r'_',name):
            split_upper_case=re.split(r'[A-Z]+',name)
            upper_matches=re.findall(r'[A-Z]+',name)
            for index,piece in enumerate(split_upper_case):
                if index<len(upper_matches):
                    new_name=new_name+piece+'_'+upper_matches[index].lower()
                else:
                    new_name=new_name+piece
            exec_list.append(('self.'+new_name+'='+'self.'+name))

        elif re.search(r'_',name):
            split_name=name.split('_')
            for index,piece in enumerate(split_name):
                if index==0:
                    new_name=piece
                else :
                    new_name=new_name+piece.title()
            exec_list.append(('self.'+new_name+'='+'self.'+name))
        #else: pass
    return exec_list

#-------------------------------------------------------------------------------
# Class Definitions

class MyTestClass():
    """ A class to test the alias function: call it in a for loop inside of 
    __init__() method """

    def __init__(self):
        self.littleAttribue=[]
        self.i_like_underscores=[]
        # this calls and executes the alias function
        for command in alias(self):
            exec(command)

    def myFunctionNumberOne(self):
        pass
    def my_function_number_two(self):
        pass
    def my_funtion_Number_three(self):
        pass

#-------------------------------------------------------------------------------
# Module Scripts
def test_alias():
    print " Before making the instance the attributes defined are:"
    for attribute in dir(MyTestClass):
        print 'Attribute Name: %s'%(attribute)
    new=MyTestClass()

    print " After making the instance the attributes defined are:"
    for attribute in dir(new):
        print 'Attribute Name: %s'%(attribute)
#-------------------------------------------------------------------------------
# Module Runner

if __name__ == '__main__':

    test_alias()