-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patherars.py
6993 lines (6481 loc) · 314 KB
/
erars.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#######################################################################
#
# This is the pythonic layer on top of pyars.
# (C) 2004-2015 by Ergorion
#
# Currently supported Version: V5.1.-V8.1.0 of the Remedy API
#
#######################################################################
#
# known issues:
#
from ctypes import c_ulong, c_long, c_double, c_int, c_uint, byref,\
pointer, c_char_p
import exceptions
import time
from pyars import cars
#from pyars.ars import ARS, my_byref, pyARSNotImplemented
from pyars import ars
class ARError(exceptions.Exception):
def __init__(self, arsSession = None, msgText = None, msgType = cars.AR_RETURN_WARNING):
'''You can raise an ARError exception with an ars session or a message.
If msgType is set, it is assumed that you do want to use msgText as the
exception text; otherwise, the status list from arsSession will be read
and used as the message.
Input: (optional) arsSession
(optional) msgText
(optional) msgType (can be AR_RETURN_OK, AR_RETURN_WARNING, AR_RETURN_ERROR)
Output: n/a'''
if msgType is not None:
self.messageType = msgType
self.messageNum = 0
self.messageText = msgText
return
if arsSession is not None and arsSession.arsl is not None and arsSession.arsl.numItems > 0:
arstatusStruct = arsSession.arsl.statusList[0]
self.messageType = arstatusStruct.messageType
self.messageNum = arstatusStruct.messageNum
self.messageText = arsSession.statusText()
# arstatusStruct.messageText
# if arstatusStruct.appendedText:
# self.messageText = '%s\n%s' % (self.messageText,
# arstatusStruct.appendedText)
return
def __str__(self):
return 'An %s (%d) occured: %s' % (cars.ars_const['AR_RETURN'][self.messageType],
self.messageNum,
self.messageText)
class erARS51(ars.ARS):
def __init__(self, server='', user='', password='', language='',
authString = '',
tcpport = 0,
rpcnumber = 0):
super(erARS51, self).__init__(server, user, password, language,
authString, tcpport, rpcnumber)
if server != '':
self._InitializeCache()
def __enter__(self):
self.logger.debug('enter __enter__ of context manager')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.logger.debug('enter __exit__ of context manager')
if exc_type is not None:
pass # Exception occurred
self.Logoff()
def _InitializeCache(self):
'''InitializeCache setup the internal cache for objects retrieved
from server. This cache has a common structure:
{ 'type_of_object' :
{schema :
{ id : object }
}
}
as 'type_of_object' are currently supported: alink, fields, filter and schema.
for alink and filter the name is the id, for fields it is the fieldid, for
schema (the schema definition itself) it is the string "default".
With this setup we can define one single function to retrieve objects from
the cache.'''
self._cacheTimeout = 10 * 60
self.cache = {'alink' : {},
'fields': {},
'filter': {},
'schema': {}}
def _RetrieveObjectFromCache(self, typeOfObject,
schema,
objectId):
'''Return a certain object from the cache if it was retrieved before
and has not timed out yet.
Input: typeOfObject (can be either 'alink', 'fields', 'filter', 'schema', 'fieldtable')
schema (name of schema that the field belongs to; for alink and filter this is 'default')
objectId (something to identify (in case of 'schema' or 'fieldtable', this is 'default')
Output: object or None'''
now = time.time()
if self.cache[typeOfObject].has_key(schema):
if self.cache [typeOfObject][schema].has_key(objectId):
(object_, timestamp) = self.cache [typeOfObject][schema][objectId]
if now - timestamp < self._cacheTimeout:
self.logger.debug('_RetrieveObjectFromCache: return info for %s:%s:%s from cache' % (
schema, typeOfObject, objectId))
if object_ is None:
self.errnr = 2 # simulate an error
return object_
else: # after cache timeout
self.ARFree(object_)
else: # if the cache does not know this schema yet!
self.cache [typeOfObject].update({schema: {}})
def _StoreObjectInCache(self, typeOfObject, schema, objectId, object_):
self.cache[typeOfObject][schema][objectId] = (object_, time.time())
def conv2ContainerTypeList(self, containerArray):
'''take a list of containerTypes and return a ARContainerTypeList
Input: ARContainerTypeList, None, or integer or list of integers
Output: ARContainerTypeList
if input is an integer, then the list contains just the integer
if input is None, then the list contains ARCON_ALL
otherwise, the ARContainerTypeList contains all the values
contained in the argument'''
if isinstance(containerArray, cars.ARContainerTypeList):
return containerArray
if containerArray is None:
containerArray = [cars.ARCON_ALL]
elif isinstance(containerArray,int):
containerArray = [containerArray]
# we have received an array and have to translate it into
# the remedy structure ARContainerTypeList
tempArray = (c_int * len(containerArray))()
tempArray[:] = containerArray[:]
return cars.ARContainerTypeList(len(containerArray), tempArray)
def conv2EntryIdList(self, schemaString, entry):
'''conv2EntryIdList will try to create an AREntryIdList for either
a simple schema/entryid or a joinform/joinentryid or
joinform/list_of_entryids
input: schemaString: name of schema
entry: can be an integer or a string or a tuple/array/list
of (entryid1, entryid2)
output: AREntryIdList'''
def createSchemaIdList(schemaString, entry):
'''take a schemaString and a list of entryIds; starting
with this schema, try to find out all involved schemas
for the entryids (e.g. simple joins, joins of joins...)
Input: schemaString: name of schema
entry: array of entry ids
Output: ((schema1, entryid1), (schema2, entryid2), ...) or None in case of failure'''
# self.logger.debug('createSchemaIdList: %s and %s' % (
# schemaString, entry))
# first check if length of tuple == 1: it's not for a join...
# it just happens to be in a tuple; this time we just assume
# it's a string, we don't check for integers any more...
if len(entry) == 1:
return ((schemaString, entry[0]), )
else:
# self.logger.debug(' assuming a join, fetching schema')
# Assumption here:
# it is a join schema; so we need to find the names of the
# underlying forms
# in order to find out the max. length of the entry ids!
self.logger.debug('looking up %s' % schemaString)
try:
schema = self.GetSchema(schemaString)
except ARError:
self.logger.error(self.statusText())
return None
# as we can have joins of joins, we need to
# call ourselves recursively
if schema.schema.schemaType == cars.AR_SCHEMA_JOIN:
# if one of the following calls fails, the result
# exception will not be caught. This is on purpose!
# otherwise the cause for not returning a useful result
# will not be known.
schemaA = self.GetSchema(schema.schema.u.join.memberA)
schemaB = self.GetSchema(schema.schema.u.join.memberB)
if schemaA.schema.schemaType == cars.AR_SCHEMA_JOIN and \
schemaB.schema.schemaType == cars.AR_SCHEMA_JOIN:
return (createSchemaIdList(schema.schema.u.join.memberA,
entry[:len(entry)/2])+
createSchemaIdList(schema.schema.u.join.memberB,
entry[len(entry)/2:]))
elif schemaA.schema.schemaType == cars.AR_SCHEMA_JOIN:
return (createSchemaIdList(schema.schema.u.join.memberA,
entry[:-1])+
((schema.schema.u.join.memberB, entry[-1]),)
)
elif schemaB.schema.schemaType == cars.AR_SCHEMA_JOIN:
return (((schema.schema.u.join.memberA, entry[0]),)+
createSchemaIdList(schema.schema.u.join.memberB,
entry[1:])
)
else:
return ((schema.schema.u.join.memberA, entry[0]),
(schema.schema.u.join.memberB, entry[1]))
else: # this should actually not happen!
# we assume we have a join schema, but the schemaType is not join?
# throw an error!
self.logger.error('''createSchemaIdList: wrong type of entry id %s
for this schema %s''' % (entry, schemaString))
self.errnr = 2
return None
# self.logger.debug('conv2EntryIdList for %s and %s' % (
# schemaString, entry))
if isinstance(entry, cars.AREntryIdList):
return entry
if entry is None:
return None
self.errnr = 0
# if we are handed over a tuple as the id, it means that the id is for a join schema
# in order to handle a single string or tuple the same way, we generate a tuple from the
# string
if isinstance(entry, unicode): # try to convert to standard string
entry = str(entry)
if isinstance(entry, str) and entry.find('|') < 0: # no | found
entrylist = ((schemaString, entry), )
elif isinstance(entry, (long, int)):
entrylist = ((schemaString, str(entry)), )
else:
# we were given a tuple for the entry id
# either via a tuple or via a concatenated string --> split the string:
if isinstance(entry, str) and entry.find('|') > -1:
entry = entry.split('|')
# this smells like join, so hand it over to the specialized
# function, that can handle recursion
entrylist = createSchemaIdList(schemaString, entry)
self.logger.debug('result of schemaIdList: %s!' % (str(entrylist)))
if self.errnr > 1:
return None
# now generate the AREntryIdList from the handed over ids for the API call
tempArray = (cars.AREntryIdType * len(entrylist))()
# construct a temporary array
for i in range(len(entrylist)):
# as we had only trouble with the padEntry, I guess
# people should do this before calling this function!
filler = '\0' * (cars.AR_MAX_ENTRYID_SIZE-len(entrylist[i][1])+1)
tempArray[i][:] = (entrylist[i][1]+filler)[:]
return cars.AREntryIdList(len(entrylist), tempArray)
#
#
### this used to be the old code that tries to
### do a padEntry as well...
# fi = self.GetField (entrylist[i][0], 1)
# if self.errnr > 1:
# self.logger.error(' : GetField(%s, 1) failed!' % entrylist[i][0])
# return None
# # we know that entryIds are chars!
# # it is important for padEntry not to take the limits of the join
# # schema, but of the underlying original forms...!
# try:
# # for debugging purposes I split this into two lines and
# # assign a temp variable
# result = self.padEntryid(entrylist[i][1],
# fi.defaultVal.u.charVal,
# fi.limit.u.charLimits.maxLength)
# # self.logger.debug('padEntryid returned for %d a string of length %d' % (
# # (fi.limit.u.charLimits.maxLength, len(result))))
#
# tempArray[i][:] = result [:]
# self.logger.debug(' generating id %s' % (result))
# except ValueError:
# self.logger.error(' wrong length of id: %s' % (result))
# self.errnr = 2
# return None
def conv2EntryIdListList (self, schema, entryIdArray):
'''take an array of entryids and convert them to a
AREntryIdListList.
Input: schema (not used any more)
entryIdArray (pythonic list of entryids)
Output: AREntryIdListList'''
if isinstance(entryIdArray, cars.AREntryIdListList):
return entryIdArray
tempArray = (cars.AREntryIdType * len(entryIdArray))()
for i in range(len(entryIdArray)):
# TODO: here we need the exact field information for
# padEntryid!
tempArray[i][:] = self.padEntryid(entryIdArray[i])[:]
# this is a list of lists!
# the question now is which one stores the single entry ids
# to retrieve? First try: the inner list
secondList = (cars.AREntryIdList * len(entryIdArray))()
for i in range(len(entryIdArray)):
secondList[i].numItems = 1
secondList[i].entryIdList = pointer(tempArray[i])
return cars.AREntryIdListList(len(entryIdArray), secondList)
def conv2EntryListFieldList(self, fieldList, schema):
'''conv2EntryListFieldList: take a tuple/array/list of
(fieldId, column width, seperator)
and return an AREntryListFieldList. This is useful
to control the output of GetListEntry and others...
future improvement: if columnwidth and/or seperator are not given,
take the information from the schema...'''
if isinstance(fieldList, cars.AREntryListFieldList):
return fieldList
if not fieldList:
return None
try:
tempArray = (cars.AREntryListFieldStruct * len(fieldList))()
for i in range(len(fieldList)):
if isinstance (fieldList[i], (long, int, str)):
# self.logger.debug(' found a fieldid, no additional info')
tempArray[i].fieldId = int(fieldList[i])
# setting sensible defaults -- we could look them up
# in the schema definition!
tempArray[i].columnWidth = 10
tempArray[i].separator = ''
elif isinstance (fieldList[i], (tuple, list)): # assuming a tuple with at least the id
# self.logger.debug(' found a tuple with fieldid and additional info')
tempArray[i].fieldId = int(fieldList[i][0])
try:
tempArray[i].columnWidth = fieldList[i][1]
except KeyError:
tempArray[i].columnWidth = 10
try:
tempArray[i].separator = fieldList[i][2]
except KeyError:
tempArray[i].separator = ''
else: # just try to convert to int...
try:
tempArray[i].fieldId = int(fieldList[i])
except ValueError:
self.logger.error('conv2EntryListFieldList: TypeError at position %d' % i)
return cars.AREntryListFieldList (len(fieldList), tempArray)
except TypeError:
self.logger.error('conv2EntryListFieldList: TypeError')
self.errnr = 2
return None
def conv2FieldValueList(self, schema, fieldList):
'''conv2FieldValueList: take a dict or a tuple/array/list of (fieldId, value)
and return an ARFieldValueList
the schema used to be necessary as this function tried to get
more detailed information about the fields.
Special case attachment: (fieldId, (name, origSize, compSize, filename))
*please note* only filenames currently supported, no buffers!
Special case coords: (fieldid, (numItems, x1, y1, x2, y2...))'''
if isinstance(fieldList, cars.ARFieldValueList):
return fieldList
if fieldList is None:
return None
# create a temporary array that we will assign to the fieldvaluelist
# afterwards....
tempArray = (cars.ARFieldValueStruct * len(fieldList))()
if isinstance(fieldList, (tuple, list)):
for i in range(len(fieldList)):
tempArray[i].fieldId = fieldList[i][0]
self.conv2ValueStruct(tempArray[i].value,
fieldList[i][1])
elif isinstance(fieldList, dict):
for (fieldId, i) in zip(fieldList.keys(), range(len(fieldList))):
tempArray[i].fieldId = fieldId
self.conv2ValueStruct(tempArray[i].value,
fieldList[fieldId])
return cars.ARFieldValueList(len(fieldList), tempArray)
# now create the correct ARValueStruct!
# first find out which datatype this field has:
# fi = self.GetField(schema, fieldList[i][0])
# if self.errnr > 1:
# self.logger.error('''conv2FieldValueList: could not lookup field: %d!''' % (
# fieldList[i][0]))
# return None
# tempArray[i].value.dataType = fi.dataType
# self.logger.debug('''conv2FieldValueList: fieldId: %d, type: %d/%s!!!''' % (
# fieldList[i][0], fi.dataType, cars.ars_const['AR_DATA_TYPE'][fi.dataType]))
# numerical types should not be a problem
# AR_DATA_TYPE_NULL ???
# does this work? we hand over the ARValueStruct
# by reference and conv2ValueStruct sets the members
# correctly...
# self.conv2ValueStruct(tempArray[i].value,
# fieldList[i][1],
# fi.dataType)
def conv2FullTextInfoRequestList(self, requestArray):
'''conv2FullTextInfoRequestList: take a tuple/array/list of integers
and return an ARFullTextInfoRequestList:
>>> res=ar.conv2FullTextInfoRequestList((1, 2, 3))
>>> print res.numItems
3
>>> print res.requestList[2]
3'''
if isinstance(requestArray, cars.ARFullTextInfoRequestList):
return requestArray
if isinstance(requestArray, int):
requestArray = [requestArray]
elif isinstance(requestArray, str):
requestArray = [int(requestArray)]
if isinstance(requestArray, (tuple, list)):
tempArray = (c_uint * len(requestArray))()
tempArray[:] = requestArray[:]
return cars.ARFullTextInfoRequestList(len(requestArray),
tempArray)
else:
return None
def conv2InternalIdList (self, idList):
'''take an array of internal fieldids (or a single int)
and return ARInternalIdList'''
if isinstance(idList, cars.ARInternalIdList):
return idList
if isinstance(idList, int):
idList = [idList]
elif isinstance(idList, str):
idList = [int(idList)]
if isinstance(idList, (tuple, list)):
tempArray = (cars.ARInternalId * len(idList))()
for i in range(len(idList)):
tempArray[i] = idList [i]
return cars.ARInternalIdList (len(idList), tempArray)
else:
return None
def conv2NameList(self, names):
'''take a list of names and convert it to an ARNameList'''
if isinstance(names, cars.ARNameList):
return names
if names is None:
return None
tempArray = (cars.ARNameType * len(names))()
temp = '\0' * 255
for i in range(len(names)):
tempArray[i][:] = names[i][:]+temp[:255-len(names[i])]
return cars.ARNameList(len(names), tempArray)
def conv2PermList(self, permArray):
'''take a list of (groupid, permission) and turn it
into an ARPermissionList'''
if isinstance(permArray, cars.ARPermissionList):
return permArray
tempArray = (cars.ARPermissionStruct * len(permArray))()
for i in range(len(permArray)):
tempArray[i].groupId = permArray [i][0]
tempArray[i].permissions = permArray [i][1]
return cars.ARPermissionList(len(permArray), tempArray)
def conv2QualifierStruct(self, schema, query, displayTag=None):
if query is None:
return None
elif isinstance(query, cars.ARQualifierStruct):
return query
else:
q = cars.ARQualifierStruct()
self.errnr = self.arapi.ARLoadARQualifierStruct(byref(self.context),
schema,
displayTag,
query,
byref(q),
byref(self.arsl))
if self.errnr > 1:
self.logger.error ('conv2QualifierStruct: LoadQualifier failed!')
raise ARError(self)
return q
def conv2ReferenceTypeList(self, refList):
'''take list of reference types and return an ARReferenceTypeList'''
if isinstance(refList, cars.ARReferenceTypeList):
return refList
if isinstance(refList, int):
refList = [refList]
tempArray = (c_int * len(refList))() # FIXME cars.c_int
try:
if len(refList) > 1: # bug in ctypes?
tempArray [:] = refList[:]
else:
tempArray [0] = refList[0]
return cars.ARReferenceTypeList(len(refList), tempArray)
except ValueError:
self.logger.error('conv2ReferenceTypeList: received reflist: %s' % (
refList))
def conv2ServerInfoList(self, serverInfoList):
if isinstance(serverInfoList, cars.ARServerInfoList):
return serverInfoList
tempArray = (cars.ARServerInfoStruct * len(serverInfoList))()
if isinstance(serverInfoList, dict):
for (i, operation) in enumerate(serverInfoList.keys()):
tempArray[i].operation = operation
self.conv2ValueStruct(tempArray[i].value, serverInfoList[operation])
if isinstance(serverInfoList, (list, tuple)):
for i in range(len(serverInfoList)):
tempArray[i].operation = serverInfoList[i][0]
self.conv2ValueStruct(tempArray[i].value, serverInfoList[i][1])
return cars.ARServerInfoList(len(serverInfoList), tempArray)
def conv2ServerInfoRequestList(self, requestArray):
'''take a tuple of serverinforequests and return a ARServerInfoRequestList'''
if isinstance(requestArray, cars.ARServerInfoRequestList):
return requestArray
if isinstance(requestArray, int):
requestArray = [requestArray]
tempArray = (c_uint * len(requestArray))()
try:
tempArray[:] = requestArray[:]
return cars.ARServerInfoRequestList(len(requestArray),tempArray)
except ValueError:
self.logger.error('conv2ServerInfoRequestList: received requestArray: %s' % (
requestArray))
def conv2SortList(self, fieldList):
'''conv2SortList: take a tuple/array/list of (fieldId, de/ascending)
and return an ARSortList; ascending is 1 (or string beginning with 'a'),
descending is 2 (or string beginning with 'd').
default is ascending order.'''
if isinstance(fieldList, cars.ARSortList):
return fieldList
if not fieldList:
return None
try:
tempArray = (cars.ARSortStruct * len(fieldList))()
for i in range(len(fieldList)):
if isinstance(fieldList[i], (long, int, str)):
tempArray[i].fieldId = int(fieldList[i])
tempArray[i].sortOrder = cars.AR_SORT_ASCENDING
else:
tempArray[i].fieldId = fieldList[i][0]
if isinstance(fieldList[i][1], str):
if fieldList[i][1][0] == 'd':
tempArray[i].sortOrder = cars.AR_SORT_DESCENDING
else:
tempArray[i].sortOrder = cars.AR_SORT_ASCENDING
else: # assumption: integer 1 or 2
tempArray[i].sortOrder = fieldList[i][1]
return cars.ARSortList (len(fieldList), tempArray)
except TypeError:
self.logger.error('conv2SortList: ran into a TypeError with fieldList: %s!' % (
fieldList))
self.errnr = 2
return None
def conv2StructItemList(self, itemArray):
'''conv2StructItemList takes a list of ints and names and converts
it into a ARStructItemList; currently the namelist (as the third entry)
for selected elements is not supported'''
if isinstance(itemArray, cars.ARStructItemList):
return itemArray
structItems = (cars.ARStructItemStruct * len(itemArray)) ()
for i in range(len(itemArray)):
structItems[i].type = itemArray[i][0] # c_uint(itemArray[i][0])
structItems[i].name = itemArray[i][1] # create_string_buffer(itemArray[i][1], cars.AR_MAX_NAME_SIZE + 1)
structItems[i].selectedElements = cars.ARNameList()
return cars.ARStructItemList(len(itemArray), structItems)
def conv2TimestampList (self, ratioTimestamps):
'''conv2TimestampList takes a list of ints and converts it
into an ARTimestampList; if None is handed over, the default
is to return a list with one entry of AR_CURRENT_CURRENCY_RATIOS.'''
if isinstance(ratioTimestamps, cars.ARTimestampList):
return ratioTimestamps
if not ratioTimestamps:
ratioTimestamps = [cars.AR_CURRENT_CURRENCY_RATIOS]
tempArray = (cars.ARTimestamp * len(ratioTimestamps))()
tempArray[:] = ratioTimestamps[:]
return cars.ARTimestampList(len(ratioTimestamps), tempArray)
def conv2ValueStruct(self, valueStruct, value, dataType = None):
'''take a value and set the members of valueStruct according to
dataType
Input: valueStruct (ARValueStruct that will be modified inplace)
value (the actual value)
(optional) dataType (the dataType to be used)
Output: none'''
if isinstance(value, cars.ARValueStruct):
return value
if dataType is None:
if isinstance(value, (int, long)):
valueStruct.dataType = cars.AR_DATA_TYPE_INTEGER
valueStruct.u.intVal = c_long(value)
return
elif isinstance(value, float):
valueStruct.dataType = cars.AR_DATA_TYPE_REAL
valueStruct.u.realVal = c_double(value)
return
elif isinstance(value, unicode):
valueStruct.dataType = cars.AR_DATA_TYPE_CHAR
valueStruct.u.charVal = value
return
elif isinstance(value, str):
valueStruct.dataType = cars.AR_DATA_TYPE_CHAR
valueStruct.u.charVal = value
return
if isinstance(value, tuple) and len(value) == 4:
# this is an attachment!
# value should look like (name, origSize, compSize, filename)
attachment = cars.ARAttachStruct()
attachment.name = value[0]
attachment.origSize = value[1]
attachment.compSize = value[2]
attachment.loc = cars.ARLocStruct(cars.AR_LOC_FILENAME)
attachment.loc.u.filename = value[3]
valueStruct.dataType = cars.AR_DATA_TYPE_ATTACH
valueStruct.u.attachVal = pointer(attachment)
elif value is None:
valueStruct.dataType = cars.AR_DATA_TYPE_NULL
return
else:
self.logger.error("conv2ValueStruct: don't really know how to handle %s, will try string" % (
value))
valueStruct.dataType = cars.AR_DATA_TYPE_CHAR
valueStruct.u.charVal = str(value)
return
# open issue: what happens when:
# 2) keyword with _INTEGER?
# 3) DATE with _INTEGER?
# solved:
# DECIMAL can be set with integer
# TIME can be set with integer
# enum can be set with integer
# worklog with string...
else: # dataType is handed over...
valueStruct.dataType = dataType
if dataType == cars.AR_DATA_TYPE_KEYWORD:
valueStruct.u.keyNum = c_uint(int(value))
elif dataType == cars.AR_DATA_TYPE_INTEGER:
valueStruct.u.intVal = c_long(int(value))
elif dataType == cars.AR_DATA_TYPE_REAL:
valueStruct.u.realVal = c_double(float(value))
elif dataType == cars.AR_DATA_TYPE_CHAR:
valueStruct.u.charVal = str(value) # my_byref(value)
elif dataType == cars.AR_DATA_TYPE_DIARY:
valueStruct.u.diaryVal = ars.my_byref(value)
elif dataType == cars.AR_DATA_TYPE_ENUM:
valueStruct.u.enumVal = c_ulong(int(value))
elif dataType == cars.AR_DATA_TYPE_TIME:
valueStruct.u.timeVal = cars.ARTimestamp(long(value))
elif dataType == cars.AR_DATA_TYPE_BITMASK:
valueStruct.u.maskVal = c_ulong(int(value))
elif dataType == cars.AR_DATA_TYPE_TIME_OF_DAY:
valueStruct.u.timeOfDayVal = cars.ARTime(long(value))
# this requires an union!!!!
elif dataType == cars.AR_DATA_TYPE_BYTES:
valueStruct.u.byteListVal = ars.my_byref(value)
elif dataType == cars.AR_DATA_TYPE_DECIMAL:
# this is analog to charVal
valueStruct.u.decimalVal = str(value) # mybyref
# this requires an union!!!!
elif dataType == cars.AR_DATA_TYPE_ATTACH:
tempLocStruct = cars.ARLocStruct()
# at this time we only support filenames in here!
tempLocStruct.locType = cars.AR_LOC_FILENAME
# FIXME: currently this is not supported!
self.logger.error('*Attachments not yet supported! inserting default values*')
tempLocStruct.u.filename = 'testfilename'
valueStruct.attachVal = None
# tempLocStruct.u.filename = value[3]
# tempAttachStruct = cars.ARAttachStruct(value[0],
# value[1],
# value[2],
# tempLocStruct)
# valueStruct.attachVal = byref(tempAttachStruct)
# TODO: this requires an union!!!!
elif dataType == cars.AR_DATA_TYPE_CURRENCY:
valueStruct.u.currencyVal = value
elif dataType == cars.AR_DATA_TYPE_DATE:
valueStruct.u.dateVal = value
elif dataType == cars.AR_DATA_TYPE_ULONG:
valueStruct.u.ulongVal = value
elif dataType == cars.AR_DATA_TYPE_ATTACH_POOL:
valueStruct.u.keyNum = value
# TODO: test this!!!
elif dataType == cars.AR_DATA_TYPE_COORDS:
tempCoordList = cars.ARCoordList()
tempCoordList.numItems = value[0]
tempCoordArray = cars.ARCoordStruct() * tempCoordList.numItems
for i in range(tempCoordList.numItems):
tempCoordArray[i].x = value[i*2+1]
tempCoordArray[i].y = value[i*2+2]
tempCoordList.coords = tempCoordArray
valueStruct.u.coordListVal = byref(tempCoordList)
else:
self.logger.debug('''conv2ValueStruct: unknown type: %d!!!''' % (
dataType))
self.errnr = 2
return None
# except TypeError:
# if value == None or value == '':
# # correc the data type -- we don't have any value to assign
# valueStruct.dataType = cars.AR_DATA_TYPE_NULL
# else:
# self.logger.debug('''conv2ValueStruct: TypeError
# while trying to convert: (%d, %s)''' % (dataType,
# value))
# self.errnr = 2
# return None
def convAccessNameList2List(self, obj):
return [obj.nameList[i].value
for i in range(obj.numItems)]
def convBooleanList2List(self, booleanList):
return [booleanList.booleanList[i] and True or False
for i in range(booleanList.numItems)]
def convDispInstList2Dict(self, dispInstList):
'''droppes the common properties and returns as a dict
the VUIds, with the display property lists as dicts
for each VUI'''
return dict([[dispInstList.dInstanceList[i].vui,
self.convPropList2Dict(dispInstList.dInstanceList[i].props)]
for i in range(dispInstList.numItems)])
def convEntryIdList2String(self, entryId):
'''we received an AREntryIdList (e.g. from GetListEntry) for
a single entry (e.g. in a join form) and need this to be
flatened out in a string'''
if entryId is None:
self.logger.error('convEntryIdList2String: received None as entryId')
return None
if isinstance (entryId , str):
self.logger.error('convEntryIdList2String: received simple string')
return entryId
return '|'.join([entryId.entryIdList[i].value for i in range(entryId.numItems)])
def convEntryIdListList2List(self, obj):
'''if you want to convert an AREntryIdListList (e.g. from ARGetListEntry) for
multiple entries into a pythonic list of entryid strings.'''
return [self.convEntryIdList2String(obj.entryIdList[i])
for i in range(obj.numItems)]
def convEntryListFieldValueList2Dict(self, obj):
'''take an AREntryListFieldValueList (e.g. result of
GetListEntryWithFields) and return a dictionary:
{entryid1: {fid1: value, fid2: value...}, entryid2: ....}'''
return dict([self.convEntryListFieldValueStruct2List(obj.entryList[i])
for i in range(obj.numItems)])
def convEntryListFieldValueList2List(self, obj):
'''take an AREntryListFieldValueList (e.g. result of
GetListEntryWithFields) and return a list:
((entryid1, {fid1: value, fid2: value...}), (entryid2, {}), ....)'''
return [self.convEntryListFieldValueStruct2List(obj.entryList[i])
for i in range(obj.numItems)]
def convEntryListFieldValueList2StringDict(self, obj):
'''take an AREntryListFieldValueList (e.g. result of
GetListEntryWithFields) and return a dictionary:
{entryid1: {"fid1": value, "fid2": value...}, entryid2: ....} '''
return dict([self.convEntryListFieldValueStruct2StringList(obj.entryList[i])
for i in range(obj.numItems)])
def convEntryListFieldValueStruct2List(self, obj):
'''take an AREntryListFieldValueStruct and return
[entryid, {fid1: value, fid2:value, ...}]'''
return [self.convEntryIdList2String(obj.entryId),
self.convFieldValueList2Dict(obj.entryValues.contents)]
def convEntryListFieldValueStruct2StringList(self, obj):
'''take an AREntryListFieldValueStruct and return
[entryid, {"fid1": value, "fid2":value, ...}]; the dict
can be passed to a template string.'''
return [self.convEntryIdList2String(obj.entryId),
self.convFieldValueList2StringDict(obj.entryValues.contents)]
def convEntryListList2EntryIdListList(self, obj):
'''EntryListList is returned by GetListEntry, but GetMultipleEntries
expects a EntryIdListList -- this function will convert it'''
tempArray = (cars.AREntryIdList * obj.numItems)()
tempArray [:] = [obj.entryList[i].entryId for i in range(obj.numItems)]
return cars.AREntryIdListList (obj.numItems, tempArray)
def convEntryListList2Dict(self, obj):
'''return a dictionary of {entryid: shortdesc, ....} (output of GetListEntry)'''
return dict(self.convEntryListList2List(obj))
def convEntryListList2List(self, obj):
'''return a list of (entryid, shortdesc) (output of GetListEntry)'''
return [(self.convEntryIdList2String(obj.entryList[i].entryId),
obj.entryList[i].shortDesc)
for i in range(obj.numItems)]
def convEnumLimitsStruct2Dict (self, eLS):
return dict(self.convEnumLimitsStruct2List(eLS))
def convEnumLimitsStruct2List (self, eLS):
'''take an AREnumLimitsStruct and generate a python list out of it.
ATTENTION: For AR_ENUM_STYLE_QUERY style EnumLimitsStruct, we should
execute the query!
Input: AREnumLimitsStruct
Output: ('execute query on', queryList.server,
queryList.schema,
queryList.qualifier,
queryList.nameField,
queryList.numberField)'''
if eLS.listStyle == cars.AR_ENUM_STYLE_REGULAR:
return [(i, eLS.u.regularList.nameList[i].value)
for i in range(eLS.u.regularList.numItems)]
elif eLS.listStyle == cars.AR_ENUM_STYLE_CUSTOM:
return [(eLS.u.customList.enumItemList[i].itemNumber,
eLS.u.customList.enumItemList[i].itemName)
for i in range(eLS.u.customList.numItems)]
elif eLS.listStyle == cars.AR_ENUM_STYLE_QUERY:
# TODO: retrieve the list
return ('execute query on', eLS.u.queryList.server,
eLS.u.queryList.schema,
eLS.u.queryList.qualifier,
eLS.u.queryList.nameField,
eLS.u.queryList.numberField )
else:
self.logger.error('unknown list style (%d) in AREnumLimitsStruct!' %
eLS.listStyle)
raise ValueError
def convFieldValueStruct2List (self, obj):
'''take an ARFieldValueStruct and return [fieldid, value]'''
return [obj.fieldId, self.convValueStruct2Value(obj.value)]
def convFieldValueStruct2StringList (self, obj):
'''take an ARFieldValueStruct and return [str(fieldid), value] '''
return [str(obj.fieldId), self.convValueStruct2Value(obj.value)]
def convFieldValueList2Dict (self, obj):
'''take an ARFieldValueList and returns a dictionary of
fieldid: value for all fieldids in the list'''
return dict([self.convFieldValueStruct2List(obj.fieldValueList[i])
for i in range(obj.numItems)])
def convFieldValueList2StringDict (self, obj):
'''take an ARFieldValueList and returns a dictionary of
str(fieldid): value for all fieldids in the list; this is
especially useful in combination with string formatting, then
you can have: 'value of fieldid: %(1)s' % dict'''
return dict([self.convFieldValueStruct2StringList(obj.fieldValueList[i])
for i in range(obj.numItems)])
def convFieldValueListList2List (self, obj):
'''take an ARFieldValueListList and returns a list of
[{fieldid: value for all fieldids in the list}]'''
return [self.convFieldValueList2Dict(obj.valueListList[i])
for i in range(obj.numItems)]
def convGroupInfoList2Dict(self, obj):
return dict([self.convGroupInfoStruct2List(obj.groupList[i])
for i in range(obj.numItems)])
def convGroupInfoStruct2List(self, obj):
return (obj.groupId, (obj.groupType,
self.convAccessNameList2List(obj.groupName),
obj.groupCategory))
def convInternalIdList2List(self, idList):
return [idList.internalIdList[i] for i in range(idList.numItems)]
def convNameList2List (self, nameList):
'''generate a python list out of an ARNameList'''
return [nameList.nameList[i].value for i in range(nameList.numItems)]
def convObjectChangeTimestampList2List(self, obj):
return [(obj.objectChanges[i].objectType,
obj.objectChanges[i].createTime,
obj.objectChanges[i].changeTime,
obj.objectChanges[i].deleteTime) for i in range(obj.numItems)]
def convPermissionList2Dict(self, obj):
'''convert a permissionList to a dictionary of [groupId: right]'''
return dict([(obj.permissionList[i].groupId, obj.permissionList[i].permissions)
for i in range(obj.numItems)])
def convPropList2Dict(self, obj):
return dict([(obj.props[i].prop, self.convValueStruct2Value(obj.props[i].value))
for i in range (obj.numItems)])
def convServerInfoList2Dict(self, serverInfoList):
return dict(self.convServerInfoList2List(serverInfoList))
def convServerInfoList2ExpDict(self, serverInfoList):
return dict(self.convServerInfoList2ExpList(serverInfoList))
def convServerInfoList2ExpList(self, serverInfoList):
'''lookup the operation and return the string explanation for it; if the
lookup fails for any value, we just return the list with the numerical values'''
try:
return [(cars.ars_const['AR_SERVER_STAT'][serverInfoList.serverInfoList[i].operation],
self.convValueStruct2Value(serverInfoList.serverInfoList[i].value))
for i in range(serverInfoList.numItems)]
except KeyError:
return self.convServerInfoList2List(serverInfoList)
def convServerInfoList2List(self, serverInfoList):
return [(serverInfoList.serverInfoList[i].operation,
self.convValueStruct2Value(serverInfoList.serverInfoList[i].value))
for i in range(serverInfoList.numItems)]
def convServerNameList2List (self, serverNameList):
return [serverNameList.nameList[i].value
for i in range(serverNameList.numItems)]
def convStatusHistoryList2List(self, statHistList):
return [self.convStatusHistoryStruct2List(statHistList.statHistList[i])
for i in range(statHistList.numItems) ]
def convStatusHistoryStruct2List(self, statHist):
return [statHist.timeVal, statHist.user]
def convUserInfoList2dict(self, userInfoList):
return dict(self.convUserInfoList2List(userInfoList))
def convUserInfoList2List(self, userInfoList):
'''takes an ARUserInfoList and returns the following list:
((userName, (license, connectTime, lastAccessTime, defaultNotifier, email)), ...)'''
return [(userInfoList.userList[i].userName, (userInfoList.userList[i].licenseInfo,
userInfoList.userList[i].connectTime,
userInfoList.userList[i].lastAccess,
userInfoList.userList[i].defaultNotifyMech,
userInfoList.userList[i].emailAddr))
for i in range(userInfoList.numItems)]
def convUserLicenseList2list(self, userLicenseList):
return [(userLicenseList.licenseList[i].licenseTag,
userLicenseList.licenseList[i].licenseType,
userLicenseList.licenseList[i].currentLicenseType,
userLicenseList.licenseList[i].licensePool,
userLicenseList.licenseList[i].appLicenseDescriptor,
userLicenseList.licenseList[i].lastAccess)
for i in range(userLicenseList.numItems)]
def convValueStruct2Value(self, obj):
# special handling for unicode
if self.context.localeInfo.charSet.lower() == 'utf-8':
if obj.dataType == cars.AR_DATA_TYPE_CHAR:
return obj.u.charVal.decode('utf-8')
elif obj.dataType == cars.AR_DATA_TYPE_ATTACH:
return (obj.u.attachVal.contents.name.decode('utf-8'),
obj.u.attachVal.contents.origSize,
obj.u.attachVal.contents.compSize)
try:
if obj.dataType in (cars.AR_DATA_TYPE_NULL,
cars.AR_DATA_TYPE_VIEW):
return None
# if obj.dataType == cars.AR_DATA_TYPE_ATTACH:
# return (obj.u.attachVal.contents.name,
# obj.u.attachVal.contents.origSize,
# obj.u.attachVal.contents.compSize)
return eval('obj.%s' % (cars.ARValueStruct._mapping_so_ [obj.dataType]))
except KeyError:
try:
return eval('%s' % (cars.ARValueStruct._mapping_co_ [obj.dataType]))
except KeyError:
raise ARError(None,
'unknown ARValueStruct type: %d!' % obj.dataType,
cars.AR_RETURN_ERROR)
def convValueList2List(self, obj):
return [self.convValueStruct2Value(obj.valueList[i])
for i in range(obj.numItems)]
def convValueListList2List(self, obj):
'''a SQL command executed through ARSystem API returns a ValueListList. Per result line
you get the values of the query. This function returns a pythonic list of lists.'''
return [self.convValueList2List(obj.valueListList[i])
for i in range(obj.numItems)]
def CreateActiveLink (self,
name,
order,
schemaList,
groupList,
executeMask,
controlField = None,
focusField = None,
enable = True,
query = None,
actionList = None,
elseList = None,
helpText = None,
owner = None,
changeDiary = None,
objPropList = None):
'''CreateActiveLink creates a new active link with the indicated name
on the specified server.
CreateActiveLink creates a new active link with the indicated name
on the specified server. The active link is added to the server
immediately and returned to users who request information about
active links.
Input: name (ARNameType)
order (c_uint)
schemaList (ARWorkflowConnectStruct)
groupList (ARInternalIdList)
executeMask (c_uint)
(optional) controlField (ARInternalId, default = None)