Skip to content

Commit

Permalink
feat(objects): Adding objects for room, aperture, shade, and door
Browse files Browse the repository at this point in the history
This is fleshing out the key objects that make up honeybee-core and lays down a lot of rules for how they interact with one another.
  • Loading branch information
chriswmackey authored and Chris Mackey committed Jul 19, 2019
1 parent 1527ee7 commit df43701
Show file tree
Hide file tree
Showing 23 changed files with 6,062 additions and 264 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
![Honeybee](http://www.ladybug.tools/assets/img/honeybee.png)

[![Build Status](https://travis-ci.org/ladybug-tools/honeybee-core.svg?branch=master)](https://travis-ci.org/ladybug-tools/honeybee-core)
[![Coverage Status](https://coveralls.io/repos/github/ladybug-tools/honeybee-core/badge.svg?branch=master)](https://coveralls.io/github/ladybug-tools/honeybee-core)

[![Python 2.7](https://img.shields.io/badge/python-2.7-green.svg)](https://www.python.org/downloads/release/python-270/) [![Python 3.6](https://img.shields.io/badge/python-3.6-blue.svg)](https://www.python.org/downloads/release/python-360/) [![IronPython](https://img.shields.io/badge/ironpython-2.7-red.svg)](https://github.com/IronLanguages/ironpython2/releases/tag/ipy-2.7.8/)

# honeybee-core

Honeybee core library.
Expand Down
96 changes: 96 additions & 0 deletions honeybee/_lockable.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# coding=utf-8
"""Descriptor that for locking and unlocking an object, preventing attrbute setting."""
from functools import wraps
from inspect import getmro


def lockable(cls):
"""A decorator for making lockable class.
If a class is locked, attributes can no longer be set on the class.
The class will throw an AttributeError if one tries to do so.
Classes start out as unlocked but can be locked by calling the `lock()` method.
If the class needs to be unlocked again, calling the `unlock()` method will
unlock it and allow you to edit attributes on the class. You can also create
a class that starts out as locked by putting `self._locked = True` at the end
of a class's `__init__` method.
Note that classes using __slots__ must specify a '_locked' variable within
the __slots__ in order to work correctly with this decorator.
This example if modified from:
http://stackoverflow.com/questions/3603502/prevent-creating-new-attributes-outside-init
Usage:
@lockable
class Foo(object):
def __init__(self):
self.bar = 10
foo = Foo()
foo.bar = 20
foo.lock()
try:
foo.bar = 30
except AttributeError as e:
print(e)
> Failed to set bar to 30. bar cannot be set on Foo while it is locked.
The unlock() method can unlock the class but you do so at your own risk.
Objects are typically locked when they are referenced from many other objects.
So it is usually better to make a new instance of Foo and proceed using that.
foo.unlock()
foo.bar = 30
foo.lock()
"""

def lockedsetattr(self, key, value):
"""Method to overwrite __setattr__ on the decorated class."""
if hasattr(self, '_locked') and self._locked and not key == '_locked':
raise AttributeError(
'Failed to set {1} to {2}. {1} cannot be set on {0} while it is locked.'
'\nThe unlock() method can unlock the class but you do so at '
'your own risk.\nObjects are typically locked when they are referenced '
'from several other objects.\n So it is usually better practice to'
'make a new instance of {0} and proceed using that.'.format(
cls.__name__, key, value))
else:
object.__setattr__(self, key, value)

def init_decorator(func):
"""Initialize the locabke decorator for the class."""

@wraps(func)
def wrapper(self, *args, **kwargs):
func(self, *args, **kwargs)
return wrapper

def lock(self):
self._locked = True

def unlock(self):
self._locked = False

# overwrite the various methods on the class to support lockability
cls.__setattr__ = lockedsetattr
cls.__init__ = init_decorator(cls.__init__)
if not hasattr(cls, 'lock'): # allow developers to add their own lock method
cls.lock = lock
if not hasattr(cls, 'unlock'): # allow developers to add their own unlock method
cls.unlock = unlock

# if the class uses __slots__, check that _locked is somewhere in inheritance tree
if hasattr(cls, '__slots__'):
_all_good = False
for parent_class in getmro(cls)[:-1]:
if '_locked' in parent_class.__slots__:
_all_good = True
break
if not _all_good:
raise AttributeError(
'When using the @locakble decorator on a class with __slots__, '
'a "_locked" variable must be specified within __slots__.')

return cls
Loading

0 comments on commit df43701

Please # to comment.