I am building an ODM/ORM for my system in Python. With the intent of making my queries and writes into UV more pythonic and easier to code (I am VERY lazy). For me this is primarily allowing read and writes to and from UV with a Python dictionary leveraging the readnamedfields() and writenamedfield() within the u2py.File class. While I have a specific issue below, I think there is room for a general discussion around u2Py error handling.
My specific issue lies in getting "u2py.U2Error: (3) unknown " back in my trace. I am getting this error back when trying to write data to a record I have open in editor (so the file is locked). While I would expect to get an error here, I would also expect that error to be a little more descriptive of what the issue is.
I have a couple questions that should hopefully give me a good path forward here...
1. Are there plans to improve the u2Py module's error handling in the near term future?
2. Does the (3) in my error mean/represent anything? (I could parse this to get what I need if it does)
3. has anyone built their own error class within the U2Py module to resolve issues like this? If so, I'd love to hear about it.
My plan is to use the u2py.File's islocked() method to catch the error and make a check and raise a more specific error, (u2py.FileLockedError or something) but if it has already been done, I hate to reinvent the wheel.
I'm going to mark this an "Open ended Discussion" post in the hopes that a discussion can arise surrounding U2Py Errors. Admins, my feelings will not be hurt if this post is changed to a question instead.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Page 1 / 1
I am building an ODM/ORM for my system in Python. With the intent of making my queries and writes into UV more pythonic and easier to code (I am VERY lazy). For me this is primarily allowing read and writes to and from UV with a Python dictionary leveraging the readnamedfields() and writenamedfield() within the u2py.File class. While I have a specific issue below, I think there is room for a general discussion around u2Py error handling.
My specific issue lies in getting "u2py.U2Error: (3) unknown " back in my trace. I am getting this error back when trying to write data to a record I have open in editor (so the file is locked). While I would expect to get an error here, I would also expect that error to be a little more descriptive of what the issue is.
I have a couple questions that should hopefully give me a good path forward here...
1. Are there plans to improve the u2Py module's error handling in the near term future?
2. Does the (3) in my error mean/represent anything? (I could parse this to get what I need if it does)
3. has anyone built their own error class within the U2Py module to resolve issues like this? If so, I'd love to hear about it.
My plan is to use the u2py.File's islocked() method to catch the error and make a check and raise a more specific error, (u2py.FileLockedError or something) but if it has already been done, I hate to reinvent the wheel.
I'm going to mark this an "Open ended Discussion" post in the hopes that a discussion can arise surrounding U2Py Errors. Admins, my feelings will not be hurt if this post is changed to a question instead.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
My specific issue lies in getting "u2py.U2Error: (3) unknown " back in my trace. I am getting this error back when trying to write data to a record I have open in editor (so the file is locked). While I would expect to get an error here, I would also expect that error to be a little more descriptive of what the issue is.
I have a couple questions that should hopefully give me a good path forward here...
1. Are there plans to improve the u2Py module's error handling in the near term future?
2. Does the (3) in my error mean/represent anything? (I could parse this to get what I need if it does)
3. has anyone built their own error class within the U2Py module to resolve issues like this? If so, I'd love to hear about it.
My plan is to use the u2py.File's islocked() method to catch the error and make a check and raise a more specific error, (u2py.FileLockedError or something) but if it has already been done, I hate to reinvent the wheel.
I'm going to mark this an "Open ended Discussion" post in the hopes that a discussion can arise surrounding U2Py Errors. Admins, my feelings will not be hurt if this post is changed to a question instead.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
1. I do not believe there are plans to enhance the the u2py error handling in the near future.
2. Not sure how you got the error 3, when trying to write something that is locked, I would expect something like:
U2Error: (30002) File or record is locked by another user
How is the file opened, outside of the Python program?
Can you put a small snip it of code?
3. I have a few examples of functions I wrote to do the reads and writes, yet none with extensive lock handling at this time.
I do agree this topic should stay open. Note that the topic of an ORM has come up in the past, I have tinkered with writing my own from time to time. I have a few functions at the Rocket Github site, that I use as a poor man's ORM, I tend to use it more than my more elaborate attempts ( which in most cases uses these functions ).
In the u2support.py module, there is u2PyReadDict and u2PyWriteDict, that allows you to use a list of U2 Dictionary Items, when reading from the U2 file, it returns a Python Dictionary, that you can use/update and write back.
i.e.
python> import u2support
python> u2dictitems = [ "FIRST_NAME", "LAST_NAME", "CITY", "STATE", "ZIP" ]
python> pydict = u2support.u2ReadPyDict( "MEMBERS", "0110", u2dictitems )
Welcome to the XDEMO Account
Version: 3.1.5
python> pydict
{'FIRST_NAME': 'Anita', 'LAST_NAME': 'Johnson', 'CITY': 'New Glasgow', 'STATE': 'Nebraska', 'ZIP': '01870'}
python>
Note this sample code is not that extensive, and does not handle locking at this time.
------------------------------
Michael Rajkowski
Rocket Software
------------------------------
Nic,
1. I do not believe there are plans to enhance the the u2py error handling in the near future.
2. Not sure how you got the error 3, when trying to write something that is locked, I would expect something like:
How is the file opened, outside of the Python program?
Can you put a small snip it of code?
3. I have a few examples of functions I wrote to do the reads and writes, yet none with extensive lock handling at this time.
I do agree this topic should stay open. Note that the topic of an ORM has come up in the past, I have tinkered with writing my own from time to time. I have a few functions at the Rocket Github site, that I use as a poor man's ORM, I tend to use it more than my more elaborate attempts ( which in most cases uses these functions ).
In the u2support.py module, there is u2PyReadDict and u2PyWriteDict, that allows you to use a list of U2 Dictionary Items, when reading from the U2 file, it returns a Python Dictionary, that you can use/update and write back.
i.e.
python> import u2support
python> u2dictitems = [ "FIRST_NAME", "LAST_NAME", "CITY", "STATE", "ZIP" ]
python> pydict = u2support.u2ReadPyDict( "MEMBERS", "0110", u2dictitems )
Welcome to the XDEMO Account
Version: 3.1.5
python> pydict
{'FIRST_NAME': 'Anita', 'LAST_NAME': 'Johnson', 'CITY': 'New Glasgow', 'STATE': 'Nebraska', 'ZIP': '01870'}
python>
Note this sample code is not that extensive, and does not handle locking at this time.
------------------------------
Michael Rajkowski
Rocket Software
------------------------------
1. I do not believe there are plans to enhance the the u2py error handling in the near future.
2. Not sure how you got the error 3, when trying to write something that is locked, I would expect something like:
U2Error: (30002) File or record is locked by another user
How is the file opened, outside of the Python program?
Can you put a small snip it of code?
3. I have a few examples of functions I wrote to do the reads and writes, yet none with extensive lock handling at this time.
I do agree this topic should stay open. Note that the topic of an ORM has come up in the past, I have tinkered with writing my own from time to time. I have a few functions at the Rocket Github site, that I use as a poor man's ORM, I tend to use it more than my more elaborate attempts ( which in most cases uses these functions ).
In the u2support.py module, there is u2PyReadDict and u2PyWriteDict, that allows you to use a list of U2 Dictionary Items, when reading from the U2 file, it returns a Python Dictionary, that you can use/update and write back.
i.e.
python> import u2support
python> u2dictitems = [ "FIRST_NAME", "LAST_NAME", "CITY", "STATE", "ZIP" ]
python> pydict = u2support.u2ReadPyDict( "MEMBERS", "0110", u2dictitems )
Welcome to the XDEMO Account
Version: 3.1.5
python> pydict
{'FIRST_NAME': 'Anita', 'LAST_NAME': 'Johnson', 'CITY': 'New Glasgow', 'STATE': 'Nebraska', 'ZIP': '01870'}
python>
Note this sample code is not that extensive, and does not handle locking at this time.
------------------------------
Michael Rajkowski
Rocket Software
------------------------------
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
class U2Reader(U2Handler):
.......
def read_field(self, record_id, field_name):
""" reads and returns a value of a field corresponding to the record_id and a field name.
Converts pythonic fieldnames (equip_status) to UV ones (EQUIP.STATUS) by replaceing . with _ and lowercase. """
if isinstance(record_id, list):
record_id = record_id[0]
# _py_to_uv changes a Pythonic field name into a UV fiendly one.
field_name = self._py_to_uv(field_name)
# make my field name a DynArray so I can use it with U2py.
dyn_array_field = u2py.DynArray(field_name)
# self.uv_file is a u2py.File object of the file I am working with. This is created in the U2Handler class on the __init__
value = self.uv_file.readnamedfields(record_id, dyn_array_field, self.lock_flag)
if field_name == "@ID":
# if we are looking at the Record ID field, we need to just keep it as is.
rec_id = value.to_list()[0]
return rec_id
value = self._unarray(value)
if self.value_convert:
# convert the values, if we are supposed to.
#UV string to Py Object will use the Conversion code in the UVDict file to convert to a proper python object (list, dict, int...)
value = self.uv_string_to_py_obj(value)
conv_code = self.get_conversion_code(field_name)
# if my value is None, why convert it?
if value == None:
return value
else:
# if I dont have a conversion code in my UVDict, I can't convert it.
if conv_code:
value = self.uv_string_conversion_code(conv_code, value)
return value
else:
return value
else:
return value
class U2Writer(U2Handler):
.........
def write_field(self, record_id, field_name, value):
""" Writes to a named field. Converts pythonic objects to approppriate strings when necessary. """
# change my pythonic fieldname into a UV one
field = self._py_to_uv(field_name)
if value == None:
# If the value None, keep the writeable_value as none
writeable_value = None
else:
if isinstance(value, datetime.datetime):
# If the value is a datetime object, it needs to be converted
# regardless of self.calue_convert. If u2py could handle datetime objects this would go away!
# I have a Python dict in a config file that maps UV CONV codes to the Datetime library partner. EX: DTIZ gets paired with "%Y-%m-%dT%H:%M:%SZ"
conv_code = self.get_conversion_code(field)
if conv_code:
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
elif self.value_convert and not isinstance(value, datetime.datetime):
if isinstance(value, str):
writeable_value = value
else:
conv_code = self.get_conversion_code(field)
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
dyn_field = u2py.DynArray(field)
dyn_value = u2py.DynArray([writeable_value])
if self.locking:
# set exclusive lock - Locking logic is not done yet, placeholder
self.lock_record(record_id, True)
try:
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
except u2py.U2Error as e:
# printing here for debugging. I have not made my logger for this module yet,
#
print(record_id, dyn_field, dyn_value)
raise e
if self.verify:
# Not implemented as of yet, but will eventually veify writes and log errors as such.
self.verify_write(record_id, field, value)
if self.uv_file.islocked(record_id):
# If for some reason I locked the file, make sure I unlock it at the end.
self.unlock_record(record_id)
return
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
def odm_test():
# Start up my U2Odm object with a file name. I can also pass paramaters on locking, write verificaition and a boolean on if I should try to convert fields based on line 3 of the field's UVdictonary.
my_odm = u2odm.U2Odm('equipment_sales')
# Instead of having to type "ENG.MAIN.MAKE" I can keep my variables pythonic. Us younger python guys are allergic to capital letters...
value = my_odm.read_field(3257, 'eng_main_make')
write_val = my_odm.write_field('3257', 'eng_main_make', value)
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
U2 ERROR
3257 ENG.MAIN.MAKE 857
Traceback (most recent call last):
File "PP/nictest.py", line 197, in <module>
odm_test()
File "PP/nictest.py", line 190, in odm_test
write_val = my_odm.write_field('3257', 'eng_main_make', value)
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 412, in write_field
raise e
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 408, in write_field
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
u2py.U2Error: (3) unknown
# The "(3) unknown" is the weirdest thing here. I do get a proper 3001 code for record id not found when I break that intentionally.
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
def nic_breaks_u2py():
my_file = u2py.File('EQUIPMENT.SALES')
field_arr = u2py.DynArray('ENG.MAIN.MAKE')
value = my_file.readnamedfields('3257', field_arr)
write = my_file.writenamedfields('3257', field_arr, value)
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Hey Michael, I appreciate the info. Let me get some code snippets in here. I do intend to throw the ODM on GitHub once I have it a little more refined. It turned into quite a large module when I started adding some of the ICONV and OCONV functionality, and to be frank....I would be embarrassed to show it all in it's current state :)
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
class U2Reader(U2Handler):
.......
def read_field(self, record_id, field_name):
""" reads and returns a value of a field corresponding to the record_id and a field name.
Converts pythonic fieldnames (equip_status) to UV ones (EQUIP.STATUS) by replaceing . with _ and lowercase. """
if isinstance(record_id, list):
record_id = record_id[0]
# _py_to_uv changes a Pythonic field name into a UV fiendly one.
field_name = self._py_to_uv(field_name)
# make my field name a DynArray so I can use it with U2py.
dyn_array_field = u2py.DynArray(field_name)
# self.uv_file is a u2py.File object of the file I am working with. This is created in the U2Handler class on the __init__
value = self.uv_file.readnamedfields(record_id, dyn_array_field, self.lock_flag)
if field_name == "@ID":
# if we are looking at the Record ID field, we need to just keep it as is.
rec_id = value.to_list()[0]
return rec_id
value = self._unarray(value)
if self.value_convert:
# convert the values, if we are supposed to.
#UV string to Py Object will use the Conversion code in the UVDict file to convert to a proper python object (list, dict, int...)
value = self.uv_string_to_py_obj(value)
conv_code = self.get_conversion_code(field_name)
# if my value is None, why convert it?
if value == None:
return value
else:
# if I dont have a conversion code in my UVDict, I can't convert it.
if conv_code:
value = self.uv_string_conversion_code(conv_code, value)
return value
else:
return value
else:
return value
class U2Writer(U2Handler):
.........
def write_field(self, record_id, field_name, value):
""" Writes to a named field. Converts pythonic objects to approppriate strings when necessary. """
# change my pythonic fieldname into a UV one
field = self._py_to_uv(field_name)
if value == None:
# If the value None, keep the writeable_value as none
writeable_value = None
else:
if isinstance(value, datetime.datetime):
# If the value is a datetime object, it needs to be converted
# regardless of self.calue_convert. If u2py could handle datetime objects this would go away!
# I have a Python dict in a config file that maps UV CONV codes to the Datetime library partner. EX: DTIZ gets paired with "%Y-%m-%dT%H:%M:%SZ"
conv_code = self.get_conversion_code(field)
if conv_code:
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
elif self.value_convert and not isinstance(value, datetime.datetime):
if isinstance(value, str):
writeable_value = value
else:
conv_code = self.get_conversion_code(field)
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
dyn_field = u2py.DynArray(field)
dyn_value = u2py.DynArray([writeable_value])
if self.locking:
# set exclusive lock - Locking logic is not done yet, placeholder
self.lock_record(record_id, True)
try:
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
except u2py.U2Error as e:
# printing here for debugging. I have not made my logger for this module yet,
#
print(record_id, dyn_field, dyn_value)
raise e
if self.verify:
# Not implemented as of yet, but will eventually veify writes and log errors as such.
self.verify_write(record_id, field, value)
if self.uv_file.islocked(record_id):
# If for some reason I locked the file, make sure I unlock it at the end.
self.unlock_record(record_id)
return
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
def odm_test():
# Start up my U2Odm object with a file name. I can also pass paramaters on locking, write verificaition and a boolean on if I should try to convert fields based on line 3 of the field's UVdictonary.
my_odm = u2odm.U2Odm('equipment_sales')
# Instead of having to type "ENG.MAIN.MAKE" I can keep my variables pythonic. Us younger python guys are allergic to capital letters...
value = my_odm.read_field(3257, 'eng_main_make')
write_val = my_odm.write_field('3257', 'eng_main_make', value)
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
U2 ERROR
3257 ENG.MAIN.MAKE 857
Traceback (most recent call last):
File "PP/nictest.py", line 197, in <module>
odm_test()
File "PP/nictest.py", line 190, in odm_test
write_val = my_odm.write_field('3257', 'eng_main_make', value)
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 412, in write_field
raise e
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 408, in write_field
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
u2py.U2Error: (3) unknown
# The "(3) unknown" is the weirdest thing here. I do get a proper 3001 code for record id not found when I break that intentionally.
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
def nic_breaks_u2py():
my_file = u2py.File('EQUIPMENT.SALES')
field_arr = u2py.DynArray('ENG.MAIN.MAKE')
value = my_file.readnamedfields('3257', field_arr)
write = my_file.writenamedfields('3257', field_arr, value)
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Interesting, I am not getting an error 3, but it does raise an exception.
Note I altered your example to use the XDEMO MEMBERS file
python> my_file = u2py.File('MEMBERS')
python> field_arr = u2py.DynArray([ "@ID", "FIRST_NAME" ] )
python> value = my_file.readnamedfields('0110', field_arr)
python> try:
... my_write = my_file.writenamedfields('0110', field_arr, value)
... except u2py.U2Error as e:
... print( "the item can not be locked")
... print( str(e))
...
the item can not be locked
(305727) unknown
python>
Yet, if I get a lock prior to trying to write the data, it returns the message that it is locked.
python> my_file = u2py.File('MEMBERS')
python> field_arr = u2py.DynArray([ "@ID", "FIRST_NAME" ] )
python> value = my_file.readnamedfields('0110', field_arr)
python> try:
... my_file.lock("0110")
... my_write = my_file.writenamedfields('0110', field_arr, value)
... except u2py.U2Error as e:
... print( "the item can not be locked")
... print( str(e))
...
the item can not be locked
(30002) File or record is locked by another user
Can I get the Database Version and the OS you are running this on?
------------------------------
Michael Rajkowski
Rocket Software
------------------------------
Hey Michael, I appreciate the info. Let me get some code snippets in here. I do intend to throw the ODM on GitHub once I have it a little more refined. It turned into quite a large module when I started adding some of the ICONV and OCONV functionality, and to be frank....I would be embarrassed to show it all in it's current state :)
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
class U2Reader(U2Handler):
.......
def read_field(self, record_id, field_name):
""" reads and returns a value of a field corresponding to the record_id and a field name.
Converts pythonic fieldnames (equip_status) to UV ones (EQUIP.STATUS) by replaceing . with _ and lowercase. """
if isinstance(record_id, list):
record_id = record_id[0]
# _py_to_uv changes a Pythonic field name into a UV fiendly one.
field_name = self._py_to_uv(field_name)
# make my field name a DynArray so I can use it with U2py.
dyn_array_field = u2py.DynArray(field_name)
# self.uv_file is a u2py.File object of the file I am working with. This is created in the U2Handler class on the __init__
value = self.uv_file.readnamedfields(record_id, dyn_array_field, self.lock_flag)
if field_name == "@ID":
# if we are looking at the Record ID field, we need to just keep it as is.
rec_id = value.to_list()[0]
return rec_id
value = self._unarray(value)
if self.value_convert:
# convert the values, if we are supposed to.
#UV string to Py Object will use the Conversion code in the UVDict file to convert to a proper python object (list, dict, int...)
value = self.uv_string_to_py_obj(value)
conv_code = self.get_conversion_code(field_name)
# if my value is None, why convert it?
if value == None:
return value
else:
# if I dont have a conversion code in my UVDict, I can't convert it.
if conv_code:
value = self.uv_string_conversion_code(conv_code, value)
return value
else:
return value
else:
return value
class U2Writer(U2Handler):
.........
def write_field(self, record_id, field_name, value):
""" Writes to a named field. Converts pythonic objects to approppriate strings when necessary. """
# change my pythonic fieldname into a UV one
field = self._py_to_uv(field_name)
if value == None:
# If the value None, keep the writeable_value as none
writeable_value = None
else:
if isinstance(value, datetime.datetime):
# If the value is a datetime object, it needs to be converted
# regardless of self.calue_convert. If u2py could handle datetime objects this would go away!
# I have a Python dict in a config file that maps UV CONV codes to the Datetime library partner. EX: DTIZ gets paired with "%Y-%m-%dT%H:%M:%SZ"
conv_code = self.get_conversion_code(field)
if conv_code:
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
elif self.value_convert and not isinstance(value, datetime.datetime):
if isinstance(value, str):
writeable_value = value
else:
conv_code = self.get_conversion_code(field)
writeable_value = self.apply_conversion_code(value, conv_code)
else:
writeable_value = value
dyn_field = u2py.DynArray(field)
dyn_value = u2py.DynArray([writeable_value])
if self.locking:
# set exclusive lock - Locking logic is not done yet, placeholder
self.lock_record(record_id, True)
try:
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
except u2py.U2Error as e:
# printing here for debugging. I have not made my logger for this module yet,
#
print(record_id, dyn_field, dyn_value)
raise e
if self.verify:
# Not implemented as of yet, but will eventually veify writes and log errors as such.
self.verify_write(record_id, field, value)
if self.uv_file.islocked(record_id):
# If for some reason I locked the file, make sure I unlock it at the end.
self.unlock_record(record_id)
return
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
def odm_test():
# Start up my U2Odm object with a file name. I can also pass paramaters on locking, write verificaition and a boolean on if I should try to convert fields based on line 3 of the field's UVdictonary.
my_odm = u2odm.U2Odm('equipment_sales')
# Instead of having to type "ENG.MAIN.MAKE" I can keep my variables pythonic. Us younger python guys are allergic to capital letters...
value = my_odm.read_field(3257, 'eng_main_make')
write_val = my_odm.write_field('3257', 'eng_main_make', value)
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
U2 ERROR
3257 ENG.MAIN.MAKE 857
Traceback (most recent call last):
File "PP/nictest.py", line 197, in <module>
odm_test()
File "PP/nictest.py", line 190, in odm_test
write_val = my_odm.write_field('3257', 'eng_main_make', value)
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 412, in write_field
raise e
File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 408, in write_field
self.uv_file.writenamedfields(record_id, dyn_field, dyn_value)
u2py.U2Error: (3) unknown
# The "(3) unknown" is the weirdest thing here. I do get a proper 3001 code for record id not found when I break that intentionally.
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
def nic_breaks_u2py():
my_file = u2py.File('EQUIPMENT.SALES')
field_arr = u2py.DynArray('ENG.MAIN.MAKE')
value = my_file.readnamedfields('3257', field_arr)
write = my_file.writenamedfields('3257', field_arr, value)
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Hi guys,
I use UniObjects for .NET for a while and noted (in all versions) that if READU a new item I get error number 30001. That's ok.
Then release the new item and try to READU the same again, i get no error number. That's wrong, must get 30001 again.
I don't know if both issues have the same root. I use UniObjects for .NET version 3.171.1.9003 and I don't know if is the latest.
El vie, 9 abr 2021 a las 15:02, Nic Davidson via Rocket Forum (<Mail@forum.rocketsoftware.com>) escribió:
Be sure to join the forums you're interested in to be notified of new content. Click the join button from either the forum listing page or the home page of any given sub-forum.
Tip: Want a single update on all your forum memberships? Go to Profile > My Account > Forum Notifications, and check 'daily consolidated digest.' Switch the discussion email drop down to 'no email' or you will receive both.
![]()
Rocket U2 | UniVerse & UniData
Post New Message Online
Re: U2Py Error Handling
Reply to Group Online Reply to Group
Apr 9, 2021 2:02 PM Nic Davidson
Hey Michael, I appreciate the info. Let me get some code snippets in here. I do intend to throw the ODM on GitHub once I have it a little more refined. It turned into quite a large module when I started adding some of the ICONV and OCONV functionality, and to be frank....I would be embarrassed to show it all in it's current state :)
I'm likely getting away from my initial topic, but this module is one of the cooler things I have done in a while, and I like showing off!
The module itself is currently 4 classes, a U2Handler, U2Reader, and U2Writer. My handler holds and works all of the U2py.File objects and acts as the wrapper around most of the u2py.File functionality. It gets the fieldnames (Dictionary record IDs) for the file. It also converts pythonic fieldnames (engine_make) to and from the Universe fieldnames (ENGINE.MAKE). So I can call a field with either, and the string is converted to a DynArray without me having to deal with it.
UVReader and UVWriter use the u2py.File's read and write methods respectively. I get everything into one nice and clean object with a U2Odm class that inherits from U2Reader and U2Writer. Passing *args and **kwargs up as needed. I did all of this because I am lazy, and us Python guys have an irrational fear of caps lock :)
I'll show you my read and write functions, as they are the heavy lifters, I expanded on my comments to hopefully help make understanding it easier, but if anyone has questions, let me know. Happy to post more.
class U2Reader(U2Handler): ....... def read_field(self, record_id, field_name): """ reads and returns a value of a field corresponding to the record_id and a field name. Converts pythonic fieldnames (equip_status) to UV ones (EQUIP.STATUS) by replaceing . with _ and lowercase. """ if isinstance(record_id, list): record_id = record_id[0] # _py_to_uv changes a Pythonic field name into a UV fiendly one. field_name = self._py_to_uv(field_name) # make my field name a DynArray so I can use it with U2py. dyn_array_field = u2py.DynArray(field_name) # self.uv_file is a u2py.File object of the file I am working with. This is created in the U2Handler class on the __init__ value = self.uv_file.readnamedfields(record_id, dyn_array_field, self.lock_flag) if field_name == "@ID": # if we are looking at the Record ID field, we need to just keep it as is. rec_id = value.to_list()[0] return rec_id value = self._unarray(value) if self.value_convert: # convert the values, if we are supposed to. #UV string to Py Object will use the Conversion code in the UVDict file to convert to a proper python object (list, dict, int...) value = self.uv_string_to_py_obj(value) conv_code = self.get_conversion_code(field_name) # if my value is None, why convert it? if value == None: return value else: # if I dont have a conversion code in my UVDict, I can't convert it. if conv_code: value = self.uv_string_conversion_code(conv_code, value) return value else: return value else: return valueclass U2Writer(U2Handler): ......... def write_field(self, record_id, field_name, value): """ Writes to a named field. Converts pythonic objects to approppriate strings when necessary. """ # change my pythonic fieldname into a UV one field = self._py_to_uv(field_name) if value == None: # If the value None, keep the writeable_value as none writeable_value = None else: if isinstance(value, datetime.datetime): # If the value is a datetime object, it needs to be converted # regardless of self.calue_convert. If u2py could handle datetime objects this would go away! # I have a Python dict in a config file that maps UV CONV codes to the Datetime library partner. EX: DTIZ gets paired with "%Y-%m-%dT%H:%M:%SZ" conv_code = self.get_conversion_code(field) if conv_code: writeable_value = self.apply_conversion_code(value, conv_code) else: writeable_value = value elif self.value_convert and not isinstance(value, datetime.datetime): if isinstance(value, str): writeable_value = value else: conv_code = self.get_conversion_code(field) writeable_value = self.apply_conversion_code(value, conv_code) else: writeable_value = value dyn_field = u2py.DynArray(field) dyn_value = u2py.DynArray([writeable_value]) if self.locking: # set exclusive lock - Locking logic is not done yet, placeholder self.lock_record(record_id, True) try: self.uv_file.writenamedfields(record_id, dyn_field, dyn_value) except u2py.U2Error as e: # printing here for debugging. I have not made my logger for this module yet, # print(record_id, dyn_field, dyn_value) raise e if self.verify: # Not implemented as of yet, but will eventually veify writes and log errors as such. self.verify_write(record_id, field, value) if self.uv_file.islocked(record_id): # If for some reason I locked the file, make sure I unlock it at the end. self.unlock_record(record_id) return
As you can see, I am basically just using readnamedfield() and writenamedfields() on the u2py.File object. The beauty for this is that my read/write code looks like:
def odm_test(): # Start up my U2Odm object with a file name. I can also pass paramaters on locking, write verificaition and a boolean on if I should try to convert fields based on line 3 of the field's UVdictonary. my_odm = u2odm.U2Odm('equipment_sales') # Instead of having to type "ENG.MAIN.MAKE" I can keep my variables pythonic. Us younger python guys are allergic to capital letters... value = my_odm.read_field(3257, 'eng_main_make') write_val = my_odm.write_field('3257', 'eng_main_make', value)
When I run this with the file open in an editor (ED EQUIPMENT.SALES 3257) I get the following:
U2 ERROR 3257 ENG.MAIN.MAKE 857 Traceback (most recent call last): File "PP/nictest.py", line 197, in <module> odm_test() File "PP/nictest.py", line 190, in odm_test write_val = my_odm.write_field('3257', 'eng_main_make', value) File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 412, in write_field raise e File "/u2/COMBINED/GM.JR/PP/u2odm/odm.py", line 408, in write_field self.uv_file.writenamedfields(record_id, dyn_field, dyn_value) u2py.U2Error: (3) unknown # The "(3) unknown" is the weirdest thing here. I do get a proper 3001 code for record id not found when I break that intentionally.
My intent is to make my ODM(ORM?) more robust and catch/try to resolve these errors. My read_as_dict(), read_as_list(), write_dict() and write_list() methods all call the above functions to make their magic happen.
Because we are smart programmers, here is a min working example just using u2py
def nic_breaks_u2py(): my_file = u2py.File('EQUIPMENT.SALES') field_arr = u2py.DynArray('ENG.MAIN.MAKE') value = my_file.readnamedfields('3257', field_arr) write = my_file.writenamedfields('3257', field_arr, value)
This will work if the record is not open, but will show the same (3) unknown error if the file is open in an editor.
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Reply to Group Online View Thread Recommend Forward Flag as Inappropriate Post New Message Online
DB Version is 11.3.2.7001 Nic,
Interesting, I am not getting an error 3, but it does raise an exception.
Note I altered your example to use the XDEMO MEMBERS file
python> my_file = u2py.File('MEMBERS')
python> field_arr = u2py.DynArray([ "@ID", "FIRST_NAME" ] )
python> value = my_file.readnamedfields('0110', field_arr)
python> try:
... my_write = my_file.writenamedfields('0110', field_arr, value)
... except u2py.U2Error as e:
... print( "the item can not be locked")
... print( str(e))
...
the item can not be locked
(305727) unknown
python>
Yet, if I get a lock prior to trying to write the data, it returns the message that it is locked.
python> my_file = u2py.File('MEMBERS')
python> field_arr = u2py.DynArray([ "@ID", "FIRST_NAME" ] )
python> value = my_file.readnamedfields('0110', field_arr)
python> try:
... my_file.lock("0110")
... my_write = my_file.writenamedfields('0110', field_arr, value)
... except u2py.U2Error as e:
... print( "the item can not be locked")
... print( str(e))
...
the item can not be locked
(30002) File or record is locked by another user
Can I get the Database Version and the OS you are running this on?
------------------------------
Michael Rajkowski
Rocket Software
------------------------------
On RHEL 7.7
I thought your idea about trying explicitly locking the file in the try loop was a good one so I tried it myself...and the error is displaying how I would expect it to. I am thinking I am doing something wrong with the locking in my ORM. I am going to target that area and see what I can find. If I run a test without any type of locking, I am getting the unknown error, from my uneducated perspective I am guessing Python is not understanding the lock flag when the record is being locked within the TCL editor, OR my ORM is not actually locking the record appropriately.
Would a general best practice/recommendation be to do a shared lock on read operations and an exclusive lock on write operations?
------------------------------
Nic Davidson
Developer
Combined Transport
OR United States
------------------------------
Sign up
Already have an account? Login
Welcome to the Rocket Forum!
Please log in or register:
Employee Login | Registration Member Login | RegistrationEnter your E-mail address. We'll send you an e-mail with instructions to reset your password.