pybox-nlp 0.1.0__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.
pybox/__init__.py ADDED
@@ -0,0 +1,57 @@
1
+ """
2
+ pybox: Bundles 11 Python programs into one installable package with source inspection and export capabilities.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from typing import Dict, Tuple
8
+
9
+ from .core import Program
10
+
11
+ __version__ = "0.1.0"
12
+
13
+ PROGRAM_NAMES: Tuple[str, ...] = (
14
+ "one",
15
+ "two",
16
+ "three",
17
+ "four",
18
+ "five",
19
+ "six",
20
+ "seven",
21
+ "eight",
22
+ "nine",
23
+ "ten",
24
+ "eleven",
25
+ )
26
+
27
+ PROGRAMS: Dict[str, Program] = {name: Program(name) for name in PROGRAM_NAMES}
28
+
29
+ one: Program = PROGRAMS["one"]
30
+ two: Program = PROGRAMS["two"]
31
+ three: Program = PROGRAMS["three"]
32
+ four: Program = PROGRAMS["four"]
33
+ five: Program = PROGRAMS["five"]
34
+ six: Program = PROGRAMS["six"]
35
+ seven: Program = PROGRAMS["seven"]
36
+ eight: Program = PROGRAMS["eight"]
37
+ nine: Program = PROGRAMS["nine"]
38
+ ten: Program = PROGRAMS["ten"]
39
+ eleven: Program = PROGRAMS["eleven"]
40
+
41
+ __all__ = [
42
+ "Program",
43
+ "PROGRAM_NAMES",
44
+ "PROGRAMS",
45
+ "__version__",
46
+ "one",
47
+ "two",
48
+ "three",
49
+ "four",
50
+ "five",
51
+ "six",
52
+ "seven",
53
+ "eight",
54
+ "nine",
55
+ "ten",
56
+ "eleven",
57
+ ]
pybox/core.py ADDED
@@ -0,0 +1,163 @@
1
+ """
2
+ Core implementation of the PyBox Program abstraction.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import os
8
+ from pathlib import Path
9
+ import tempfile
10
+ from typing import Union
11
+
12
+
13
+ class Program:
14
+ """
15
+ Represents an individual bundled Python program within pybox.
16
+
17
+ Provides safe inspection of original source code without executing it,
18
+ as well as export functionality to save standalone .py files.
19
+ """
20
+
21
+ def __init__(self, identifier: str) -> None:
22
+ if not identifier or not isinstance(identifier, str):
23
+ raise ValueError(f"Program identifier must be a non-empty string, got: {identifier!r}")
24
+ self._identifier: str = identifier
25
+ self._filename: str = f"{identifier}.py"
26
+
27
+ @property
28
+ def identifier(self) -> str:
29
+ """The identifier of this program (e.g., 'one', 'two')."""
30
+ return self._identifier
31
+
32
+ @property
33
+ def filename(self) -> str:
34
+ """The default filename for this program (e.g., 'one.py')."""
35
+ return self._filename
36
+
37
+ def _read_source(self) -> str:
38
+ """
39
+ Locate and read the packaged source file using UTF-8 encoding.
40
+
41
+ Raises:
42
+ FileNotFoundError: If the source file cannot be found in the package.
43
+ OSError: If an error occurs while reading the file.
44
+ """
45
+ # Try importlib.resources (Python 3.9+)
46
+ try:
47
+ from importlib import resources
48
+ traversable = resources.files("pybox.programs").joinpath(self._filename)
49
+ # traversable.is_file() might raise AttributeError on older backports, so check safely
50
+ try:
51
+ is_file = traversable.is_file()
52
+ except AttributeError:
53
+ is_file = True
54
+
55
+ if is_file:
56
+ return traversable.read_text(encoding="utf-8")
57
+ except Exception:
58
+ pass
59
+
60
+ # Fallback to direct filesystem resolution relative to this file
61
+ fallback_path = Path(__file__).resolve().parent / "programs" / self._filename
62
+ if fallback_path.is_file():
63
+ return fallback_path.read_text(encoding="utf-8")
64
+
65
+ raise FileNotFoundError(
66
+ f"Packaged source file for program '{self._identifier}' "
67
+ f"('{self._filename}') was not found in pybox.programs."
68
+ )
69
+
70
+ @property
71
+ def code(self) -> str:
72
+ """The complete original source code of the program as a string."""
73
+ return self._read_source()
74
+
75
+ def __str__(self) -> str:
76
+ """Return the complete source code when the program is converted to str or printed."""
77
+ return self.code
78
+
79
+ def __repr__(self) -> str:
80
+ """Return a helpful developer representation."""
81
+ return f"Program({self._identifier!r})"
82
+
83
+ def save(
84
+ self,
85
+ destination: Union[str, Path, None] = None,
86
+ *,
87
+ overwrite: bool = False,
88
+ ) -> Path:
89
+ """
90
+ Export the program's source code into a standalone Python file.
91
+
92
+ Args:
93
+ destination: Optional file path or directory. Defaults to '<identifier>.py'
94
+ in the current working directory.
95
+ overwrite: If False (default), raises FileExistsError if the destination exists.
96
+ If True, safely replaces the destination file.
97
+
98
+ Returns:
99
+ The resolved Path to the saved Python file.
100
+
101
+ Raises:
102
+ FileExistsError: If destination exists and overwrite is False.
103
+ IsADirectoryError: If destination is an existing directory and no filename is given.
104
+ OSError: If an error occurs creating directories or writing the file.
105
+ """
106
+ source_code = self.code
107
+
108
+ if destination is None:
109
+ dest_path = Path.cwd() / self._filename
110
+ else:
111
+ dest_path = Path(destination)
112
+ dest_str = str(destination)
113
+ if dest_str.endswith(("/", "\\")) or (dest_path.is_dir() and not dest_path.suffix):
114
+ dest_path = dest_path / self._filename
115
+
116
+ # Refuse to overwrite directory
117
+ if dest_path.is_dir():
118
+ raise IsADirectoryError(
119
+ f"Destination path '{dest_path}' is an existing directory. "
120
+ "Cannot overwrite a directory with a file."
121
+ )
122
+
123
+ # Strict overwrite check
124
+ if dest_path.exists() and not overwrite:
125
+ raise FileExistsError(
126
+ f"Destination file '{dest_path}' already exists. "
127
+ "Pass 'overwrite=True' to allow overwriting."
128
+ )
129
+
130
+ parent_dir = dest_path.parent
131
+ try:
132
+ parent_dir.mkdir(parents=True, exist_ok=True)
133
+ except OSError as e:
134
+ raise OSError(f"Failed to create directory '{parent_dir}': {e}") from e
135
+
136
+ # Safe atomic write via temporary file in the same target directory
137
+ temp_file_path: Path | None = None
138
+ try:
139
+ with tempfile.NamedTemporaryFile(
140
+ mode="w",
141
+ encoding="utf-8",
142
+ dir=parent_dir,
143
+ delete=False,
144
+ prefix=f".tmp_{dest_path.stem}_",
145
+ suffix=".tmp",
146
+ ) as tmp:
147
+ temp_file_path = Path(tmp.name)
148
+ tmp.write(source_code)
149
+ tmp.flush()
150
+ os.fsync(tmp.fileno())
151
+
152
+ # Atomic replace
153
+ os.replace(temp_file_path, dest_path)
154
+ temp_file_path = None
155
+ except Exception as e:
156
+ if temp_file_path is not None and temp_file_path.exists():
157
+ try:
158
+ temp_file_path.unlink()
159
+ except OSError:
160
+ pass
161
+ raise OSError(f"Failed to export source code to '{dest_path}': {e}") from e
162
+
163
+ return dest_path.resolve()
@@ -0,0 +1,6 @@
1
+ """
2
+ Bundled Python program assets for pybox.
3
+
4
+ These modules are packaged source code resources.
5
+ They are read as text and are never imported or executed directly by pybox.
6
+ """
@@ -0,0 +1,27 @@
1
+ import nltk
2
+ from nltk.corpus import wordnet as wn
3
+ from nltk.wsd import lesk
4
+ # Download necessary resources
5
+ nltk.download('wordnet')
6
+ nltk.download('punkt')
7
+ nltk.download('omw-1.4')
8
+ def perform_wsd(sentences):
9
+ for sentence in sentences:
10
+ tokens = nltk.word_tokenize(sentence)
11
+ print(f"\nSentence: '{sentence}'")
12
+ for word in tokens:
13
+ synset = lesk(sentence, word)
14
+ if synset:
15
+ print(f"Word: {word}")
16
+ print(f"Sense: {synset.name()}")
17
+ print(f"Definition: {synset.definition()}")
18
+ else:
19
+ print(f"Word: {word}")
20
+ print("Sense: No disambiguation found")
21
+ # Example usage with three sentences
22
+ sentences = [
23
+ "The bank can guarantee deposits will eventually cover future tuition costs.",
24
+ "He went to the bank to deposit his money.",
25
+ "The river bank was full of blooming flowers."
26
+ ]
27
+ perform_wsd(sentences)
@@ -0,0 +1,36 @@
1
+ import nltk
2
+ from nltk.featstruct import FeatStruct
3
+ # Define selectional restrictions for a predicate
4
+ selectional_restrictions = {
5
+ 'eat': {'AGENT': {'ANIMATED': '+', 'HUMAN': '+'}, 'THEME': {'EDIBLE': '+'}},
6
+ 'sleep': {'SUBJECT': {'ANIMATED': '+', 'HUMAN': '+'}}
7
+ }
8
+ # Define a feature structure for an entity
9
+ entity_feature_structure = FeatStruct(
10
+ ANIMATED='+',
11
+ HUMAN='+'
12
+ )
13
+ # Define a feature structure for a food item
14
+ food_feature_structure = FeatStruct(
15
+ EDIBLE='+'
16
+ )
17
+ # Function to check if a feature structure satisfies selectional restrictions for a predicate
18
+ def satisfies_selectional_restrictions(predicate, argument_feature_structure):
19
+ if predicate in selectional_restrictions:
20
+ for arg_name, restrictions in selectional_restrictions[predicate].items():
21
+ for feature, value in restrictions.items():
22
+ if value == '+':
23
+ if feature not in argument_feature_structure or argument_feature_structure[feature] != '+':
24
+ return False
25
+ elif value == '-':
26
+ if feature in argument_feature_structure and argument_feature_structure[feature] == '+':
27
+ return False
28
+ return True
29
+ # Example usage
30
+ predicate = 'eat'
31
+ agent = entity_feature_structure
32
+ theme = food_feature_structure
33
+ if satisfies_selectional_restrictions(predicate, agent) and satisfies_selectional_restrictions(predicate, theme):
34
+ print(f"The feature structures satisfy selectional restrictions for the predicate '{predicate}'.")
35
+ else:
36
+ print(f"The feature structures do not satisfy selectional restrictions for the predicate '{predicate}'.")
pybox/programs/five.py ADDED
@@ -0,0 +1,30 @@
1
+ import nltk
2
+ from nltk.corpus import treebank
3
+ # Download necessary resources
4
+ nltk.download('treebank')
5
+ nltk.download('punkt')
6
+ def analyze_sentential_components():
7
+ # Access the parsed sentences in the Penn Treebank
8
+ parsed_sentences = treebank.parsed_sents()
9
+ # Analyze a sample sentence
10
+ sample_sentence = parsed_sentences[0]
11
+
12
+ print("Sample sentence:")
13
+ print(" ".join(sample_sentence.leaves()))
14
+ print("\nParse tree:")
15
+ print(sample_sentence)
16
+
17
+ # Find and print specific components
18
+ print("\nNoun Phrases (NP):")
19
+ for subtree in sample_sentence.subtrees(filter=lambda t: t.label() == 'NP'):
20
+ print(" ".join(subtree.leaves()))
21
+
22
+ print("\nVerb Phrases (VP):")
23
+ for subtree in sample_sentence.subtrees(filter=lambda t: t.label() == 'VP'):
24
+ print(" ".join(subtree.leaves()))
25
+
26
+ print("\nPrepositional Phrases (PP):")
27
+ for subtree in sample_sentence.subtrees(filter=lambda t: t.label() == 'PP'):
28
+ print(" ".join(subtree.leaves()))
29
+ # Example usage
30
+ analyze_sentential_components()
pybox/programs/four.py ADDED
@@ -0,0 +1,40 @@
1
+ import nltk
2
+ from collections import Counter, defaultdict
3
+ from nltk.util import ngrams
4
+ from nltk.tokenize import word_tokenize
5
+ import math
6
+ # Download necessary resources
7
+ nltk.download('punkt')
8
+ def generate_ngrams(text, n):
9
+ # Tokenize the text
10
+ tokens = word_tokenize(text.lower())
11
+
12
+ # Generate n-grams
13
+ n_grams = list(ngrams(tokens, n))
14
+ return n_grams
15
+ def calculate_ngram_probabilities(ngrams):
16
+ # Calculate frequencies of n-grams and (n-1)-grams
17
+ ngram_freq = Counter(ngrams)
18
+ n_minus_1_gram_freq = Counter([ngram[:-1] for ngram in ngrams])
19
+
20
+ # Calculate probabilities
21
+ ngram_probabilities = defaultdict(float)
22
+ for ngram in ngram_freq:
23
+ n_minus_1_gram = ngram[:-1]
24
+ ngram_probabilities[ngram] = ngram_freq[ngram] / n_minus_1_gram_freq[n_minus_1_gram]
25
+
26
+ return ngram_probabilities
27
+ def generate_bigram_language_model(text):
28
+ # Generate bigrams (2-grams)
29
+ bigrams = generate_ngrams(text, 2)
30
+
31
+ # Calculate bigram probabilities
32
+ bigram_probabilities = calculate_ngram_probabilities(bigrams)
33
+
34
+ return bigram_probabilities
35
+ # Example usage
36
+ text = "This is a simple example sentence for demonstrating a bigram language model. This example is simple."
37
+ bigram_model = generate_bigram_language_model(text)
38
+ # Print bigram probabilities
39
+ for bigram, prob in bigram_model.items():
40
+ print(f"Bigram: {bigram}, Probability: {prob:.4f}")
pybox/programs/nine.py ADDED
@@ -0,0 +1,41 @@
1
+ import nltk
2
+ from nltk.corpus import wordnet as wn
3
+ from nltk.tokenize import word_tokenize
4
+ from nltk import pos_tag
5
+ # Download required nltk data
6
+ nltk.download('punkt')
7
+ nltk.download('averaged_perceptron_tagger')
8
+ nltk.download('wordnet')
9
+ # Define a simple feature structure
10
+ class FeatureStructure:
11
+ def __init__(self, word, pos, synsets):
12
+ self.word = word
13
+ self.pos = pos
14
+ self.synsets = synsets
15
+ def __repr__(self):
16
+ return f"FeatureStructure(word='{self.word}', pos='{self.pos}', synsets={self.synsets})"
17
+ # Function to identify semantic roles
18
+ def identify_semantic_roles(sentence):
19
+ tokens = word_tokenize(sentence)
20
+ tagged_tokens = pos_tag(tokens)
21
+ # Create feature structures for each word
22
+ features = []
23
+ for word, pos in tagged_tokens:
24
+ synsets = wn.synsets(word)
25
+ features.append(FeatureStructure(word, pos, synsets))
26
+ # Simple semantic role assignment based on POS tags
27
+ roles = []
28
+ for feature in features:
29
+ if feature.pos.startswith('VB'):
30
+ roles.append((feature.word, 'Action'))
31
+ elif feature.pos.startswith('NN'):
32
+ # This is a simplistic approach; normally semantic roles are determined
33
+ # based on syntactic structure and more complex rules
34
+ roles.append((feature.word, 'Agent' if 'nsubj' in pos else 'Patient'))
35
+ else:
36
+ roles.append((feature.word, 'None'))
37
+ return roles
38
+ # Example usage
39
+ sentence = "The cat chased the mouse"
40
+ roles = identify_semantic_roles(sentence)
41
+ print(roles)
pybox/programs/one.py ADDED
@@ -0,0 +1,27 @@
1
+ def count_words(sentence):
2
+ # Convert the sentence to lower case to make the counting case-insensitive
3
+ sentence = sentence.lower()
4
+
5
+ # Remove punctuation from the sentence
6
+ import string
7
+ translator = str.maketrans('', '', string.punctuation)
8
+ sentence = sentence.translate(translator)
9
+
10
+ # Split the sentence into words
11
+ words = sentence.split()
12
+
13
+ # Create a dictionary to count the words
14
+ word_count = {}
15
+
16
+ for word in words:
17
+ if word in word_count:
18
+ word_count[word] += 1
19
+ else:
20
+ word_count[word] = 1
21
+
22
+ return word_count
23
+ # Example usage
24
+ sentence = "This is a test. This test is only a test."
25
+ word_count = count_words(sentence)
26
+ for word, count in word_count.items():
27
+ print(f"{word}: {count}")
@@ -0,0 +1,37 @@
1
+ import nltk
2
+ from nltk import CFG
3
+ from nltk.parse.generate import generate
4
+ # Define a small fragment of English using CFG
5
+ cfg_grammar = CFG.fromstring("""
6
+ S -> NP VP
7
+ NP -> Det N | Det Adj N | NP PP
8
+ VP -> V NP | VP PP
9
+ PP -> P NP
10
+ Det -> 'the' | 'a'
11
+ N -> 'dog' | 'cat' | 'park' | 'telescope'
12
+ Adj -> 'big' | 'small'
13
+ V -> 'saw' | 'chased'
14
+ P -> 'in' | 'with'
15
+ """)
16
+ # Initialize the parser
17
+ parser = nltk.ChartParser(cfg_grammar)
18
+ # Define some test sentences
19
+ test_sentences = [
20
+ "the dog saw a cat",
21
+ "a big dog chased the small cat",
22
+ "the cat saw the dog in the park",
23
+ "the dog saw the cat with the telescope"
24
+ ]
25
+ # Parse and display the test sentences
26
+ for sentence in test_sentences:
27
+ print(f"Parsing sentence: '{sentence}'")
28
+ tokens = sentence.split()
29
+ for tree in parser.parse(tokens):
30
+ print(tree)
31
+ # Save the parse tree as text
32
+ with open("parse_tree.txt", "a") as f:
33
+ f.write(str(tree) + "\n")
34
+ # Generate some sentences from the CFG (optional)
35
+ print("\nGenerated sentences from the CFG:")
36
+ for sentence in generate(cfg_grammar, n=10):
37
+ print(' '.join(sentence))
pybox/programs/six.py ADDED
@@ -0,0 +1,59 @@
1
+ import nltk
2
+ from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
3
+ from nltk.corpus import stopwords
4
+ from nltk.stem import PorterStemmer
5
+ from nltk.stem import WordNetLemmatizer
6
+ from nltk.tokenize import word_tokenize
7
+ # Download necessary resources
8
+ nltk.download('punkt')
9
+ nltk.download('stopwords')
10
+ nltk.download('wordnet')
11
+ def preprocess_text(text):
12
+ # Tokenize the text
13
+ tokens = word_tokenize(text.lower())
14
+
15
+ # Remove stopwords
16
+ stop_words = set(stopwords.words('english'))
17
+ filtered_tokens = [token for token in tokens if token.isalnum() and token not in stop_words]
18
+
19
+ return filtered_tokens
20
+ def stem_tokens(tokens):
21
+ # Initialize the stemmer
22
+ stemmer = PorterStemmer()
23
+ stemmed_tokens = [stemmer.stem(token) for token in tokens]
24
+ return stemmed_tokens
25
+ def lemmatize_tokens(tokens):
26
+ # Initialize the lemmatizer
27
+ lemmatizer = WordNetLemmatizer()
28
+ lemmatized_tokens = [lemmatizer.lemmatize(token) for token in tokens]
29
+ return lemmatized_tokens
30
+ def extract_features(texts):
31
+ # Preprocess the text
32
+ preprocessed_texts = [" ".join(preprocess_text(text)) for text in texts]
33
+
34
+ # Extract features using CountVectorizer
35
+ count_vectorizer = CountVectorizer()
36
+ count_features = count_vectorizer.fit_transform(preprocessed_texts)
37
+
38
+ # Extract features using TfidfVectorizer
39
+ tfidf_vectorizer = TfidfVectorizer()
40
+ tfidf_features = tfidf_vectorizer.fit_transform(preprocessed_texts)
41
+
42
+ return count_features, tfidf_features, count_vectorizer, tfidf_vectorizer
43
+ # Example usage
44
+ texts = [
45
+ "This is a simple example sentence for demonstrating feature extraction.",
46
+ "Feature extraction involves various techniques like tokenization, stemming, and lemmatization.",
47
+ "Text preprocessing is essential for text analysis and machine learning."
48
+ ]
49
+ # Extract features
50
+ count_features, tfidf_features, count_vectorizer, tfidf_vectorizer = extract_features(texts)
51
+ # Display the feature names and feature vectors
52
+ print("CountVectorizer Feature Names:")
53
+ print(count_vectorizer.get_feature_names_out())
54
+ print("\nCountVectorizer Feature Vectors:")
55
+ print(count_features.toarray())
56
+ print("\nTfidfVectorizer Feature Names:")
57
+ print(tfidf_vectorizer.get_feature_names_out())
58
+ print("\nTfidfVectorizer Feature Vectors:")
59
+ print(tfidf_features.toarray())
pybox/programs/ten.py ADDED
@@ -0,0 +1,29 @@
1
+ import re
2
+ def translate_formula(formula):
3
+ formula = formula.strip()
4
+ # Universal quantifier
5
+ if formula.startswith("forall"):
6
+ match = re.match(r"forall\s+(\w+)\s*\((\w+)\((\w+)\)\s*->\s*(\w+)\((\w+)\)\)", formula)
7
+ if match:
8
+ var, pred1, _, pred2, _ = match.groups()
9
+ return f"Every {pred1.lower()} is {pred2.lower()}."
10
+ # Existential quantifier with AND
11
+ if formula.startswith("exists"):
12
+ match = re.match(
13
+ r"exists\s+(\w+)\s*\((\w+)\((\w+)\)\s*&\s*(\w+)\((\w+)\)\)",
14
+ formula
15
+ )
16
+ if match:
17
+ var, pred1, _, pred2, _ = match.groups()
18
+ return f"There exists a {pred1.lower()} who is {pred2.lower()}."
19
+ return "Formula format not recognized."
20
+ # Test formulas
21
+ formulas = [
22
+ "forall x (Dog(x) -> Animal(x))",
23
+ "forall x (Human(x) -> Mortal(x))",
24
+ "exists x (Student(x) & Smart(x))"
25
+ ]
26
+ for formula in formulas:
27
+ print("Predicate Formula:", formula)
28
+ print("Translation:", translate_formula(formula))
29
+ print()
@@ -0,0 +1,30 @@
1
+ import nltk
2
+ from nltk.corpus import stopwords
3
+ from nltk.tokenize import word_tokenize
4
+ from nltk.stem import WordNetLemmatizer
5
+ # Download necessary resources
6
+ nltk.download('punkt')
7
+ nltk.download('wordnet')
8
+ nltk.download('stopwords')
9
+ def morphological_analysis_and_remove_stopwords(sentence):
10
+ # Tokenize the sentence
11
+ words = word_tokenize(sentence)
12
+
13
+ # Initialize the lemmatizer
14
+ lemmatizer = WordNetLemmatizer()
15
+
16
+ # Perform lemmatization
17
+ lemmatized_words = [lemmatizer.lemmatize(word) for word in words]
18
+
19
+ # Retrieve the list of stopwords
20
+ stop_words = set(stopwords.words('english'))
21
+
22
+ # Remove stopwords
23
+ filtered_words = [word for word in lemmatized_words if word.lower() not in stop_words]
24
+
25
+ return filtered_words
26
+ # Example usage
27
+ sentence = "This is a simple example sentence for demonstrating morphological analysis and removing stopwords."
28
+ filtered_words = morphological_analysis_and_remove_stopwords(sentence)
29
+ print("Original Sentence:", sentence)
30
+ print("Filtered Words:", filtered_words)
pybox/programs/two.py ADDED
@@ -0,0 +1,23 @@
1
+ import re
2
+ def demonstrate_regex_operations(sentence):
3
+ # Example usage of re.match()
4
+ # Match checks for a pattern only at the beginning of the string
5
+ match_result = re.match(r'\w+', sentence)
6
+ if match_result:
7
+ print(f"Match: '{match_result.group()}' found at the beginning of the sentence")
8
+ else:
9
+ print("No match found at the beginning of the sentence")
10
+ # Example usage of re.search()
11
+ # Search checks for a pattern anywhere in the string
12
+ search_result = re.search(r'\bis\b', sentence)
13
+ if search_result:
14
+ print(f"Search: '{search_result.group()}' found in the sentence")
15
+ else:
16
+ print("No search result found in the sentence")
17
+ # Example usage of re.sub()
18
+ # Sub replaces occurrences of the pattern with the replacement string
19
+ modified_sentence = re.sub(r'\bis\b', 'was', sentence)
20
+ print(f"Sub: Modified sentence: '{modified_sentence}'")
21
+ # Example usage
22
+ sentence = "This is a test. This test is only a test."
23
+ demonstrate_regex_operations(sentence)
pybox/py.typed ADDED
@@ -0,0 +1 @@
1
+ # Marker file for PEP 561. Pybox uses inline types.
@@ -0,0 +1,357 @@
1
+ Metadata-Version: 2.4
2
+ Name: pybox-nlp
3
+ Version: 0.1.0
4
+ Summary: A production-ready Python library bundling 11 standalone NLP programs with source inspection and export capabilities.
5
+ Author: PyBox Maintainers
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/pybox-dev/pybox
8
+ Project-URL: Repository, https://github.com/pybox-dev/pybox
9
+ Project-URL: Issues, https://github.com/pybox-dev/pybox/issues
10
+ Project-URL: Changelog, https://github.com/pybox-dev/pybox/blob/main/CHANGELOG.md
11
+ Keywords: pybox,bundle,programs,source-code,exporter
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Typing :: Typed
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
29
+ Requires-Dist: build>=0.10.0; extra == "dev"
30
+ Requires-Dist: twine>=4.0.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # PyBox (`pybox`)
34
+
35
+ A production-ready Python library bundling 11 standalone Python programs into one installable package. Access each program via intuitive top-level attributes, inspect its original source code directly, and safely export it into standalone `.py` scripts.
36
+
37
+ [![PyPI Version](https://img.shields.io/badge/pypi-v0.1.0-blue.svg)](https://pypi.org/project/pybox/)
38
+ [![Python Versions](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/pybox/)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
40
+
41
+ ---
42
+
43
+ ## Table of Contents
44
+
45
+ - [Overview](#overview)
46
+ - [Key Distinction: Inspection vs. Execution](#key-distinction-inspection-vs-execution)
47
+ - [Installation](#installation)
48
+ - [Quick Start](#quick-start)
49
+ - [Program Identifiers](#program-identifiers)
50
+ - [Features and Usage](#features-and-usage)
51
+ - [1. Viewing Source Code](#1-viewing-source-code)
52
+ - [2. Accessing Raw Source String](#2-accessing-raw-source-string)
53
+ - [3. Exporting to Standalone Files](#3-exporting-to-standalone-files)
54
+ - [4. Custom Export Destinations](#4-custom-export-destinations)
55
+ - [5. Overwrite Protection](#5-overwrite-protection)
56
+ - [6. Developer Representation](#6-developer-representation)
57
+ - [Individual Program Dependencies](#individual-program-dependencies)
58
+ - [Safety and Security](#safety-and-security)
59
+ - [Compatibility](#compatibility)
60
+ - [Development and Testing](#development-and-testing)
61
+ - [Publishing to PyPI](#publishing-to-pypi)
62
+ - [Contributing](#contributing)
63
+ - [License](#license)
64
+
65
+ ---
66
+
67
+ ## Overview
68
+
69
+ `pybox` bundles 11 standalone Python programs into a unified package. Instead of copying and pasting code snippets, developers can:
70
+ - Import `pybox` and inspect any bundled program's complete source code in Python interactive shells, logging, or scripts.
71
+ - Export bundled programs into standalone `.py` files on demand with atomic write safety and directory creation.
72
+ - Keep source code intact: all comments, imports, functions, classes, and logic are preserved identically.
73
+
74
+ ---
75
+
76
+ ## Key Distinction: Inspection vs. Execution
77
+
78
+ > [!IMPORTANT]
79
+ > **`pybox` does NOT execute bundled programs when you import the library, inspect their source code, or export them to disk.**
80
+
81
+ `pybox` acts as a curated code distribution and extraction engine. When you access `pybox.one` or invoke `pybox.one.save()`, `pybox` reads the packaged source assets as UTF-8 text.
82
+
83
+ To **run** an exported program after saving it, execute it in Python directly using your terminal:
84
+
85
+ ```bash
86
+ python one.py
87
+ ```
88
+
89
+ Ensure any third-party dependencies required by that specific program are installed in your Python environment before running it.
90
+
91
+ ---
92
+
93
+ ## Installation
94
+
95
+ ### From PyPI
96
+
97
+ ```bash
98
+ python -m pip install pybox
99
+ ```
100
+
101
+ ### From Local Source (Editable Mode)
102
+
103
+ ```bash
104
+ git clone https://github.com/pybox-dev/pybox.git
105
+ cd pybox
106
+ python -m pip install -e ".[dev]"
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Quick Start
112
+
113
+ ```python
114
+ import pybox
115
+
116
+ # 1. Print the complete source code of a program
117
+ print(pybox.one)
118
+
119
+ # 2. Get the raw source code string
120
+ code = pybox.two.code
121
+ print(f"Total lines: {len(code.splitlines())}")
122
+
123
+ # 3. Export to a standalone Python script
124
+ saved_path = pybox.one.save()
125
+ print(f"Exported to: {saved_path}")
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Program Identifiers & Bundled Programs
131
+
132
+ The package exposes 11 curated NLP programs as attributes on the top-level `pybox` module:
133
+
134
+ | Attribute | Default Export | Description | Dependencies |
135
+ | :--- | :--- | :--- | :--- |
136
+ | `pybox.one` | `one.py` | **Word Frequency & Punctuation Stripper**: Counts word frequencies after stripping punctuation and normalizing case. | Standard Library (`string`) |
137
+ | `pybox.two` | `two.py` | **Regex Demonstrator**: Demonstrates pattern matching, searching, extracting, and substitution using regex. | Standard Library (`re`) |
138
+ | `pybox.three` | `three.py` | **Morphological Analyzer & Stopwords Filter**: Lemmatizes tokens and filters English stopwords. | `nltk` |
139
+ | `pybox.four` | `four.py` | **N-Gram Generator & Probability Calculator**: Generates N-grams and calculates sentence probabilities. | `nltk` |
140
+ | `pybox.five` | `five.py` | **Penn Treebank Component Analyzer**: Inspects and parses sentential constituents using Penn Treebank trees. | `nltk` |
141
+ | `pybox.six` | `six.py` | **Vectorization & Feature Extraction Pipeline**: Preprocesses text with stemming/lemmatization and extracts Count/TF-IDF vectors. | `nltk`, `scikit-learn` |
142
+ | `pybox.seven` | `seven.py` | **Context-Free Grammar (CFG) Generator**: Generates sentences adhering to formal phrase structure grammar rules. | `nltk` |
143
+ | `pybox.eight` | `eight.py` | **Word Sense Disambiguation (WSD)**: Resolves word senses in context using the Lesk algorithm and WordNet. | `nltk` |
144
+ | `pybox.nine` | `nine.py` | **Semantic Role & Feature Structure Identifier**: Maps syntactic tokens and POS tags to thematic roles and feature structures. | `nltk` |
145
+ | `pybox.ten` | `ten.py` | **First-Order Logic (FOL) Translator**: Translates quantified formal logic expressions into natural language sentences. | Standard Library (`re`) |
146
+ | `pybox.eleven` | `eleven.py` | **Selectional Restrictions & Anomaly Checker**: Evaluates semantic predicate-argument compatibility using feature structures. | `nltk` |
147
+
148
+ You can iterate over all programs programmatically:
149
+
150
+ ```python
151
+ import pybox
152
+
153
+ for name, prog in pybox.PROGRAMS.items():
154
+ print(f"Loaded {prog.identifier}: {prog.filename}")
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Features and Usage
160
+
161
+ ### 1. Viewing Source Code
162
+
163
+ Converting any program object to `str` (or passing it to `print()`) renders its complete source code:
164
+
165
+ ```python
166
+ import pybox
167
+
168
+ print(pybox.one)
169
+ ```
170
+
171
+ ### 2. Accessing Raw Source String
172
+
173
+ Access the `.code` property on any program object to obtain the unmodified source code as a Python `str`:
174
+
175
+ ```python
176
+ import pybox
177
+
178
+ source = pybox.one.code
179
+ assert isinstance(source, str)
180
+ print(f"Total lines: {len(source.splitlines())}")
181
+ ```
182
+
183
+ ### 3. Exporting to Standalone Files
184
+
185
+ Call `.save()` without arguments to export the program to the current working directory under its default filename (e.g., `one.py`):
186
+
187
+ ```python
188
+ import pybox
189
+
190
+ path = pybox.one.save()
191
+ print(path) # /path/to/cwd/one.py
192
+ ```
193
+
194
+ ### 4. Custom Export Destinations
195
+
196
+ Specify a custom file name or path. If intermediate parent directories do not exist, `pybox` creates them automatically:
197
+
198
+ ```python
199
+ import pybox
200
+
201
+ # Export to a custom filename in the current directory
202
+ pybox.one.save("my_program.py")
203
+
204
+ # Export to a nested subdirectory (directories created automatically)
205
+ pybox.two.save("exports/tools/run_two.py")
206
+
207
+ # Export into an existing directory (uses default filename 'three.py')
208
+ pybox.three.save("exports/")
209
+ ```
210
+
211
+ ### 5. Overwrite Protection
212
+
213
+ To protect existing scripts from accidental loss, `pybox` **refuses to overwrite existing files by default**:
214
+
215
+ ```python
216
+ import pybox
217
+
218
+ # First export succeeds
219
+ pybox.one.save("script.py")
220
+
221
+ # Second export raises FileExistsError
222
+ try:
223
+ pybox.one.save("script.py")
224
+ except FileExistsError as e:
225
+ print("Caught expected protection error:", e)
226
+
227
+ # Explicitly authorize overwriting
228
+ pybox.one.save("script.py", overwrite=True)
229
+ ```
230
+
231
+ Export writes use atomic temporary file replacement (`os.replace`) to ensure a partially written file is never left on disk in the event of an interruption.
232
+
233
+ ### 6. Developer Representation
234
+
235
+ In interactive environments, `repr()` provides clear identification:
236
+
237
+ ```python
238
+ import pybox
239
+
240
+ print(repr(pybox.one))
241
+ # Output: Program('one')
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Individual Program Dependencies
247
+
248
+ `pybox` itself has **zero runtime third-party dependencies**. It relies strictly on Python standard library modules (`pathlib`, `tempfile`, `os`, `importlib.resources`).
249
+
250
+ Exporting a program writes its standalone source code to disk. Before executing the exported scripts, install any required third-party libraries:
251
+
252
+ ```bash
253
+ # To run all exported NLP programs:
254
+ pip install nltk scikit-learn
255
+ ```
256
+
257
+ | Program | Standard Library Modules | External Dependencies | NLTK Corpora Required (Auto-downloaded on run) |
258
+ | :--- | :--- | :--- | :--- |
259
+ | `one.py` | `string` | None | None |
260
+ | `two.py` | `re` | None | None |
261
+ | `three.py` | Standard library | `nltk` | `punkt`, `wordnet`, `stopwords` |
262
+ | `four.py` | `collections`, `math` | `nltk` | `punkt` |
263
+ | `five.py` | Standard library | `nltk` | `treebank`, `punkt` |
264
+ | `six.py` | Standard library | `nltk`, `scikit-learn` | `punkt`, `stopwords`, `wordnet` |
265
+ | `seven.py` | Standard library | `nltk` | None |
266
+ | `eight.py` | Standard library | `nltk` | `wordnet`, `punkt`, `omw-1.4` |
267
+ | `nine.py` | Standard library | `nltk` | `punkt`, `averaged_perceptron_tagger`, `wordnet` |
268
+ | `ten.py` | `re` | None | None |
269
+ | `eleven.py` | Standard library | `nltk` | None |
270
+
271
+ ---
272
+
273
+ ## Safety and Security
274
+
275
+ - **No Execution on Import**: Bundled code is never imported, evaluated, or executed by `pybox`.
276
+ - **Atomic Writes**: Export files are written to a temporary file before being atomically moved into destination path.
277
+ - **Directory Traversal & Overwrite Guards**: Prevents accidental directory replacement and unintended data destruction.
278
+ - **Zero Secrets**: Bundled programs must never contain API tokens, passwords, or personal credentials.
279
+
280
+ ---
281
+
282
+ ## Compatibility
283
+
284
+ - **Python**: `>= 3.8` (fully tested across Python 3.8, 3.9, 3.10, 3.11, 3.12, and 3.13)
285
+ - **Platforms**: Windows, macOS, and Linux
286
+ - **Packaging Standard**: PEP 517 / PEP 518 / PEP 621 compliant build
287
+
288
+ ---
289
+
290
+ ## Development and Testing
291
+
292
+ ### Setup Environment
293
+
294
+ ```powershell
295
+ # Windows PowerShell
296
+ python -m venv .venv
297
+ .\.venv\Scripts\Activate.ps1
298
+ python -m pip install --upgrade pip
299
+ python -m pip install -e ".[dev]"
300
+ ```
301
+
302
+ ```bash
303
+ # Linux / macOS
304
+ python3 -m venv .venv
305
+ source .venv/bin/activate
306
+ python -m pip install --upgrade pip
307
+ python -m pip install -e ".[dev]"
308
+ ```
309
+
310
+ ### Run Tests
311
+
312
+ ```bash
313
+ pytest -v
314
+ ```
315
+
316
+ ### Build Distribution Artifacts
317
+
318
+ ```bash
319
+ python -m build
320
+ python -m twine check dist/*
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Publishing to PyPI
326
+
327
+ > [!NOTE]
328
+ > PyPI distribution names are globally unique. Before publishing, verify name availability on [PyPI](https://pypi.org/). If `pybox` is already registered, set an alternative name (such as `pybox-lib` or `pybox-bundle`) in `pyproject.toml`.
329
+
330
+ ### Option A: PyPI Trusted Publishing (Recommended)
331
+
332
+ 1. Connect your GitHub repository to PyPI at [PyPI Manage Account > Publishing](https://pypi.org/manage/account/publishing/).
333
+ 2. Push a release tag or trigger the included `.github/workflows/publish.yml` workflow.
334
+ 3. GitHub Actions authenticates via short-lived OIDC tokens without requiring static API keys.
335
+
336
+ ### Option B: Manual Publishing via Twine
337
+
338
+ ```bash
339
+ python -m twine upload --repository testpypi dist/* # Test on TestPyPI first
340
+ python -m twine upload dist/* # Publish to production PyPI
341
+ ```
342
+
343
+ ---
344
+
345
+ ## Contributing
346
+
347
+ 1. Fork the repository.
348
+ 2. Create a feature branch (`git checkout -b feature/my-feature`).
349
+ 3. Commit your changes (`git commit -m "Add feature"`).
350
+ 4. Run the test suite (`pytest -v`).
351
+ 5. Open a Pull Request.
352
+
353
+ ---
354
+
355
+ ## License
356
+
357
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,20 @@
1
+ pybox/__init__.py,sha256=pa2TYgUk_K5hjAL5Jp-wEHPU4buT7JMsHkgylL3kNPk,1073
2
+ pybox/core.py,sha256=spTNJVfcTWty1dPfbKtAj6fYc9fBhXZk4hWweRCH2Xg,5785
3
+ pybox/py.typed,sha256=I4fsYtPBETPV1VDKpOCZp2k9qCuc2zWbrnA9pg1evyk,52
4
+ pybox/programs/__init__.py,sha256=vhZnSCIgwO5LMmsJ-5zb0mT8f--kfZY6w9gbkureCcU,176
5
+ pybox/programs/eight.py,sha256=22LuJzc5twkmfCLXfaeWGfC0yCkWw6oAOopHJ2D2A8c,941
6
+ pybox/programs/eleven.py,sha256=_89admk5a6myq_mwtx5Yid4qVd-3UaShxvHRNFAlx5k,1654
7
+ pybox/programs/five.py,sha256=quVgZ1finrsD4hVXkAhjWSeC83I-clRelXrPT28WUes,1041
8
+ pybox/programs/four.py,sha256=n_oEPHDwC2WNuJoWoK8x9D0nckX0tBnaX9yyA_jW4VQ,1389
9
+ pybox/programs/nine.py,sha256=fBjfbd3XAPuVBArZMJIEQeS41lvy7Q6F58r099wrOF0,1545
10
+ pybox/programs/one.py,sha256=hxJk0MSob9uGkuKv51wgq5RrX0lgr0yLx8Rm37XYcZE,771
11
+ pybox/programs/seven.py,sha256=DU78Z1aFxugQSuFTuL8pJcSVPkMjBJhS2rpx6DTFFa4,1150
12
+ pybox/programs/six.py,sha256=Mfp7fxA7LW6R6guk60-0JbIvwgFqOAnhnK1mFp2KziQ,2316
13
+ pybox/programs/ten.py,sha256=hDSlEB--JQGJopOo3hC-7JVj0xFmDIXIxUP1sBXlyp0,1043
14
+ pybox/programs/three.py,sha256=l6FSS0OJdlvPnsdUS8iUxq03KCshaABDS_XePUO-ayA,1031
15
+ pybox/programs/two.py,sha256=G2hsReL4qiAWD2F7oNssd2vCMjVaLIaSlY92lnRmuPw,1028
16
+ pybox_nlp-0.1.0.dist-info/licenses/LICENSE,sha256=HyKa_6xXkhmQKyj4ymCYD64vEu7jzRafTT-eIPlPOy0,1087
17
+ pybox_nlp-0.1.0.dist-info/METADATA,sha256=Ohr0ftWe4aVEbvnb31ppAgNfRjQLJua0YlbPAtbe4Sc,12518
18
+ pybox_nlp-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
19
+ pybox_nlp-0.1.0.dist-info/top_level.txt,sha256=jyiglQVZaayV6LzbWjl4RERgL92aJ9-L1WRp2OUTJbg,6
20
+ pybox_nlp-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PyBox Authors and Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ pybox