a2p2 0.7.4__py3-none-any.whl → 0.7.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
a2p2/jmmc/catalogs.py CHANGED
@@ -4,6 +4,9 @@ __all__ = []
4
4
 
5
5
  import logging
6
6
 
7
+ import pyvo
8
+ import astropy.table.table
9
+
7
10
  from ..client import A2P2ClientPreferences
8
11
 
9
12
  from .utils import JmmcAPI
@@ -17,20 +20,36 @@ class Catalog():
17
20
  Credential can be explicitly given for method that require an authentication, else:
18
21
  - a2p2 preferences login will be used if present (see a2p2 -c)
19
22
  - or uses .netrc file
23
+ A where clause can be added to limit on rows of interest (adql syntax)
24
+ A joins list of dictionnary can be provided to combine this catalog to other ones ( format is: [{"name":"cattojoin","id":"commonkey"},...] )
20
25
  """
21
26
 
22
- def __init__(self, catalogName, username=None, password=None, prod=False, apiUrl=None):
27
+ def __init__(self, catalogName, username=None, password=None, prod=False, apiUrl=None, tapUrl=None, where=None, joins=None):
23
28
  self.catalogName = catalogName
29
+ self.where = where
30
+ self.joins = joins
24
31
  self.prod = prod
32
+ self.colDelimiterName = "coldelimiter___"
25
33
 
26
34
  # Manage prod & preprod or user provided access points
27
35
  if apiUrl:
28
36
  self.apiUrl = apiUrl # trust given url as catalogAPI if value is provided
29
- elif self.prod:
30
- self.apiUrl = "https://oidb.jmmc.fr/restxq/catalogs"
31
- else:
32
- self.apiUrl = "https://oidb-beta.jmmc.fr/restxq/catalogs"
33
-
37
+ if tapUrl:
38
+ self.tapUrl = tapUrl # trust given url as TAP server if value is provided
39
+
40
+ if not(apiUrl):
41
+ if self.prod:
42
+ self.apiUrl = "https://oidb.jmmc.fr/restxq/catalogs"
43
+ else:
44
+ self.apiUrl = "https://oidb-beta.jmmc.fr/restxq/catalogs"
45
+
46
+ if not(tapUrl):
47
+ if self.prod:
48
+ self.tapUrl = "https://tap.jmmc.fr/vollt/tap"
49
+ else:
50
+ self.tapUrl = "https://tap-preprod.jmmc.fr/vollt/tap"
51
+
52
+ self.tap = pyvo.dal.TAPService(self.tapUrl)
34
53
  self.api = JmmcAPI(self.apiUrl, username, password)
35
54
 
36
55
  logger.info(f"Create catalog wrapper to access '{catalogName}' ({PRODLABEL[self.prod]} API at {self.api.rootURL})")
@@ -40,7 +59,7 @@ class Catalog():
40
59
  return self.api._get("")
41
60
 
42
61
  def metadata(self):
43
- """ Get catalog metadata """
62
+ """ Get catalog metadata"""
44
63
  return self.api._get(f"/meta/{self.catalogName}")
45
64
 
46
65
  def pis(self):
@@ -66,12 +85,82 @@ class Catalog():
66
85
  return pi["name"]
67
86
 
68
87
  def getRow(self, id):
69
- """ Get a single catalog record for the given id.
88
+ """ Get a single catalog record for the given id on the main catalog.
70
89
 
71
90
  usage: cat.getRow(42)
72
91
  """
73
92
  return self.api._get(f"/{self.catalogName}/{id}")
74
93
 
