Skip to content

Commit

Permalink
automated detection of updates to example files
Browse files Browse the repository at this point in the history
  • Loading branch information
quaquel committed Oct 18, 2024
1 parent f069c9e commit 0751622
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 55 deletions.
71 changes: 37 additions & 34 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,20 +296,33 @@



def write_example_md_file(agent_filename, model_filename, readme_filename, app_filename, md_filepath, template):
with open(agent_filename) as content_file:
agent_file = content_file.read()
with open(model_filename) as content_file:
model_file = content_file.read()
with open(readme_filename) as content_file:
readme_file = content_file.read()
with open(app_filename) as content_file:
app_file = content_file.read()

with open(md_filepath, "w") as fh:
content = template.substitute(
dict(agent_file=agent_file, model_file=model_file,
readme_file=readme_file, app_file=app_file)
)
fh.write(content)

def setup_examples_pages():
# create rst files for all examples
# create md files for all examples
# check what examples exist
examples_folder = osp.abspath(osp.join(HERE, "..", "examples"))

# fixme shift to walkdir
# we should have a single rst page for each subdirectory

basic_examples = [f.path for f in os.scandir(osp.join(examples_folder, "basic")) if f.is_dir() ]
advanced_examples = []
# advanced_examples = [f.path for f in os.scandir(osp.join(examples_folder, "advanced")) if f.is_dir()]
examples = basic_examples + advanced_examples

# get all existing rst files
# get all existing md files
md_files = glob.glob(os.path.join(HERE, "examples", "*.md"))
md_files = {os.path.basename(os.path.normpath(entry)) for entry in md_files}

Expand All @@ -327,33 +340,23 @@ def setup_examples_pages():
app_filename = os.path.join(example, "app.py")

md_filename = f"{base_name}.md"
examples_md.append((base_name, f"./examples/{base_name}"))

# fixme should be replaced with something based on timestep
# so if any(mymodelfiles) is newer then existing_md_filename
if md_filename not in md_files:
with open(agent_filename) as content_file:
agent_file = content_file.read()
with open(model_filename) as content_file:
model_file = content_file.read()
with open(readme_filename) as content_file:
readme_file = content_file.read()
with open(app_filename) as content_file:
app_file = content_file.read()

with open(os.path.join(HERE, "examples", md_filename), "w") as fh:
content = template.substitute(
dict(agent_file=agent_file, model_file=model_file,
readme_file=readme_file, app_file=app_file)
)
fh.write(content)
else:
md_files.remove(md_filename)

# these md files are outdated because the example has been removed
for entry in md_files:
fn = os.path.join(HERE, "examples", entry)
os.remove(fn)
examples_md.append(base_name)

# let's establish the latest update to the example files
timestamps = [osp.getmtime(fh) for fh in [agent_filename, model_filename, readme_filename, app_filename]]
latest_edit = max(timestamps)

md_filepath = os.path.join(HERE, "examples", md_filename)

# if the example is new or the existing example md file is older than the latest update, create a new file
if md_filename not in md_files or latest_edit > osp.getmtime(md_filepath):
write_example_md_file(agent_filename, model_filename, readme_filename, app_filename, md_filepath, template)


# check if any md files should be removed because the example is removed
outdated_md_files = md_files - {f"{entry}.md" for entry in examples_md}
for entry in outdated_md_files:
os.remove(os.path.join(HERE, "examples", entry) )

# create overview of examples.md
with open(os.path.join(HERE, "examples_overview_template.txt")) as fh:
Expand All @@ -362,7 +365,7 @@ def setup_examples_pages():
with open(os.path.join(HERE, "examples.md"), "w") as fh:
content = template.substitute(
dict(
examples="\n".join([f"{' '.join(base_name.split('_'))} <{file_path[2::]}>" for base_name, file_path in examples_md]),
examples="\n".join([f"{' '.join(base_name.split('_'))} </examples/<base_name>>" for base_name in examples_md]),
)
)
fh.write(content)
Expand Down
10 changes: 5 additions & 5 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
```{toctree}
:maxdepth: 1
boid flockers <examples/boid_flockers>
virus on network <examples/virus_on_network>
conways game of life <examples/conways_game_of_life>
schelling <examples/schelling>
boltzmann wealth model <examples/boltzmann_wealth_model>
boid flockers </examples/<base_name>>
virus on network </examples/<base_name>>
conways game of life </examples/<base_name>>
schelling </examples/<base_name>>
boltzmann wealth model </examples/<base_name>>
```
16 changes: 8 additions & 8 deletions docs/examples/conways_game_of_life.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ class Cell(Agent):
super().__init__(model)
self.x, self.y = pos
self.state = init_state
self._nextState = None
self._next_state = None

@property
def isAlive(self):
def is_alive(self):
return self.state == self.ALIVE

@property
Expand All @@ -72,20 +72,20 @@ class Cell(Agent):
"""
# Get the neighbors and apply the rules on whether to be alive or dead
# at the next tick.
live_neighbors = sum(neighbor.isAlive for neighbor in self.neighbors)
live_neighbors = sum(neighbor.is_alive for neighbor in self.neighbors)

# Assume nextState is unchanged, unless changed below.
self._nextState = self.state
if self.isAlive:
self._next_state = self.state
if self.is_alive:
if live_neighbors < 2 or live_neighbors > 3:
self._nextState = self.DEAD
self._next_state = self.DEAD
else:
if live_neighbors == 3:
self._nextState = self.ALIVE
self._next_state = self.ALIVE

def assume_state(self):
"""Set the state to the new computed state -- computed in step()."""
self.state = self._nextState
self.state = self._next_state

```

Expand Down
16 changes: 8 additions & 8 deletions examples/basic/conways_game_of_life/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def __init__(self, pos, model, init_state=DEAD):
super().__init__(model)
self.x, self.y = pos
self.state = init_state
self._nextState = None
self._next_state = None

@property
def isAlive(self):
def is_alive(self):
return self.state == self.ALIVE

@property
Expand All @@ -31,17 +31,17 @@ def determine_state(self):
"""
# Get the neighbors and apply the rules on whether to be alive or dead
# at the next tick.
live_neighbors = sum(neighbor.isAlive for neighbor in self.neighbors)
live_neighbors = sum(neighbor.is_alive for neighbor in self.neighbors)

# Assume nextState is unchanged, unless changed below.
self._nextState = self.state
if self.isAlive:
self._next_state = self.state
if self.is_alive:
if live_neighbors < 2 or live_neighbors > 3:
self._nextState = self.DEAD
self._next_state = self.DEAD
else:
if live_neighbors == 3:
self._nextState = self.ALIVE
self._next_state = self.ALIVE

def assume_state(self):
"""Set the state to the new computed state -- computed in step()."""
self.state = self._nextState
self.state = self._next_state

0 comments on commit 0751622

Please sign in to comment.