edsl 0.1.27.dev2__py3-none-any.whl → 0.1.28__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. edsl/Base.py +99 -22
  2. edsl/BaseDiff.py +260 -0
  3. edsl/__init__.py +4 -0
  4. edsl/__version__.py +1 -1
  5. edsl/agents/Agent.py +26 -5
  6. edsl/agents/AgentList.py +62 -7
  7. edsl/agents/Invigilator.py +4 -9
  8. edsl/agents/InvigilatorBase.py +5 -5
  9. edsl/agents/descriptors.py +3 -1
  10. edsl/conjure/AgentConstructionMixin.py +152 -0
  11. edsl/conjure/Conjure.py +56 -0
  12. edsl/conjure/InputData.py +628 -0
  13. edsl/conjure/InputDataCSV.py +48 -0
  14. edsl/conjure/InputDataMixinQuestionStats.py +182 -0
  15. edsl/conjure/InputDataPyRead.py +91 -0
  16. edsl/conjure/InputDataSPSS.py +8 -0
  17. edsl/conjure/InputDataStata.py +8 -0
  18. edsl/conjure/QuestionOptionMixin.py +76 -0
  19. edsl/conjure/QuestionTypeMixin.py +23 -0
  20. edsl/conjure/RawQuestion.py +65 -0
  21. edsl/conjure/SurveyResponses.py +7 -0
  22. edsl/conjure/__init__.py +9 -4
  23. edsl/conjure/examples/placeholder.txt +0 -0
  24. edsl/conjure/naming_utilities.py +263 -0
  25. edsl/conjure/utilities.py +165 -28
  26. edsl/conversation/Conversation.py +238 -0
  27. edsl/conversation/car_buying.py +58 -0
  28. edsl/conversation/mug_negotiation.py +81 -0
  29. edsl/conversation/next_speaker_utilities.py +93 -0
  30. edsl/coop/coop.py +191 -12
  31. edsl/coop/utils.py +20 -2
  32. edsl/data/Cache.py +55 -17
  33. edsl/data/CacheHandler.py +10 -9
  34. edsl/inference_services/AnthropicService.py +1 -0
  35. edsl/inference_services/DeepInfraService.py +20 -13
  36. edsl/inference_services/GoogleService.py +7 -1
  37. edsl/inference_services/InferenceServicesCollection.py +33 -7
  38. edsl/inference_services/OpenAIService.py +17 -10
  39. edsl/inference_services/models_available_cache.py +69 -0
  40. edsl/inference_services/rate_limits_cache.py +25 -0
  41. edsl/inference_services/write_available.py +10 -0
  42. edsl/jobs/Jobs.py +240 -36
  43. edsl/jobs/buckets/BucketCollection.py +9 -3
  44. edsl/jobs/interviews/Interview.py +4 -1
  45. edsl/jobs/interviews/InterviewTaskBuildingMixin.py +24 -10
  46. edsl/jobs/interviews/retry_management.py +4 -4
  47. edsl/jobs/runners/JobsRunnerAsyncio.py +87 -45
  48. edsl/jobs/runners/JobsRunnerStatusData.py +3 -3
  49. edsl/jobs/tasks/QuestionTaskCreator.py +4 -2
  50. edsl/language_models/LanguageModel.py +37 -44
  51. edsl/language_models/ModelList.py +96 -0
  52. edsl/language_models/registry.py +14 -0
  53. edsl/language_models/repair.py +95 -24
  54. edsl/notebooks/Notebook.py +119 -31
  55. edsl/questions/QuestionBase.py +109 -12
  56. edsl/questions/descriptors.py +5 -2
  57. edsl/questions/question_registry.py +7 -0
  58. edsl/results/Result.py +20 -8
  59. edsl/results/Results.py +85 -11
  60. edsl/results/ResultsDBMixin.py +3 -6
  61. edsl/results/ResultsExportMixin.py +47 -16
  62. edsl/results/ResultsToolsMixin.py +5 -5
  63. edsl/scenarios/Scenario.py +59 -5
  64. edsl/scenarios/ScenarioList.py +97 -40
  65. edsl/study/ObjectEntry.py +97 -0
  66. edsl/study/ProofOfWork.py +110 -0
  67. edsl/study/SnapShot.py +77 -0
  68. edsl/study/Study.py +491 -0
  69. edsl/study/__init__.py +2 -0
  70. edsl/surveys/Survey.py +79 -31
  71. edsl/surveys/SurveyExportMixin.py +21 -3
  72. edsl/utilities/__init__.py +1 -0
  73. edsl/utilities/gcp_bucket/__init__.py +0 -0
  74. edsl/utilities/gcp_bucket/cloud_storage.py +96 -0
  75. edsl/utilities/gcp_bucket/simple_example.py +9 -0
  76. edsl/utilities/interface.py +24 -28
  77. edsl/utilities/repair_functions.py +28 -0
  78. edsl/utilities/utilities.py +57 -2
  79. {edsl-0.1.27.dev2.dist-info → edsl-0.1.28.dist-info}/METADATA +43 -17
  80. {edsl-0.1.27.dev2.dist-info → edsl-0.1.28.dist-info}/RECORD +83 -55
  81. edsl-0.1.28.dist-info/entry_points.txt +3 -0
  82. edsl/conjure/RawResponseColumn.py +0 -327
  83. edsl/conjure/SurveyBuilder.py +0 -308
  84. edsl/conjure/SurveyBuilderCSV.py +0 -78
  85. edsl/conjure/SurveyBuilderSPSS.py +0 -118
  86. edsl/data/RemoteDict.py +0 -103
  87. {edsl-0.1.27.dev2.dist-info → edsl-0.1.28.dist-info}/LICENSE +0 -0
  88. {edsl-0.1.27.dev2.dist-info → edsl-0.1.28.dist-info}/WHEEL +0 -0
