Move GithubObject

This commit is contained in:
Vincent Jacques
2012-03-14 23:13:37 +01:00
parent 8213df1d74
commit 32ed0ebc37
8 changed files with 5 additions and 4 deletions
@@ -0,0 +1,36 @@
import itertools
class ArgumentsChecker:
def __init__( self, mandatoryParameters, optionalParameters ):
self.__mandatoryParameters = mandatoryParameters
self.__optionalParameters = optionalParameters
def check( self, args, kwds ):
data = dict( kwds )
for arg, argumentName in itertools.izip( args, itertools.chain( self.__mandatoryParameters, self.__optionalParameters ) ):
if argumentName in kwds:
raise TypeError()
else:
data[ argumentName ] = arg
for argumentName in data:
if argumentName not in itertools.chain( self.__mandatoryParameters, self.__optionalParameters ):
raise TypeError()
for argumentName in self.__mandatoryParameters:
if argumentName not in data:
raise TypeError()
return data
def documentParameters( self ):
mandatory = ", ".join( self.__mandatoryParameters )
optional = "[" + ", ".join( self.__optionalParameters ) + "]"
if len( self.__mandatoryParameters ) == 0:
if len( self.__optionalParameters ) == 0:
return ""
else:
return " " + optional + " "
else:
if len( self.__optionalParameters ) == 0:
return " " + mandatory + " "
else:
return " " + mandatory + ", " + optional + " "
+120
View File
@@ -0,0 +1,120 @@
from ArgumentsChecker import *
class AttributeFromCallable:
class AttributeDefinition:
def __init__( self, name, callable ):
self.__name = name
self.__callable = callable
def getValueFromRawValue( self, obj, rawValue ):
return rawValue
def updateAttributes( self, obj ):
obj._updateAttributes( { self.__name: self.__callable( obj ) } )
def isLazy( self ):
return False
def __init__( self, name, callable ):
self.__name = name
self.__callable = callable
def apply( self, cls ):
cls._addAttribute( self.__name, AttributeFromCallable.AttributeDefinition( self.__name, self.__callable ) )
def autoDocument( self ):
return ""
class MethodFromCallable:
def __init__( self, name, mandatoryParameters, optionalParameters, callable, returnTypePolicy ):
self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters )
self.__name = name
self.__callable = callable
self.__returnTypePolicy = returnTypePolicy
def apply( self, cls ):
cls._addMethod( self.__name, self.__execute )
def __execute( self, obj, *args, **kwds ):
data = self.__argumentsChecker.check( args, kwds )
return self.__callable( obj, **data )
def autoDocument( self ):
if self.__name.startswith( "_" ):
return ""
else:
doc = "* `" + self.__name + "(" + self.__argumentsChecker.documentParameters() + ")`"
if self.__returnTypePolicy.hasMeaningfulDocumentation():
doc += ": " + self.__returnTypePolicy.documentTypeName()
doc += "\n"
return doc
class InternalAttribute:
class AttributeDefinition:
def __init__( self, typePolicy ):
self.__typePolicy = typePolicy
def getValueFromRawValue( self, obj, rawValue ):
if rawValue is None:
return None
else:
return self.__typePolicy.createLazy( obj, rawValue )
def updateAttributes( self, obj ):
attributes = obj._github._dataRequest( "GET", obj._baseUrl(), None, None )
obj._updateAttributes( attributes )
obj._markAsCompleted()
def isLazy( self ):
return True
def __init__( self, attributeName, typePolicy ):
self.__attributeName = attributeName
self.__typePolicy = typePolicy
def apply( self, cls ):
cls._addAttribute( self.__attributeName, InternalAttribute.AttributeDefinition( self.__typePolicy ) )
def autoDocument( self ):
if self.__attributeName.startswith( "_" ):
return ""
doc = "* `" + self.__attributeName + "`"
if self.__typePolicy.hasMeaningfulDocumentation():
doc += ": " + self.__typePolicy.documentTypeName()
doc += "\n"
return doc
class ExternalAttribute:
def __init__( self, attributeName, typePolicy ):
self.__attributeName = attributeName
self.__typePolicy = typePolicy
def apply( self, cls ):
cls._addMethod( "get_" + self.__attributeName, self.__execute )
def __execute( self, obj ):
return self.__typePolicy.createLazy(
obj,
obj._github._dataRequest( "GET", obj._baseUrl() + "/" + self.__attributeName, None, None )
)
def autoDocument( self ):
return "* `get_" + self.__attributeName + "()`: " + self.__typePolicy.documentTypeName() + "\n"
class SeveralAttributePolicies:
def __init__( self, attributePolicies, documentationSection = None ):
self.__attributePolicies = attributePolicies
self.__documentationSection = documentationSection
def apply( self, cls ):
for attributePolicy in self.__attributePolicies:
attributePolicy.apply( cls )
def autoDocument( self ):
doc = ""
if self.__documentationSection is not None:
doc += "\n"
doc += self.__documentationSection + "\n"
doc += "-" * len( self.__documentationSection ) + "\n"
doc += "".join( attributePolicy.autoDocument() for attributePolicy in self.__attributePolicies )
return doc
@@ -0,0 +1,572 @@
import unittest
import MockMockMock
from GithubObject import *
class GithubObjectTestCase( unittest.TestCase ):
def testDuplicatedAttributeInOnePolicy( self ):
with self.assertRaises( BadGithubObjectException ):
GithubObject( "", InternalSimpleAttributes( "a", "a" ) )
def testDuplicatedAttributeInTwoPolicies( self ):
with self.assertRaises( BadGithubObjectException ):
GithubObject( "", InternalSimpleAttributes( "a" ), InternalSimpleAttributes( "a" ) )
class TestCaseWithGithubTestObject( unittest.TestCase ):
def setUp( self ):
unittest.TestCase.setUp( self )
self.g = MockMockMock.Mock( "github" )
self.o = self.GithubTestObject( self.g.object, { "a1": 1, "a2": 2 }, lazy = True )
self.GithubTestObject._autoDocument() # Only for coverage
def tearDown( self ):
self.g.tearDown()
unittest.TestCase.tearDown( self )
def expectDataGet( self, url, arguments = None ):
return self.g.expect._dataRequest( "GET", url, arguments, None )
def expectDataPost( self, url, data ):
return self.g.expect._dataRequest( "POST", url, None, data )
def expectDataPatch( self, url, data ):
return self.g.expect._dataRequest( "PATCH", url, None, data )
def expectStatusGet( self, url ):
return self.g.expect._statusRequest( "GET", url, None, None )
def expectStatusPost( self, url, data ):
return self.g.expect._statusRequest( "POST", url, None, data )
def expectStatusPut( self, url, data = None ):
return self.g.expect._statusRequest( "PUT", url, None, data )
def expectStatusDelete( self, url, data = None ):
return self.g.expect._statusRequest( "DELETE", url, None, data )
class GithubObjectWithDocumentationCoveringSpecialCases( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2", "_a3" ),
MethodFromCallable( "myMethod", [ "mock", "arg" ], [], lambda obj: 42, ObjectTypePolicy( GithubObject ) ),
AttributeFromCallable( "myAttr", lambda obj: 42 )
)
def testNothing( self ):
pass
class GithubObjectWithBaseUrlDependingOnAttribute( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test/" + str( obj.a1 ) ),
InternalSimpleAttributes( "a1", "a2", "a3", "a4" ),
Editable( [ "a1" ], [] )
)
def test( self ):
self.expectDataPatch( "/test/1", { "a1": 11 } ).andReturn( { "a1": 110 } )
self.expectDataPatch( "/test/110", { "a1": 111 } ).andReturn( { "a1": 1110 } )
self.o.edit( 11 )
self.o.edit( 111 )
class GithubObjectWithOnlyInternalSimpleAttributes( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2", "a3", "a4" )
)
def testInterface( self ):
self.assertEqual( [ e for e in dir( self.o ) if not e.startswith( "_" ) ], [ "a1", "a2", "a3", "a4" ] )
def testCompletion( self ):
# A GithubObject:
# - knows the attributes given to its constructor
self.assertEqual( self.o.a1, 1 )
self.assertEqual( self.o.a2, 2 )
# - is completed the first time any unknown attribute is requested
self.expectDataGet( "/test" ).andReturn( { "a2": 22, "a3": 3 } )
self.assertEqual( self.o.a3, 3 )
# - remembers the attributes that were not updated
self.assertEqual( self.o.a1, 1 )
# - acknowledges updates of attributes
self.assertEqual( self.o.a2, 22 )
# - remembers that some attributes are absent even after an update
self.assertEqual( self.o.a4, None )
def testUnknownAttribute( self ):
self.assertRaises( AttributeError, lambda: self.o.foobar )
def testNonLazyConstruction( self ):
self.expectDataGet( "/test" ).andReturn( { "a2": 2, "a3": 3 } )
o = self.GithubTestObject( self.g.object, {}, lazy = False )
self.g.tearDown()
self.assertEqual( o.a1, None )
self.assertEqual( o.a2, 2 )
self.assertEqual( o.a3, 3 )
self.assertEqual( o.a4, None )
class GithubObjectWithOtherBaseUrl( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/other/" + str( obj.a1 ) ),
InternalSimpleAttributes( "a1", "a2", "a3", "a4" )
)
def testCompletion( self ):
self.expectDataGet( "/other/1" ).andReturn( { "a2": 22, "a3": 3 } )
self.assertEqual( self.o.a3, 3 )
class EditableGithubObject( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2", "a3", "a4" ),
Editable( [ "a1" ], [ "a2", "a4" ] ),
)
def testEditWithoutArgument( self ):
with self.assertRaises( TypeError ):
self.o.edit()
def testEditWithoutMandatoryArgument( self ):
with self.assertRaises( TypeError ):
self.o.edit( a2 = 2, a4 = 3 )
def testEditWithSillyArgument( self ):
with self.assertRaises( TypeError ):
self.o.edit( foobar = 42 )
def testEditWithOneKeywordArgument( self ):
self.expectDataPatch( "/test", { "a1": 11 } ).andReturn( {} )
self.o.edit( a1 = 11 )
def testEditWithTwoKeywordArguments( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22 } ).andReturn( {} )
self.o.edit( a1 = 11, a2 = 22 )
def testEditWithTwoKeywordArgumentsSkipingFirstOptionalArgument( self ):
self.expectDataPatch( "/test", { "a1": 11, "a4": 44 } ).andReturn( {} )
self.o.edit( a1 = 11, a4 = 44 )
def testEditWithThreeKeywordArguments( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22, "a4": 44 } ).andReturn( {} )
self.o.edit( a1 = 11, a4 = 44, a2 = 22 )
def testEditWithOnePositionalArgument( self ):
self.expectDataPatch( "/test", { "a1": 11 } ).andReturn( {} )
self.o.edit( 11 )
def testEditWithRepeatedPositionalArgument( self ):
with self.assertRaises( TypeError ):
self.o.edit( 11, a1 = 11 )
def testEditWithTwoPositionalArguments( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22 } ).andReturn( {} )
self.o.edit( 11, 22 )
def testEditWithThreePositionalArguments( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22, "a4": 44 } ).andReturn( {} )
self.o.edit( 11, 22, 44 )
def testEditWithMixedArguments_1( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22 } ).andReturn( {} )
self.o.edit( 11, a2 = 22 )
def testEditWithMixedArguments_2( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22, "a4": 44 } ).andReturn( {} )
self.o.edit( 11, a2 = 22, a4 = 44 )
def testEditWithMixedArguments_3( self ):
self.expectDataPatch( "/test", { "a1": 11, "a2": 22, "a4": 44 } ).andReturn( {} )
self.o.edit( 11, 22, a4 = 44 )
def testAcknoledgeUpdatesOfAttributes( self ):
self.expectDataPatch( "/test", { "a1": 11 } ).andReturn( { "a2": 22, "a3": 3 } )
self.o.edit( a1 = 11 )
self.assertEqual( self.o.a1, 1 )
self.assertEqual( self.o.a2, 22 )
self.assertEqual( self.o.a3, 3 )
self.expectDataGet( "/test" ).andReturn( {} )
self.assertEqual( self.o.a4, None )
class DeletableGithubObject( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2", "a3", "a4" ),
Deletable(),
)
def testDelete( self ):
self.expectStatusDelete( "/test" ).andReturn( 204 )
self.o.delete()
class GithubObjectWithInternalObjectAttribute( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name", "desc" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
InternalObjectAttribute( "a3", ContainedObject )
)
def testCompletion( self ):
self.expectDataGet( "/test" ).andReturn( { "a3": { "id": "id1", "name": "name1" } } )
self.assertEqual( self.o.a3.id, "id1" )
self.assertEqual( self.o.a3.name, "name1" )
self.expectDataGet( "/test/a3s/id1" ).andReturn( { "desc": "desc1" } )
self.assertEqual( self.o.a3.desc, "desc1" )
def testCompletionWithNone( self ):
self.expectDataGet( "/test" ).andReturn( { "a3": None } )
self.assertIsNone( self.o.a3 )
class GithubObjectWithListGetableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ListGetable( [], [ "type" ] ) )
)
def testGetList( self ):
self.expectDataGet( "/test/a3s", {} ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] )
a3s = self.o.get_a3s()
self.assertEqual( len( a3s ), 3 )
self.assertEqual( a3s[ 0 ].id, "id1" )
self.expectDataGet( "/test/a3s/id1" ).andReturn( { "name": "name1" } )
self.assertEqual( a3s[ 0 ].name, "name1" )
def testGetListWithType( self ):
self.expectDataGet( "/test/a3s", { "type": "foobar" } ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] )
a3s = self.o.get_a3s( "foobar" )
self.assertEqual( len( a3s ), 3 )
class GithubObjectWithListGetableExternalListOfObjectsWithOtherUrl( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/other/" + obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ListGetable( [], [ "type" ] ), url = "/other" )
)
def testGetList( self ):
self.expectDataGet( "/other", {} ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] )
a3s = self.o.get_a3s()
self.assertEqual( len( a3s ), 3 )
self.assertEqual( a3s[ 0 ].id, "id1" )
self.expectDataGet( "/other/id1" ).andReturn( { "name": "name1" } )
self.assertEqual( a3s[ 0 ].name, "name1" )
class GithubObjectWithListGetableExternalListOfObjectsWithAttributeModifier( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name", "_a" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ListGetable( [], [ "type" ], { "_a": lambda obj: 42 } ) )
)
def testGetList( self ):
self.expectDataGet( "/test/a3s", {} ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] )
a3s = self.o.get_a3s()
self.assertEqual( len( a3s ), 3 )
self.assertEqual( a3s[ 0 ].id, "id1" )
self.assertEqual( a3s[ 0 ]._a, 42 )
self.expectDataGet( "/test/a3s/id1" ).andReturn( { "name": "name1" } )
self.assertEqual( a3s[ 0 ].name, "name1" )
class GithubObjectWithElementAddableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" ),
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ElementAddable() )
)
def testAddToList( self ):
a3ToAdd = self.ContainedObject( self.g.object, { "id": "idAdd", "name": "nameAdd" }, lazy = True )
self.expectStatusPut( "/test/a3s/idAdd" ).andReturn( 204 )
self.o.add_to_a3s( a3ToAdd )
class GithubObjectWithElementRemovableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" ),
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ElementRemovable() )
)
def testRemoveFromList( self ):
a3ToRemove = self.ContainedObject( self.g.object, { "id": "idRemove", "name": "nameRemove" }, lazy = True )
self.expectStatusDelete( "/test/a3s/idRemove" ).andReturn( 204 )
self.o.remove_from_a3s( a3ToRemove )
class GithubObjectWithElementHasableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" ),
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ElementHasable() )
)
def testHasInList( self ):
a3ToQuery = self.ContainedObject( self.g.object, { "id": "idQuery", "name": "nameQuery" }, lazy = True )
self.expectStatusGet( "/test/a3s/idQuery" ).andReturn( 204 )
self.assertTrue( self.o.has_in_a3s( a3ToQuery ) )
self.expectStatusGet( "/test/a3s/idQuery" ).andReturn( 404 )
self.assertFalse( self.o.has_in_a3s( a3ToQuery ) )
class GithubObjectWithElementCreatableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" ),
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ElementCreatable( [ "name" ], [ "p1", "p2" ] ) )
)
def testCreate( self ):
self.expectDataPost( "/test/a3s", { "name": "nameCreate" } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( name = "nameCreate" ).id, "idCreate" )
def testCreateWithOptionalArguments( self ):
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p1": 1 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( name = "nameCreate", p1 = 1 ).id, "idCreate" )
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p2": 2 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( name = "nameCreate", p2 = 2 ).id, "idCreate" )
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p1": 1, "p2": 2 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( name = "nameCreate", p2 = 2, p1 = 1 ).id, "idCreate" )
def testCreateWithPositionalArguments( self ):
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p1": 1 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( "nameCreate", 1 ).id, "idCreate" )
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p2": 2 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( "nameCreate", p2 = 2 ).id, "idCreate" )
self.expectDataPost( "/test/a3s", { "name": "nameCreate", "p1": 1, "p2": 2 } ).andReturn( { "id": "idCreate" } )
self.assertEqual( self.o.create_a3( "nameCreate", 1, 2 ).id, "idCreate" )
def testCreateWithSillyArgument( self ):
self.g.expect._dataRequest.andReturn( None )
with self.assertRaises( TypeError ):
self.o.create_a3( foobar = 42 )
class GithubObjectWithSeveralElementsAddableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, SeveralElementsAddable() )
)
def testAddToList( self ):
self.expectStatusPost( "/test/a3s", [ "id1", "id2" ] )
self.o.add_to_a3s( self.ContainedObject( self.g, { "id": "id1" }, lazy = True ), self.ContainedObject( self.g, { "id": "id2" }, lazy = True ) )
class GithubObjectWithListSetableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
Identity( lambda obj: obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ListSetable() )
)
def testSetList( self ):
self.expectStatusPut( "/test/a3s", [ "id1", "id2" ] )
self.o.set_a3s( self.ContainedObject( self.g, { "id": "id1" }, lazy = True ), self.ContainedObject( self.g, { "id": "id2" }, lazy = True ) )
class GithubObjectWithListDeletableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ListDeletable() )
)
def testGetList( self ):
self.expectStatusDelete( "/test/a3s" )
self.o.delete_a3s()
class GithubObjectWithElementGetableExternalListOfObjects( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfObjects( "a3s", "a3", ContainedObject, ElementGetable( [ "id" ], [] ) )
)
def testGetList( self ):
self.expectDataGet( "/test/a3s/idGet" ).andReturn( { "id": "idGet" } )
self.assertEqual( self.o.get_a3( "idGet" ).id, "idGet" )
class GithubObjectWithMultiCapacityExternalListOfSimpleTypes( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalListOfSimpleTypes( "a3s", "a3", "",
ListGetable( [], [] ),
SeveralElementsAddable(),
SeveralElementsRemovable(),
)
)
def testGetList( self ):
self.expectDataGet( "/test/a3s", {} ).andReturn( [ "a", "b", "c" ] )
a3s = self.o.get_a3s()
self.assertEqual( len( a3s ), 3 )
self.assertEqual( a3s[ 0 ], "a" )
def testAddToList( self ):
self.expectStatusPost( "/test/a3s", [ "a", "b", "c" ] ).andReturn( 204 )
a3s = self.o.add_to_a3s( "a", "b", "c" )
def testDeleteFromList( self ):
self.expectStatusDelete( "/test/a3s", [ "a", "b", "c" ] ).andReturn( 204 )
a3s = self.o.remove_from_a3s( "a", "b", "c" )
class GithubObjectWithExternalSimpleAttribute( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
ExternalSimpleAttribute( "a3", "" )
)
def testGetAttribute( self ):
self.expectDataGet( "/test/a3" ).andReturn( 72 )
self.assertEqual( self.o.get_a3(), 72 )
def myCallable( obj, mock, arg ):
return mock.call( arg )
class GithubObjectWithMethodFromCallable( TestCaseWithGithubTestObject ):
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a1", "a2" ),
MethodFromCallable( "myMethod", [ "mock", "arg" ], [], myCallable, SimpleTypePolicy( None ) )
)
def testCallMethod( self ):
mock = MockMockMock.Mock( "myCallable" )
mock.expect.call( 42 ).andReturn( 72 )
self.assertEqual( self.o.myMethod( mock.object, 42 ), 72 )
mock.tearDown()
class GithubObjectWithSeveralInternalSimpleAttributesAndInternalObjectAttributes( TestCaseWithGithubTestObject ):
ContainedObject = GithubObject(
"ContainedObject",
BaseUrl( lambda obj: "/test/a3s/" + obj.id ),
InternalSimpleAttributes( "id", "name" )
)
GithubTestObject = GithubObject(
"GithubTestObject",
BaseUrl( lambda obj: "/test" ),
InternalSimpleAttributes( "a2", "a4" ),
InternalSimpleAttributes( "a1", "a3" ),
InternalObjectAttribute( "a5", ContainedObject ),
)
def testCompletionInOneCall_1( self ):
self.expectDataGet( "/test" ).andReturn( {} )
self.assertIsNone( self.o.a3 )
self.assertIsNone( self.o.a4 )
self.assertIsNone( self.o.a5 )
def testCompletionInOneCall_2( self ):
self.expectDataGet( "/test" ).andReturn( {} )
self.assertIsNone( self.o.a4 )
self.assertIsNone( self.o.a3 )
self.assertIsNone( self.o.a5 )
def testCompletionInOneCall_3( self ):
self.expectDataGet( "/test" ).andReturn( {} )
self.assertIsNone( self.o.a5 )
self.assertIsNone( self.o.a3 )
self.assertIsNone( self.o.a4 )
def testCompletionInOneCall_4( self ):
self.expectDataGet( "/test" ).andReturn( {} )
self.assertIsNone( self.o.a5 )
self.assertIsNone( self.o.a4 )
self.assertIsNone( self.o.a3 )
unittest.main()
@@ -0,0 +1,114 @@
import itertools
from ArgumentsChecker import *
from Basic import *
from List import *
from TypePolicies import *
class BadGithubObjectException( Exception ):
pass
def InternalSimpleAttribute( attributeName ):
return InternalAttribute( attributeName, SimpleTypePolicy( None ) )
def InternalSimpleAttributes( *attributeNames ):
return SeveralAttributePolicies( [ InternalSimpleAttribute( attributeName ) for attributeName in attributeNames ], "Attributes" )
def InternalObjectAttribute( attributeName, type ):
return InternalAttribute( attributeName, ObjectTypePolicy( type ) )
def ExternalSimpleAttribute( attributeName, type ):
return ExternalAttribute( attributeName, SimpleTypePolicy( type ) )
def BaseUrl( baseUrl ):
return MethodFromCallable( "_baseUrl", [], [], baseUrl, SimpleTypePolicy( None ) )
def Identity( identity ):
return AttributeFromCallable( "_identity", identity )
def Editable( mandatoryParameters, optionalParameters ):
def __execute( obj, **data ):
attributes = obj._github._dataRequest( "PATCH", obj._baseUrl(), None, data )
obj._updateAttributes( attributes )
return SeveralAttributePolicies( [ MethodFromCallable( "edit", mandatoryParameters, optionalParameters, __execute, SimpleTypePolicy( None ) ) ], "Modification" )
def Deletable():
def __execute( obj ):
obj._github._statusRequest( "DELETE", obj._baseUrl(), None, None )
return SeveralAttributePolicies( [ MethodFromCallable( "delete", [], [], __execute, SimpleTypePolicy( None ) ) ], "Deletion" )
def GithubObject( className, *attributePolicies ):
class GithubObject:
__attributeDefinitions = dict()
__methodDefinitions = dict()
__attributePolicies = list()
@staticmethod
def _addAttributePolicy( attributePolicy ):
GithubObject.__attributePolicies.append( attributePolicy )
attributePolicy.apply( GithubObject )
@staticmethod
def _addAttribute( attributeName, attributeDefinition ):
GithubObject.__checkAttributeName( attributeName )
GithubObject.__attributeDefinitions[ attributeName ] = attributeDefinition
@staticmethod
def _addMethod( methodName, methodDefinition ):
GithubObject.__checkAttributeName( methodName )
GithubObject.__methodDefinitions[ methodName ] = methodDefinition
@staticmethod
def __checkAttributeName( attributeName ):
if attributeName in GithubObject.__attributeDefinitions or attributeName in GithubObject.__methodDefinitions:
raise BadGithubObjectException( "Same attribute defined by two policies" )
def __init__( self, github, attributes, lazy ):
self._github = github
self.__attributes = dict()
self._updateAttributes( attributes )
if not lazy:
for attributeName in GithubObject.__attributeDefinitions:
if attributeName not in self.__attributes:
self.__fetchAttribute( attributeName )
def __getattr__( self, attributeName ):
if attributeName in GithubObject.__methodDefinitions:
return lambda *args, **kwds: GithubObject.__methodDefinitions[ attributeName ]( self, *args, **kwds )
elif attributeName in GithubObject.__attributeDefinitions:
if attributeName not in self.__attributes:
self.__fetchAttribute( attributeName )
return self.__attributes[ attributeName ]
else:
raise AttributeError( attributeName )
def _updateAttributes( self, attributes ):
for attributeName, attributeValue in attributes.iteritems():
attributeDefinition = GithubObject.__attributeDefinitions[ attributeName ]
self.__attributes[ attributeName ] = attributeDefinition.getValueFromRawValue( self, attributeValue )
def _markAsCompleted( self ):
for attributeName, attributeDefinition in GithubObject.__attributeDefinitions.iteritems():
if attributeDefinition.isLazy() and attributeName not in self.__attributes:
self.__attributes[ attributeName ] = None
def __dir__( self ):
return GithubObject.__attributeDefinitions.keys()
def __fetchAttribute( self, attributeName ):
attributeDefinition = GithubObject.__attributeDefinitions[ attributeName ]
attributeDefinition.updateAttributes( self )
@classmethod
def _autoDocument( cls ):
doc = "Class `" + cls.__name__ + "`\n"
doc += "=" * ( len( cls.__name__ ) + 8 ) + "\n"
for attributePolicy in cls.__attributePolicies:
doc += attributePolicy.autoDocument()
doc += "\n"
return doc
GithubObject.__name__ = className
GithubObject._addAttributePolicy( SeveralAttributePolicies( attributePolicies ) )
return GithubObject
+224
View File
@@ -0,0 +1,224 @@
import itertools
from Basic import *
from TypePolicies import *
from ArgumentsChecker import *
class ListCapacity:
def setList( self, attributeName, singularName, typePolicy, url = None ):
self.attributeName = attributeName
self.singularName = singularName
self.safeAttributeName = attributeName.replace( "/", "_" )
self.safeSingularName = singularName.replace( "/", "_" )
self.typePolicy = typePolicy
self.__url = url
def baseUrl( self, obj ):
if self.__url is None:
return obj._baseUrl() + "/" + self.attributeName
else:
return self.__url
class ElementAddable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "add_to_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, toBeAdded ):
obj._github._statusRequest(
"PUT",
self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeAdded ),
None,
None
)
def autoDocument( self ):
return "* `add_to_" + self.safeAttributeName + "( " + self.singularName + " )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class ElementRemovable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "remove_from_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, toBeDeleted ):
obj._github._statusRequest(
"DELETE",
self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeDeleted ),
None,
None
)
def autoDocument( self ):
return "* `remove_from_" + self.safeAttributeName + "( " + self.singularName + " )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class ElementHasable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "has_in_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, toBeQueried ):
return obj._github._statusRequest(
"GET",
self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeQueried ),
None,
None
) == 204
def autoDocument( self ):
return "* `has_in_" + self.safeAttributeName + "( " + self.singularName + " )`: bool\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class ListCapacityWithModifier( ListCapacity ):
def __init__( self, attributeModifiers ):
self.__attributeModifiers = attributeModifiers
def _modifyAttributes( self, obj, attributes ):
for attributeName, attributeModifier in self.__attributeModifiers.iteritems():
attributes[ attributeName ] = attributeModifier( obj )
return attributes
class ElementCreatable( ListCapacityWithModifier ):
def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ):
ListCapacityWithModifier.__init__( self, attributeModifiers )
self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters )
def apply( self, cls ):
cls._addMethod( "create_" + self.singularName, self.__execute )
def __execute( self, obj, *args, **kwds ):
return self.typePolicy.createLazy(
obj,
self._modifyAttributes(
obj,
obj._github._dataRequest(
"POST",
self.baseUrl( obj ),
None,
self.__argumentsChecker.check( args, kwds )
)
)
)
def autoDocument( self ):
return "* `create_" + self.singularName + "(" + self.__argumentsChecker.documentParameters() + ")`: " + self.typePolicy.documentTypeName() + "\n"
class ElementGetable( ListCapacityWithModifier ):
def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ):
ListCapacityWithModifier.__init__( self, attributeModifiers )
self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters )
def apply( self, cls ):
cls._addMethod( "get_" + self.singularName, self.__execute )
def __execute( self, obj, *args, **kwds ):
return self.typePolicy.createNonLazy(
obj,
self._modifyAttributes(
obj,
self.__argumentsChecker.check( args, kwds )
)
)
def autoDocument( self ):
return "* `get_" + self.singularName + "(" + self.__argumentsChecker.documentParameters() + ")`: " + self.typePolicy.documentTypeName() + "\n"
class SeveralElementsAddable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "add_to_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, *toBeAddeds ):
obj._github._statusRequest(
"POST",
self.baseUrl( obj ),
None,
[
self.typePolicy.getIdentity( toBeAdded )
for toBeAdded in toBeAddeds
]
)
def autoDocument( self ):
return "* `add_to_" + self.safeAttributeName + "( " + self.singularName + ", ... )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class SeveralElementsRemovable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "remove_from_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, *toBeDeleteds ):
obj._github._statusRequest(
"DELETE",
self.baseUrl( obj ),
None,
[
self.typePolicy.getIdentity( toBeDeleted )
for toBeDeleted in toBeDeleteds
]
)
def autoDocument( self ):
return "* `remove_from_" + self.safeAttributeName + "( " + self.singularName + ", ... )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class ListGetable( ListCapacityWithModifier ):
def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ):
ListCapacityWithModifier.__init__( self, attributeModifiers )
self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters )
def apply( self, cls ):
cls._addMethod( "get_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, *args, **kwds ):
params = self.__argumentsChecker.check( args, kwds )
return [
self.typePolicy.createLazy(
obj,
self._modifyAttributes( obj, attributes )
)
for attributes in obj._github._dataRequest(
"GET",
self.baseUrl( obj ),
params,
None
)
]
def autoDocument( self ):
return "* `get_" + self.safeAttributeName + "(" + self.__argumentsChecker.documentParameters() + ")`: list of " + self.typePolicy.documentTypeName() + "\n"
class ListSetable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "set_" + self.safeAttributeName, self.__execute )
def __execute( self, obj, *toBeSets ):
obj._github._statusRequest(
"PUT",
self.baseUrl( obj ),
None,
[
self.typePolicy.getIdentity( toBeSet )
for toBeSet in toBeSets
]
)
def autoDocument( self ):
return "* `set_" + self.safeAttributeName + "( " + self.singularName + ", ... )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n"
class ListDeletable( ListCapacity ):
def apply( self, cls ):
cls._addMethod( "delete_" + self.safeAttributeName, self.__execute )
def __execute( self, obj ):
obj._github._statusRequest(
"DELETE",
self.baseUrl( obj ),
None,
None
)
def autoDocument( self ):
return "* `delete_" + self.safeAttributeName + "()`\n"
def ExternalListOfObjects( attributeName, singularName, type, *capacities, **kwds ):
for capacity in capacities:
capacity.setList( attributeName, singularName, ObjectTypePolicy( type ), **kwds )
return SeveralAttributePolicies( capacities, attributeName.capitalize().replace( "_", " " ).replace( "/", " " ) )
def ExternalListOfSimpleTypes( attributeName, singularName, type, *capacities ):
for capacity in capacities:
capacity.setList( attributeName, singularName, SimpleTypePolicy( type ) )
return SeveralAttributePolicies( capacities, attributeName.capitalize().replace( "_", " " ).replace( "/", " " ) )
@@ -0,0 +1,35 @@
class SimpleTypePolicy:
def __init__( self, type ):
self.__type = type
def createLazy( self, obj, value ):
return value
def getIdentity( self, value ):
return value
def hasMeaningfulDocumentation( self ):
return self.__type is not None
def documentTypeName( self ):
return self.__type
class ObjectTypePolicy:
def __init__( self, type ):
self.__type = type
def createLazy( self, obj, attributes ):
return self.__type( obj._github, attributes, lazy = True )
def createNonLazy( self, obj, attributes ):
return self.__type( obj._github, attributes, lazy = False )
def getIdentity( self, obj ):
assert isinstance( obj, self.__type )
return obj._identity
def hasMeaningfulDocumentation( self ):
return True
def documentTypeName( self ):
return "`" + self.__type.__name__ + "`"
@@ -0,0 +1 @@
from GithubObject import *