94
+ def getDataFrame(self):
95
+ """ Get a pandas DataFrame from the main catalog joined the other if provided in constructor.
96
+
97
+ usage: cat.getDataFrame()
98
+ """
99
+
100
+ return self.getTable().to_pandas()
101
+
102
+ def getTable(self, maxrec=10000):
103
+ """ Get an astropy table from the main catalog joined the other if provided in constructor.
104
+
105
+ usage: cat.getTable()
106
+ """
107
+ # using SELECT TOP N below to workarround astroquery.utils.tap BUG
108
+
109
+ clauses = []
110
+ if self.joins :
111
+ joinedCatalogNames = []
112
+ for join in self.joins:
113
+ joinedCatalogNames.append(join["name"] + ".*")
114
+
115
+ # colDelimiterName is added so we can keep the mainCatalog colnames for later updates (using rowsToDict)
116
+ clauses.append(f"SELECT TOP {maxrec} {self.catalogName}.*, '' as {self.colDelimiterName}, {', '.join(joinedCatalogNames)} FROM {self.catalogName}" )
117
+
118
+ for join in self.joins:
119
+ if "catalogKey" in join.keys():
120
+ catalogKey=join["catalogKey"]
121
+ else:
122
+ # we could use the (cached) metadata key, but this would add a additional remote call.A2P2ClientPreferences
123
+ # let's try with this convention using the same key name
124
+ catalogKey=join["id"]
125
+ name=join["name"]
126
+ id=join["id"]
127
+ # LEFT JOIN may be an option provided by join key ?
128
+ clauses.append (f" LEFT JOIN {name} ON {self.catalogName}.{catalogKey} = {name}.{id}")
129
+
130
+ if self.where:
131
+ clauses.append(f" WHERE {self.catalogName}.{self.where}")
132
+ else:
133
+ clauses.append(f"SELECT TOP {maxrec} * FROM {self.catalogName}")
134
+ if self.where:
135
+ clauses.append(f" WHERE {self.where}")
136
+
137
+ query = " ".join(clauses)
138
+ logger.info(f"Querying remote catalog : {query}")
139
+ return self.tap.search(query,maxrec=maxrec).to_table()
140
+
141
+ def tableToDict(self, table):
142
+ """ Convert table (astropy.table or row) to a list of dict so we can modify content and update remote catalog using updateRows().
143
+
144
+ usage: cat.tableToDict(table)
145
+ """
146
+ colnames = table.colnames
147
+ if "coldelimiter___" in colnames:
148
+ colnames = colnames[0:colnames.index("coldelimiter___")]
149
+ dicts=[]
150
+ # handle single row case
151
+ table = table if isinstance(table, astropy.table.table.Table ) else [table]
152
+ for row in table:
153
+ dict = {}
154
+ for colname in colnames:
155
+ v=row[colname]
156
+ if isinstance(v,str):
157
+ dict[colname] = v
158
+ else:
159
+ # avoid np.numeric type to make it json serializable
160
+ dict[colname] = v.item()
161
+ dicts.append(dict)
162
+ return dicts
163
+
75
164
  def updateRow(self, id, values):
76
165
  """ Update record identified by given id and associated values.
77
166
 
@@ -87,6 +176,7 @@ class Catalog():
87
176
  """
88
177
 
89
178
  # We may check befere sending payload that we always provide an id for every record
179
+ # What is the behaviour if we provide various data assosiated to the same id ?
90
180
  return self.api._put(f"/{self.catalogName}", values)
91
181
 
92
182
  def addRows(self, values):
@@ -97,6 +187,7 @@ class Catalog():
97
187
  """
98
188
  return self.api._post(f"/{self.catalogName}", json=values)
99
189
 
190
+
100
191
  def getDelegations(self, pi=None):
101
192
  """ Get -all- delegations.
102
193
  A specific pi parameter may be given but requires admin priviledges. Else use current piname will be used by remote service.
a2p2/version.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.7.4"
1
+ __version__ = "0.7.6"
2
2
 
