adss 1.25__tar.gz

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.
adss-1.25/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, the respective contributors, as shown by the AUTHORS file.
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ * Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ * Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ * Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
adss-1.25/PKG-INFO ADDED
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: adss
3
+ Version: 1.25
4
+ Summary: Astronomical Data Smart System
5
+ Author-email: Gustavo Schwarz <gustavo.b.schwarz@gmail.com>
6
+ Project-URL: Homepage, https://github.com/schwarzam/adss
7
+ Classifier: Programming Language :: Python :: 3
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: requests
12
+ Requires-Dist: astropy
13
+ Dynamic: license-file
14
+
15
+ # ADSS
16
+ Astronomical Data Smart System
17
+
18
+ ADSS is a database/server project hosted at CBPF (Brazilian Center for Research in Physics) that provides access to astronomical data from different surveys.
19
+
20
+ This repository provides a set of tools for querying astronomical ADSS services using ADQL. You can perform cone searches, cross-match queries between tables, and even cross-match against user-supplied data. The library supports both synchronous and asynchronous query execution.
21
+
22
+ ## Instalation
23
+
24
+ ```bash
25
+ pip install adss
26
+ ```
27
+
28
+ or
29
+
30
+ ```bash
31
+ git clone https://github.com/schwarzam/adss.git
32
+ cd adss
33
+ pip install .
34
+ ```
35
+
36
+ ## Tutorials
37
+
38
+ We provide a set of tutorials to help you get started with the library:
39
+
40
+ Perform a simple query to retrieve the available tables from the service, print the columns of a table, set the columns and constraints to perform a query and retrieve the data.
41
+ - [Basic API](docs/basic_api.md)
42
+
43
+ Learn the difference between sync and async queries and when to use each one.
44
+ - [Methods of query](docs/sync_async.md)
45
+
46
+ Perform a raw query to the service.
47
+ - [Raw Query](docs/perform_raw_queries.md)
48
+
49
+ Perform a match between two database tables and a match between a database table and a user input table.
50
+ - [Match API](docs/match_api.md)
51
+
52
+ Perform a match between a database table and a user input table.
53
+ - [User Table Input Match](docs/usertable_input_match.md)
54
+
55
+
56
+ ## Contributing
57
+
58
+ We welcome contributions to this project.
adss-1.25/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # ADSS
2
+ Astronomical Data Smart System
3
+
4
+ ADSS is a database/server project hosted at CBPF (Brazilian Center for Research in Physics) that provides access to astronomical data from different surveys.
5
+
6
+ This repository provides a set of tools for querying astronomical ADSS services using ADQL. You can perform cone searches, cross-match queries between tables, and even cross-match against user-supplied data. The library supports both synchronous and asynchronous query execution.
7
+
8
+ ## Instalation
9
+
10
+ ```bash
11
+ pip install adss
12
+ ```
13
+
14
+ or
15
+
16
+ ```bash
17
+ git clone https://github.com/schwarzam/adss.git
18
+ cd adss
19
+ pip install .
20
+ ```
21
+
22
+ ## Tutorials
23
+
24
+ We provide a set of tutorials to help you get started with the library:
25
+
26
+ Perform a simple query to retrieve the available tables from the service, print the columns of a table, set the columns and constraints to perform a query and retrieve the data.
27
+ - [Basic API](docs/basic_api.md)
28
+
29
+ Learn the difference between sync and async queries and when to use each one.
30
+ - [Methods of query](docs/sync_async.md)
31
+
32
+ Perform a raw query to the service.
33
+ - [Raw Query](docs/perform_raw_queries.md)
34
+
35
+ Perform a match between two database tables and a match between a database table and a user input table.
36
+ - [Match API](docs/match_api.md)
37
+
38
+ Perform a match between a database table and a user input table.
39
+ - [User Table Input Match](docs/usertable_input_match.md)
40
+
41
+
42
+ ## Contributing
43
+
44
+ We welcome contributions to this project.
@@ -0,0 +1,29 @@
1
+ """
2
+ Astronomy TAP Client - A Python client for interacting with the Astronomy TAP Service API.
3
+
4
+ This package provides a comprehensive client for working with the Astronomy TAP Service,
5
+ including authentication, query execution, user management, and administrative functions.
6
+ """
7
+
8
+ #__version__ = "0.1.0"
9
+
10
+ from adss.client import ADSSClient
11
+ from adss.exceptions import (
12
+ ADSSClientError, AuthenticationError, PermissionDeniedError,
13
+ ResourceNotFoundError, QueryExecutionError
14
+ )
15
+ from adss.models.user import User, Role
16
+ from adss.models.query import Query, QueryResult
17
+ from adss.models.metadata import Schema, Table, Column
18
+
19
+ from adss.utils import (
20
+ handle_response_errors, parse_datetime, parquet_to_dataframe
21
+ )
22
+
23
+ __all__ = [
24
+ 'ADSSClient',
25
+ 'ADSSClientError', 'AuthenticationError', 'PermissionDeniedError',
26
+ 'ResourceNotFoundError', 'QueryExecutionError',
27
+ 'User', 'Role', 'Query', 'QueryResult', 'Schema', 'Table', 'Column',
28
+ 'handle_response_errors', 'parse_datetime', 'parquet_to_dataframe'
29
+ ]
adss-1.25/adss/auth.py ADDED
@@ -0,0 +1,121 @@
1
+ import requests
2
+ from typing import Dict, Optional, Tuple
3
+
4
+ from adss.exceptions import AuthenticationError
5
+ from adss.utils import handle_response_errors
6
+ from adss.models.user import User
7
+
8
+
9
+ class Auth:
10
+ """
11
+ Handles authentication, token management, and HTTP requests for the TAP client.
12
+ """
13
+
14
+ def __init__(self, base_url: str, verify_ssl: bool = True):
15
+ self.base_url = base_url.rstrip('/')
16
+ self.token: Optional[str] = None
17
+ self.current_user: Optional[User] = None
18
+ self.verify_ssl = verify_ssl
19
+
20
+ def login(self, username: str, password: str, **kwargs) -> Tuple[str, User]:
21
+ """
22
+ Log in with username and password, obtaining an authentication token.
23
+ """
24
+ login_url = f"{self.base_url}/adss/v1/auth/login"
25
+ data = {"username": username, "password": password}
26
+
27
+ try:
28
+ # Use our own request() method here
29
+ response = self.request(
30
+ method="POST",
31
+ url=login_url,
32
+ auth_required=False,
33
+ data=data,
34
+ **kwargs
35
+ )
36
+ handle_response_errors(response)
37
+
38
+ token_data = response.json()
39
+ self.token = token_data.get("access_token")
40
+ if not self.token:
41
+ raise AuthenticationError("Login succeeded but no token returned")
42
+
43
+ # Now fetch user info (this will use auth_required=True internally)
44
+ self.current_user = self._get_current_user(**kwargs)
45
+ return self.token, self.current_user
46
+
47
+ except requests.RequestException as e:
48
+ raise AuthenticationError(f"Login failed: {e}")
49
+
50
+ def logout(self) -> None:
51
+ self.token = None
52
+ self.current_user = None
53
+
54
+ def is_authenticated(self) -> bool:
55
+ return self.token is not None
56
+
57
+ def _get_current_user(self, **kwargs) -> User:
58
+ """
59
+ Fetch the current user's information using the stored token.
60
+ """
61
+ if not self.token:
62
+ raise AuthenticationError("Not authenticated")
63
+
64
+ me_url = f"{self.base_url}/adss/v1/users/me"
65
+ auth_headers = self._get_auth_headers()
66
+
67
+ try:
68
+ # Again, use request() so SSL and auth headers are applied consistently
69
+ response = self.request(
70
+ method="GET",
71
+ url=me_url,
72
+ headers=auth_headers,
73
+ auth_required=True,
74
+ **kwargs
75
+ )
76
+ handle_response_errors(response)
77
+
78
+ user_data = response.json()
79
+ return User.from_dict(user_data)
80
+
81
+ except requests.RequestException as e:
82
+ raise AuthenticationError(f"Failed to get user info: {e}")
83
+
84
+ def _get_auth_headers(self) -> Dict[str, str]:
85
+ headers = {"Accept": "application/json"}
86
+ if self.token:
87
+ headers["Authorization"] = f"Bearer {self.token}"
88
+ return headers
89
+
90
+ def request(
91
+ self,
92
+ method: str,
93
+ url: str,
94
+ headers: Optional[Dict[str, str]] = None,
95
+ auth_required: bool = False,
96
+ **kwargs
97
+ ) -> requests.Response:
98
+ """
99
+ Make an HTTP request with automatic base_url prefix, SSL config, and auth headers.
100
+ """
101
+ if auth_required and not self.is_authenticated():
102
+ raise AuthenticationError("Authentication required for this request")
103
+
104
+ # Prepend base_url if needed
105
+ if not url.startswith(('http://', 'https://')):
106
+ url = f"{self.base_url}/{url.lstrip('/')}"
107
+
108
+ # Merge headers
109
+ final_headers = self._get_auth_headers()
110
+ if headers:
111
+ final_headers.update(headers)
112
+
113
+ # Apply verify_ssl unless overridden
114
+ if 'verify' not in kwargs:
115
+ kwargs['verify'] = self.verify_ssl
116
+
117
+ return requests.request(method, url, headers=final_headers, **kwargs)
118
+
119
+ def refresh_user_info(self, **kwargs) -> User:
120
+ self.current_user = self._get_current_user(**kwargs)
121
+ return self.current_user