-
Notifications
You must be signed in to change notification settings - Fork 2
Programs & service programs #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
b33d5c2
aea658b
593571c
b08e9ee
58141e3
9b566cf
5699a63
f009c39
db70ae6
4c4ba0f
d003132
c690807
7b2047a
8e5991e
e519f36
3b5782a
2c48f1d
d7ae862
15db895
c88f046
c100b78
12b8cec
b2b99b8
a326c36
d023d68
4f8e0f4
2574aa7
d8bd434
050abb9
302688a
58ad5bb
9de5a1c
9a95a4a
75a6bbb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,10 @@ | ||
| __version__ = "0.2.0" | ||
| from .ClCommand import ClCommand | ||
| from .types import Integer | ||
| from .types import Float | ||
| from .types import Character | ||
| from .types import Decimal | ||
| from .types import Binary | ||
| from .types import Parameter | ||
| from .program import Program | ||
| from .program import ServiceProgram |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| class Program: | ||
| """ | ||
| Object for calling an IBM i Program. | ||
| """ | ||
| def __init__(self, name, library=''): | ||
| self.name = name | ||
| self.library = library | ||
| self.parameters = [] | ||
| self.payload = { | ||
| "pgm": [{"name": name, "lib": library}] | ||
| } | ||
|
|
||
| def add_parameter(self, parameter): | ||
| """ | ||
|
|
||
| :param parameter: Parameter to be added | ||
| :return: | ||
| """ | ||
| self.parameters.append(parameter) | ||
|
|
||
|
|
||
| def get_payload(self): | ||
| if len(self.parameters) is 1: | ||
| self.payload["pgm"].append({"s": self.parameters[0].get_payload()}) | ||
| else: | ||
| self.payload["pgm"].append({"s":[]}) | ||
| for p in self.parameters: | ||
| self.payload["pgm"][-1]["s"].append(p.get_payload()) | ||
|
|
||
| return self.payload | ||
|
|
||
|
|
||
| class ServiceProgram(Program): | ||
| """ | ||
| Object for calling an IBM i Program. | ||
| """ | ||
| def __init__(self, name, library='', function=''): | ||
| self.name = name | ||
| self.library = library | ||
| self.parameters = [] | ||
| self.payload = { | ||
| "pgm": [{"name": name, "lib": library, "func": function}] | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import unittest | ||
| import os | ||
| from pykit.transport.http import connect | ||
| from pykit import * | ||
|
|
||
|
|
||
| class TestProgram(unittest.TestCase): | ||
| def setUp(self): | ||
| char = Parameter(Character("char", 128, "Hi there")) | ||
| self.hello_prog = Program("HELLO", "DB2JSON") | ||
| self.hello_prog.add_parameter(char) | ||
|
|
||
| def test_hello_world(self): | ||
| self.assertEqual( | ||
| self.hello_prog.get_payload(), | ||
| {"pgm":[{"name":"HELLO", "lib":"DB2JSON"}, {"s":{"name":"char", "type":"128a", "value":"Hi there"}}]} | ||
| ) | ||
|
|
||
| # WIP | ||
| def test_rainbow(self): | ||
| int = Parameter(Integer("aint8", 3, 1)) | ||
| float = Parameter(Float("afloat", 4, 2, 5.55)) | ||
| char = Parameter(Character("achar", 32, "A")) | ||
| rainbow = Program("RAINBOW", "DB2JSON") | ||
| rainbow.add_parameter(int) | ||
| rainbow.add_parameter(float) | ||
| rainbow.add_parameter(char) | ||
| self.assertEqual( | ||
| rainbow.get_payload(), | ||
| {"pgm":[{"name":"RAINBOW", "lib":"DB2JSON"}, {"s": [ | ||
| {"name":"aint8", "type":"3i0", "value":1}, | ||
| {"name":"afloat", "type":"4f2", "value":5.55}, | ||
| {"name":"achar", "type":"32a", "value":"A"} | ||
| ]}]} | ||
| ) | ||
|
|
||
| def test_execute_hello_world(self): | ||
| connection = connect( | ||
| os.environ['PK_DB2SOCK_URL'], | ||
| db2sock_auth=( | ||
| os.environ['PK_DB2SOCK_USER'], os.environ['PK_DB2SOCK_PASS'])) | ||
| toolkit = connection.toolkit() | ||
| toolkit.add(self.hello_prog) | ||
| response = toolkit.execute() | ||
| self.assertEqual(response, {"script": [{"pgm": ["HELLO", "DB2JSON", {"char": "Hello World"}]}]}) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| import unittest | ||
| import os | ||
| from pykit.transport.http import connect | ||
| from pykit import * | ||
|
|
||
|
|
||
| class TestServiceProgram(unittest.TestCase): | ||
| def setUp(self): | ||
| char = Parameter(Character("char", 128, "Hi there")) | ||
| char_return = Parameter(Character("char", 128, "Hi back"), direction='out', byValue=False, isReturn=True) | ||
| self.hello_prog = ServiceProgram("HELLOSRV", "DB2JSON", "HELLO") | ||
| self.hello_prog.add_parameter(char) | ||
| self.hello_prog_return = ServiceProgram("HELLOSRV", "DB2JSON", "HELLOAGAIN") | ||
| self.hello_prog_return.add_parameter(char) | ||
| self.hello_prog_return.add_parameter(char_return) | ||
|
|
||
|
|
||
| def test_hello(self): | ||
| self.assertEqual( | ||
| self.hello_prog.get_payload(), | ||
| {"pgm":[{"name":"HELLOSRV", "lib":"DB2JSON", "func": "HELLO"}, | ||
| {"s":{"name":"char", "type":"128a", "value":"Hi there"}}]} | ||
| ) | ||
| self.assertEqual( | ||
| self.hello_prog_return.get_payload(), | ||
| {"pgm":[{"name":"HELLOSRV", "lib":"DB2JSON", "func": "HELLOAGAIN"}, | ||
| {"s":[{"name":"char", "type":"128a", "value":"Hi there"}, | ||
| {"name":"char", "type":"128a", "value":"Hi back", "by":"return"}]}]} | ||
| ) | ||
|
|
||
| def test_execute_hello_world(self): | ||
| connection = connect( | ||
| os.environ['PK_DB2SOCK_URL'], | ||
| db2sock_auth=( | ||
| os.environ['PK_DB2SOCK_USER'], os.environ['PK_DB2SOCK_PASS'])) | ||
| toolkit = connection.toolkit() | ||
| toolkit.add(self.hello_prog) | ||
| response = toolkit.execute() | ||
| self.assertEqual(response, {"script": [{"pgm": ["HELLOSRV", "DB2JSON", "HELLO", {"char": "Hello World"}]}]}) | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import unittest | ||
| import os | ||
| from pykit import Integer, Float, Character, Decimal, Binary, Parameter | ||
|
|
||
|
|
||
| class TestInteger(unittest.TestCase): | ||
| def test_integer_payload(self): | ||
| new_int = Parameter(Integer('aint8', 3, 1)) | ||
| self.assertEqual(new_int.get_payload(), {"name":"aint8", "type":"3i0", "value":1}) | ||
|
|
||
| def test_unsigned_integer_payload(self): | ||
| new_int = Parameter(Integer('auint8', 3, 1, False)) | ||
| self.assertEqual(new_int.get_payload(), {"name":"auint8", "type":"3u0", "value":1}) | ||
|
|
||
|
|
||
| class TestFloat(unittest.TestCase): | ||
| def test_float_payload(self): | ||
| new_float = Parameter(Float('afloat', 4, 2, 5.55)) | ||
| self.assertEqual(new_float.get_payload(), {"name":"afloat", "type":"4f2", "value":5.55}) | ||
|
|
||
|
|
||
| class TestCharacter(unittest.TestCase): | ||
| def test_character_payload(self): | ||
| char = Parameter(Character('achar', 10, "Hello")) | ||
| self.assertEqual(char.get_payload(), {"name":"achar", "type":"10a", "value":"Hello"}) | ||
|
|
||
| def test_character_varying_payload(self): | ||
| char = Parameter(Character('bchar', 100, "Bye", 2)) | ||
| self.assertEqual(char.get_payload(), {"name":"bchar", "type":"100av2", "value":"Bye"}) | ||
|
|
||
|
|
||
| class TestDecimal(unittest.TestCase): | ||
| def test_decimal_payload(self): | ||
| dec = Parameter(Decimal('adec', 10, 2, 850.2)) | ||
| self.assertEqual(dec.get_payload(), {"name":"adec", "type":"10p2", "value":850.2}) | ||
|
|
||
| def test_signed_decimal_payload(self): | ||
| dec = Parameter(Decimal('bdec', 9, 0, 800, True)) | ||
| self.assertEqual(dec.get_payload(), {"name":"bdec", "type":"9s0", "value":800}) | ||
|
|
||
| class TestBinary(unittest.TestCase): | ||
| def test_binary_payload(self): | ||
| bin = Parameter(Binary('abin', 2, "0000")) | ||
| self.assertEqual(bin.get_payload(), {"name":"abin", "type":"2b", "value":"0000"}) | ||
|
|
||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| class Parameter: | ||
| def __init__(self, parameterType, direction='inout', byValue=False, isReturn=False): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The way dbsock handles return values is weird and unintuitive. A return value by definition cannot be an input, so why does it have a direction? I think there should have been a separate way to specify the return value instead of trying to shoe-horn it in as a "parameter". I'd like to see us hide this quirk as much as possible. Can we split out the return value handling in to a separate class, maybe |
||
| """ | ||
| :param name: | ||
| :param value: | ||
| """ | ||
| self.parameterType = parameterType | ||
| self.direction = direction | ||
| self.isReturn = isReturn | ||
| self.byValue = False | ||
| self.payload = {} | ||
|
|
||
| def get_payload(self): | ||
| self.payload = self.parameterType.get_payload() | ||
| if self.isReturn: | ||
| self.payload['by'] = 'return' | ||
| if self.byValue: | ||
| self.payload['by'] = 'val' | ||
|
|
||
| return self.payload | ||
|
|
||
|
|
||
| class ParameterType: | ||
| """ | ||
| Object for IBM i ParameterTypes. | ||
| """ | ||
| def __init__(self, name, value): | ||
| """ | ||
| :param name: | ||
| :param value: | ||
| """ | ||
| self.value = value | ||
| self.name = str(name) | ||
| self.payload = {"name":self.name} | ||
|
|
||
|
|
||
| def get_payload(self): | ||
| self.payload['value'] = self.value | ||
| return self.payload | ||
|
|
||
| class Float(ParameterType): | ||
| """ | ||
| Object for IBM i Float. | ||
| """ | ||
| def __init__(self, name, length, precision, value): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can a float have a precision? I think it has to be specified as 0. If so, just like the |
||
| """ | ||
| How much error checking do we want here? | ||
| Should we check that length is positive? | ||
| Should we check if value matches length? | ||
| Should we truncate the value to the length? | ||
|
|
||
| :param length: | ||
| :param precision:s | ||
| :param value: | ||
| """ | ||
| ParameterType.__init__(self, name, value) | ||
| self.length = length | ||
| self.precision = precision | ||
|
|
||
| def get_payload(self): | ||
| self.payload['type'] = str(self.length) + 'f' + str(self.precision) | ||
| ParameterType.get_payload(self) | ||
| return self.payload | ||
|
|
||
|
|
||
| class Integer(ParameterType): | ||
| """ | ||
| Object for IBM i Integer. | ||
| """ | ||
| def __init__(self, name, length, value, signed=True): | ||
| """ | ||
| How much error checking do we want here? | ||
| Should we check that length is positive? | ||
| Should we check if value matches length? | ||
| Should we truncate the value to the length? | ||
|
|
||
| :param length: | ||
| :param value: | ||
| """ | ||
| ParameterType.__init__(self, name, value) | ||
| self.length = length | ||
| self.signed = signed | ||
|
|
||
| def get_payload(self): | ||
| self.payload['type'] = str(self.length) + ('i' if self.signed else 'u') + '0' | ||
| ParameterType.get_payload(self) | ||
|
|
||
| return self.payload | ||
|
|
||
|
|
||
| class Character(ParameterType): | ||
| """ | ||
| Object for IBM i Character. | ||
| """ | ||
| def __init__(self, name, length, value, varying=''): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe a separate |
||
| """ | ||
| :param length: | ||
| :param value: | ||
| """ | ||
| ParameterType.__init__(self, name, value) | ||
| self.length = length | ||
| self.varying = varying | ||
|
|
||
| def get_payload(self): | ||
| self.payload['type'] = str(self.length) + 'a' | ||
| if self.varying: | ||
| self.payload['type'] = self.payload['type'] + 'v' + str(self.varying) | ||
|
|
||
| ParameterType.get_payload(self) | ||
| return self.payload | ||
|
|
||
|
|
||
| class Decimal(ParameterType): | ||
| """ | ||
| Object for IBM i Decimal. | ||
| """ | ||
| def __init__(self, name, length, decimals, value, signed=False): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh, apparently indeed the Alternatively instead of a parameter, use separate classes: |
||
| """ | ||
| How much error checking do we want here? | ||
| Should we check that length is positive? | ||
| Should we check if value matches length? | ||
| Should we truncate the value to the length? | ||
|
|
||
| :param length: | ||
| :param value: | ||
| """ | ||
| ParameterType.__init__(self, name, value) | ||
| self.length = length | ||
| self.signed = signed | ||
| self.decimals = decimals | ||
|
|
||
| def get_payload(self): | ||
| self.payload['type'] = str(self.length) + ('s' if self.signed else 'p') + str(self.decimals) | ||
| ParameterType.get_payload(self) | ||
|
|
||
| return self.payload | ||
|
|
||
|
|
||
| class Binary(ParameterType): | ||
| """ | ||
| Object for IBM i Binary. | ||
| """ | ||
| def __init__(self, name, length, value): | ||
| """ | ||
|
|
||
| :param length: | ||
| :param value: | ||
| """ | ||
| ParameterType.__init__(self, name, value) | ||
| self.length = length | ||
|
|
||
| def get_payload(self): | ||
| self.payload['type'] = str(self.length) + 'b' | ||
| ParameterType.get_payload(self) | ||
| return self.payload | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If these are going to be private fields, we should think about indicating as so with a preceding single or double underscore: https://docs.python.org/3/tutorial/classes.html#private-variables
Not something to hold this up, but something to think about.