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.
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... -posted to the "Rocket U2 | UniVerse & UniData" forum
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. | | | Post New Message Online | Re: U2Py Error Handling | | | 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 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 ------------------------------ | | Reply to Group Online View Thread Recommend Forward Flag as Inappropriate Post New Message Online |
Original Message: Sent: 04-09-2021 12:40 | |
| |
--
Ing. Sergio Perin
Baseware Systems Original Message:
Sent: 4/9/2021 2:02:00 PM
From: Nic Davidson
Subject: RE: U2Py Error Handling
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 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
------------------------------
Original Message:
Sent: 04-09-2021 12:40
From: Michael Rajkowski
Subject: U2Py Error Handling
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:
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