Skip to content

Conversation

@tsmathis
Copy link
Collaborator

should just work™️

@tsmathis
Copy link
Collaborator Author

tsmathis commented Oct 23, 2025

some notes:

  1. depends on Compatibility with emmet-core 0.86.0rc1 #1021
    2. could supersede exclude gnome for full downloads if needed #974
  2. this will need to be addressed for the progress bar to be accurate in the case were has_gnome_access=False:
    # TODO: Update tasks (+ others?) resource to have emmet-api BatchIdQuery operator
    # -> need to modify BatchIdQuery operator to handle root level
    # batch_id, not only builder_meta.batch_id
    # if not has_gnome_access:
    # num_docs_needed = self.count(
    # {"batch_id_neq_any": SETTINGS.ACCESS_CONTROLLED_BATCH_IDS}
    # )

    the count can be retrieved from s3, but the COUNT(*) ... WHERE NOT IN ... is slow
  3. wasn't sure how to emit messages to the user, warnings might not be the best choice:
    warnings.warn(
    f"Dataset for {suffix} already exists at {target_path}, delete or move existing dataset "
    "or re-run search query with MPRester(force_renew=True)",
    MPLocalDatasetWarning,

    warnings.warn(
    f"Dataset for {suffix} written to {target_path}. It is recommended to optimize "
    "the table according to your usage patterns prior to running intensive workloads, "
    "see: https://delta-io.github.io/delta-rs/delta-lake-best-practices/#optimizing-table-layout",
    MPLocalDatasetWarning,
    )
  4. On the fence if MPDataset should inherit user's choice of use_document_model or default to False, its extra overhead when True
    use_document_model=self.use_document_model,
  5. re: document model's, wasn't sure if making an MPDataDoc model was the right route so the emmet model is just passed through now.
  6. @esoteric-ephemera, is this how coercing user input to AlphaIDs should go? Do you want to do something different?
    as_alpha = str(AlphaID(task_id, padlen=8)).split("-")[-1]
  7. Is MPAPIClientSettings the right place for these? Not sure if the user has the ability to adjust these if needed:
    LOCAL_DATASET_CACHE: str = Field(
    os.path.expanduser("~") + "/mp_datasets",
    description="Target directory for downloading full datasets",
    )
    DATASET_FLUSH_THRESHOLD: int = Field(
    100000,
    description="Threshold number of rows to accumulate in memory before flushing dataset to disk",
    )
    ACCESS_CONTROLLED_BATCH_IDS: list[str] = Field(
    ["gnome_r2scan_statics"], description="Batch ids with access restrictions"
    )

@tsmathis
Copy link
Collaborator Author

ah and based on the failing test for trajectories, I assumed returning the pymatgen object was correct, should the dict be returned? @esoteric-ephemera

return RelaxTrajectory(**traj_data[0]).to_pmg()

@esoteric-ephemera
Copy link
Collaborator

esoteric-ephemera commented Oct 23, 2025

@tsmathis think the API was set up to return the jsanitized trajectory info:
https://github.com/materialsproject/emmet/blob/3447c5af4746d539f1f4faf26b97715cb119c85d/emmet-api/emmet/api/routes/materials/tasks/query_operators.py#L73

Either way yeah I guess it returned the as_dict but we don't need to keep with that paradigm

For the AlphaID, to handle either the no prefix/separator ("aaaaaaft") and with prefix/separator ("mp-aaaaaaft") cases, both of these should work, but I can also just save the "padded identifier" as an attr on it to make this cleaner - I'll do that in the PR you linked:

"a"*(x._padlen-len(x._identifier)) + x._identifier

or

if (alpha := AlphaID(task_id, padlen=8))._separator:
  padded = str(alpha).rsplit(alpha._separator)[-1] 
else:
  padded = str(alpha)

@tsmathis
Copy link
Collaborator Author

tsmathis commented Oct 23, 2025

For the AlphaID, to handle either the no prefix/separator ("aaaaaaft") and with prefix/separator ("mp-aaaaaaft") cases, both of these should work, but I can also just save the "padded identifier" as an attr on it to make this cleaner - I'll do that in the PR you linked:

either way on this works for me, just want to make sure I stick to the intended usage (edit: or that we're at least consistent across the client)

Either way yeah I guess it returned the as_dict but we don't need to keep with that paradigm

Was going to say we could stick to whatever the frontend was expecting, but looking now the frontend doesn't even use the tasks.get_trajectory(...) function so it will need to be rewritten either way. The frontend does end up making a dataframe from the trajectory dict, so maybe just returning the dict will be best

@codecov-commenter
Copy link

codecov-commenter commented Oct 23, 2025

Codecov Report

❌ Patch coverage is 42.20183% with 63 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.92%. Comparing base (5ecebec) to head (33b787f).

Files with missing lines Patch % Lines
mp_api/client/core/client.py 16.66% 45 Missing ⚠️
mp_api/client/core/utils.py 55.00% 18 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1023      +/-   ##
==========================================
- Coverage   66.85%   65.92%   -0.94%     
==========================================
  Files          50       50              
  Lines        2767     2870     +103     
==========================================
+ Hits         1850     1892      +42     
- Misses        917      978      +61     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@tschaume tschaume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Looking forward to rolling this out 😄

has_gnome_access = bool(
self._submit_requests(
url=urljoin(
"https://api.materialsproject.org/", "materials/summary/"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use self.endpoint

Copy link
Collaborator Author

@tsmathis tsmathis Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be self.base_endpoint? I think this tripped me up when I tried using self.endpoint originally

if self.suffix:
self.endpoint = urljoin(self.endpoint, self.suffix)

for the tasks rester -> self.endpoint caused the urljoin here to yield something like {base_url}/materials/tasks/materials/summary

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, self.base_endpoint should work.

_flush(accumulator, group)
group += 1
size = 0
accumulator = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accumulator.clear() for better memory management?

description="Threshold number of rows to accumulate in memory before flushing dataset to disk",
)

ACCESS_CONTROLLED_BATCH_IDS: list[str] = Field(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

settings is the right place for the first two. Access-controlled batch ids should probably be hardcoded and change with client releases.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

akin to one of these?

def get_database_version(self):
"""The Materials Project database is periodically updated and has a
database version associated with it. When the database is updated,
consolidated data (information about "a material") may and does
change, while calculation data about a specific calculation task
remains unchanged and available for querying via its task_id.
The database version is set as a date in the format YYYY_MM_DD,
where "_DD" may be optional. An additional numerical suffix
might be added if multiple releases happen on the same day.
Returns: database version as a string
"""
return get(url=self.endpoint + "heartbeat").json()["db_version"]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: the use of self.endpoint? If so, then yes :)

Copy link
Collaborator Author

@tsmathis tsmathis Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah no, I mean for the access controlled batch ids.
Should those be added to the heartbeat so they aren't defined in the client code/settings? And then the client can just call get_access_controlled_batch_ids()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a good idea.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to start a PR to add it to the heartbeat_meta here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants