Skip to content
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.opencode

# Dask
dask-worker-space

Expand Down
2 changes: 2 additions & 0 deletions src/projspec/content/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Contents classes - information declared in project specs"""

from projspec.content.base import BaseContent
from projspec.content.data import FrictionlessData, IntakeSource
from projspec.content.env_var import EnvironmentVariables
Expand Down
8 changes: 8 additions & 0 deletions src/projspec/proj/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
"""Project and spec classes"""

from projspec.proj.base import ParseFailed, Project, ProjectSpec, ProjectExtra

from projspec.proj.ai import AIEnabled
from projspec.proj.briefcase import Briefcase
from projspec.proj.conda_package import CondaRecipe, RattlerRecipe
from projspec.proj.conda_project import CondaProject
Expand All @@ -11,6 +15,7 @@
from projspec.proj.node import JLabExtension, Node, Yarn
from projspec.proj.pixi import Pixi
from projspec.proj.poetry import Poetry
from projspec.proj.published import Citation, Zenodo
from projspec.proj.pyscript import PyScript
from projspec.proj.python_code import PythonCode, PythonLibrary
from projspec.proj.rust import Rust, RustPython
Expand All @@ -22,7 +27,9 @@
"ParseFailed",
"Project",
"ProjectSpec",
"AIEnabled",
"Briefcase",
"Citation",
"CondaRecipe",
"CondaProject",
"Golang",
Expand All @@ -49,4 +56,5 @@
"Uv",
"VSCode",
"Yarn",
"Zenodo",
]
15 changes: 15 additions & 0 deletions src/projspec/proj/ai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from projspec.proj.base import ProjectSpec


class AIEnabled(ProjectSpec):
"""This project has text files intended for LLM/AI to read."""

spec_doc = "https://agents.md/"

def match(self) -> bool:
return bool(
{"AGENTS.md", "CLAUDE.md", ".specify"}.intersection(self.proj.basenames)
)

def parse(self) -> None:
pass
4 changes: 3 additions & 1 deletion src/projspec/proj/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def resolve(
:param types: names of types to allow while parsing. If empty or None, allow all
:param xtypes: names of types to disallow while parsing.
"""
if types and set(types) - set(registry):
types = set(camel_to_snake(_) for _ in types or ())
if types and types - set(registry):
raise ValueError(f"Unknown types: {set(types) - set(registry)}")
# sorting to ensure consistency
for name in sorted(registry):
Expand Down Expand Up @@ -405,6 +406,7 @@ def make(self, qname: str, **kwargs):
spec, artifact, name = None, qname, None
else:
spec, artifact, *name = qname.split(".")
spec = camel_to_snake(spec)
specs = [self.specs[spec]] if spec else self.specs.values()
art = None
for spec in specs:
Expand Down
27 changes: 22 additions & 5 deletions src/projspec/proj/ide.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""Code project container config within IDEs"""

from projspec.artifact import BaseArtifact
from projspec.proj import ProjectSpec


Expand All @@ -12,15 +12,28 @@ def match(self) -> bool:
return self.proj.fs.exists(f"{self.proj.url}/.project/spec.yaml")

def parse(self) -> None:
...
from projspec.artifact.process import Process

# "opens" the project in the sense that it is set as the current context.
# Editing still happens in jupyter/vscode/etc
self.artifacts["set_project"] = Process(
self.proj, cmd=["nvwb", "open", self.proj.url]
)

# create:
# https://docs.nvidia.com/ai-workbench/user-guide/latest/reference/user-interface/cli.html#create-project


class JetbrainsIDE(ProjectSpec):
def match(self) -> bool:
return self.proj.fs.exists(f"{self.proj.url}/.idea")

def parse(self) -> None:
...
from projspec.artifact.process import Process

self.artifacts["launch"] = Process(
self.proj, cmd=["pycharm", self.proj.url, "nosplash", "dontReopenProjects"]
)


class VSCode(ProjectSpec):
Expand All @@ -32,7 +45,9 @@ def match(self) -> bool:
return self.proj.fs.exists(f"{self.proj.url}/.vscode/settings.json")

def parse(self) -> None:
...
from projspec.artifact.process import Process

self.artifacts["launch"] = Process(self.proj, cmd=["code", self.proj.url])


class Zed(ProjectSpec):
Expand All @@ -42,4 +57,6 @@ def match(self) -> bool:
return self.proj.fs.exists(f"{self.proj.url}/.zed/settings.json")

def parse(self) -> None:
...
from projspec.artifact.process import Process

self.artifacts["launch"] = Process(self.proj, cmd=["zed", self.proj.url])
41 changes: 41 additions & 0 deletions src/projspec/proj/published.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import yaml

from projspec.proj.base import ProjectSpec


class Citation(ProjectSpec):
"""A github-specified format to say how this project should be cited."""

spec_doc = "https://citation-file-format.github.io/"

def match(self):
return "CITATION.cff" in self.proj.basenames

def parse(self) -> None:
from projspec.content.metadata import DescriptiveMetadata

with self.proj.fs.open(self.proj.basenames["CITATION.cff"], "rt") as f:
meta = yaml.safe_load(f)
self.contents["descriptive_metadata"] = DescriptiveMetadata(
proj=self.proj, meta=meta
)


class Zenodo(ProjectSpec):
"""This project has been published on Zenodo"""

spec_doc = "https://help.zenodo.org/docs/github/describe-software/zenodo-json/"

def match(self):
# NB: zenodo picks up CITATION.cff too, but this format is more specific
return ".zenodo.json" in self.proj.basenames

def parse(self) -> None:
from projspec.content.metadata import DescriptiveMetadata

with self.proj.fs.open(self.proj.basenames[".zenodo.json"], "rt") as f:
meta = yaml.safe_load(f)
# TODO: extract known contents such as license.
self.contents["descriptive_metadata"] = DescriptiveMetadata(
proj=self.proj, meta=meta
)
1 change: 1 addition & 0 deletions src/projspec/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import contextlib
import enum
import logging
import os
import pathlib
import re
import subprocess
Expand Down
Loading