3
3
  __release_notes__ = {
4
4
  # "0.1.6": {
@@ -23,7 +23,15 @@ __release_notes__ = {
23
23
  # "Try to read OB in P2 and send them back to Aspro2 as a new obs",
24
24
  # ],
25
25
 
26
- "0.7.4": {
26
+ "0.7.6": {
27
+ "A2P2": [
28
+ "add getDataFrame() to a2p2.jmmc.Catalog to provide remote data with pandas format",
29
+ ],
30
+ },"0.7.5": {
31
+ "A2P2": [
32
+ "Add support for join and filter in a2p2.jmmc.Catalog wrapper",
33
+ ],
34
+ },"0.7.4": {
27
35
  "A2P2": [
28
36
  "Use pyproject.toml for python installation",
29
37
  ],"VLTI": [
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: a2p2
3
- Version: 0.7.4
3
+ Version: 0.7.6
4
4
  Author-email: JMMC Tech Group <jmmc-tech-group@jmmc.fr>
5
5
  License: OSI Approved :: GNU General Public License v3 (GPLv3)
6
6
  Project-URL: Homepage, https://www.jmmc.fr/a2p2
@@ -15,8 +15,10 @@ Requires-Python: >=3
15
15
  Description-Content-Type: text/x-rst
16
16
  License-File: LICENSE
17
17
  Requires-Dist: appdirs
18
- Requires-Dist: astropy >=5.2.2
18
+ Requires-Dist: astropy>=5.2.2
19
+ Requires-Dist: pyvo>=1.6.1
19
20
  Requires-Dist: p2api
21
+ Dynamic: license-file
20
22
 
21
23
  a2p2 |A2P2Badge|
22
24
  ================
@@ -7,12 +7,12 @@ a2p2/instrument.py,sha256=JI1i8vsGu1ku_3i7my278b8y8vL5Z-SF3V8XkHPSs48,732
7
7
  a2p2/ob.py,sha256=lcSm5eXv79K6cjp0VxvxD4sSlsBTKHGbmT85XEx74lY,6268
8
8
  a2p2/samp.py,sha256=DN20lWszkuuneR1BV1MBLEyoGyN8tZWvOeC5rEVLICo,3438
9
9
  a2p2/utils.py,sha256=QEA9cpc2TaqXDa4yqrFiGkCl__1wV8--rVw_A-p_HM0,23833
10
- a2p2/version.py,sha256=_N6fsRiq6jonys8LHzHhDDHK23gABI2vSSLu4quaQDM,12353
10
+ a2p2/version.py,sha256=SBcM00GM4AaYrNLt35Q9OmYC5RG20coTbavUQYpboB0,12614
11
11
  a2p2/chara/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  a2p2/chara/facility.py,sha256=otv0UVQVYD7dE_ENojjatjld5owgM9qRm7vsAc0jyqQ,2754
13
13
  a2p2/chara/gui.py,sha256=4O8u-g-UJSeqEV9CUPNflVNWIsmH0b_xf8c9huxAivs,5119
14
14
  a2p2/jmmc/__init__.py,sha256=Yx8Ae77UQA_aLMzhKgWym4m2fbMR_4m77TGfaXy6I4A,187
15
- a2p2/jmmc/catalogs.py,sha256=8hf8nUVfAdgROpPGzP-aD4Haulp7lWGCSHod5ZhmJNM,4801
15
+ a2p2/jmmc/catalogs.py,sha256=bEmG_gkte5uGeKcbsnz6BTMYLnWB4HFpp_XmgSxcwyg,8624
16
16
  a2p2/jmmc/generated_models.py,sha256=69fmPfkCMBc0GyDeHp1rs0vkoPqOE4j0egMBWX5mB1U,11823
17
17
  a2p2/jmmc/models.py,sha256=ikI8Dk-9ThkG1uHtoPJwB43tPF_YZj8M5tftIcJio7s,3776
18
18
  a2p2/jmmc/services.py,sha256=kcRaRnR4COKijF5izDqqNHjKyU1j2H8PEPvbDsBUFcw,312
@@ -31,9 +31,9 @@ a2p2/vlti/conf/MATISSE_ditTable.json,sha256=2RQXb9UL1_VlcAAGoxqpe3nTrRfO4gyOX_IG
31
31
  a2p2/vlti/conf/MATISSE_rangeTable.json,sha256=_j5m-EOh4bbfwdaANdh23yjgNef95AUku_uNujr9BDc,5770
32
32
  a2p2/vlti/conf/PIONIER_ditTable.json,sha256=BKK7nF0nE_LOP44l_fAvAnpG8oOq5p9srcdTNQ2udKo,857
33
33
  a2p2/vlti/conf/PIONIER_rangeTable.json,sha256=71Ycm2h-uBUVSAWy6lTpaBDOYwKKL5MuZH6F5ESHOI0,2113
34
- a2p2-0.7.4.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
35
- a2p2-0.7.4.dist-info/METADATA,sha256=igT2BELh2nCRDMYuJO5C_tgKxWS9LJWz1eBgKyHHUDA,4140
36
- a2p2-0.7.4.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
37
- a2p2-0.7.4.dist-info/entry_points.txt,sha256=5Pq7faxs04hSEtjpqtBAlHw3cGUpvTmBugnS5PzgJMY,44
38
- a2p2-0.7.4.dist-info/top_level.txt,sha256=lLDb6xGRyHYSbrO0EUx8vNEzTiCDtPe2z7PSbqGY4kE,5
39
- a2p2-0.7.4.dist-info/RECORD,,
34
+ a2p2-0.7.6.dist-info/licenses/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
35
+ a2p2-0.7.6.dist-info/METADATA,sha256=7JQoo7_dNUObegDtEqWxnsdSkFIOZOeTziMDx7hKyTY,4188
36
+ a2p2-0.7.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
37
+ a2p2-0.7.6.dist-info/entry_points.txt,sha256=5Pq7faxs04hSEtjpqtBAlHw3cGUpvTmBugnS5PzgJMY,44
38
+ a2p2-0.7.6.dist-info/top_level.txt,sha256=lLDb6xGRyHYSbrO0EUx8vNEzTiCDtPe2z7PSbqGY4kE,5
39
+ a2p2-0.7.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5