@@ -0,0 +1,97 @@
1
+ import time
2
+ from typing import Optional, Dict, Any, Type
3
+
4
+
5
+ class ObjectEntry:
6
+ def __init__(
7
+ self,
8
+ variable_name: str,
9
+ object: Any,
10
+ description: str,
11
+ coop_info: Optional[Dict[str, Any]] = None,
12
+ created_at: Optional[float] = None,
13
+ edsl_class_name: Optional[str] = None,
14
+ ):
15
+ self.created_at = created_at or time.time()
16
+ self.variable_name = variable_name
17
+ self.object = object
18
+ self.edsl_class_name = edsl_class_name or object.__class__.__name__
19
+ self.description = description
20
+ self.coop_info = coop_info
21
+
22
+ @classmethod
23
+ def _get_class(self, obj_dict: Dict[str, Any]) -> Type:
24
+ "Get the class of an object from its dictionary representation."
25
+ class_name = obj_dict["edsl_class_name"]
26
+ if class_name == "QuestionBase":
27
+ from edsl import QuestionBase
28
+
29
+ return QuestionBase
30
+ else:
31
+ from edsl.Base import RegisterSubclassesMeta
32
+
33
+ return RegisterSubclassesMeta._registry[class_name]
34
+
35
+ def __repr__(self) -> str:
36
+ return f"ObjectEntry(variable_name='{self.variable_name}', object={self.object!r}, description='{self.description}', coop_info={self.coop_info}, created_at={self.created_at}, edsl_class_name='{self.edsl_class_name}')"
37
+
38
+ def to_dict(self) -> Dict[str, Any]:
39
+ return {
40
+ "created_at": self.created_at,
41
+ "variable_name": self.variable_name,
42
+ "object": self.object.to_dict(),
43
+ "edsl_class_name": self.edsl_class_name,
44
+ "description": self.description,
45
+ "coop_info": self.coop_info,
46
+ }
47
+
48
+ @classmethod
49
+ def from_dict(cls, d: Dict[str, Any]) -> "ObjectEntry":
50
+ d["object"] = cls._get_class(d["object"]).from_dict(d["object"])
51
+ return cls(**d)
52
+
53
+ @property
54
+ def hash(self) -> str:
55
+ return str(hash(self.object))
56
+
57
+ def add_to_namespace(self) -> None:
58
+ globals()[self.variable_name] = self.object
59
+
60
+ @property
61
+ def coop_info(self) -> Optional[Dict[str, Any]]:
62
+ return self._coop_info
63
+
64
+ @coop_info.setter
65
+ def coop_info(self, coop_info: Optional[Dict[str, Any]]) -> None:
66
+ self._coop_info = coop_info
67
+
68
+ def view_on_coop(self) -> None:
69
+ if self.coop_info is None:
70
+ print("Object not pushed to coop")
71
+ return
72
+ url = self.coop_info["url"]
73
+ import webbrowser
74
+
75
+ webbrowser.open(url)
76
+
77
+ def push(self, refresh: bool = False) -> Dict[str, Any]:
78
+ if self.coop_info is None or refresh:
79
+ self.coop_info = self.object.push(description=self.description)
80
+ print(
81
+ f"Object {self.variable_name} pushed to coop with info: {self._coop_info}"
82
+ )
83
+ else:
84
+ print(
85
+ f"Object {self.variable_name} already pushed to coop with info: {self._coop_info}"
86
+ )
87
+
88
+
89
+ if __name__ == "__main__":
90
+ from edsl import QuestionFreeText
91
+
92
+ q = QuestionFreeText.example()
93
+
94
+ oe = ObjectEntry("q", q, "This is a question")
95
+ d = oe.to_dict()
96
+ new_oe = ObjectEntry.from_dict(d)
97
+ # print(oe.coop_info)
@@ -0,0 +1,110 @@
1
+ import hashlib
2
+ import time
3
+ from typing import Optional, Any, Dict, List
4
+
5
+
6
+ class ProofOfWork:
7
+ def __init__(
8
+ self,
9
+ input_data: Optional[Any] = None,
10
+ proof: Optional[Dict[int, List[Dict[str, Any]]]] = None,
11
+ ):
12
+ self.input_data = input_data
13
+ self.proof = proof or {}
14
+
15
+ def add_input_data(self, input_data: Any) -> None:
16
+ self.input_data = input_data
17
+
18
+ def to_dict(self) -> Dict[str, Any]:
19
+ return {"input_data": self.input_data, "proof": self.proof}
20
+
21
+ @classmethod
22
+ def from_dict(cls, data: Dict[str, Any]) -> "ProofOfWork":
23
+ return cls(data["input_data"], data["proof"])
24
+
25
+ def __repr__(self) -> str:
26
+ return f"ProofOfWork(input_data={self.input_data}, proof={self.proof})"
27
+
28
+ def to_hash(self, nonce: int) -> str:
29
+ """
30
+ Hash the input data combined with the nonce.
31
+
32
+ Returns:
33
+ str: The resulting hash.
34
+ """
35
+ hash_input = self.input_data + str(nonce)
36
+ return hashlib.md5(hash_input.encode()).hexdigest()
37
+
38
+ def verify_work(self) -> bool:
39
+ for difficulty in self.proof:
40
+ for proof in self.proof[difficulty]:
41
+ nonce = proof["nonce"]
42
+ hash_result = self.to_hash(nonce)
43
+ prefix = "0" * difficulty
44
+ if not hash_result.startswith(prefix):
45
+ return False
46
+ if hash_result != proof["hash"]:
47
+ return False
48
+ return True
49
+
50
+ def add_proof(self, difficulty: int, starting_nonce: Optional[int] = None) -> None:
51
+ """
52
+ Find a nonce that results in a hash with `difficulty` number of leading zeros.
53
+
54
+ Returns:
55
+ int, str: The nonce that solves the proof of work and the resulting hash.
56
+ """
57
+ # Convert the difficulty into a string of zeros for comparison
58
+ prefix = "0" * difficulty
59
+ if not starting_nonce:
60
+ import random
61
+
62
+ starting_nonce = random.randint(0, 1000000)
63
+ nonce = starting_nonce
64
+ start = time.time()
65
+ while True:
66
+ # Combine the input data with the nonce and hash it
67
+ hash_result = self.to_hash(nonce)
68
+
69
+ # Check if the hash meets the difficulty requirement
70
+ if hash_result.startswith(prefix):
71
+ cycles = nonce - starting_nonce
72
+ end = time.time()
73
+ if difficulty in self.proof:
74
+ self.proof[difficulty].append(
75
+ {
76
+ "nonce": nonce,
77
+ "hash": hash_result,
78
+ "time": end - start,
79
+ "cycles": cycles,
80
+ }
81
+ )
82
+ else:
83
+ self.proof[difficulty] = [
84
+ {
85
+ "nonce": nonce,
86
+ "hash": hash_result,
87
+ "time": end - start,
88
+ "cycles": cycles,
89
+ }
90
+ ]
91
+ return
92
+
93
+ nonce += 1
94
+
95
+
96
+ if __name__ == "__main__":
97
+ from edsl.study import ProofOfWork
98
+
99
+ p = ProofOfWork("hello world")
100
+ p.add_proof(3)
101
+ print(p)
102
+ p.add_proof(6)
103
+ print(p)
104
+
105
+ # Takes about a minute to run
106
+ p.add_proof(7)
107
+ print(p)
108
+
109
+ ok = p.verify_work()
110
+ print(ok)
edsl/study/SnapShot.py ADDED
@@ -0,0 +1,77 @@
1
+ from typing import Generator
2
+ import inspect
3
+
4
+
5
+ class SnapShot:
6
+ def __init__(self, namespace, exclude=None):
7
+ self.namespace = namespace
8
+
9
+ if exclude is None:
10
+ self.exclude = []
11
+ else:
12
+ self.exclude = exclude
13
+
14
+ self.edsl_objects = dict(self._get_edsl_objects(namespace=self.namespace))
15
+ self.edsl_classes = dict(self._get_edsl_classes(namespace=self.namespace))
16
+
17
+ def _all_object_keys(self):
18
+ return self.namespace.keys()
19
+
20
+ def __repr__(self):
21
+ return f"SnapShot(edsl_objects={self.edsl_objects}, edsl_classes={self.edsl_objects})"
22
+
23
+ def _get_edsl_classes(
24
+ self, namespace: dict
25
+ ) -> Generator[tuple[str, type], None, None]:
26
+ """Get all EDSL classes in the namespace.
27
+
28
+ :param namespace: The namespace to search for EDSL classes. The default is the global namespace.
29
+
30
+ >>> sn = SnapShot(namespace = {})
31
+ >>> sn.edsl_classes
32
+ {}
33
+
34
+ >>> from edsl.data.Cache import Cache
35
+ >>> sn = SnapShot(namespace = globals())
36
+ >>> sn.edsl_classes
37
+ {'Cache': <class 'edsl.data.Cache.Cache'>}
38
+ """
39
+ from edsl.Base import RegisterSubclassesMeta
40
+ from edsl import QuestionBase
41
+
42
+ all_edsl_objects = RegisterSubclassesMeta.get_registry()
43
+
44
+ for name, value in namespace.items():
45
+ if (
46
+ inspect.isclass(value)
47
+ and name in all_edsl_objects
48
+ and value != RegisterSubclassesMeta
49
+ ):
50
+ yield name, value
51
+ if inspect.isclass(value) and issubclass(value, QuestionBase):
52
+ yield name, value
53
+
54
+ def _get_edsl_objects(self, namespace) -> Generator[tuple[str, type], None, None]:
55
+ """Get all EDSL objects in the global namespace.
56
+
57
+ >>> sn = SnapShot(namespace = globals())
58
+ >>> sn.edsl_objects
59
+ {}
60
+
61
+ """
62
+ from edsl.Base import Base
63
+ from edsl.study.Study import Study
64
+
65
+ for name, value in namespace.items():
66
+ if (
67
+ hasattr(value, "to_dict")
68
+ and not inspect.isclass(value)
69
+ and value.__class__ not in [o.__class__ for o in self.exclude]
70
+ ):
71
+ yield name, value
72
+
73
+
74
+ if __name__ == "__main__":
75
+ import doctest
76
+
77
+ doctest.testmod(optionflags=doctest.ELLIPSIS)