Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.7.1 #117

Merged
merged 6 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) format.

## [0.7.1] -- 2023-01-22
- Fixed bug in Stars annotation
- SQL efficiency improvements
- Added sort by date in stared projects

## [0.7.0] -- 2023-01-17
- Added `pop` to project table and annotation model [#107](https://github.com/pepkit/pepdbagent/issues/107)
- Added `forked_from` feature [#73](https://github.com/pepkit/pepdbagent/issues/73)
Expand Down
2 changes: 1 addition & 1 deletion pepdbagent/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.7.0"
__version__ = "0.7.1"
9 changes: 7 additions & 2 deletions pepdbagent/db_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class Projects(Base):
number_of_stars: Mapped[int] = mapped_column(default=0)
submission_date: Mapped[datetime.datetime]
last_update_date: Mapped[Optional[datetime.datetime]] = mapped_column(
onupdate=deliver_update_date, default=deliver_update_date
default=deliver_update_date, # onupdate=deliver_update_date, # This field should not be updated, while we are adding project to favorites
)
pep_schema: Mapped[Optional[str]]
pop: Mapped[Optional[bool]] = mapped_column(default=False)
Expand Down Expand Up @@ -168,7 +168,9 @@ class User(Base):
id: Mapped[int] = mapped_column(primary_key=True)
namespace: Mapped[str]
stars_mapping: Mapped[List["Stars"]] = relationship(
back_populates="user_mapping", cascade="all, delete-orphan"
back_populates="user_mapping",
cascade="all, delete-orphan",
order_by="Stars.star_date.desc()",
)


Expand All @@ -183,6 +185,9 @@ class Stars(Base):
project_id = mapped_column(ForeignKey("projects.id", ondelete="CASCADE"), primary_key=True)
user_mapping: Mapped[List["User"]] = relationship(back_populates="stars_mapping")
project_mapping: Mapped["Projects"] = relationship(back_populates="stars_mapping")
star_date: Mapped[datetime.datetime] = mapped_column(
onupdate=deliver_update_date, default=deliver_update_date
)


class Views(Base):
Expand Down
6 changes: 6 additions & 0 deletions pepdbagent/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,9 @@ class CreateViewDictModel(BaseModel):
project_name: str
project_tag: str
sample_list: List[str]


class RegistryPath(BaseModel):
namespace: str
name: str
tag: Optional[str] = "default"
78 changes: 71 additions & 7 deletions pepdbagent/modules/annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
from pepdbagent.db_utils import BaseEngine, Projects
from pepdbagent.exceptions import FilterError, ProjectNotFoundError, RegistryPathError
from pepdbagent.models import AnnotationList, AnnotationModel
from pepdbagent.models import AnnotationList, AnnotationModel, RegistryPath
from pepdbagent.utils import convert_date_string_to_date, registry_path_converter, tuple_converter

_LOGGER = logging.getLogger(PKG_NAME)
Expand Down Expand Up @@ -309,7 +309,7 @@ def _get_projects(

if admin is None:
admin = []
statement = select(Projects.id)
statement = select(Projects)

statement = self._add_condition(
statement,
Expand All @@ -325,13 +325,10 @@ def _get_projects(
if pep_type:
statement = statement.where(Projects.pop.is_(pep_type == "pop"))

id_results = self._pep_db_engine.session_execute(statement).all()

results_list = []
with Session(self._sa_engine) as session:
for prj_ids in id_results:
result = session.scalar(select(Projects).where(Projects.id == prj_ids[0]))

results = session.scalars(statement)
for result in results:
results_list.append(
AnnotationModel(
namespace=result.namespace,
Expand Down Expand Up @@ -572,3 +569,70 @@ def get_by_rp_list(

else:
return self.get_by_rp(registry_paths, admin)

def get_projects_list(
self,
namespace: str = None,
search_str: str = None,
admin: Union[str, List[str]] = None,
limit: int = DEFAULT_LIMIT,
offset: int = DEFAULT_OFFSET,
order_by: str = "update_date",
order_desc: bool = False,
filter_by: Optional[Literal["submission_date", "last_update_date"]] = None,
filter_start_date: Optional[str] = None,
filter_end_date: Optional[str] = None,
pep_type: Optional[Literal["pep", "pop"]] = None,
) -> List[RegistryPath]:
"""
Retrieve a list of projects by providing a search string.
This function serves as a lightweight version of the full 'get' function,
returning only a list of registry paths without annotations.
It is designed for use cases where a large list of projects is needed with minimal processing time.

:param namespace: namespace where to search for a project
:param search_str: search string that has to be found in the name or tag
:param admin: True, if user is admin of the namespace [Default: False]
:param limit: limit of return results
:param offset: number of results off set (that were already showed)
:param order_by: sort the result-set by the information
Options: ["name", "update_date", "submission_date"]
[Default: "update_date"]
:param order_desc: Sort the records in descending order. [Default: False]
:param filter_by: data to use filter on.
Options: ["submission_date", "last_update_date"]
[Default: filter won't be used]
:param filter_start_date: Filter start date. Format: "YYYY:MM:DD"
:param filter_end_date: Filter end date. Format: "YYYY:MM:DD". if None: present date will be used
:param pep_type: Get pep with specified type. Options: ["pep", "pop"]. Default: None, get all peps
:return: list of found projects with their annotations.
"""
_LOGGER.info(f"Running project search: (namespace: {namespace}, query: {search_str}.")

if admin is None:
admin = []
statement = select(Projects.namespace, Projects.name, Projects.tag)

statement = self._add_condition(
statement,
namespace=namespace,
search_str=search_str,
admin_list=admin,
)
statement = self._add_date_filter_if_provided(
statement, filter_by, filter_start_date, filter_end_date
)
statement = self._add_order_by_keyword(statement, by=order_by, desc=order_desc)
statement = statement.limit(limit).offset(offset)
if pep_type:
statement = statement.where(Projects.pop.is_(pep_type == "pop"))

results_list = []
with Session(self._sa_engine) as session:
results = session.execute(statement)

for result in results:
results_list.append(
RegistryPath(namespace=result[0], name=result[1], tag=result[2])
)
return results_list
2 changes: 1 addition & 1 deletion pepdbagent/modules/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def get(

try:
with Session(self._sa_engine) as session:
found_prj = session.scalars(statement).one()
found_prj = session.scalar(statement)

if found_prj:
_LOGGER.info(
Expand Down
32 changes: 16 additions & 16 deletions pepdbagent/modules/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
)

from pepdbagent.db_utils import BaseEngine, User, Stars, Projects
from pepdbagent.modules.project import PEPDatabaseProject
from pepdbagent.models import AnnotationList, AnnotationModel
from pepdbagent.exceptions import ProjectNotInFavorites, ProjectAlreadyInFavorites

Expand Down Expand Up @@ -114,7 +113,7 @@ def remove_project_from_favorites(
:return: None
"""
_LOGGER.debug(
f"Removing project {project_namespace}/{project_name}:{project_tag} from fProjectNotInFavorites for user {namespace}"
f"Removing project {project_namespace}/{project_name}:{project_tag} from favorites in {namespace}"
)

user_id = self.get_user_id(namespace)
Expand Down Expand Up @@ -166,22 +165,23 @@ def get_favorites(self, namespace: str) -> AnnotationList:
number_of_projects = len([kk.project_mapping for kk in query_result.stars_mapping])
project_list = []
for prj_list in query_result.stars_mapping:
prj = prj_list.project_mapping
project_list.append(
AnnotationModel(
namespace=prj_list.project_mapping.namespace,
name=prj_list.project_mapping.name,
tag=prj_list.project_mapping.tag,
is_private=prj_list.project_mapping.private,
number_of_samples=prj_list.project_mapping.number_of_samples,
description=prj_list.project_mapping.description,
last_update_date=str(prj_list.project_mapping.last_update_date),
submission_date=str(prj_list.project_mapping.submission_date),
digest=prj_list.project_mapping.digest,
pep_schema=prj_list.project_mapping.pep_schema,
pop=prj_list.project_mapping.pop,
stars_number=prj_list.project_mapping.number_of_stars,
forked_from=f"{prj_list.project_mapping.namespace}/{prj_list.project_mapping.name}:{prj_list.project_mapping.tag}"
if prj_list.project_mapping
namespace=prj.namespace,
name=prj.name,
tag=prj.tag,
is_private=prj.private,
number_of_samples=prj.number_of_samples,
description=prj.description,
last_update_date=str(prj.last_update_date),
submission_date=str(prj.submission_date),
digest=prj.digest,
pep_schema=prj.pep_schema,
pop=prj.pop,
stars_number=prj.number_of_stars,
forked_from=f"{prj.forked_from_mapping.namespace}/{prj.forked_from_mapping.name}:{prj.forked_from_mapping.tag}"
if prj.forked_from_mapping
else None,
)
)
Expand Down
14 changes: 14 additions & 0 deletions pepdbagent/modules/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def get(
_subsample_dict: dict
}
"""
_LOGGER.debug(f"Get view {view_name} from {namespace}/{name}:{tag}")
view_statement = select(Views).where(
and_(
Views.project_mapping.has(namespace=namespace, name=name, tag=tag),
Expand Down Expand Up @@ -106,6 +107,7 @@ def get_annotation(
description: str,
number_of_samples: int}
"""
_LOGGER.debug(f"Get annotation for view {view_name} in {namespace}/{name}:{tag}")
view_statement = select(Views).where(
and_(
Views.project_mapping.has(namespace=namespace, name=name, tag=tag),
Expand Down Expand Up @@ -149,6 +151,7 @@ def create(
:param description: description of the view
retrun: None
"""
_LOGGER.debug(f"Creating view {view_name} with provided info: (view_dict: {view_dict})")
if isinstance(view_dict, dict):
view_dict = CreateViewDictModel(**view_dict)

Expand Down Expand Up @@ -205,6 +208,9 @@ def delete(
:param view_name: name of the view
:return: None
"""
_LOGGER.debug(
f"Deleting view {view_name} from {project_namespace}/{project_name}:{project_tag}"
)
view_statement = select(Views).where(
and_(
Views.project_mapping.has(
Expand Down Expand Up @@ -241,6 +247,9 @@ def add_sample(
:param sample_name: sample name
:return: None
"""
_LOGGER.debug(
f"Adding sample {sample_name} to view {view_name} in {namespace}/{name}:{tag}"
)
if isinstance(sample_name, str):
sample_name = [sample_name]
view_statement = select(Views).where(
Expand Down Expand Up @@ -296,6 +305,9 @@ def remove_sample(
:param sample_name: sample name
:return: None
"""
_LOGGER.debug(
f"Removing sample {sample_name} from view {view_name} in {namespace}/{name}:{tag}"
)
view_statement = select(Views).where(
and_(
Views.project_mapping.has(namespace=namespace, name=name, tag=tag),
Expand Down Expand Up @@ -341,6 +353,7 @@ def get_snap_view(
:param raw: retrieve unprocessed (raw) PEP dict.
:return: peppy.Project object
"""
_LOGGER.debug(f"Creating snap view for {namespace}/{name}:{tag}")
project_statement = select(Projects).where(
and_(
Projects.namespace == namespace,
Expand Down Expand Up @@ -386,6 +399,7 @@ def get_views_annotation(
:param tag: tag of the project
:return: list of views of the project
"""
_LOGGER.debug(f"Get views annotation for {namespace}/{name}:{tag}")
statement = select(Views).where(
Views.project_mapping.has(namespace=namespace, name=name, tag=tag),
)
Expand Down
15 changes: 15 additions & 0 deletions tests/test_pepagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,21 @@ def test_search_incorrect_incorrect_pep_type(
with pytest.raises(ValueError):
initiate_pepdb_con.annotation.get(namespace=namespace, pep_type="incorrect")

@pytest.mark.parametrize(
"namespace, query, found_number",
[
["namespace1", "ame", 2],
],
)
def test_project_list_without_annotation(
self, initiate_pepdb_con, namespace, query, found_number
):
result = initiate_pepdb_con.annotation.get_projects_list(
namespace=namespace,
search_str=query,
)
assert len(result) == found_number


@pytest.mark.skipif(
not db_setup(),
Expand Down
Loading