### Install and Verify ChemPrice Source: https://context7.com/bsaliou/chemprice/llms.txt Install the ChemPrice library using pip and verify its installation and version. You can also install pytest to run the library's test suite. ```bash pip install chemprice # Verify installation pip show chemprice # Name: chemprice # Version: 1.1.0 # ... # Run the test suite pip install pytest pytest chemprice/tests/ ``` -------------------------------- ### Install ChemPrice using pip Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/installation.md Use this command to install the latest official release of ChemPrice from PyPi. ```bash ~$ pip install chemprice ``` -------------------------------- ### Verify ChemPrice Installation Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/installation.md Check if ChemPrice is installed by displaying its package information. If the package is not found, it indicates an issue with the installation or system path. ```bash ~$ pip show chemprice Name: chemprice ... ``` ```bash WARNING: Package(s) not found: chemprice ``` -------------------------------- ### Run ChemPrice Tests Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/installation.md After successful installation, you can run the package's tests using pytest to ensure everything is functioning correctly. Ensure pytest is installed first. ```bash ~$ pip install pytest ~$ pytest chemprice/tests/ ``` -------------------------------- ### Install ChemPrice using pip Source: https://github.com/bsaliou/chemprice/blob/main/README.md Install the ChemPrice package using pip. This is the primary method for adding the library to your Python environment. ```bash pip install chemprice ``` -------------------------------- ### Full End-to-End Workflow for ChemPrice Source: https://context7.com/bsaliou/chemprice/llms.txt Demonstrates a complete workflow from installation to exporting results for a multi-compound library search across all three integrators (Molport, ChemSpace, MCule). ```python from chemprice import PriceCollector import pandas as pd # 1. Instantiate the collector pc = PriceCollector() # 2. Configure credentials for all three integrators pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setChemSpaceApiKey("cs-your-chemspace-key") pc.setMCuleApiKey("your-mcule-token") # 3. Verify credential status (no network call) pc.status() # Status: Molport : creditential is set. # Status: Chemspace : creditential is set. # Status: MCule : creditential is set. # 4. Validate credentials against live APIs is_valid = pc.check() if not is_valid: raise RuntimeError("No valid credentials found. Aborting.") # 5. Define compound library in SMILES notation smiles_list = [ "CC(=O)NC1=CC=C(C=C1)O", # Paracetamol "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", # Ibuprofen "O=C(C)Oc1ccccc1C(=O)O", # Aspirin "c1ccc2c(c1)cc1ccc3cccc4ccc2c1c34", # Pyrene ] # 6. Collect all available prices across all integrators all_prices = pc.collect(smiles_list) print(f"Found {len(all_prices)} price entries for {all_prices['Input SMILES'].nunique()} molecules") # 7. Filter for best price-per-unit (best USD/g, USD/mol, USD/l per molecule) best = pc.selectBest(all_prices) print(f"Best prices table has {len(best)} rows") # 8. Export both tables all_prices.to_csv("all_prices.csv", index=False) best.to_csv("best_prices.csv", index=False) ``` -------------------------------- ### Instantiate PriceCollector Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Create an instance of the PriceCollector class to connect to integrators and initiate price searches. Ensure the chemprice library is installed. ```python3 from chemprice import PriceCollector pc = PriceCollector() ``` -------------------------------- ### Install ChemPrice in Editable Mode Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/development.md Install ChemPrice in editable mode using pip. This allows code changes to be reflected without reinstallation. Navigate to the cloned repository's root directory first. ```bash ~//ChemPrice$ pip install -e . ``` -------------------------------- ### Initialize PriceCollector and Define Molecules Source: https://context7.com/bsaliou/chemprice/llms.txt Instantiate the PriceCollector class and define a list of molecules to search for using their SMILES notation. This is the starting point for collecting pricing data. ```python from chemprice import PriceCollector pc = PriceCollector() # Define molecules to search using SMILES notation smiles_list = [ "CC(=O)NC1=CC=C(C=C1)O", # Paracetamol (Acetaminophen) "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", # Ibuprofen "O=C(C)Oc1ccccc1C(=O)O", # Aspirin ] ``` -------------------------------- ### Set Molport API Key Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Configure the Molport API key for the PriceCollector instance. Replace the example key with your actual Molport API key obtained from their platform. ```python3 pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") ``` -------------------------------- ### Get Cheapest Gram-Price per Molecule Source: https://context7.com/bsaliou/chemprice/llms.txt Sorts compounds by USD/g and prints relevant pricing information. Requires the 'best' DataFrame to be pre-populated and have a 'USD/g' column. ```python gram_prices = best.dropna(subset=["USD/g"]) print(gram_prices[["Input SMILES", "Supplier Name", "Amount", "Measure", "Price_USD", "USD/g"]]) ``` -------------------------------- ### Get MCule Molecule IDs and Build Packages Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Use this snippet to collect molecule IDs and build packages from a list of SMILES strings using the MCule API. Ensure 'smiles_list' is pre-defined and the 'mcule_get_ids' and 'build_packages' functions are available. ```python print(f"Collecting ID's for given {len(smiles_list)} SMILES from MCule...") df_molecule_ids = mcule_get_ids(smiles_list) smiles_exists = df_molecule_ids['Input SMILES'].nunique() package_id = build_packages(df_molecule_ids) print(f"Total: {smiles_exists} molecules and {len(df_molecule_ids)} conformers are found in MCule.\n") ``` -------------------------------- ### Get Chemspace API Token Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Retrieves an authentication token from the Chemspace API. Requires the chemspace_api_key to be set. Returns the access token or None if the request fails. ```python def chemspace_get_token(): url = "https://api.chem-space.com/auth/token" headers = { "Authorization": f"Bearer {chemspace_api_key}" } response = requests.get(url, headers=headers) # Check if the request was successful (status code 200) if response.status_code == 200: # Retrieve the access token from the response access_token = response.json()["access_token"] return access_token else: # The request failed, print the status code and response content print("The request failed with the status code:", response.status_code) return None ``` -------------------------------- ### Molport Get IDs Function Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Collects Molport IDs from a list of SMILES strings for subsequent searches. Requires Molport API credentials. ```python # Collects molport ids from the given list smiles (we will use this ids to search) def molport_get_ids(smiles_list): # List to store t he IDs and SMILES id_smiles_list = [] for smiles in tqdm(smiles_list): # Data to send to the Molport server if molport_username != None: payload = { "User Name": molport_username, "Authentication Code": molport_authcode, "Structure": smiles, "Search Type": 5, # Perfect research "Maximum Search Time": 60000, "Maximum Result Count": 1000, "Chemical Similarity Index": 0.9 } # Send the request to the Molport server r = requests.post('https://api.molport.com/api/chemical-search/search', json=payload) # Get the Python dictionary from the server response response = r.json() if response["Result"]["Status"] == 1: molecules = response["Data"]["Molecules"] # Iterate over the molecules and their information for molecule in molecules: molecule_id = molecule["Id"] id_smiles_list.append((molecule_id, smiles)) df = pd.DataFrame(id_smiles_list, columns=["ID", "Input SMILES"]) return df ``` -------------------------------- ### Initialize SMILES List Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Create a list of molecules in SMILES notation to be searched by ChemPrice. This is the first step before collecting pricing data. ```python3 smiles_list = ["CC(=O)NC1=CC=C(C=C1)O", "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", "O=C(C)Oc1ccccc1C(=O)O"] ``` -------------------------------- ### Initialize PriceCollector Source: https://github.com/bsaliou/chemprice/blob/main/README.md Create a list of molecules in SMILES notation and then instantiate the PriceCollector class to begin interacting with chemical pricing platforms. ```python smiles_list = ["CC(=O)NC1=CC=C(C=C1)O", "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", "O=C(C)Oc1ccccc1C(=O)O"] ``` ```python from chemiprice import PriceCollector pc = PriceCollector() ``` -------------------------------- ### Select Best Prices Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Process the collected price data to identify the best price-to-quantity ratio for each molecule, considering different units of measurement (moles, grams, liters). ```python3 pc.selectBest(all_prices) ``` -------------------------------- ### Build MCule Quote Packages Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Constructs quote packages for a list of chemical IDs across various predefined amounts. Requires `requests`, `tqdm`, and a `mcule_token` to be set. ```python def build_packages(df): if df.empty: return # Define the API URL url = "https://mcule.com/api/v1/iquote-queries/" # Headers for authorization headers = { "Authorization": "Token " + mcule_token, "Content-Type": "application/json", "Accept": "application/json, */*", "Accept-Encoding": "gzip, deflate" } package_ids = [] # List to store package IDs amount_list = ["1", "5", "10", "100", "1000", "10000", "100000", "1000000"] for index,amount in tqdm(enumerate(amount_list),total=len(amount_list)): # Request body in JSON format data = { "amount": amount, "customer_first_name": "John", "customer_last_name": "Doe", "delivery_country": "US", "mcule_ids": df["ID"].tolist(), "min_amount": None } # Send the POST request response = requests.post(url, json=data, headers=headers) # Check the response if response.status_code == 201: # Status code 201 for Created results = response.json() package_id = results["id"] package_ids.append(package_id) # Add package ID to the list else: print("POST request failed for amount:", amount) print("Response code:", response.status_code) print(response.text) return package_ids ``` -------------------------------- ### Run Unit Tests with Pytest Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/development.md Execute the unit tests for ChemPrice using the pytest command. Ensure you are in the root directory of the cloned repository. ```bash ~$ pytest chemprice/tests/ ``` -------------------------------- ### Collect Pricing Data from MCule Quotes Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Iterates through MCule quote package IDs, checks their status, and collects detailed pricing and product information. Requires `pandas`, `requests`, `tqdm`, `time`, and a `mcule_token`. The `get_quotes` helper function is also used. ```python from pandas.core.generic import DataFrameRenderer # Function to get quotes def get_quotes(quote): for quote_data in quote.get('group', {}).get('quotes', []): quote_id = quote_data['id'] headers = { 'Authorization': f'Token {mcule_token}', 'Content-Type': 'application/json', } url = f'https://mcule.com/api/v1/iquotes/{quote_id}/' response = requests.get(url, headers=headers) yield response.json() # Function to collect prices and data from MCule API def mcule_collect_prices(package_ids, check_freq=0.5): data = [] if package_ids is None: # Create a DataFrame with collected data df = pd.DataFrame(data, columns=["Source", "ID", "Supplier Name", "SMILES", "Purity", "Price_USD", "Amount", "Measure"]) return df # Define headers for authorization headers = { 'Authorization': f'Token {mcule_token}', 'Content-Type': 'application/json', } for index, package_id in tqdm(enumerate(package_ids),total=len(package_ids)): # Construct the URL for the specific quote request url = f'https://mcule.com/api/v1/iquote-queries/{package_id}/' # Function to check the status of the quote request def check_status(): response_package = requests.get(url, headers=headers).json() status = response_package['state'] if status == 40: return None elif status == 30 and response_package['group']: return response_package elif status == 30 and not response_package['group']: return None else: return 1 response_package = check_status() while response_package == 1: time.sleep(check_freq) response_package = check_status() if response_package is None: continue for quote in get_quotes(response_package): # Extract values from each product item in the quote product_items = quote.get('items', []) for item in product_items: source = "MCule" mcule_id = item.get('structure_origin_mcule_id') product_supplier_name = item.get('product_supplier_name') smiles = item.get('product_smiles') purity = item.get('product_purity') price = item.get('product_price') amount = item.get('amount') measure = "mg" data.append((source, mcule_id, product_supplier_name, smiles, purity, price, amount, measure)) # Create a DataFrame with collected data df = pd.DataFrame(data, columns=["Source", "ID", "Supplier Name", "SMILES", "Purity", "Price_USD", "Amount", "Measure"]) return df ``` -------------------------------- ### Clone ChemPrice Repository (HTTPS) Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/development.md Clone the ChemPrice repository from GitHub using HTTPS. Replace `` with your GitHub username. ```bash ~$ git clone https://github.com//ChemPrice.git ``` -------------------------------- ### Clone ChemPrice Repository (SSH) Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/development.md Clone the ChemPrice repository from GitHub using SSH. Replace `` with your GitHub username. ```bash ~$ git clone git@github.com:/ChemPrice.git ``` -------------------------------- ### Collect and Add MCule Prices Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Collects prices from MCule using package IDs and then merges this data with existing results using the add_input_smiles_columns function. ```python mcule_prices = mcule_collect_prices(package_ids) mcule_prices = add_input_smiles_columns(result_df, mcule_prices) mcule_prices ``` -------------------------------- ### status Source: https://context7.com/bsaliou/chemprice/llms.txt Prints a summary of the currently set credentials for each integrator on the PriceCollector instance without making network calls. ```APIDOC ## status — Check Credential Status Prints a human-readable summary of which credentials are currently set on the `PriceCollector` instance without making any network calls. Useful for quickly confirming which integrators are configured before running a search. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setMolportUsername("john.spade") pc.setMolportPassword("fasdga34a3") pc.setChemSpaceApiKey("cs-your-api-key-here") # MCule not configured pc.status() # Status: Molport : both creditentials are set. # Status: Chemspace : creditential is set. # Status: MCule : no credential is set. ``` ``` -------------------------------- ### Set ChemSpace and MCule API Keys Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Configure API keys for ChemSpace and MCule. These functions are used similarly to setting the Molport API key, but require specific keys for each platform. ```python3 pc.setChemSpaceApiKey() pc.setMCuleApiKey() ``` -------------------------------- ### Collect All Prices Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Execute the price search for the provided list of SMILES. This method gathers all available pricing information from the configured integrators. ```python3 all_prices = pc.collect(smiles_list) ``` -------------------------------- ### Set MCule API Token Source: https://context7.com/bsaliou/chemprice/llms.txt Set the MCule API token for authentication. MCule requires only an API token. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMCuleApiKey("your-mcule-token-here") ``` -------------------------------- ### Filter for Best Price-per-Unit with selectBest Source: https://context7.com/bsaliou/chemprice/llms.txt Filters a pricing DataFrame to find the lowest USD-per-unit ratio for each molecule, considering grams, moles, and liters separately. It adds normalized 'USD/g', 'USD/mol', and 'USD/l' columns. Returns an empty DataFrame if the input is empty. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.check() smiles_list = [ "CC(=O)NC1=CC=C(C=C1)O", "O=C(C)Oc1ccccc1C(=O)O", ] all_prices = pc.collect(smiles_list) best_prices = pc.selectBest(all_prices) print(best_prices) # Input SMILES Source Supplier Name Purity Amount Measure Price_USD USD/g USD/mol # CC(=O)NC1=CC=C(C=C1)O Molport Cayman Europe >=98 500 g 407.1 0.22 # O=C(C)Oc1ccccc1C(=O)O Molport Cayman Europe >=90 500 g 112.8 0.1606 # O=C(C)Oc1ccccc1C(=O)O Molport Life Chemicals Inc. >90 20 micromol 50.0 3.95e+06 # Export results to CSV best_prices.to_csv("best_prices.csv", index=False) # Filter best prices for a specific molecule acetaminophen = best_prices[best_prices["Input SMILES"] == "CC(=O)NC1=CC=C(C=C1)O"] print(acetaminophen[["Supplier Name", "Amount", "Measure", "Price_USD", "USD/g"]]) ``` -------------------------------- ### Process MCule Prices and Merge Data Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb This snippet focuses on collecting prices from MCule, adding SMILES columns, merging with other vendor data, standardizing units, and filtering for the best prices. It assumes MCule data collection has already occurred. ```python print(f"Collecting Prices for given {len(smiles_list)} IDs from MCule...") mcule_prices = mcule_collect_prices(package_id) mcule_prices = add_input_smiles_columns(df_molecule_ids, mcule_prices) smiles_with_price = mcule_prices.loc[mcule_prices['Price_USD'].notnull(), 'Input SMILES'].nunique() print(f"\nTotal: {len(mcule_prices)} prices for {smiles_with_price} molecules are found in MCule.\n") print(f"Merging Results from Molport, ChemSpace and MCule...") merged_df = merge_dataframes([molport_prices, chemspace_prices, mcule_prices]) unique_smiles_count_merged = merged_df['Input SMILES'].nunique() smiles_with_price_merged = len(merged_df.loc[merged_df['Price_USD'].notnull(), 'Input SMILES']) print(f"Total: {smiles_with_price_merged} prices for {unique_smiles_count_merged} molecules are exist in the Merged file.\n") print(f"Standardazing units...") standardized_df = add_standardized_columns(merged_df) print(f"File saved: standardized_merged_prices.csv\n") print(f"Selecting best prices...") best_price_df = filter_csv_by_min_price(standardized_df) total_unique_smiles_best = best_price_df['Input SMILES'].nunique() print(f"Total: {len(best_price_df)} Best prices for {total_unique_smiles_best} molecules.") print(f"File saved: best_prices.csv\n") print(f"Vendor price collection is successfully done!") time_end = time.perf_counter() print(f"Total time: {time_end - time_start:0.4f} seconds") ``` } ] } ] } ``` -------------------------------- ### Execute MCule ID Retrieval and Package Building Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb This snippet shows how to first retrieve chemical IDs using `mcule_get_ids` and then use the resulting DataFrame to build quote packages via the `build_packages` function. Assumes `smiles_list` is defined and `mcule_get_ids` is available. ```python result_df = mcule_get_ids(smiles_list) print(result_df) package_ids = build_packages(result_df) print(package_ids) ``` -------------------------------- ### Collect Vendor Prices and Merge Data Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb This function orchestrates the collection of prices from specified vendors (Molport, ChemSpace, MCule). It handles ID collection, price fetching, merging, standardization, and filtering for best prices. Ensure vendor credentials are correctly configured. ```python def collect_vendors(smiles_list, ChemSpace=True, Molport=True, MCule=True): time_start = time.perf_counter() # List of selected suppliers selected_providers = [] if Molport: # Get the molecule IDs and print count MolPort print(f"Collecting ID's for given {len(smiles_list)} SMILES from MolPort...") df_molecule_ids = molport_get_ids(smiles_list) smiles_exists = df_molecule_ids['Input SMILES'].nunique() print(f"Total: {smiles_exists} molecules and {len(df_molecule_ids)} conformers are found in MolPort.\n") # Get the prices and print count from MolPort print(f"Collecting Prices for given {len(smiles_list)} IDs from MolPort...") molport_prices=molport_collect_prices(df_molecule_ids) smiles_with_price = molport_prices.loc[molport_prices['Price_USD'].notnull(), 'Input SMILES'].nunique() print(f"Total: {len(molport_prices)} prices for {smiles_with_price} molecules are found in MolPort.\n") selected_providers.append(("Molport", molport_prices)) if ChemSpace: # Get the prices and print count from ChemSpace print(f"Collecting Prices for given {len(smiles_list)} SMILES from ChemSpace...") chemspace_prices=chemspace_collect_prices(smiles_list) unique_smiles_count = chemspace_prices['Input SMILES'].nunique() smiles_with_price_cs = len(chemspace_prices[chemspace_prices['Price_USD'].notnull()]) print(f"Total: {smiles_with_price_cs} prices for {unique_smiles_count} molecules are found in ChemSpace.\n") selected_providers.append(("ChemSpace", chemspace_prices)) if MCule: # Get the molecule IDs and print count MolPort print(f"Collecting ID's for given {len(smiles_list)} SMILES from MCule...") df_molecule_ids = mcule_get_ids(smiles_list) smiles_exists = df_molecule_ids['Input SMILES'].nunique() package_id = build_packages(df_molecule_ids) print(f"Total: {smiles_exists} molecules and {len(df_molecule_ids)} conformers are found in MCule.\n") # Get the prices and print count from MCule print(f"Collecting Prices for given {len(smiles_list)} IDs from MCule...") mcule_prices = mcule_collect_prices(package_id) mcule_prices = add_input_smiles_columns(df_molecule_ids, mcule_prices) smiles_with_price = mcule_prices.loc[mcule_prices['Price_USD'].notnull(), 'Input SMILES'].nunique() print(f"Total: {len(mcule_prices)} prices for {smiles_with_price} molecules are found in MCule.\n") selected_providers.append(("MCule", mcule_prices)) if selected_providers: name_providers = [row[0] for row in selected_providers] if len(name_providers) >= 2: all_providers = ", ".join(name_providers[:-1]) + " and " + name_providers[-1] else: all_providers = name_providers[0] print(f"Merging Results from {all_providers}...") merged_df = merge_dataframes([row[1] for row in selected_providers]) unique_smiles_count_merged = merged_df['Input SMILES'].nunique() smiles_with_price_merged = len(merged_df.loc[merged_df['Price_USD'].notnull(), 'Input SMILES']) print(f"Total: {smiles_with_price_merged} prices for {unique_smiles_count_merged} molecules exist in the Merged file.\n") else: print(f"The credentials are missing or incorrect. You need to set credential for at least one integrator.") return pd.DataFrame([]) ``` -------------------------------- ### Collect Vendor Prices Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Initiates the collection of vendor prices, with options to include data from ChemSpace, Molport, and MCule. Ensure 'smiles_list' is defined before calling. ```python collect_vendors(smiles_list, ChemSpace=True, Molport=True, MCule=True) ``` -------------------------------- ### Import Libraries Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Imports necessary libraries for data manipulation, API requests, and progress tracking. ```python import pandas as pd import requests import time import re from tqdm import tqdm ``` -------------------------------- ### Collect Pricing Data with PriceCollector Source: https://context7.com/bsaliou/chemprice/llms.txt Queries configured integrators for pricing data for a list of SMILES. It resolves molecule IDs, fetches packings with prices, normalizes currencies to USD, and merges results. An optional progress_output list can be passed to track collection progress. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setChemSpaceApiKey("cs-your-api-key-here") pc.check() smiles_list = [ "CC(=O)NC1=CC=C(C=C1)O", "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", "O=C(C)Oc1ccccc1C(=O)O", ] all_prices = pc.collect(smiles_list) # Collecting ID's for given 3 SMILES from MolPort... # Total: 3 molecules and 9 conformers are found in MolPort. # # Collecting Prices for given 3 SMILES from ChemSpace... # Total: 47 prices for 3 molecules are found in ChemSpace. # # Merging Results from Molport and ChemSpace... # Total: 312 prices for 3 molecules exist in the Merged file. # Total time: 18.4231 seconds # Vendor price collection is successfully done! print(all_prices.head()) # Input SMILES Source Supplier Name Purity Amount Measure Price_USD # CC(=O)NC1=CC=C(C=C1)O Molport ChemDiv, Inc. >90 100 mg 407.1 # CC(=O)NC1=CC=C(C=C1)O Molport MedChemExpress Europe 98.83 10 g 112.8 # CC(=O)NC1=CC=C(C=C1)O Molport TargetMol Chemicals 100.0 500 mg 50.0 # Track progress in a Streamlit app progress_output = [] all_prices = pc.collect(smiles_list, progress_output=progress_output) # progress_output will contain floats from 0.0 to 1.0 as collection proceeds ``` -------------------------------- ### Check Integrator Status Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Verify the connection status of the configured integrators. This helps confirm if credentials have been successfully set for each platform. ```python3 pc.status() ``` -------------------------------- ### check Source: https://context7.com/bsaliou/chemprice/llms.txt Validates API credentials by sending a test query to each configured integrator. Returns 1 if at least one integrator responds successfully, 0 otherwise. Individual integrators can be excluded. ```APIDOC ## check — Validate API Credentials Sends a live test query (using Paracetamol SMILES `CC(=O)NC1=CC=C(C=C1)O`) to each configured integrator's API to verify that the credentials are correct and functional. Returns `1` if at least one integrator responds successfully, `0` otherwise. Individual integrators can be excluded from the check using keyword arguments. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setChemSpaceApiKey("cs-your-api-key-here") # Check all configured integrators result = pc.check() # Check: Molport api key is correct. # Check: Chemspace api key is correct. # Check only specific integrators pc.check(Molport=True, ChemSpace=False, MCule=False) # Check: Molport api key is correct. # result == 1 means at least one integrator is valid if result: print("Ready to collect prices.") ``` ``` -------------------------------- ### Collect Data from Chemical Vendors Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb This code block initiates data collection from chemical vendors (MolPort and ChemSpace) for a given list of SMILES. It measures the time taken for the process and prints the counts of collected molecule IDs and prices. ```python import time time_start = time.perf_counter() # Get the molecule IDs and print count MolPort print(f"Collecting ID's for given {len(smiles_list)} SMILES from MolPort...") df_molecule_ids = molport_get_ids(smiles_list) smiles_exists = df_molecule_ids['Input SMILES'].nunique() print(f"Total: {smiles_exists} molecules and {len(df_molecule_ids)} conformers are found in MolPort.\n") # Get the prices and print count from MolPort print(f"Collecting Prices for given {len(smiles_list)} IDs from MolPort...") molport_prices=molport_collect_prices(df_molecule_ids) smiles_with_price = molport_prices.loc[molport_prices['Price_USD'].notnull(), 'Input SMILES'].nunique() print(f"Total: {len(molport_prices)} prices for {smiles_with_price} molecules are found in MolPort.\n") # Get the prices and print count from ChemSpace print(f"Collecting Prices for given {len(smiles_list)} SMILES from ChemSpace...") chemspace_prices=chemspace_collect_prices(smiles_list) unique_smiles_count = chemspace_prices['Input SMILES'].nunique() smiles_with_price_cs = len(chemspace_prices[chemspace_prices['Price_USD'].notnull()]) print(f"Total: {smiles_with_price_cs} prices for {unique_smiles_count} molecules are found in ChemSpace.\n") ``` -------------------------------- ### API Key Configuration Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Configuration section for API keys and authentication credentials for various chemical databases. ```python molport_username = "" molport_authcode = "" molport_api_key = "" chemspace_api_key = "" mcule_token = "" ``` -------------------------------- ### PriceCollector Constructor Source: https://context7.com/bsaliou/chemprice/llms.txt Instantiate the PriceCollector class to manage API credentials and pricing data collection. This object holds credentials for Molport, ChemSpace, and MCule. ```APIDOC ## PriceCollector Constructor `PriceCollector()` is the central class of the library. Instantiating it creates an object that holds API credentials for all three integrators (Molport, ChemSpace, MCule) and exposes methods to set credentials, validate them, collect prices, and filter for best deals. ```python from chemprice import PriceCollector pc = PriceCollector() # Define molecules to search using SMILES notation smiles_list = [ "CC(=O)NC1=CC=C(C=C1)O", # Paracetamol (Acetaminophen) "CC(C)CC1=CC=C(C=C1)C(C)C(=O)O", # Ibuprofen "O=C(C)Oc1ccccc1C(=O)O", # Aspirin ] ``` ``` -------------------------------- ### Check API Key Validity Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Validate the entered API keys with the respective integrators before initiating a price search. This ensures that the credentials are correct and active. ```python3 pc.check() ``` -------------------------------- ### Set ChemSpace API Key Source: https://context7.com/bsaliou/chemprice/llms.txt Set the ChemSpace API key for authentication. This is the only authentication method supported by ChemSpace. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setChemSpaceApiKey("cs-your-api-key-here") ``` -------------------------------- ### Execute Molport Price Collection Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb This snippet shows how to call the molport_collect_prices function with a DataFrame of molecule IDs and displays the resulting DataFrame. ```python molport_prices=molport_collect_prices(df_molecule_ids) molport_prices ``` -------------------------------- ### Set Molport Username and Password Source: https://github.com/bsaliou/chemprice/blob/main/docs/source/user_manual/getting_started.md Provide Molport login credentials if you prefer to authenticate using a username and password instead of an API key. This is an alternative to setting the API key. ```python3 pc.setMolportUsername("john.spade") pc.setMolportPassword("fasdga34a3") ``` -------------------------------- ### Collect Prices from ChemSpace API Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Collects prices for a list of SMILES strings from the ChemSpace API. Requires authentication and handles API responses, including error checking and data extraction into a pandas DataFrame. Includes a delay between requests to respect API rate limits. ```python def chemspace_collect_prices(smiles_list): access_token = chemspace_get_token() url = "https://api.chem-space.com/v3/search/exact" headers = { "Accept": "application/json; version=3.1", "Authorization": "Bearer " + access_token, } params = { "count": 3, "page": 1, "categories": "CSCS,CSMB" } response_data = [] for index, smiles in tqdm(enumerate(smiles_list),total=len(smiles_list)): data = { "SMILES": smiles } response = requests.post(url, headers=headers, data=data, params=params) # Check if the request was successful (status code 200) if response.status_code == 200: # Process the response here molecule_data = response.json() # original smiles added for item in molecule_data['items']: item['input smiles'] = smiles response_data.append(molecule_data) else: # The request failed, print the status code and response content print("Request failed with status code:", response.status_code) print("Response content:", response.text) time.sleep(1.5) chemspace_data = [] # Iterate through the elements of the JSON file for data in response_data: for item in data['items']: for offer in item['offers']: for price in offer['prices']: source = "ChemSpace" input_smiles = item['input smiles'] smiles = item["smiles"] cas = item["cas"] supplier_name = offer['vendorName'] purity = offer['purity'] amount = price['pack'] measure = price['uom'] price_usd = price['priceUsd'] chemspace_data.append((source, input_smiles, smiles, cas, supplier_name, purity, amount, measure, price_usd)) df = pd.DataFrame(chemspace_data, columns=["Source", "Input SMILES", "SMILES", "CAS", "Supplier Name", "Purity", "Amount", "Measure", "Price_USD"]) df = df.dropna(subset=["Price_USD"], how='all') return df ``` ```python chemspace_prices=chemspace_collect_prices(smiles_list) chemspace_prices ``` -------------------------------- ### Check Credential Status Source: https://context7.com/bsaliou/chemprice/llms.txt Check the status of configured credentials for Molport, ChemSpace, and MCule on the PriceCollector instance. This method does not make network calls. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setMolportUsername("john.spade") pc.setMolportPassword("fasdga34a3") pc.setChemSpaceApiKey("cs-your-api-key-here") # MCule not configured pc.status() # Status: Molport : both creditentials are set. # Status: Chemspace : creditential is set. # Status: MCule : no credential is set. ``` -------------------------------- ### Data Standardization Functions Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Provides functions to clean and standardize 'Purity' and 'Price' columns from vendor data. The `process_purity` function cleans the purity string, and `molport_standardize_columns` adjusts price and purity formats. ```python #cleans the purity text def process_purity(value): if value == "('',)": return "" else: return value.strip('\'()\%\'),') # standardize the price and purity columns with chemspace data def molport_standardize_columns(data): data = data.astype(str) # Apply the custom function to the 'Purity' column data['Purity'] = data['Purity'].apply(process_purity) # Create new columns Price_USD and Price_EUR with empty strings data['Price_USD'] = "" # Replace relevant values with corresponding prices data.loc[data['Currency'] == 'USD', 'Price_USD'] = data.loc[data['Currency'] == 'USD', 'Price'] # Remove the Price and Currency columns data.drop(['Price', 'Currency'], axis=1, inplace=True) return data ``` -------------------------------- ### Standardize Prices to USD per Unit Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Converts a given price to a standardized unit (USD/g, USD/mol, or USD/l) based on the 'Measure' column. Uses `extract_unit_bulk` for complex units and `conversion_factors` for known units. Returns None if units are unknown or conversion fails. ```python conversion_factors = { 'g': 1.0, 'mg': 1e-3, 'kg': 1e3, 'microg': 1e-6, 'ug': 1e-6, 'mol': 1.0, 'micromol': 1e-6, 'mmol': 1e-3, 'kmol': 1e3, 'umol': 1e-6, 'ml': 1e-3, 'microl': 1e-6, 'l': 1.0, 'mL': 1e-3, 'kl': 1e3, 'ul': 1e-6 } def standardize_prices(row): measure = row['Measure'] amount = float(row['Amount']) price = float(row['Price_USD']) if measure in conversion_factors: return price / (conversion_factors[measure] * amount) else: bulk, unit = extract_unit_bulk(measure) if amount and unit: if unit in conversion_factors: return price / (conversion_factors[unit] * (amount * bulk)) print("Unknown measure units for:",measure) return None ``` -------------------------------- ### Define Unit Conversion Factors Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Defines a dictionary of conversion factors for various units of mass (kg, g, mg, ug), moles (kmol, mol, mmol, umol), and volume (kl, l, ml, ul). ```python # Define conversion factors for different measures conversion_factors = { # Conversion to g 'kg': 1000, 'g': 1, 'mg': 1 / 1000, 'microg': 1 / 1000000, 'ug': 1 / 1000000, # Conversion to mol 'kmol': 1000, 'mol': 1, 'mmol': 1 / 1000, 'micromol': 1 / 1000000, 'umol': 1 / 1000000, # Conversion to l 'kl': 1000, 'l': 1, 'ml': 1 / 1000, 'mL': 1 / 1000, 'microl': 1 / 1000000, 'ul': 1 / 1000000, } ``` -------------------------------- ### Collect MCule IDs from MCule API Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Collects MCule IDs for a list of SMILES strings from the MCule API. Processes SMILES in batches of 500 to respect API limits and returns a DataFrame containing MCule IDs and their corresponding input SMILES. Requires an MCule API token for authentication. ```python # Function to collect MCule IDs with respect to limits def mcule_get_ids(smiles_list): id_smiles_list = [] headers = { 'Authorization': 'Token ' + mcule_token, } # Iterate through smiles_list while respecting the limits for i in range(0, len(smiles_list), 500): # Process 500 SMILES at a time batch_smiles = smiles_list[i:i+500] # Extract a batch of SMILES data = { 'queries': batch_smiles } # Send a POST request to MCule API for exact search response = requests.post('https://mcule.com/api/v1/search/exact/', headers=headers, json=data) if response.status_code == 200: results = response.json()["results"] # Extract MCule IDs and corresponding SMILES for result in results: molecule_id = result["mcule_id"] query = result["query"] id_smiles_list.append((molecule_id, query)) # Create a DataFrame with collected data df = pd.DataFrame(id_smiles_list, columns=["ID", "Input SMILES"]) return df ``` -------------------------------- ### Merge Vendor Price DataFrames Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Merges price dataframes from Molport, Chemspace, and MCule into a single dataframe. Displays the resulting merged dataframe. ```python merged_df = merge_dataframes([molport_prices, chemspace_prices, mcule_prices]) merged_df ``` -------------------------------- ### Validate API Credentials Source: https://context7.com/bsaliou/chemprice/llms.txt Validate API credentials by sending a test query to configured integrators. Returns 1 if at least one integrator responds successfully, 0 otherwise. Individual integrators can be excluded from the check. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") pc.setChemSpaceApiKey("cs-your-api-key-here") # Check all configured integrators result = pc.check() # Check: Molport api key is correct. # Check: Chemspace api key is correct. # Check only specific integrators pc.check(Molport=True, ChemSpace=False, MCule=False) # Check: Molport api key is correct. # result == 1 means at least one integrator is valid if result: print("Ready to collect prices.") ``` -------------------------------- ### Set Molport API Key Source: https://context7.com/bsaliou/chemprice/llms.txt Set the Molport API key for authentication with the Molport platform. Alternatively, you can use username and password authentication. ```python from chemprice import PriceCollector pc = PriceCollector() # Option 1: Authenticate with API key pc.setMolportApiKey("880d8343-8ui2-418c-9g7a-68b4e2e78c8b") # Option 2: Authenticate with username and password (alternative to API key) pc.setMolportUsername("john.spade") pc.setMolportPassword("fasdga34a3") ``` -------------------------------- ### Print Collection Time and Status Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Prints the total time taken for vendor price collection and a success message. This is typically used at the end of a data collection process. ```python time_end = time.perf_counter() print(f"Total time: {time_end - time_start:0.4f} seconds") print(f"Vendor price collection is successfully done!") return merged_df ``` -------------------------------- ### Execute Molport ID Search Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Calls the `molport_get_ids` function with the predefined SMILES list and prints the resulting DataFrame of molecule IDs and input SMILES. ```python df_molecule_ids = molport_get_ids(smiles_list) print(df_molecule_ids) ``` -------------------------------- ### setMCuleApiKey Source: https://context7.com/bsaliou/chemprice/llms.txt Sets the MCule token on the PriceCollector instance. MCule requires only an API token for authentication. ```APIDOC ## setMCuleApiKey — Set MCule API Key Sets the MCule token on the `PriceCollector` instance. MCule requires only an API token. Obtain your key at https://mcule.com/contact/. ```python from chemprice import PriceCollector pc = PriceCollector() pc.setMCuleApiKey("your-mcule-token-here") ``` ``` -------------------------------- ### Apply Minimum Price Filtering Source: https://github.com/bsaliou/chemprice/blob/main/notebook/vendor-search.ipynb Applies the `filter_csv_by_min_price` function to the `standardized_df` to obtain a DataFrame containing the best price for each molecule. The result is stored in `best_price_df`. ```python best_price_df = filter_csv_by_min_price(standardized_df) best_price_df ```