| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import requests
- import threading
- from concurrent.futures import ThreadPoolExecutor, as_completed
- from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
- from credentials import Credentials
- class AcumaticaODataClient:
- def __init__(self, base_url, username, password, page_size=1000, max_workers=8):
- self.base_url = self._add_format_and_top(base_url, page_size)
- self.page_size = page_size
- self.session = requests.Session()
- self.session.auth = (username, password)
- self.session.headers.update({
- "Accept": "application/json"
- })
- self.lock = threading.Lock()
- self.max_workers = max_workers
- self.results = []
- def _add_format_and_top(self, url, top):
- # Add or update $format and $top in query string
- parts = list(urlparse(url))
- query = parse_qs(parts[4])
- query['$format'] = ['json']
- query['$top'] = [str(top)]
- parts[4] = urlencode(query, doseq=True)
- return urlunparse(parts)
- def _fetch_initial_links(self):
- """Collect all paginated URLs before multithreaded fetch."""
- next_url = self.base_url
- urls = []
- while next_url:
- print(f"[DISCOVER] {next_url}")
- resp = self.session.get(next_url)
- resp.raise_for_status()
- data = resp.json()
- urls.append(next_url)
- next_url = data.get('@odata.nextLink')
- return urls
- def _fetch_page(self, url):
- try:
- resp = self.session.get(url)
- resp.raise_for_status()
- data = resp.json()
- records = data.get('value', [])
- with self.lock:
- self.results.extend(records)
- print(f"[FETCHED] {len(records)} records from {url}")
- except Exception as e:
- print(f"[ERROR] {url} -> {e}")
- def fetch_all(self):
- page_urls = self._fetch_initial_links()
- with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
- futures = [executor.submit(self._fetch_page, url) for url in page_urls]
- for _ in as_completed(futures):
- pass
- return self.results
- if __name__ == "__main__":
- # 🔧 Replace with your actual OData endpoint
- odata_url = "https://acumatica.conciseit.net/Odata/Project%20UDF%20Example"
-
- creds = Credentials()
- client = AcumaticaODataClient(
- base_url=odata_url,
- username=creds.username,
- password=creds.password,
- page_size=500, # Adjustable page size
- max_workers=6 # Adjustable thread count
- )
- records = client.fetch_all()
- print(f"\n✅ Total records retrieved: {len(records)}\n")
- for i, record in enumerate(records, 1):
- print(f"[{i}] {record}")
|