PyModule(C.py): Now Python has REAL constants -- and they're scopedto boot!

Discussion in 'Python' started by Rick Johnson, Nov 13, 2013.

  1. Rick Johnson

    Rick Johnson Guest

    # Copyright 2013, Rick "rantingrick" Johnson
    #
    # Permission to use, copy, modify, and distribute this software for
    # any purpose and without fee is hereby granted, provided that the above
    # copyright notice appear in all copies.
    #
    # THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
    # IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
    # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
    #-----------------------------------------------------------------------------
    #
    # This script needs to be loaded when Python starts. But since i'm
    # not supplying an installer, you'll have to tell Python how to load
    # it yourself. Which is not very difficult really.
    #
    # The easiest method to "auto-load" this script is to create a .pth
    # file and save it somewhere that python can find it. If your a noob
    # and don't know what that means, then just throw the .pth file in
    # your PythonXY folder.
    #
    # The contents of the .pth file MUST include the following line:
    #
    # import C
    #
    # Noob Note: You can name the .pth file anything you want, but this
    # module must be named C.py. Yes, with a capital C!
    #
    # Enjoy.

    import sys as _sys


    class ConstantDeletionError(Exception):
    pass
    class ConstantSyntaxError(Exception):
    pass
    class ConstantMutationError(Exception):
    pass


    class _Constants(object):
    """
    DESIGN NOTES:
    This object is meant to provide a namespace for true constant
    variables in Python -- with no need to import anything!

    A toplevel "constants" object is injected at runtime, and always
    available within ANY Python module via the name "C". Note the
    capital letter, it's significant!

    I like constant variables to be qualified, but not behind a
    long name, and only a single letter can fulfill both wishes.

    I also wanted constants access to be noticeable in the source,
    but not overwhelming! Hence the choice of capital "C" over
    lowercase "c".

    Those of you withJava background should be comfortable
    with "C" due to your experiences with the "R" object.

    PUBLIC METHODS:
    add_namespace(str name)
    get_path()

    USAGE:
    Assignment:
    C.name = value
    Query:
    C.name
    Expansion:
    C.add_namespace(name)
    """
    MUTATE_MSG = "Constants cannot be mutated once intitalized!"
    DELETE_MSG = 'WARNING: The constant variable {0!r} was deleted!'
    ACCESS_MSG = 'Access to private variable {0!r} is denied!'

    def __init__(self, name):
    self.__dict__["__private"] = {
    "dirlst":[],
    "name":name,
    }

    def __str__(self):
    fmtstr1 = "{0}(\n{1}\n )"
    fmtstr2 = "{0}(<empty>)"
    lst = []
    pDict = self.__dict__["__private"]
    for name in pDict["dirlst"]:
    value = self.__dict__[name]
    lst.append( " {0} = {1!r}".format(name, value))
    values = '\n'.join(lst)
    if not values:
    fmtstr1 = fmtstr2
    return fmtstr1.format(pDict["name"], values)

    def __dir__(self):
    return self.__dict__["__private"]["dirlst"]

    def __getattribute__(self, name):
    ## print "_Constants.__getattribute__({0!r})".format(name)
    if name == "__private" :
    # This only stops direct access!
    raise Exception(self.ACCESS_MSG.format(name))
    return object.__getattribute__(self, name)

    def __setattr__(self, name, value):
    ## print "_Constants.__setattr__({0!r}, {1!r})".format(name, value)
    if name in self.__dict__ and name != "__private":
    # This only stops direct access!
    raise ConstantMutationError(self.MUTATE_MSG.format(name))
    else:
    self.__dict__["__private"]["dirlst"].append(name.upper())
    self.__dict__[name.upper()] = value

    def __delattr__(self, name):
    ## print "_Constants.__delattr__({0!r})".format(name)
    pDict = self.__dict__["__private"]
    path = "{0}.{1}".format(pDict["name"], name)
    if name == "__private":
    raise Exception(self.ACCESS_MSG.format(path))
    elif name in self.__dict__:
    raise ConstantDeletionError()

    def get_path(self):
    return self.__dict__["__private"]["name"]

    def add_namespace(self, name):
    """Add a new constants namespace named <name>"""
    name = name.upper()
    pDict = self.__dict__["__private"]
    pDict["dirlst"].append(name)
    newname = pDict["name"] + ".{0}".format(name)
    self.__dict__[name] = _Constants(newname)

    #
    # Inject a toplevel instance of _Constants (named "C") into the
    # builtins module namespace.
    _sys.modules['__builtin__'].__dict__['C'] = _Constants("C")

    if __name__ == '__main__':
    print C
    print '\nAdding constants to "C"'
    C.str = ""
    C.int = 1
    C.float = 1.333
    print C
    print '\nMutating constants of "C"'
    try:
    C.STR = "XXX"
    except ConstantMutationError:
    pass
    try:
    C.INT = 10
    except ConstantMutationError:
    pass
    try:
    C.FLOAT = 5.333
    except ConstantMutationError:
    pass
    print C

    # Test for case sensitivity.
    try:
    C.int
    except Exception:
    pass
    # Test for correct members.
    for name in ("INT", "STR", "FLOAT"):
    getattr(C, name)
    assert len(dir(C)) == 3
    print '\nDeleting constants of "C"'
    try:
    del C.INT
    except ConstantDeletionError:
    pass
    try:
    del C.STR
    except ConstantDeletionError:
    pass
    try:
    del C.FLOAT
    except ConstantDeletionError:
    pass
    print C
    print '\nAdding new space "C.math"'
    C.add_namespace("math")
    C.MATH.PI = 3.14
    print C.MATH
    Rick Johnson, Nov 13, 2013
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. neilmac
    Replies:
    2
    Views:
    634
    mcdjnaja
    Feb 7, 2008
  2. Chris Calloway
    Replies:
    0
    Views:
    273
    Chris Calloway
    May 19, 2008
  3. David A. Black
    Replies:
    2
    Views:
    213
    Tim Hunter
    Aug 19, 2004
  4. Luca Cerone
    Replies:
    4
    Views:
    269
    Luca Cerone
    Mar 2, 2012
  5. Rick Johnson
    Replies:
    0
    Views:
    106
    Rick Johnson
    Nov 13, 2013
Loading...

Share This Page